From 876c5caff51d144c72c134960581a5f63b16cda8 Mon Sep 17 00:00:00 2001 From: David Peer Date: Sun, 11 Sep 2022 18:26:56 +0200 Subject: [PATCH 01/25] First tests with new clock_info --- apps/bwclk/app.js | 597 +++++++++------------------------------------- 1 file changed, 119 insertions(+), 478 deletions(-) diff --git a/apps/bwclk/app.js b/apps/bwclk/app.js index cd1979e98..15de3f870 100644 --- a/apps/bwclk/app.js +++ b/apps/bwclk/app.js @@ -3,13 +3,12 @@ */ const locale = require('locale'); const storage = require('Storage'); +// const clock_info = require("clock_info"); /************ * Statics */ const SETTINGS_FILE = "bwclk.setting.json"; -const TIMER_IDX = "bwclk_timer"; -const TIMER_AGENDA_IDX = "bwclk_agenda"; const W = g.getWidth(); const H = g.getHeight(); @@ -86,279 +85,81 @@ function imgLock(){ } } -function imgSteps(){ - return { - width : 24, height : 24, bpp : 1, - transparent : 1, - buffer : require("heatshrink").decompress(atob("/H///wv4CBn4CD8ACCj4IBj8f+Eeh/wjgCBngCCg/4nEH//4h/+jEP/gRBAQX+jkf/wgB//8GwP4FoICDHgICCBwIA==")) - } -} -function imgBattery(){ - return { - width : 24, height : 24, bpp : 1, - transparent : 1, - buffer : require("heatshrink").decompress(atob("/4AN4EAg4TBgd///9oEAAQv8ARQRDDQQgCEwQ4OA")) - } -} - -function imgCharging() { - return { - width : 24, height : 24, bpp : 1, - transparent : 1, - buffer : require("heatshrink").decompress(atob("//+v///k///4AQPwBANgBoMxBoMb/P+h/w/kH8H4gfB+EBwfggHH4EAt4CBn4CBj4CBh4FCCIO/8EB//Agf/wEH/8Gh//x////fAQIA=")) - } -} - -function imgBpm() { - return { - width : 24, height : 24, bpp : 1, - transparent : 1, - buffer : require("heatshrink").decompress(atob("/4AOn4CD/wCCjgCCv/8jF/wGYgOA5MB//BC4PDAQnjAQPnAQgANA")) - } -} - -function imgTemperature() { - return { - width : 24, height : 24, bpp : 1, - transparent : 1, - buffer : require("heatshrink").decompress(atob("//D///wICBjACBngCNkgCP/0kv/+s1//nDn/8wICEBAIOC/08v//IYJECA==")) - } -} - -function imgWeather(){ - return { - width : 24, height : 24, bpp : 1, - transparent : 0, - buffer : require("heatshrink").decompress(atob("AAcYAQ0MgEwAQUAngLB/8AgP/wACCgf/4Fz//OAQQICCIoaCEAQpGHA4ACA=")) - } -} - -function imgWind () { - return { - width : 24, height : 24, bpp : 1, - transparent : 1, - buffer : require("heatshrink").decompress(atob("/0f//8h///Pn//zAQXzwf/88B//mvGAh18gEevn/DIICB/PwgEBAQMHBAIADFwM/wEAGAP/54CD84CE+eP//wIQU/A==")) - } -} - -function imgHumidity () { - return { - width : 24, height : 24, bpp : 1, - transparent : 1, - buffer : require("heatshrink").decompress(atob("//7///+YCB+ICB8ACE4F/AQX9AQP54H//AOB+F/34CBj/gn8f4E+h/Aj0H4Ecg+AjED4ACE8E4gfwvEDEgICB/kHGwMP")) - } -} - -function imgTimer() { - return { - width : 24, height : 24, bpp : 1, - transparent : 1, - buffer : require("heatshrink").decompress(atob("/+B/4CD84CEBAPygFP+F+h/x/+P+fz5/n+HnAQNn5/wuYCBmYCC5kAAQfOgFz80As/ngHn+fD54mC/F+j/+gF/HAQA==")) - } -} - -function imgWatch() { - return { - width : 24, height : 24, bpp : 1, - transparent : 1, - buffer : require("heatshrink").decompress(atob("/8B//+ARANB/l4//5/1/+f/n/n5+fAQnf9/P44CC8/n7/n+YOB/+fDQQgCEwQsCHBBEC")) - } -} - -function imgHomeAssistant() { - return { - width : 24, height : 24, bpp : 1, - transparent : 1, - buffer : require("heatshrink").decompress(atob("/4AF84CB4YCBwICBCAP+jFH/k8g/4kkH+AFB8ACB4cY4eHzPhgmZkHnzPn8fb4/gvwUD8EYARhAC")) - } -} - -function imgAgenda() { - return { - width : 24, height : 24, bpp : 1, - transparent : 1, - buffer : require("heatshrink").decompress(atob("/4AFnPP+ALBAQX4CIgLFAQvggEBAQvAgEDAQMCwEAgwTBhgiB/AlCGQ8BGQQ")) - } -} - -function imgMountain() { - return { - width : 24, height : 24, bpp : 1, - transparent : 1, - buffer : atob("//////////////////////3///n///D//uZ//E8//A+/+Z+f8//P5//n7//3z//zn//5AAAAAAAA////////////////////") - } -} - -/************ - * 2D MENU with entries of: - * [name, icon, opt[customDownFun], opt[customUpFun], opt[customCenterFun]] - * - */ -var menu = [ - [ - function(){ return [ null, null ] }, - function(){ return [ "Week " + weekOfYear(), null ] }, - ], - [ - function(){ return [ "Bangle", imgWatch() ] }, - function(){ return [ E.getBattery() + "%", Bangle.isCharging() ? imgCharging() : imgBattery() ] }, - function(){ return [ getSteps(), imgSteps() ] }, - function(){ return [ Math.round(Bangle.getHealthStatus("last").bpm) + " bpm", imgBpm()] }, - function(){ return [ measureAltitude, imgMountain() ]}, - ] -] - -/* - * Timer Menu - */ -try{ - require('sched'); - menu.push([ - function(){ - var text = isAlarmEnabled(TIMER_IDX) ? getAlarmMinutes(TIMER_IDX) + " min." : "Timer"; - return [text, imgTimer(), () => decreaseAlarm(TIMER_IDX), () => increaseAlarm(TIMER_IDX), null ] - }, - ]); -} catch(ex) { - // If sched is not installed, we hide this menu item -} - - -/* - * AGENDA MENU - * Note that we handle the agenda differently in order to hide old entries... - */ -var agendaIdx = 0; -var agendaTimerIdx = 0; -if(storage.readJSON("android.calendar.json") !== undefined){ - function nextAgendaEntry(){ - agendaIdx += 1; - } - - function previousAgendaEntry(){ - agendaIdx -= 1; - } - - menu.push([ - function(){ - var now = new Date(); - var agenda = storage.readJSON("android.calendar.json") - .filter(ev=>ev.timestamp + ev.durationInSeconds > now/1000) - .sort((a,b)=>a.timestamp - b.timestamp); - - if(agenda.length <= 0){ - return ["All done", imgAgenda()] - } - - agendaIdx = agendaIdx < 0 ? 0 : agendaIdx; - agendaIdx = agendaIdx >= agenda.length ? agendaIdx -1 : agendaIdx; - - var entry = agenda[agendaIdx]; - var title = entry.title.slice(0,14); - var date = new Date(entry.timestamp*1000); - var dateStr = locale.date(date).replace(/\d\d\d\d/,""); - dateStr += entry.durationInSeconds < 86400 ? "/ " + locale.time(date,1) : ""; - - function dynImgAgenda(){ - if(isAlarmEnabled(TIMER_AGENDA_IDX) && agendaTimerIdx == agendaIdx){ - return imgTimer(); - } else { - return imgAgenda(); - } - } - - return [title + "\n" + dateStr, dynImgAgenda(), () => nextAgendaEntry(), () => previousAgendaEntry(), function(){ - try{ - var alarm = require('sched') - - // If other time, we disable the old one and enable this one. - if(agendaIdx != agendaTimerIdx){ - agendaTimerIdx = -1; - alarm.setAlarm(TIMER_AGENDA_IDX, undefined); - } - - // Disable alarm if enabled - if(isAlarmEnabled(TIMER_AGENDA_IDX)){ - agendaTimerIdx = -1; - alarm.setAlarm(TIMER_AGENDA_IDX, undefined); - alarm.reload(); - return - } - - // Otherwise, set alarm for given event - agendaTimerIdx = agendaIdx; - alarm.setAlarm(TIMER_AGENDA_IDX, { - msg: title, - timer : parseInt((date - now)), - }); - alarm.reload(); - } catch(ex){ } - }] - }, - ]); -} - - -/* - * WEATHER MENU - */ -if(storage.readJSON('weather.json') !== undefined){ - menu.push([ - function(){ return [ "Weather", imgWeather() ] }, - function(){ return [ getWeather().temp, imgTemperature() ] }, - function(){ return [ getWeather().hum, imgHumidity() ] }, - function(){ return [ getWeather().wind, imgWind() ] }, - ]); -} - - -/* - * HOME ASSISTANT MENU - */ -try{ - var triggers = require("ha.lib.js").getTriggers(); - var haMenu = [ - function(){ return [ "Home", imgHomeAssistant() ] }, - ]; - - triggers.forEach(trigger => { - haMenu.push(function(){ - return [trigger.display, trigger.getIcon(), () => {}, () => {}, function(){ - var ha = require("ha.lib.js"); - ha.sendTrigger("TRIGGER_BW"); - ha.sendTrigger(trigger.trigger); - }] +// clock_info ######################################################## +function load() { + // info used for drawing... + var hrm = "--"; + var alt = "--"; + // callbacks (needed for easy removal of listeners) + function batteryUpdateHandler() { bangleItems[0].emit("redraw"); } + function stepUpdateHandler() { bangleItems[1].emit("redraw"); } + function hrmUpdateHandler() { bangleItems[2].emit("redraw"); } + function altUpdateHandler() { + Bangle.getPressure().then(data=>{ + if (!data) return; + alt = Math.round(data.altitude) + "m"; + bangleItems[3].emit("redraw"); }); - }) - menu.push(haMenu); -} catch(ex){ - // If HomeAssistant is not installed, we hide this item -} - - -function getMenuEntry(){ - // In case the user removes HomeAssistant entries, showInfo - // could be larger than infoArray.length... - settings.menuPosX = settings.menuPosX % menu.length; - settings.menuPosY = settings.menuPosY % menu[settings.menuPosX].length; - var menuEntry = menu[settings.menuPosX][settings.menuPosY](); - - if(menuEntry[0] == null){ - return menuEntry; } - - // For the first entry we always convert it into a callback function - // such that the menu is compatible with async functions such as - // measuring the pressure, altitude or sending http requests... - if(typeof menuEntry[0] !== 'function'){ - var value = menuEntry[0]; - menuEntry[0] = function(callbackFun){ - callbackFun(String(value), settings.menuPosX, settings.menuPosY); + // actual items + var items = [ + { + name: "Bangle", + img: atob("/8B//+ARANB/l4//5/1/+f/n/n5+fAQnf9/P44CC8/n7/n+YOB/+fDQQgCEwQsCHBBEC"), + items: [ + { name : "Battery", + get : () => ({ + text : E.getBattery() + "%", + img : atob(Bangle.isCharging() ? "GBiBAAABgAADwAAHwAAPgACfAAHOAAPkBgHwDwP4Hwf8Pg/+fB//OD//kD//wD//4D//8D//4B//QB/+AD/8AH/4APnwAHAAACAAAA==" : "GBiBAAAAAAAAAAAAAAAAAAAAAD//+P///IAAAr//Ar//Ar//A7//A7//A7//A7//Ar//AoAAAv///D//+AAAAAAAAAAAAAAAAAAAAA==") }), + show : function() { + this.interval = setInterval(()=>this.emit('redraw'), 60000); + Bangle.on("charging", batteryUpdateHandler); + batteryUpdateHandler(); + }, + hide : function() { + clearInterval(this.interval); + delete this.interval; + Bangle.removeListener("charging", batteryUpdateHandler); + }, + }, + { name : "Steps", get : () => ({ + text : Bangle.getHealthStatus("day").steps, + img : atob("GBiBAAcAAA+AAA/AAA/AAB/AAB/gAA/g4A/h8A/j8A/D8A/D+AfH+AAH8AHn8APj8APj8AHj4AHg4AADAAAHwAAHwAAHgAAHgAADAA==") }), + show : function() { Bangle.on("step", stepUpdateHandler); stepUpdateHandler(); }, + hide : function() { Bangle.removeListener("step", stepUpdateHandler); }, + }, + { name : "HRM", get : () => ({ + text : Math.round(Bangle.getHealthStatus("last").bpm) + " bpm", + img : atob("GBiBAAAAAAAAAAAAAAAAAAAAAADAAADAAAHAAAHjAAHjgAPngH9n/n82/gA+AAA8AAA8AAAcAAAYAAAYAAAAAAAAAAAAAAAAAAAAAA==") }), + show : function() { Bangle.setHRMPower(1,"clkinfo"); Bangle.on("HRM", hrmUpdateHandler); hrm = Math.round(Bangle.getHealthStatus("last").bpm); hrmUpdateHandler(); }, + hide : function() { Bangle.setHRMPower(0,"clkinfo"); Bangle.removeListener("HRM", hrmUpdateHandler); hrm = "--"; }, } + ], + }]; + var bangleItems = items[0].items; + + if (Bangle.getPressure){ // Altimeter may not exist + bangleItems.push({ name : "Altitude", get : () => ({ + text : alt, + img : atob("GBiBAAAAAAAAAAAAAAAAAAAAAAACAAAGAAAPAAEZgAOwwAPwQAZgYAwAMBgAGBAACDAADGAABv///////wAAAAAAAAAAAAAAAAAAAA==") }), + show : function() { this.interval = setInterval(altUpdateHandler, 60000); alt = "--"; altUpdateHandler(); }, + hide : function() { clearInterval(this.interval); delete this.interval; }, + }); } - return menuEntry; -} + + // now load extra data from a third party files + require("Storage").list(/clkinfo.js$/).forEach(fn => { + items = items.concat(eval(require("Storage").read(fn))()); + }); + + // return it all! + return items; +}; +// clock_info ######################################################## + + +var clock_items = load(); /************ @@ -373,144 +174,6 @@ function isFullscreen(){ } } -function getSteps() { - var steps = 0; - try{ - if (WIDGETS.wpedom !== undefined) { - steps = WIDGETS.wpedom.getSteps(); - } else if (WIDGETS.activepedom !== undefined) { - steps = WIDGETS.activepedom.getSteps(); - } else { - steps = Bangle.getHealthStatus("day").steps; - } - } catch(ex) { - // In case we failed, we can only show 0 steps. - } - - return steps; -} - - -function getWeather(){ - var weatherJson; - - try { - weatherJson = storage.readJSON('weather.json'); - var weather = weatherJson.weather; - - // Temperature - weather.temp = locale.temp(weather.temp-273.15); - - // Humidity - weather.hum = weather.hum + "%"; - - // Wind - const wind = locale.speed(weather.wind).match(/^(\D*\d*)(.*)$/); - weather.wind = Math.round(wind[1]) + "kph"; - - return weather - - } catch(ex) { - // Return default - } - - return { - temp: " ? ", - hum: " ? ", - txt: " ? ", - wind: " ? ", - wdir: " ? ", - wrose: " ? " - }; -} - -// From https://weeknumber.com/how-to/javascript -function weekOfYear() { - var date = new Date(); - date.setHours(0, 0, 0, 0); - // Thursday in current week decides the year. - date.setDate(date.getDate() + 3 - (date.getDay() + 6) % 7); - // January 4 is always in week 1. - var week1 = new Date(date.getFullYear(), 0, 4); - // Adjust to Thursday in week 1 and count number of weeks from date to week1. - return 1 + Math.round(((date.getTime() - week1.getTime()) / 86400000 - - 3 + (week1.getDay() + 6) % 7) / 7); -} - - -function isAlarmEnabled(idx){ - try{ - var alarm = require('sched'); - var alarmObj = alarm.getAlarm(idx); - if(alarmObj===undefined || !alarmObj.on){ - return false; - } - - return true; - - } catch(ex){ } - return false; -} - - -function getAlarmMinutes(idx){ - if(!isAlarmEnabled(idx)){ - return -1; - } - - var alarm = require('sched'); - var alarmObj = alarm.getAlarm(idx); - return Math.round(alarm.getTimeToAlarm(alarmObj)/(60*1000)); -} - - -function increaseAlarm(idx){ - try{ - var minutes = isAlarmEnabled(idx) ? getAlarmMinutes(idx) : 0; - var alarm = require('sched'); - alarm.setAlarm(idx, { - timer : (minutes+5)*60*1000, - }); - alarm.reload(); - } catch(ex){ } -} - - -function decreaseAlarm(idx){ - try{ - var minutes = getAlarmMinutes(idx); - minutes -= 5; - - var alarm = require('sched') - alarm.setAlarm(idx, undefined); - - if(minutes > 0){ - alarm.setAlarm(idx, { - timer : minutes*60*1000, - }); - } - - alarm.reload(); - } catch(ex){ } -} - - -function measureAltitude(callbackFun){ - var oldX = settings.menuPosX; - var oldY = settings.menuPosY; - try{ - Bangle.getPressure().then(data=>{ - if(data && data.altitude && data.altitude > -100){ - callbackFun(Math.round(data.altitude) + "m", oldX, oldY); - } else { - callbackFun("???", oldX, oldY); - } - }); - }catch(ex){ - callbackFun("err", oldX, oldY); - } -} - /************ * DRAW @@ -577,56 +240,34 @@ function drawTime(){ // Set y coordinates correctly y += parseInt((H - y)/2) + 5; - var menuEntry = getMenuEntry(); - var menuTextFun = menuEntry[0]; - var menuImg = menuEntry[1]; - var printImgLeft = settings.menuPosY != 0; - // Show large or small time depending on info entry - if(menuTextFun == null){ - g.setLargeFont(); - g.drawString(timeStr, W/2, y); - return; - } else { - y -= 15; - g.setMediumFont(); - g.drawString(timeStr, W/2, y); + y -= 15; + g.setMediumFont(); + g.drawString(timeStr, W/2, y); + + // Draw item if needed + var appItems = clock_items[0]; + console.log(appItems.name); + + var item = appItems.items[0]; + console.log(item.name); + function drawItem() { + console.log("Draw item", item.name); + + g.setFontAlign(0,0); + g.setSmallFont(); + + y += 35; + var info = item.get(); + var imgWidth = 24; + var strWidth = g.stringWidth(info.text); + g.setColor(g.theme.fg).fillRect(0, y-14, W, H); + g.setColor(g.theme.bg).drawString(info.text, W/2 + imgWidth/2 + 2, y+3); + g.drawImage(info.img, W/2 + -strWidth/2-4 - parseInt(imgWidth/2), y - parseInt(imgWidth/2)); } - // Async set the menu (could be that some data is async fetched) - menuTextFun((menuText, oldX, oldY) => { - - // We display the text IFF the user did not change the menu - if(settings.menuPosX != oldX || settings.menuPosY != oldY){ - return; - } - - // As its a callback, we have to ensure that the color - // font etc. is still correct... - g.setColor(g.theme.bg); - g.setFontAlign(0,0); - y += 35; - - if(menuText.split('\n').length > 1){ - g.setMiniFont(); - } else { - g.setSmallFont(); - } - - var imgWidth = 0; - if(menuImg){ - imgWidth = 24.0; - var strWidth = g.stringWidth(menuText); - var scale = imgWidth / menuImg.width; - g.drawImage( - menuImg, - W/2 + (printImgLeft ? -strWidth/2-4 : strWidth/2+4) - parseInt(imgWidth/2), - y - parseInt(imgWidth/2), - { scale: scale } - ); - } - g.drawString(menuText, printImgLeft ? W/2 + imgWidth/2 + 2 : W/2 - imgWidth/2 - 2, y+3); - }); + item.on('redraw', drawItem); + item.show(); } @@ -715,10 +356,10 @@ Bangle.on('touch', function(btn, e){ settings.menuPosY = (settings.menuPosY+1) % menu[settings.menuPosX].length; // Handle custom menu entry function - var menuEntry = getMenuEntry(); - if(menuEntry.length > 2){ - menuEntry[2](); - } + // var menuEntry = getMenuEntry(); + // if(menuEntry.length > 2){ + // menuEntry[2](); + // } drawTime(); } @@ -733,10 +374,10 @@ Bangle.on('touch', function(btn, e){ settings.menuPosY = settings.menuPosY < 0 ? menu[settings.menuPosX].length-1 : settings.menuPosY; // Handle custom menu entry function - var menuEntry = getMenuEntry(); - if(menuEntry.length > 3){ - menuEntry[3](); - } + // var menuEntry = getMenuEntry(); + // if(menuEntry.length > 3){ + // menuEntry[3](); + // } drawTime(); } @@ -763,21 +404,21 @@ Bangle.on('touch', function(btn, e){ } if(is_center){ - var menuEntry = getMenuEntry(); - if(menuEntry.length > 4 && menuEntry[4] != null){ - Bangle.buzz(80, 0.6).then(()=>{ - try{ - menuEntry[4](); - setTimeout(()=>{ - Bangle.buzz(80, 0.6); - drawTime(); - }, 250); - } catch(ex){ - // In case it fails, we simply ignore it. - } - } - ); - } + // var menuEntry = getMenuEntry(); + // if(menuEntry.length > 4 && menuEntry[4] != null){ + // Bangle.buzz(80, 0.6).then(()=>{ + // try{ + // menuEntry[4](); + // setTimeout(()=>{ + // Bangle.buzz(80, 0.6); + // drawTime(); + // }, 250); + // } catch(ex){ + // // In case it fails, we simply ignore it. + // } + // } + // ); + // } } }); From daedc1068e2101a134c6bdf9fea01534245a04b8 Mon Sep 17 00:00:00 2001 From: David Peer Date: Mon, 12 Sep 2022 07:20:11 +0200 Subject: [PATCH 02/25] Some improvements --- apps/bwclk/app.js | 133 +++++++++++++++++++++++++--------------------- 1 file changed, 72 insertions(+), 61 deletions(-) diff --git a/apps/bwclk/app.js b/apps/bwclk/app.js index 15de3f870..93fc0f1d7 100644 --- a/apps/bwclk/app.js +++ b/apps/bwclk/app.js @@ -44,14 +44,12 @@ Graphics.prototype.setLargeFont = function(scale) { return this; }; - Graphics.prototype.setMediumFont = function(scale) { // Actual height 41 (42 - 2) this.setFontCustom(atob("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/AAAAAAAA/AAAAAAAA/AAAAAAAA/AAAAAAAA/AAAAAAAA/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHAAAAAAAB/AAAAAAAP/AAAAAAD//AAAAAA///AAAAAP///AAAAB///8AAAAf///AAAAH///wAAAB///+AAAAH///gAAAAH//4AAAAAH/+AAAAAAH/wAAAAAAH8AAAAAAAHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA///8AAAAH////AAAAP////wAAAf////4AAA/////8AAB/////+AAD/gAAH+AAD+AAAD/AAH8AAAB/AAH4AAAA/gAH4AAAAfgAH4AAAAfgAPwAAAAfgAPwAAAAfgAPwAAAAfgAHwAAAAfgAH4AAAAfgAH4AAAA/gAH8AAAA/AAD+AAAD/AAD/gAAH/AAB/////+AAB/////8AAA/////4AAAf////wAAAH////gAAAB///+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPgAAAAAAAfwAAAAAAA/gAAAAAAA/AAAAAAAB/AAAAAAAD+AAAAAAAD8AAAAAAAH8AAAAAAAH//////AAH//////AAH//////AAH//////AAH//////AAH//////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD4AAA/AAAP4AAB/AAAf4AAD/AAA/4AAD/AAB/4AAH/AAD/4AAP/AAH/AAAf/AAH8AAA//AAH4AAB//AAP4AAD//AAPwAAH+/AAPwAAP8/AAPwAAf4/AAPwAA/4/AAPwAA/w/AAPwAB/g/AAPwAD/A/AAP4AH+A/AAH8AP8A/AAH/A/4A/AAD///wA/AAD///gA/AAB///AA/AAA//+AA/AAAP/8AA/AAAD/wAA/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADgAAH4AAAHwAAH4AAAH4AAH4AAAH8AAH4AAAP+AAH4AAAH+AAH4A4AB/AAH4A+AA/AAH4B/AA/gAH4D/AAfgAH4H+AAfgAH4P+AAfgAH4f+AAfgAH4/+AAfgAH5/+AAfgAH5//AAfgAH7+/AA/gAH/8/gB/AAH/4f4H/AAH/wf//+AAH/gP//8AAH/AH//8AAH+AD//wAAH8AB//gAAD4AAf+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+AAAAAAAD/AAAAAAAP/AAAAAAB//AAAAAAH//AAAAAAf//AAAAAB///AAAAAH///AAAAAf/8/AAAAB//w/AAAAH/+A/AAAA//4A/AAAD//gA/AAAH/+AA/AAAH/4AA/AAAH/gAA/AAAH+AAA/AAAHwAAA/AAAHAAf///AAEAAf///AAAAAf///AAAAAf///AAAAAf///AAAAAf///AAAAAAA/AAAAAAAA/AAAAAAAA/AAAAAAAA/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGAAAAAP/AHgAAH///AP4AAH///gP8AAH///gP8AAH///gP+AAH///gD/AAH/A/AB/AAH4A/AA/gAH4A+AAfgAH4B+AAfgAH4B+AAfgAH4B8AAfgAH4B8AAfgAH4B+AAfgAH4B+AAfgAH4B+AA/gAH4B/AA/AAH4A/gD/AAH4A/4H+AAH4Af//+AAH4AP//8AAH4AP//4AAHwAD//wAAAAAB//AAAAAAAf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA///8AAAAD////AAAAP////wAAAf////4AAA/////8AAB/////+AAD/gP4H+AAD/AfgD/AAH8A/AB/AAH8A/AA/gAH4B+AAfgAH4B+AAfgAPwB8AAfgAPwB8AAfgAPwB+AAfgAPwB+AAfgAH4B+AAfgAH4B/AA/gAH8B/AB/AAH+A/wD/AAD+A/8P+AAB8Af//+AAB4AP//8AAAwAH//4AAAAAD//gAAAAAA//AAAAAAAP4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPwAAAAAAAPwAAAAAAAPwAAAAAAAPwAAAAAAAPwAAAAHAAPwAAAA/AAPwAAAD/AAPwAAAf/AAPwAAB//AAPwAAP//AAPwAA//8AAPwAH//wAAPwAf/+AAAPwB//4AAAPwP//AAAAPw//8AAAAP3//gAAAAP//+AAAAAP//wAAAAAP//AAAAAAP/4AAAAAAP/gAAAAAAP+AAAAAAAHwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP+AAAAH+A//gAAAf/h//4AAA//z//8AAB/////+AAD/////+AAD///+H/AAH+H/4B/AAH8B/wA/gAH4A/gAfgAH4A/gAfgAPwA/AAfgAPwA/AAfgAPwA/AAfgAPwA/AAfgAH4A/gAfgAH4A/gAfgAH8B/wA/gAH/H/4B/AAD///+H/AAD/////+AAB/////+AAA//z//8AAAf/h//4AAAH+A//gAAAAAAH+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/gAAAAAAD/8AAAAAAP/+AAAAAAf//AAcAAA///gA8AAB///wB+AAD/x/4B/AAD+AP4B/AAH8AH8A/gAH4AH8A/gAH4AD8AfgAP4AD8AfgAPwAB8AfgAPwAB8AfgAPwAB8AfgAPwAB8AfgAH4AD8AfgAH4AD4A/gAH8AH4B/AAD+APwD/AAD/g/wP+AAB/////+AAA/////8AAAf////4AAAP////wAAAH////AAAAA///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD8APwAAAAD8APwAAAAD8APwAAAAD8APwAAAAD8APwAAAAD8APwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=="), 46, atob("DxcjFyAfISAiHCAiEg=="), 54+(scale<<8)+(1<<16)); return this; }; - Graphics.prototype.setSmallFont = function(scale) { // Actual height 28 (27 - 0) this.setFontCustom( @@ -63,7 +61,6 @@ Graphics.prototype.setSmallFont = function(scale) { return this; }; - Graphics.prototype.setMiniFont = function(scale) { // Actual height 16 (15 - 0) this.setFontCustom( @@ -75,8 +72,6 @@ Graphics.prototype.setMiniFont = function(scale) { return this; }; - - function imgLock(){ return { width : 16, height : 16, bpp : 1, @@ -91,6 +86,7 @@ function load() { // info used for drawing... var hrm = "--"; var alt = "--"; + var interval = null; // callbacks (needed for easy removal of listeners) function batteryUpdateHandler() { bangleItems[0].emit("redraw"); } function stepUpdateHandler() { bangleItems[1].emit("redraw"); } @@ -102,24 +98,29 @@ function load() { bangleItems[3].emit("redraw"); }); } + function deleteInterval(inter){ + if(inter){ + clearInterval(inter); + } + delete inter; + } // actual items - var items = [ - { + var items = [{ name: "Bangle", - img: atob("/8B//+ARANB/l4//5/1/+f/n/n5+fAQnf9/P44CC8/n7/n+YOB/+fDQQgCEwQsCHBBEC"), + img: atob("GBiBAAcAAA+AAA/AAA/AAB/AAB/gAA/g4A/h8A/j8A/D8A/D+AfH+AAH8AHn8APj8APj8AHj4AHg4AADAAAHwAAHwAAHgAAHgAADAA=="), items: [ { name : "Battery", get : () => ({ text : E.getBattery() + "%", img : atob(Bangle.isCharging() ? "GBiBAAABgAADwAAHwAAPgACfAAHOAAPkBgHwDwP4Hwf8Pg/+fB//OD//kD//wD//4D//8D//4B//QB/+AD/8AH/4APnwAHAAACAAAA==" : "GBiBAAAAAAAAAAAAAAAAAAAAAD//+P///IAAAr//Ar//Ar//A7//A7//A7//A7//Ar//AoAAAv///D//+AAAAAAAAAAAAAAAAAAAAA==") }), show : function() { - this.interval = setInterval(()=>this.emit('redraw'), 60000); + deleteInterval(interval); + interval = setInterval(()=>this.emit('redraw'), 60000); Bangle.on("charging", batteryUpdateHandler); batteryUpdateHandler(); }, hide : function() { - clearInterval(this.interval); - delete this.interval; + deleteInterval(interval); Bangle.removeListener("charging", batteryUpdateHandler); }, }, @@ -143,8 +144,8 @@ function load() { bangleItems.push({ name : "Altitude", get : () => ({ text : alt, img : atob("GBiBAAAAAAAAAAAAAAAAAAAAAAACAAAGAAAPAAEZgAOwwAPwQAZgYAwAMBgAGBAACDAADGAABv///////wAAAAAAAAAAAAAAAAAAAA==") }), - show : function() { this.interval = setInterval(altUpdateHandler, 60000); alt = "--"; altUpdateHandler(); }, - hide : function() { clearInterval(this.interval); delete this.interval; }, + show : function() { deleteInterval(); interval = setInterval(altUpdateHandler, 60000); alt = "--"; altUpdateHandler(); }, + hide : function() { deleteInterval(); }, }); } @@ -159,7 +160,41 @@ function load() { // clock_info ######################################################## -var clock_items = load(); +// Load menu +var menu = load(); + +// Set draw functions for each item +menu.forEach((menuItm, x) => { + menuItm.items.forEach((item, y) => { + function drawItem() { + // Once shown, we can disable it afterwards... + item.hide(); + + console.log("Draw item", item.name); + + g.setFontAlign(0,0); + g.setSmallFont(); + + var y = 147; + var info = item.get(); + var imgWidth = 24; + var strWidth = g.stringWidth(info.text); + g.setColor(g.theme.fg).fillRect(0, y-14, W, H); + g.setColor(g.theme.bg).drawString(info.text, W/2 + imgWidth/2 + 2, y+3); + g.drawImage(info.img, W/2 + -strWidth/2-4 - parseInt(imgWidth/2), y - parseInt(imgWidth/2)); + } + + item.on('redraw', drawItem); + }) +}); + +/************ + * Custom menu elements + * Those are BW custom and should not be available + * for other clocks... + */ + + /************ @@ -185,6 +220,7 @@ function draw() { // Draw clock drawDate(); drawTime(); + drawMenu(); drawLock(); drawWidgets(); } @@ -244,30 +280,23 @@ function drawTime(){ y -= 15; g.setMediumFont(); g.drawString(timeStr, W/2, y); +} - // Draw item if needed - var appItems = clock_items[0]; - console.log(appItems.name); - var item = appItems.items[0]; - console.log(item.name); - function drawItem() { - console.log("Draw item", item.name); +function drawMenu(){ + if(settings.menuPosX < 0){ - g.setFontAlign(0,0); - g.setSmallFont(); + return; + } - y += 35; - var info = item.get(); - var imgWidth = 24; - var strWidth = g.stringWidth(info.text); - g.setColor(g.theme.fg).fillRect(0, y-14, W, H); - g.setColor(g.theme.bg).drawString(info.text, W/2 + imgWidth/2 + 2, y+3); - g.drawImage(info.img, W/2 + -strWidth/2-4 - parseInt(imgWidth/2), y - parseInt(imgWidth/2)); - } + // Draw item if needed + var menuEntry = menu[settings.menuPosX]; + console.log(menuEntry.name); - item.on('redraw', drawItem); - item.show(); + var item = menuEntry.items[settings.menuPosY]; + console.log(item.name); + + item.show(); } @@ -333,8 +362,8 @@ Bangle.on('charging',function(charging) { drawTimeout = undefined; // Jump to battery - settings.menuPosX = 1; - settings.menuPosY = 1; + settings.menuPosX = 0; + settings.menuPosY = 0; draw(); }); @@ -353,15 +382,9 @@ Bangle.on('touch', function(btn, e){ if(is_lower){ Bangle.buzz(40, 0.6); - settings.menuPosY = (settings.menuPosY+1) % menu[settings.menuPosX].length; + settings.menuPosY = (settings.menuPosY+1) % menu[settings.menuPosX].items.length; - // Handle custom menu entry function - // var menuEntry = getMenuEntry(); - // if(menuEntry.length > 2){ - // menuEntry[2](); - // } - - drawTime(); + drawMenu(); } if(is_upper){ @@ -371,36 +394,24 @@ Bangle.on('touch', function(btn, e){ Bangle.buzz(40, 0.6); settings.menuPosY = settings.menuPosY-1; - settings.menuPosY = settings.menuPosY < 0 ? menu[settings.menuPosX].length-1 : settings.menuPosY; + settings.menuPosY = settings.menuPosY < 0 ? menu[settings.menuPosX].items.length-1 : settings.menuPosY; - // Handle custom menu entry function - // var menuEntry = getMenuEntry(); - // if(menuEntry.length > 3){ - // menuEntry[3](); - // } - - drawTime(); + drawMenu(); } if(is_right){ - // A bit hacky but we ensure that always the first agenda entry is shown... - agendaIdx = 0; - Bangle.buzz(40, 0.6); settings.menuPosX = (settings.menuPosX+1) % menu.length; - settings.menuPosY = 0; - drawTime(); + settings.menuPosY = -1; + drawMenu(); } if(is_left){ - // A bit hacky but we ensure that always the first agenda entry is shown... - agendaIdx = 0; - Bangle.buzz(40, 0.6); - settings.menuPosY = 0; + settings.menuPosY = -1; settings.menuPosX = settings.menuPosX-1; settings.menuPosX = settings.menuPosX < 0 ? menu.length-1 : settings.menuPosX; - drawTime(); + drawMenu(); } if(is_center){ From f4b1eb00328681c0fd50dd323bd3b1ba8b9a0ce2 Mon Sep 17 00:00:00 2001 From: David Peer Date: Mon, 12 Sep 2022 07:25:32 +0200 Subject: [PATCH 03/25] First menu is already working. --- apps/bwclk/app.js | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/apps/bwclk/app.js b/apps/bwclk/app.js index 93fc0f1d7..dd4856aa0 100644 --- a/apps/bwclk/app.js +++ b/apps/bwclk/app.js @@ -172,22 +172,15 @@ menu.forEach((menuItm, x) => { console.log("Draw item", item.name); - g.setFontAlign(0,0); - g.setSmallFont(); - - var y = 147; var info = item.get(); - var imgWidth = 24; - var strWidth = g.stringWidth(info.text); - g.setColor(g.theme.fg).fillRect(0, y-14, W, H); - g.setColor(g.theme.bg).drawString(info.text, W/2 + imgWidth/2 + 2, y+3); - g.drawImage(info.img, W/2 + -strWidth/2-4 - parseInt(imgWidth/2), y - parseInt(imgWidth/2)); + drawMenuItem(info.text, info.img); } item.on('redraw', drawItem); }) }); + /************ * Custom menu elements * Those are BW custom and should not be available @@ -283,9 +276,24 @@ function drawTime(){ } -function drawMenu(){ - if(settings.menuPosX < 0){ +function drawMenuItem(text, image){ + g.setFontAlign(0,0); + g.setSmallFont(); + var y = 147; + var imgWidth = 24; + var strWidth = g.stringWidth(text); + g.setColor(g.theme.fg).fillRect(0, y-14, W, H); + g.setColor(g.theme.bg).drawString(text, W/2 + imgWidth/2 + 2, y+3); + g.drawImage(image, W/2 + -strWidth/2-4 - parseInt(imgWidth/2), y - parseInt(imgWidth/2)); +} + + +function drawMenu(){ + // Draw category if needed + if(settings.menuPosY < 0){ + var menuEntry = menu[settings.menuPosX]; + drawMenuItem(menuEntry.name, menuEntry.img); return; } From d02e5db24b8cb5f526c6acccc7b9c314cb6da023 Mon Sep 17 00:00:00 2001 From: David Peer Date: Thu, 15 Sep 2022 21:01:43 +0200 Subject: [PATCH 04/25] Improvements --- apps/bwclk/app.js | 93 +++++++++++++++++++++++++---------------------- 1 file changed, 49 insertions(+), 44 deletions(-) diff --git a/apps/bwclk/app.js b/apps/bwclk/app.js index dd4856aa0..b88bb894c 100644 --- a/apps/bwclk/app.js +++ b/apps/bwclk/app.js @@ -88,14 +88,14 @@ function load() { var alt = "--"; var interval = null; // callbacks (needed for easy removal of listeners) - function batteryUpdateHandler() { bangleItems[0].emit("redraw"); } - function stepUpdateHandler() { bangleItems[1].emit("redraw"); } - function hrmUpdateHandler() { bangleItems[2].emit("redraw"); } + function batteryUpdateHandler() { bangleItems[1].emit("redraw"); } + function stepUpdateHandler() { bangleItems[2].emit("redraw"); } + function hrmUpdateHandler() { bangleItems[3].emit("redraw"); } function altUpdateHandler() { Bangle.getPressure().then(data=>{ if (!data) return; alt = Math.round(data.altitude) + "m"; - bangleItems[3].emit("redraw"); + bangleItems[4].emit("redraw"); }); } function deleteInterval(inter){ @@ -109,6 +109,11 @@ function load() { name: "Bangle", img: atob("GBiBAAcAAA+AAA/AAA/AAB/AAB/gAA/g4A/h8A/j8A/D8A/D+AfH+AAH8AHn8APj8APj8AHj4AHg4AADAAAHwAAHwAAHgAAHgAADAA=="), items: [ + { name: "Overview", + get: () => ({ text: "Bangle", img: null}), + show: function() { bangleItems[0].emit("redraw"); }, + hide: function () {} + }, { name : "Battery", get : () => ({ text : E.getBattery() + "%", @@ -169,9 +174,6 @@ menu.forEach((menuItm, x) => { function drawItem() { // Once shown, we can disable it afterwards... item.hide(); - - console.log("Draw item", item.name); - var info = item.get(); drawMenuItem(info.text, info.img); } @@ -212,8 +214,7 @@ function draw() { // Draw clock drawDate(); - drawTime(); - drawMenu(); + drawMenuAndTime(); drawLock(); drawWidgets(); } @@ -221,8 +222,8 @@ function draw() { function drawDate(){ // Draw background - var y = H/5*2; - g.reset().clearRect(0,0,W,W); + var y = H/5*2 + (isFullscreen() ? 0 : 8); + g.reset().clearRect(0,0,W,y); // Draw date y = parseInt(y/2)+4; @@ -249,11 +250,8 @@ function drawDate(){ } -function drawTime(){ +function drawTime(y, smallText){ // Draw background - var y = H/5*2 + (isFullscreen() ? 0 : 8); - g.setColor(g.theme.fg); - g.fillRect(0,y,W,H); var date = new Date(); // Draw time @@ -270,40 +268,47 @@ function drawTime(){ y += parseInt((H - y)/2) + 5; // Show large or small time depending on info entry - y -= 15; - g.setMediumFont(); + if(smallText){ + y -= 15; + g.setMediumFont(); + } else { + g.setLargeFont(); + } g.drawString(timeStr, W/2, y); } - function drawMenuItem(text, image){ - g.setFontAlign(0,0); - g.setSmallFont(); + // First clear the time region + var y = H/5*2 + (isFullscreen() ? 0 : 8); - var y = 147; - var imgWidth = 24; - var strWidth = g.stringWidth(text); - g.setColor(g.theme.fg).fillRect(0, y-14, W, H); - g.setColor(g.theme.bg).drawString(text, W/2 + imgWidth/2 + 2, y+3); - g.drawImage(image, W/2 + -strWidth/2-4 - parseInt(imgWidth/2), y - parseInt(imgWidth/2)); + g.setColor(g.theme.fg); + g.fillRect(0,y,W,H); + + // Draw menu text + var hasText = (text != null && text != ""); + if(hasText){ + g.setFontAlign(0,0); + g.setSmallFont(); + + var imgWidth = image == null ? 0 : 24; + var strWidth = g.stringWidth(text); + g.setColor(g.theme.fg).fillRect(0, 147-14, W, H); + g.setColor(g.theme.bg).drawString(text, W/2 + imgWidth/2 + 2, 147+3); + + if(image != null){ + g.drawImage(image, W/2 + -strWidth/2-4 - parseInt(imgWidth/2), 147 - parseInt(imgWidth/2)); + } + } + + // Draw time + drawTime(y, hasText); } -function drawMenu(){ - // Draw category if needed - if(settings.menuPosY < 0){ - var menuEntry = menu[settings.menuPosX]; - drawMenuItem(menuEntry.name, menuEntry.img); - return; - } - +function drawMenuAndTime(){ // Draw item if needed var menuEntry = menu[settings.menuPosX]; - console.log(menuEntry.name); - var item = menuEntry.items[settings.menuPosY]; - console.log(item.name); - item.show(); } @@ -392,7 +397,7 @@ Bangle.on('touch', function(btn, e){ Bangle.buzz(40, 0.6); settings.menuPosY = (settings.menuPosY+1) % menu[settings.menuPosX].items.length; - drawMenu(); + drawMenuAndTime(); } if(is_upper){ @@ -404,22 +409,22 @@ Bangle.on('touch', function(btn, e){ settings.menuPosY = settings.menuPosY-1; settings.menuPosY = settings.menuPosY < 0 ? menu[settings.menuPosX].items.length-1 : settings.menuPosY; - drawMenu(); + drawMenuAndTime(); } if(is_right){ Bangle.buzz(40, 0.6); settings.menuPosX = (settings.menuPosX+1) % menu.length; - settings.menuPosY = -1; - drawMenu(); + settings.menuPosY = 0; + drawMenuAndTime(); } if(is_left){ Bangle.buzz(40, 0.6); - settings.menuPosY = -1; + settings.menuPosY = 0; settings.menuPosX = settings.menuPosX-1; settings.menuPosX = settings.menuPosX < 0 ? menu.length-1 : settings.menuPosX; - drawMenu(); + drawMenuAndTime(); } if(is_center){ From 61bff3306f8087ef7938750095dd9a8bbbbf9c45 Mon Sep 17 00:00:00 2001 From: David Peer Date: Thu, 15 Sep 2022 21:16:00 +0200 Subject: [PATCH 05/25] Next improvements --- apps/bwclk/app.js | 52 ++++++++++++++++++++++++++++++++++++----------- 1 file changed, 40 insertions(+), 12 deletions(-) diff --git a/apps/bwclk/app.js b/apps/bwclk/app.js index b88bb894c..8a4b69aaa 100644 --- a/apps/bwclk/app.js +++ b/apps/bwclk/app.js @@ -106,11 +106,10 @@ function load() { } // actual items var items = [{ - name: "Bangle", - img: atob("GBiBAAcAAA+AAA/AAA/AAB/AAB/gAA/g4A/h8A/j8A/D8A/D+AfH+AAH8AHn8APj8APj8AHj4AHg4AADAAAHwAAHwAAHgAAHgAADAA=="), + id: "bangle", items: [ { name: "Overview", - get: () => ({ text: "Bangle", img: null}), + get: () => ({ text: "Bangle", img: atob("GBiBAf8B//4B//4B//4B//4A//x4//n+f/P/P+fPn+fPn+fP3+/Px+/Px+fn3+fzn+f/n/P/P/n+f/x4//4A//4B//4B//4B//8B/w==")}), show: function() { bangleItems[0].emit("redraw"); }, hide: function () {} }, @@ -165,15 +164,39 @@ function load() { // clock_info ######################################################## +// Custom menus +var clockItems = { + id: "bw_clock", + items: [ + { name: "Overview", + get: () => ({ text: null, img: null}), + show: function() { clockItems.items[0].emit("redraw"); }, + hide: function () {} + }, + { name: "Overview", + get: () => ({ text: "Week " + weekOfYear(), img: null}), + show: function() { clockItems.items[1].emit("redraw"); }, + hide: function () {} + }, + ] +}; + + // Load menu var menu = load(); +menu = menu.concat(clockItems); + // Set draw functions for each item menu.forEach((menuItm, x) => { menuItm.items.forEach((item, y) => { function drawItem() { - // Once shown, we can disable it afterwards... + // For the clock, we have a special case, as we don't wanna redraw + // immediately when something changes. Instead, we update data each minute + // to save some battery etc. Therefore, we hide (and disable the listener) + // immedeately after redraw... item.hide(); + var info = item.get(); drawMenuItem(info.text, info.img); } @@ -183,14 +206,6 @@ menu.forEach((menuItm, x) => { }); -/************ - * Custom menu elements - * Those are BW custom and should not be available - * for other clocks... - */ - - - /************ * Helper @@ -205,6 +220,19 @@ function isFullscreen(){ } +function weekOfYear() { + var date = new Date(); + date.setHours(0, 0, 0, 0); + // Thursday in current week decides the year. + date.setDate(date.getDate() + 3 - (date.getDay() + 6) % 7); + // January 4 is always in week 1. + var week1 = new Date(date.getFullYear(), 0, 4); + // Adjust to Thursday in week 1 and count number of weeks from date to week1. + return 1 + Math.round(((date.getTime() - week1.getTime()) / 86400000 + - 3 + (week1.getDay() + 6) % 7) / 7); +} + + /************ * DRAW */ From 77e1821cf44ca70cd95718bd00de4a84421509d5 Mon Sep 17 00:00:00 2001 From: David Peer Date: Thu, 15 Sep 2022 21:44:47 +0200 Subject: [PATCH 06/25] Minor changes --- apps/bwclk/app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/bwclk/app.js b/apps/bwclk/app.js index 8a4b69aaa..e031ef556 100644 --- a/apps/bwclk/app.js +++ b/apps/bwclk/app.js @@ -173,7 +173,7 @@ var clockItems = { show: function() { clockItems.items[0].emit("redraw"); }, hide: function () {} }, - { name: "Overview", + { name: "WeekOfYear", get: () => ({ text: "Week " + weekOfYear(), img: null}), show: function() { clockItems.items[1].emit("redraw"); }, hide: function () {} From 274544ec0f83d78738f4bb02eaa808e7215ac3e9 Mon Sep 17 00:00:00 2001 From: David Peer Date: Sat, 17 Sep 2022 17:14:20 +0200 Subject: [PATCH 07/25] Several improvements --- apps/bwclk/app.js | 45 ++++++++++++++++++++++----------------------- 1 file changed, 22 insertions(+), 23 deletions(-) diff --git a/apps/bwclk/app.js b/apps/bwclk/app.js index e031ef556..a0035222e 100644 --- a/apps/bwclk/app.js +++ b/apps/bwclk/app.js @@ -88,14 +88,14 @@ function load() { var alt = "--"; var interval = null; // callbacks (needed for easy removal of listeners) - function batteryUpdateHandler() { bangleItems[1].emit("redraw"); } - function stepUpdateHandler() { bangleItems[2].emit("redraw"); } - function hrmUpdateHandler() { bangleItems[3].emit("redraw"); } + function batteryUpdateHandler() { bangleItems[0].emit("redraw"); } + function stepUpdateHandler() { bangleItems[1].emit("redraw"); } + function hrmUpdateHandler() { bangleItems[2].emit("redraw"); } function altUpdateHandler() { Bangle.getPressure().then(data=>{ if (!data) return; alt = Math.round(data.altitude) + "m"; - bangleItems[4].emit("redraw"); + bangleItems[3].emit("redraw"); }); } function deleteInterval(inter){ @@ -106,13 +106,9 @@ function load() { } // actual items var items = [{ - id: "bangle", + name: "Bangle", + img: atob("GBiBAf8B//4B//4B//4B//4A//x4//n+f/P/P+fPn+fPn+fP3+/Px+/Px+fn3+fzn+f/n/P/P/n+f/x4//4A//4B//4B//4B//8B/w=="), items: [ - { name: "Overview", - get: () => ({ text: "Bangle", img: atob("GBiBAf8B//4B//4B//4B//4A//x4//n+f/P/P+fPn+fPn+fP3+/Px+/Px+fn3+fzn+f/n/P/P/n+f/x4//4A//4B//4B//4B//8B/w==")}), - show: function() { bangleItems[0].emit("redraw"); }, - hide: function () {} - }, { name : "Battery", get : () => ({ text : E.getBattery() + "%", @@ -166,16 +162,12 @@ function load() { // Custom menus var clockItems = { - id: "bw_clock", + name: null, + img: null, items: [ - { name: "Overview", - get: () => ({ text: null, img: null}), - show: function() { clockItems.items[0].emit("redraw"); }, - hide: function () {} - }, { name: "WeekOfYear", get: () => ({ text: "Week " + weekOfYear(), img: null}), - show: function() { clockItems.items[1].emit("redraw"); }, + show: function() { clockItems.items[0].emit("redraw"); }, hide: function () {} }, ] @@ -334,10 +326,17 @@ function drawMenuItem(text, image){ function drawMenuAndTime(){ - // Draw item if needed - var menuEntry = menu[settings.menuPosX]; - var item = menuEntry.items[settings.menuPosY]; - item.show(); + var menuEntry = menu[settings.menuPosX]; + + // The first entry is the overview... + if(settings.menuPosY == 0){ + drawMenuItem(menuEntry.name, menuEntry.img); + return; + } + + // Draw item if needed + var item = menuEntry.items[settings.menuPosY-1]; + item.show(); } @@ -423,7 +422,7 @@ Bangle.on('touch', function(btn, e){ if(is_lower){ Bangle.buzz(40, 0.6); - settings.menuPosY = (settings.menuPosY+1) % menu[settings.menuPosX].items.length; + settings.menuPosY = (settings.menuPosY+1) % (menu[settings.menuPosX].items.length+1); drawMenuAndTime(); } @@ -435,7 +434,7 @@ Bangle.on('touch', function(btn, e){ Bangle.buzz(40, 0.6); settings.menuPosY = settings.menuPosY-1; - settings.menuPosY = settings.menuPosY < 0 ? menu[settings.menuPosX].items.length-1 : settings.menuPosY; + settings.menuPosY = settings.menuPosY < 0 ? menu[settings.menuPosX].items.length : settings.menuPosY; drawMenuAndTime(); } From 37ff21b7fa7a8534ecc66a1cd6e5008b0366c3f4 Mon Sep 17 00:00:00 2001 From: David Peer Date: Sat, 17 Sep 2022 17:26:43 +0200 Subject: [PATCH 08/25] Improved input through locking --- apps/bwclk/app.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/apps/bwclk/app.js b/apps/bwclk/app.js index a0035222e..0474cacf1 100644 --- a/apps/bwclk/app.js +++ b/apps/bwclk/app.js @@ -28,6 +28,7 @@ for (const key in saved_settings) { settings[key] = saved_settings[key] } +var lock_input = false; /************ * Assets @@ -189,6 +190,9 @@ menu.forEach((menuItm, x) => { // immedeately after redraw... item.hide(); + // After drawing the item, we enable inputs again... + lock_input = false; + var info = item.get(); drawMenuItem(info.text, info.img); } @@ -335,6 +339,7 @@ function drawMenuAndTime(){ } // Draw item if needed + lock_input = true; var item = menuEntry.items[settings.menuPosY-1]; item.show(); } @@ -420,6 +425,10 @@ Bangle.on('touch', function(btn, e){ var is_right = e.x > right && !is_upper && !is_lower; var is_center = !is_upper && !is_lower && !is_left && !is_right; + if(lock_input){ + return; + } + if(is_lower){ Bangle.buzz(40, 0.6); settings.menuPosY = (settings.menuPosY+1) % (menu[settings.menuPosX].items.length+1); From b60f0c4687e078b6fae52e9be1764f064370efbf Mon Sep 17 00:00:00 2001 From: David Peer Date: Sat, 17 Sep 2022 18:07:43 +0200 Subject: [PATCH 09/25] Added basic version of agenda --- apps/bwclk/app.js | 54 +++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 47 insertions(+), 7 deletions(-) diff --git a/apps/bwclk/app.js b/apps/bwclk/app.js index 0474cacf1..e7fbf6a08 100644 --- a/apps/bwclk/app.js +++ b/apps/bwclk/app.js @@ -82,7 +82,7 @@ function imgLock(){ } -// clock_info ######################################################## +// ----clock_info ------------------------------------------------------ function load() { // info used for drawing... var hrm = "--"; @@ -158,7 +158,7 @@ function load() { // return it all! return items; }; -// clock_info ######################################################## +// ----clock_info ------------------------------------------------------ // Custom menus @@ -175,11 +175,45 @@ var clockItems = { }; +// ----agenda_clock_info ------------------------------------------------------ +var agendaItems = { + name: "Agenda", + img: atob("GBiBAf////////85z/AAAPAAAPgAAP////AAAPAAAPAAAPAAAOAAAeAAAeAAAcAAA8AAAoAABgAADP//+P//8PAAAPAAAPgAAf///w=="), + items: [] +}; + +var now = new Date(); +var agenda = storage.readJSON("android.calendar.json") + .filter(ev=>ev.timestamp + ev.durationInSeconds > now/1000) + .sort((a,b)=>a.timestamp - b.timestamp); + +agenda.forEach((entry, i) => { + + var title = entry.title.slice(0,14); + var date = new Date(entry.timestamp*1000); + var dateStr = locale.date(date).replace(/\d\d\d\d/,""); + dateStr += entry.durationInSeconds < 86400 ? "/ " + locale.time(date,1) : ""; + + agendaItems.items.push({ + name: "agendaEntry", + get: () => ({ text: title + "\n" + dateStr, img: null}), + show: function() { agendaItems.items[i].emit("redraw"); }, + hide: function () {} + }); +}); +// ----agenda_clock_info ------------------------------------------------------ + + +var timerItems = {}; +var weatherItems = {}; +var homeAssistantItems = {}; + + // Load menu var menu = load(); +menu = menu.concat(agendaItems); menu = menu.concat(clockItems); - // Set draw functions for each item menu.forEach((menuItm, x) => { menuItm.items.forEach((item, y) => { @@ -312,15 +346,21 @@ function drawMenuItem(text, image){ var hasText = (text != null && text != ""); if(hasText){ g.setFontAlign(0,0); - g.setSmallFont(); + + // For multiline text we show an even smaller font... + if(text.split('\n').length > 1){ + g.setMiniFont(); + } else { + g.setSmallFont(); + } var imgWidth = image == null ? 0 : 24; var strWidth = g.stringWidth(text); - g.setColor(g.theme.fg).fillRect(0, 147-14, W, H); - g.setColor(g.theme.bg).drawString(text, W/2 + imgWidth/2 + 2, 147+3); + g.setColor(g.theme.fg).fillRect(0, 149-14, W, H); + g.setColor(g.theme.bg).drawString(text, W/2 + imgWidth/2 + 2, 149+3); if(image != null){ - g.drawImage(image, W/2 + -strWidth/2-4 - parseInt(imgWidth/2), 147 - parseInt(imgWidth/2)); + g.drawImage(image, W/2 + -strWidth/2-4 - parseInt(imgWidth/2), 149 - parseInt(imgWidth/2)); } } From b06f3a9cc2902dcd0281d4d0b297c6f9735bfb35 Mon Sep 17 00:00:00 2001 From: David Peer Date: Sat, 17 Sep 2022 18:21:54 +0200 Subject: [PATCH 10/25] Added weather --- apps/bwclk/app.js | 51 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-) diff --git a/apps/bwclk/app.js b/apps/bwclk/app.js index e7fbf6a08..5cbc80bc7 100644 --- a/apps/bwclk/app.js +++ b/apps/bwclk/app.js @@ -204,14 +204,62 @@ agenda.forEach((entry, i) => { // ----agenda_clock_info ------------------------------------------------------ + +// ----weather_clock_info ------------------------------------------------------ +var weather = { + temp: "?", + hum: "?", + wind: "?", +}; + +var weatherJson = storage.readJSON('weather.json'); +if(weatherJson !== undefined && weatherJson.weather !== undefined){ + weather = weatherJson.weather; + weather.temp = locale.temp(weather.temp-273.15); + weather.hum = weather.hum + "%"; + weather.wind = locale.speed(weather.wind).match(/^(\D*\d*)(.*)$/); + weather.wind = Math.round(weather.wind[1]) + "kph"; +} + +var weatherItems = { + name: "Weather", + img: atob("GBiBAf+///u5//n7//8f/9wHP8gDf/gB//AB/7AH/5AcP/AQH/DwD/uAD84AD/4AA/wAAfAAAfAAAfAAAfgAA/////+bP/+zf/+zfw=="), + items: [ + { + name: "temperature", + get: () => ({ text: weather.temp, img: atob("GBiBAf/D//+B//8Y//88//88//88//88//88//8k//8k//8k//8k//8k//8k//4kf/5mf/zDP/yBP/yBP/zDP/5mf/48f/8A///D/w==")}), + show: function() { weatherItems.items[0].emit("redraw"); }, + hide: function () {} + }, + { + name: "humidity", + get: () => ({ text: weather.hum, img: atob("GBiBAf/7///z///x///g///g///Af//Af/3Af/nA//jg//B/v/B/H+A/H8A+D8AeB8AcB4AYA8AYA8AYA+A4A/B4A//4A//8B///Dw==")}), + show: function() { weatherItems.items[1].emit("redraw"); }, + hide: function () {} + }, + { + name: "wind", + get: () => ({ text: weather.wind, img: atob("GBiBAf4f//wP//nn//Pn//Pzg//nAf/meIAOfAAefP///P//+fAAAfAAB////////wAAP4AAH///z///z//nz//nz//zj//wH//8Pw==")}), + show: function() { weatherItems.items[2].emit("redraw"); }, + hide: function () {} + }, + ] +}; + + + +// ----weather_clock_info ------------------------------------------------------ + + +// Still missing var timerItems = {}; -var weatherItems = {}; var homeAssistantItems = {}; // Load menu var menu = load(); menu = menu.concat(agendaItems); +menu = menu.concat(weatherItems); menu = menu.concat(clockItems); // Set draw functions for each item @@ -348,6 +396,7 @@ function drawMenuItem(text, image){ g.setFontAlign(0,0); // For multiline text we show an even smaller font... + text = String(text); if(text.split('\n').length > 1){ g.setMiniFont(); } else { From 3696cff42ac35d358e7d1192078bf66f7299df62 Mon Sep 17 00:00:00 2001 From: David Peer Date: Sun, 18 Sep 2022 11:46:25 +0200 Subject: [PATCH 11/25] Minor fix -- otherwise clock works not properly --- apps/bwclk/app.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/bwclk/app.js b/apps/bwclk/app.js index 5cbc80bc7..dea7484af 100644 --- a/apps/bwclk/app.js +++ b/apps/bwclk/app.js @@ -83,7 +83,7 @@ function imgLock(){ // ----clock_info ------------------------------------------------------ -function load() { +function loadClockInfo() { // info used for drawing... var hrm = "--"; var alt = "--"; @@ -257,7 +257,7 @@ var homeAssistantItems = {}; // Load menu -var menu = load(); +var menu = loadClockInfo(); menu = menu.concat(agendaItems); menu = menu.concat(weatherItems); menu = menu.concat(clockItems); From 1d8008c127a5bf2c4d010af79d222bac22947555 Mon Sep 17 00:00:00 2001 From: David Peer Date: Sun, 18 Sep 2022 12:00:58 +0200 Subject: [PATCH 12/25] Added home assistant --- apps/bwclk/app.js | 38 ++++++++++++++++++++++++++++++++------ 1 file changed, 32 insertions(+), 6 deletions(-) diff --git a/apps/bwclk/app.js b/apps/bwclk/app.js index dea7484af..e6e621e36 100644 --- a/apps/bwclk/app.js +++ b/apps/bwclk/app.js @@ -195,7 +195,7 @@ agenda.forEach((entry, i) => { dateStr += entry.durationInSeconds < 86400 ? "/ " + locale.time(date,1) : ""; agendaItems.items.push({ - name: "agendaEntry", + name: "agendaEntry-" + i, get: () => ({ text: title + "\n" + dateStr, img: null}), show: function() { agendaItems.items[i].emit("redraw"); }, hide: function () {} @@ -245,21 +245,46 @@ var weatherItems = { }, ] }; - - - // ----weather_clock_info ------------------------------------------------------ +// ----ha_clock_info ------------------------------------------------------ +var triggers = require("ha.lib.js").getTriggers(); + +var haItems = { + name: "Home", + img: atob("GBiBAf/////////n///D//+B//8A//48T/wkD/gkD/A8D+AYB8AYA4eZ4QyZMOyZN+fb5+D/B+B+B+A8B+AYB+AYB+AYB+AYB+A8Bw=="), + items: [ + // { + // name: "item1", + // get: () => ({ text: "Item1", img: atob("GBiBAf/D//+B//8Y//88//88//88//88//88//8k//8k//8k//8k//8k//8k//4kf/5mf/zDP/yBP/yBP/zDP/5mf/48f/8A///D/w==")}), + // show: function() { haItems.items[0].emit("redraw"); }, + // hide: function () {} + // }, + ] +}; + +triggers.forEach((trigger, i) => { + haItems.items.push({ + name: "haTrigger-" + i, + get: () => ({ text: trigger.display, img: trigger.getIcon()}), + show: function() { haItems.items[i].emit("redraw"); }, + hide: function () {} + }); +}); + +// ----ha_clock_info ------------------------------------------------------ + + // Still missing var timerItems = {}; -var homeAssistantItems = {}; // Load menu var menu = loadClockInfo(); menu = menu.concat(agendaItems); menu = menu.concat(weatherItems); +menu = menu.concat(haItems); menu = menu.concat(clockItems); // Set draw functions for each item @@ -409,7 +434,8 @@ function drawMenuItem(text, image){ g.setColor(g.theme.bg).drawString(text, W/2 + imgWidth/2 + 2, 149+3); if(image != null){ - g.drawImage(image, W/2 + -strWidth/2-4 - parseInt(imgWidth/2), 149 - parseInt(imgWidth/2)); + var scale = imgWidth / image.width; + g.drawImage(image, W/2 + -strWidth/2-4 - parseInt(imgWidth/2), 149 - parseInt(imgWidth/2), {scale: scale}); } } From aeb2ec50021fe93da7c1f60930030f0ade84a11f Mon Sep 17 00:00:00 2001 From: David Peer Date: Sun, 18 Sep 2022 12:01:53 +0200 Subject: [PATCH 13/25] Fix build --- apps/bwclk/app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/bwclk/app.js b/apps/bwclk/app.js index e6e621e36..b456b5e3b 100644 --- a/apps/bwclk/app.js +++ b/apps/bwclk/app.js @@ -157,7 +157,7 @@ function loadClockInfo() { // return it all! return items; -}; +} // ----clock_info ------------------------------------------------------ From 2c1b29eb534a598ba6f1416e3c41571dacde50f6 Mon Sep 17 00:00:00 2001 From: David Peer Date: Sun, 18 Sep 2022 12:10:14 +0200 Subject: [PATCH 14/25] Added action to HA --- apps/bwclk/app.js | 55 ++++++++++++++++++++++++++++++++--------------- 1 file changed, 38 insertions(+), 17 deletions(-) diff --git a/apps/bwclk/app.js b/apps/bwclk/app.js index b456b5e3b..edc4a9272 100644 --- a/apps/bwclk/app.js +++ b/apps/bwclk/app.js @@ -249,7 +249,8 @@ var weatherItems = { // ----ha_clock_info ------------------------------------------------------ -var triggers = require("ha.lib.js").getTriggers(); +var ha = require("ha.lib.js"); +var triggers = ha.getTriggers(); var haItems = { name: "Home", @@ -269,7 +270,11 @@ triggers.forEach((trigger, i) => { name: "haTrigger-" + i, get: () => ({ text: trigger.display, img: trigger.getIcon()}), show: function() { haItems.items[i].emit("redraw"); }, - hide: function () {} + hide: function () {}, + run: function() { + ha.sendTrigger("TRIGGER_BW"); + ha.sendTrigger(trigger.trigger); + } }); }); @@ -460,6 +465,34 @@ function drawMenuAndTime(){ } +function canRunItem(){ + if(settings.menuPosY == 0){ + return false; + } + + var menuEntry = menu[settings.menuPosX]; + var item = menuEntry.items[settings.menuPosY-1]; + return item.run !== undefined; +} + +function runItem(){ + if(settings.menuPosY == 0){ + return; + } + + var menuEntry = menu[settings.menuPosX]; + var item = menuEntry.items[settings.menuPosY-1]; + + Bangle.buzz(160, 0.6).then(()=>{ + try{ + item.run(); + } catch (ex) { + // Simply ignore it... + } + }); +} + + function drawLock(){ if(settings.showLock && Bangle.isLocked()){ g.setColor(g.theme.fg); @@ -579,21 +612,9 @@ Bangle.on('touch', function(btn, e){ } if(is_center){ - // var menuEntry = getMenuEntry(); - // if(menuEntry.length > 4 && menuEntry[4] != null){ - // Bangle.buzz(80, 0.6).then(()=>{ - // try{ - // menuEntry[4](); - // setTimeout(()=>{ - // Bangle.buzz(80, 0.6); - // drawTime(); - // }, 250); - // } catch(ex){ - // // In case it fails, we simply ignore it. - // } - // } - // ); - // } + if(canRunItem()){ + runItem(); + } } }); From 24972e31280b8247339111aba6ee6c87f79fbb27 Mon Sep 17 00:00:00 2001 From: David Peer Date: Mon, 19 Sep 2022 17:23:37 +0200 Subject: [PATCH 15/25] Refactored into clkinfo.js files --- apps/agenda/ChangeLog | 1 + apps/agenda/agenda.clkinfo.js | 29 +++++ apps/agenda/metadata.json | 3 +- apps/bwclk/ChangeLog | 3 +- apps/bwclk/app.js | 234 ++++------------------------------ apps/bwclk/metadata.json | 2 +- apps/ha/ChangeLog | 3 +- apps/ha/ha.clkinfo.js | 25 ++++ apps/ha/metadata.json | 3 +- apps/weather/ChangeLog | 1 + apps/weather/clkinfo.js | 43 +++++++ apps/weather/metadata.json | 5 +- modules/clock_info.js | 47 ++++--- 13 files changed, 167 insertions(+), 232 deletions(-) create mode 100644 apps/agenda/agenda.clkinfo.js create mode 100644 apps/ha/ha.clkinfo.js create mode 100644 apps/weather/clkinfo.js diff --git a/apps/agenda/ChangeLog b/apps/agenda/ChangeLog index 2c59c3cc2..16a90242b 100644 --- a/apps/agenda/ChangeLog +++ b/apps/agenda/ChangeLog @@ -3,3 +3,4 @@ 0.03: Disable past events display from settings 0.04: Added awareness of allDay field 0.05: Displaying calendar colour and name +0.06: Added clkinfo for clocks. \ No newline at end of file diff --git a/apps/agenda/agenda.clkinfo.js b/apps/agenda/agenda.clkinfo.js new file mode 100644 index 000000000..9e89b2ac8 --- /dev/null +++ b/apps/agenda/agenda.clkinfo.js @@ -0,0 +1,29 @@ +(function() { + var agendaItems = { + name: "Agenda", + img: atob("GBiBAf////////85z/AAAPAAAPgAAP////AAAPAAAPAAAPAAAOAAAeAAAeAAAcAAA8AAAoAABgAADP//+P//8PAAAPAAAPgAAf///w=="), + items: [] + }; + + var now = new Date(); + var agenda = storage.readJSON("android.calendar.json") + .filter(ev=>ev.timestamp + ev.durationInSeconds > now/1000) + .sort((a,b)=>a.timestamp - b.timestamp); + + agenda.forEach((entry, i) => { + + var title = entry.title.slice(0,14); + var date = new Date(entry.timestamp*1000); + var dateStr = locale.date(date).replace(/\d\d\d\d/,""); + dateStr += entry.durationInSeconds < 86400 ? "/ " + locale.time(date,1) : ""; + + agendaItems.items.push({ + name: "agendaEntry-" + i, + get: () => ({ text: title + "\n" + dateStr, img: null}), + show: function() { agendaItems.items[i].emit("redraw"); }, + hide: function () {} + }); + }); + + return agendaItems; +}) \ No newline at end of file diff --git a/apps/agenda/metadata.json b/apps/agenda/metadata.json index 982870905..2bce8ca56 100644 --- a/apps/agenda/metadata.json +++ b/apps/agenda/metadata.json @@ -1,7 +1,7 @@ { "id": "agenda", "name": "Agenda", - "version": "0.05", + "version": "0.06", "description": "Simple agenda", "icon": "agenda.png", "screenshots": [{"url":"screenshot_agenda_overview.png"}, {"url":"screenshot_agenda_event1.png"}, {"url":"screenshot_agenda_event2.png"}], @@ -12,6 +12,7 @@ "storage": [ {"name":"agenda.app.js","url":"agenda.js"}, {"name":"agenda.settings.js","url":"settings.js"}, + {"name":"agenda.clkinfo.js","url":"agenda.clkinfo.js"}, {"name":"agenda.img","url":"agenda-icon.js","evaluate":true} ], "data": [{"name":"agenda.settings.json"}] diff --git a/apps/bwclk/ChangeLog b/apps/bwclk/ChangeLog index 59bf9eb96..72919e37f 100644 --- a/apps/bwclk/ChangeLog +++ b/apps/bwclk/ChangeLog @@ -18,4 +18,5 @@ 0.18: Set timer for an agenda entry by simply clicking in the middle of the screen. Only one timer can be set. 0.19: Fix - Compatibility with "Digital clock widget" 0.20: Better handling of async data such as getPressure. -0.21: On the default menu the week of year can be shown. \ No newline at end of file +0.21: On the default menu the week of year can be shown. +0.22: Use the new clkinfo module for the menu. \ No newline at end of file diff --git a/apps/bwclk/app.js b/apps/bwclk/app.js index edc4a9272..c69a4acdc 100644 --- a/apps/bwclk/app.js +++ b/apps/bwclk/app.js @@ -3,7 +3,7 @@ */ const locale = require('locale'); const storage = require('Storage'); -// const clock_info = require("clock_info"); +const clock_info = require("clock_info"); /************ * Statics @@ -82,215 +82,42 @@ function imgLock(){ } -// ----clock_info ------------------------------------------------------ -function loadClockInfo() { - // info used for drawing... - var hrm = "--"; - var alt = "--"; - var interval = null; - // callbacks (needed for easy removal of listeners) - function batteryUpdateHandler() { bangleItems[0].emit("redraw"); } - function stepUpdateHandler() { bangleItems[1].emit("redraw"); } - function hrmUpdateHandler() { bangleItems[2].emit("redraw"); } - function altUpdateHandler() { - Bangle.getPressure().then(data=>{ - if (!data) return; - alt = Math.round(data.altitude) + "m"; - bangleItems[3].emit("redraw"); - }); - } - function deleteInterval(inter){ - if(inter){ - clearInterval(inter); - } - delete inter; - } - // actual items - var items = [{ - name: "Bangle", - img: atob("GBiBAf8B//4B//4B//4B//4A//x4//n+f/P/P+fPn+fPn+fP3+/Px+/Px+fn3+fzn+f/n/P/P/n+f/x4//4A//4B//4B//4B//8B/w=="), - items: [ - { name : "Battery", - get : () => ({ - text : E.getBattery() + "%", - img : atob(Bangle.isCharging() ? "GBiBAAABgAADwAAHwAAPgACfAAHOAAPkBgHwDwP4Hwf8Pg/+fB//OD//kD//wD//4D//8D//4B//QB/+AD/8AH/4APnwAHAAACAAAA==" : "GBiBAAAAAAAAAAAAAAAAAAAAAD//+P///IAAAr//Ar//Ar//A7//A7//A7//A7//Ar//AoAAAv///D//+AAAAAAAAAAAAAAAAAAAAA==") }), - show : function() { - deleteInterval(interval); - interval = setInterval(()=>this.emit('redraw'), 60000); - Bangle.on("charging", batteryUpdateHandler); - batteryUpdateHandler(); - }, - hide : function() { - deleteInterval(interval); - Bangle.removeListener("charging", batteryUpdateHandler); - }, - }, - { name : "Steps", get : () => ({ - text : Bangle.getHealthStatus("day").steps, - img : atob("GBiBAAcAAA+AAA/AAA/AAB/AAB/gAA/g4A/h8A/j8A/D8A/D+AfH+AAH8AHn8APj8APj8AHj4AHg4AADAAAHwAAHwAAHgAAHgAADAA==") }), - show : function() { Bangle.on("step", stepUpdateHandler); stepUpdateHandler(); }, - hide : function() { Bangle.removeListener("step", stepUpdateHandler); }, - }, - { name : "HRM", get : () => ({ - text : Math.round(Bangle.getHealthStatus("last").bpm) + " bpm", - img : atob("GBiBAAAAAAAAAAAAAAAAAAAAAADAAADAAAHAAAHjAAHjgAPngH9n/n82/gA+AAA8AAA8AAAcAAAYAAAYAAAAAAAAAAAAAAAAAAAAAA==") }), - show : function() { Bangle.setHRMPower(1,"clkinfo"); Bangle.on("HRM", hrmUpdateHandler); hrm = Math.round(Bangle.getHealthStatus("last").bpm); hrmUpdateHandler(); }, - hide : function() { Bangle.setHRMPower(0,"clkinfo"); Bangle.removeListener("HRM", hrmUpdateHandler); hrm = "--"; }, - } - ], - }]; - var bangleItems = items[0].items; - - if (Bangle.getPressure){ // Altimeter may not exist - bangleItems.push({ name : "Altitude", get : () => ({ - text : alt, - img : atob("GBiBAAAAAAAAAAAAAAAAAAAAAAACAAAGAAAPAAEZgAOwwAPwQAZgYAwAMBgAGBAACDAADGAABv///////wAAAAAAAAAAAAAAAAAAAA==") }), - show : function() { deleteInterval(); interval = setInterval(altUpdateHandler, 60000); alt = "--"; altUpdateHandler(); }, - hide : function() { deleteInterval(); }, - }); - } - - // now load extra data from a third party files - require("Storage").list(/clkinfo.js$/).forEach(fn => { - items = items.concat(eval(require("Storage").read(fn))()); - }); - - // return it all! - return items; -} -// ----clock_info ------------------------------------------------------ - - -// Custom menus -var clockItems = { +// Custom bwItems menu - therefore, its added here and not in a clkinfo.js file. +var bwItems = { name: null, img: null, items: [ { name: "WeekOfYear", get: () => ({ text: "Week " + weekOfYear(), img: null}), - show: function() { clockItems.items[0].emit("redraw"); }, + show: function() { bwItems.items[0].emit("redraw"); }, hide: function () {} }, ] }; - -// ----agenda_clock_info ------------------------------------------------------ -var agendaItems = { - name: "Agenda", - img: atob("GBiBAf////////85z/AAAPAAAPgAAP////AAAPAAAPAAAPAAAOAAAeAAAeAAAcAAA8AAAoAABgAADP//+P//8PAAAPAAAPgAAf///w=="), - items: [] -}; - -var now = new Date(); -var agenda = storage.readJSON("android.calendar.json") - .filter(ev=>ev.timestamp + ev.durationInSeconds > now/1000) - .sort((a,b)=>a.timestamp - b.timestamp); - -agenda.forEach((entry, i) => { - - var title = entry.title.slice(0,14); - var date = new Date(entry.timestamp*1000); - var dateStr = locale.date(date).replace(/\d\d\d\d/,""); - dateStr += entry.durationInSeconds < 86400 ? "/ " + locale.time(date,1) : ""; - - agendaItems.items.push({ - name: "agendaEntry-" + i, - get: () => ({ text: title + "\n" + dateStr, img: null}), - show: function() { agendaItems.items[i].emit("redraw"); }, - hide: function () {} - }); -}); -// ----agenda_clock_info ------------------------------------------------------ - - - -// ----weather_clock_info ------------------------------------------------------ -var weather = { - temp: "?", - hum: "?", - wind: "?", -}; - -var weatherJson = storage.readJSON('weather.json'); -if(weatherJson !== undefined && weatherJson.weather !== undefined){ - weather = weatherJson.weather; - weather.temp = locale.temp(weather.temp-273.15); - weather.hum = weather.hum + "%"; - weather.wind = locale.speed(weather.wind).match(/^(\D*\d*)(.*)$/); - weather.wind = Math.round(weather.wind[1]) + "kph"; +function weekOfYear() { + var date = new Date(); + date.setHours(0, 0, 0, 0); + // Thursday in current week decides the year. + date.setDate(date.getDate() + 3 - (date.getDay() + 6) % 7); + // January 4 is always in week 1. + var week1 = new Date(date.getFullYear(), 0, 4); + // Adjust to Thursday in week 1 and count number of weeks from date to week1. + return 1 + Math.round(((date.getTime() - week1.getTime()) / 86400000 + - 3 + (week1.getDay() + 6) % 7) / 7); } -var weatherItems = { - name: "Weather", - img: atob("GBiBAf+///u5//n7//8f/9wHP8gDf/gB//AB/7AH/5AcP/AQH/DwD/uAD84AD/4AA/wAAfAAAfAAAfAAAfgAA/////+bP/+zf/+zfw=="), - items: [ - { - name: "temperature", - get: () => ({ text: weather.temp, img: atob("GBiBAf/D//+B//8Y//88//88//88//88//88//8k//8k//8k//8k//8k//8k//4kf/5mf/zDP/yBP/yBP/zDP/5mf/48f/8A///D/w==")}), - show: function() { weatherItems.items[0].emit("redraw"); }, - hide: function () {} - }, - { - name: "humidity", - get: () => ({ text: weather.hum, img: atob("GBiBAf/7///z///x///g///g///Af//Af/3Af/nA//jg//B/v/B/H+A/H8A+D8AeB8AcB4AYA8AYA8AYA+A4A/B4A//4A//8B///Dw==")}), - show: function() { weatherItems.items[1].emit("redraw"); }, - hide: function () {} - }, - { - name: "wind", - get: () => ({ text: weather.wind, img: atob("GBiBAf4f//wP//nn//Pn//Pzg//nAf/meIAOfAAefP///P//+fAAAfAAB////////wAAP4AAH///z///z//nz//nz//zj//wH//8Pw==")}), - show: function() { weatherItems.items[2].emit("redraw"); }, - hide: function () {} - }, - ] -}; -// ----weather_clock_info ------------------------------------------------------ - - -// ----ha_clock_info ------------------------------------------------------ -var ha = require("ha.lib.js"); -var triggers = ha.getTriggers(); - -var haItems = { - name: "Home", - img: atob("GBiBAf/////////n///D//+B//8A//48T/wkD/gkD/A8D+AYB8AYA4eZ4QyZMOyZN+fb5+D/B+B+B+A8B+AYB+AYB+AYB+AYB+A8Bw=="), - items: [ - // { - // name: "item1", - // get: () => ({ text: "Item1", img: atob("GBiBAf/D//+B//8Y//88//88//88//88//88//8k//8k//8k//8k//8k//8k//4kf/5mf/zDP/yBP/yBP/zDP/5mf/48f/8A///D/w==")}), - // show: function() { haItems.items[0].emit("redraw"); }, - // hide: function () {} - // }, - ] -}; - -triggers.forEach((trigger, i) => { - haItems.items.push({ - name: "haTrigger-" + i, - get: () => ({ text: trigger.display, img: trigger.getIcon()}), - show: function() { haItems.items[i].emit("redraw"); }, - hide: function () {}, - run: function() { - ha.sendTrigger("TRIGGER_BW"); - ha.sendTrigger(trigger.trigger); - } - }); -}); - -// ----ha_clock_info ------------------------------------------------------ - - -// Still missing -var timerItems = {}; - // Load menu -var menu = loadClockInfo(); -menu = menu.concat(agendaItems); -menu = menu.concat(weatherItems); -menu = menu.concat(haItems); -menu = menu.concat(clockItems); +var menu = clock_info.load(); +menu = menu.concat(bwItems); + + +// Ensure that our settings are still in range (e.g. app uninstall). Otherwise reset the position it. +if(settings.menuPosX >= menu.length || settings.menuPosY > menu[settings.menuPosX].items.length ){ + settings.menuPosX = 0; + settings.menuPosY = 0; +} // Set draw functions for each item menu.forEach((menuItm, x) => { @@ -328,19 +155,6 @@ function isFullscreen(){ } -function weekOfYear() { - var date = new Date(); - date.setHours(0, 0, 0, 0); - // Thursday in current week decides the year. - date.setDate(date.getDate() + 3 - (date.getDay() + 6) % 7); - // January 4 is always in week 1. - var week1 = new Date(date.getFullYear(), 0, 4); - // Adjust to Thursday in week 1 and count number of weeks from date to week1. - return 1 + Math.round(((date.getTime() - week1.getTime()) / 86400000 - - 3 + (week1.getDay() + 6) % 7) / 7); -} - - /************ * DRAW */ @@ -363,7 +177,7 @@ function drawDate(){ // Draw date y = parseInt(y/2)+4; - y += isFullscreen() ? 0 : 13; + y += isFullscreen() ? 0 : 8; var date = new Date(); var dateStr = date.getDate(); dateStr = ("0" + dateStr).substr(-2); diff --git a/apps/bwclk/metadata.json b/apps/bwclk/metadata.json index b6896ab5e..35e707f68 100644 --- a/apps/bwclk/metadata.json +++ b/apps/bwclk/metadata.json @@ -1,7 +1,7 @@ { "id": "bwclk", "name": "BW Clock", - "version": "0.21", + "version": "0.22", "description": "A very minimalistic clock to mainly show date and time.", "readme": "README.md", "icon": "app.png", diff --git a/apps/ha/ChangeLog b/apps/ha/ChangeLog index e78b4ccd0..493854eb4 100644 --- a/apps/ha/ChangeLog +++ b/apps/ha/ChangeLog @@ -1,2 +1,3 @@ 0.01: Release -0.02: Includeas the ha.lib.js library that can be used by other apps or clocks. \ No newline at end of file +0.02: Includeas the ha.lib.js library that can be used by other apps or clocks. +0.03: Added clkinfo for clocks. \ No newline at end of file diff --git a/apps/ha/ha.clkinfo.js b/apps/ha/ha.clkinfo.js new file mode 100644 index 000000000..bb3b7e5a1 --- /dev/null +++ b/apps/ha/ha.clkinfo.js @@ -0,0 +1,25 @@ +(function() { + var ha = require("ha.lib.js"); + var triggers = ha.getTriggers(); + + var haItems = { + name: "Home", + img: atob("GBiBAf/////////n///D//+B//8A//48T/wkD/gkD/A8D+AYB8AYA4eZ4QyZMOyZN+fb5+D/B+B+B+A8B+AYB+AYB+AYB+AYB+A8Bw=="), + items: [] + }; + + triggers.forEach((trigger, i) => { + haItems.items.push({ + name: "haTrigger-" + i, + get: () => ({ text: trigger.display, img: trigger.getIcon()}), + show: function() { haItems.items[i].emit("redraw"); }, + hide: function () {}, + run: function() { + ha.sendTrigger("TRIGGER_BW"); + ha.sendTrigger(trigger.trigger); + } + }); + }); + + return haItems; +}) \ No newline at end of file diff --git a/apps/ha/metadata.json b/apps/ha/metadata.json index 63308b933..e59e63c91 100644 --- a/apps/ha/metadata.json +++ b/apps/ha/metadata.json @@ -1,7 +1,7 @@ { "id": "ha", "name": "HomeAssistant", - "version": "0.02", + "version": "0.03", "description": "Integrates your BangleJS into HomeAssistant.", "icon": "ha.png", "type": "app", @@ -20,6 +20,7 @@ "storage": [ {"name":"ha.app.js","url":"ha.app.js"}, {"name":"ha.lib.js","url":"ha.lib.js"}, + {"name":"ha.clkinfo.js","url":"ha.clkinfo.js"}, {"name":"ha.img","url":"ha.icon.js","evaluate":true} ] } diff --git a/apps/weather/ChangeLog b/apps/weather/ChangeLog index 49e23e1d6..da28d8d5a 100644 --- a/apps/weather/ChangeLog +++ b/apps/weather/ChangeLog @@ -13,3 +13,4 @@ 0.14: Use weather condition code for icon selection 0.15: Fix widget icon 0.16: Don't mark app as clock +0.17: Added clkinfo for clocks. \ No newline at end of file diff --git a/apps/weather/clkinfo.js b/apps/weather/clkinfo.js new file mode 100644 index 000000000..8e502b7fc --- /dev/null +++ b/apps/weather/clkinfo.js @@ -0,0 +1,43 @@ +(function() { + var weather = { + temp: "?", + hum: "?", + wind: "?", + }; + + var weatherJson = storage.readJSON('weather.json'); + if(weatherJson !== undefined && weatherJson.weather !== undefined){ + weather = weatherJson.weather; + weather.temp = locale.temp(weather.temp-273.15); + weather.hum = weather.hum + "%"; + weather.wind = locale.speed(weather.wind).match(/^(\D*\d*)(.*)$/); + weather.wind = Math.round(weather.wind[1]) + "kph"; + } + + var weatherItems = { + name: "Weather", + img: atob("GBiBAf+///u5//n7//8f/9wHP8gDf/gB//AB/7AH/5AcP/AQH/DwD/uAD84AD/4AA/wAAfAAAfAAAfAAAfgAA/////+bP/+zf/+zfw=="), + items: [ + { + name: "temperature", + get: () => ({ text: weather.temp, img: atob("GBiBAf/D//+B//8Y//88//88//88//88//88//8k//8k//8k//8k//8k//8k//4kf/5mf/zDP/yBP/yBP/zDP/5mf/48f/8A///D/w==")}), + show: function() { weatherItems.items[0].emit("redraw"); }, + hide: function () {} + }, + { + name: "humidity", + get: () => ({ text: weather.hum, img: atob("GBiBAf/7///z///x///g///g///Af//Af/3Af/nA//jg//B/v/B/H+A/H8A+D8AeB8AcB4AYA8AYA8AYA+A4A/B4A//4A//8B///Dw==")}), + show: function() { weatherItems.items[1].emit("redraw"); }, + hide: function () {} + }, + { + name: "wind", + get: () => ({ text: weather.wind, img: atob("GBiBAf4f//wP//nn//Pn//Pzg//nAf/meIAOfAAefP///P//+fAAAfAAB////////wAAP4AAH///z///z//nz//nz//zj//wH//8Pw==")}), + show: function() { weatherItems.items[2].emit("redraw"); }, + hide: function () {} + }, + ] + }; + + return weatherItems; +}) \ No newline at end of file diff --git a/apps/weather/metadata.json b/apps/weather/metadata.json index 25037de3d..125041ec4 100644 --- a/apps/weather/metadata.json +++ b/apps/weather/metadata.json @@ -1,7 +1,7 @@ { "id": "weather", "name": "Weather", - "version": "0.16", + "version": "0.17", "description": "Show Gadgetbridge weather report", "icon": "icon.png", "screenshots": [{"url":"screenshot.png"}], @@ -13,7 +13,8 @@ {"name":"weather.wid.js","url":"widget.js"}, {"name":"weather","url":"lib.js"}, {"name":"weather.img","url":"icon.js","evaluate":true}, - {"name":"weather.settings.js","url":"settings.js"} + {"name":"weather.settings.js","url":"settings.js"}, + {"name":"weather.clkinfo.js","url":"clkinfo.js"} ], "data": [{"name":"weather.json"}] } diff --git a/modules/clock_info.js b/modules/clock_info.js index 2ee7fc2f7..df35d4e22 100644 --- a/modules/clock_info.js +++ b/modules/clock_info.js @@ -37,57 +37,74 @@ exports.load = function() { // info used for drawing... var hrm = "--"; var alt = "--"; + var interval = null; // callbacks (needed for easy removal of listeners) - function batteryUpdateHandler() { items[0].emit("redraw"); } - function stepUpdateHandler() { items[1].emit("redraw"); } - function hrmUpdateHandler() { items[2].emit("redraw"); } + function batteryUpdateHandler() { bangleItems[0].emit("redraw"); } + function stepUpdateHandler() { bangleItems[1].emit("redraw"); } + function hrmUpdateHandler() { bangleItems[2].emit("redraw"); } function altUpdateHandler() { Bangle.getPressure().then(data=>{ if (!data) return; alt = Math.round(data.altitude) + "m"; - items[3].emit("redraw"); + bangleItems[3].emit("redraw"); }); } + function deleteInterval(inter){ + if(inter){ + clearInterval(inter); + } + delete inter; + } // actual items - var items = [ + var items = [{ + name: "Bangle", + img: atob("GBiBAf8B//4B//4B//4B//4A//x4//n+f/P/P+fPn+fPn+fP3+/Px+/Px+fn3+fzn+f/n/P/P/n+f/x4//4A//4B//4B//4B//8B/w=="), + items: [ { name : "Battery", get : () => ({ text : E.getBattery() + "%", img : atob(Bangle.isCharging() ? "GBiBAAABgAADwAAHwAAPgACfAAHOAAPkBgHwDwP4Hwf8Pg/+fB//OD//kD//wD//4D//8D//4B//QB/+AD/8AH/4APnwAHAAACAAAA==" : "GBiBAAAAAAAAAAAAAAAAAAAAAD//+P///IAAAr//Ar//Ar//A7//A7//A7//A7//Ar//AoAAAv///D//+AAAAAAAAAAAAAAAAAAAAA==") }), show : function() { - this.interval = setInterval(()=>this.emit('redraw'), 60000); + deleteInterval(interval); + interval = setInterval(()=>this.emit('redraw'), 60000); Bangle.on("charging", batteryUpdateHandler); + batteryUpdateHandler(); }, hide : function() { - clearInterval(this.interval); - delete this.interval; + deleteInterval(interval); Bangle.removeListener("charging", batteryUpdateHandler); }, }, { name : "Steps", get : () => ({ text : Bangle.getHealthStatus("day").steps, img : atob("GBiBAAcAAA+AAA/AAA/AAB/AAB/gAA/g4A/h8A/j8A/D8A/D+AfH+AAH8AHn8APj8APj8AHj4AHg4AADAAAHwAAHwAAHgAAHgAADAA==") }), - show : function() { Bangle.on("step", stepUpdateHandler); }, + show : function() { Bangle.on("step", stepUpdateHandler); stepUpdateHandler(); }, hide : function() { Bangle.removeListener("step", stepUpdateHandler); }, }, { name : "HRM", get : () => ({ text : Math.round(Bangle.getHealthStatus("last").bpm) + " bpm", img : atob("GBiBAAAAAAAAAAAAAAAAAAAAAADAAADAAAHAAAHjAAHjgAPngH9n/n82/gA+AAA8AAA8AAAcAAAYAAAYAAAAAAAAAAAAAAAAAAAAAA==") }), - show : function() { Bangle.setHRMPower(1,"clkinfo"); Bangle.on("HRM", hrmUpdateHandler); hrm = Math.round(Bangle.getHealthStatus("last").bpm); }, + show : function() { Bangle.setHRMPower(1,"clkinfo"); Bangle.on("HRM", hrmUpdateHandler); hrm = Math.round(Bangle.getHealthStatus("last").bpm); hrmUpdateHandler(); }, hide : function() { Bangle.setHRMPower(0,"clkinfo"); Bangle.removeListener("HRM", hrmUpdateHandler); hrm = "--"; }, } - ]; - if (Bangle.getPressure) // Altimeter may not exist - items.push({ name : "Altitude", get : () => ({ + ], + }]; + var bangleItems = items[0].items; + + if (Bangle.getPressure){ // Altimeter may not exist + bangleItems.push({ name : "Altitude", get : () => ({ text : alt, img : atob("GBiBAAAAAAAAAAAAAAAAAAAAAAACAAAGAAAPAAEZgAOwwAPwQAZgYAwAMBgAGBAACDAADGAABv///////wAAAAAAAAAAAAAAAAAAAA==") }), - show : function() { this.interval = setInterval(altUpdateHandler, 60000); alt = "--"; altUpdateHandler(); }, - hide : function() { clearInterval(this.interval); delete this.interval; }, + show : function() { deleteInterval(interval); interval = setInterval(altUpdateHandler, 60000); alt = "--"; altUpdateHandler(); }, + hide : function() { deleteInterval(interval); }, }); + } + // now load extra data from a third party files require("Storage").list(/clkinfo.js$/).forEach(fn => { items = items.concat(eval(require("Storage").read(fn))()); }); + // return it all! return items; }; From 99999cbc88bbf743a23289b0a85f4a9ab3132488 Mon Sep 17 00:00:00 2001 From: David Peer Date: Mon, 19 Sep 2022 17:37:43 +0200 Subject: [PATCH 16/25] Minor changes --- apps/bwclk/app.js | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/apps/bwclk/app.js b/apps/bwclk/app.js index c69a4acdc..15212ea21 100644 --- a/apps/bwclk/app.js +++ b/apps/bwclk/app.js @@ -296,14 +296,12 @@ function runItem(){ var menuEntry = menu[settings.menuPosX]; var item = menuEntry.items[settings.menuPosY-1]; - - Bangle.buzz(160, 0.6).then(()=>{ - try{ - item.run(); - } catch (ex) { - // Simply ignore it... - } - }); + try{ + item.run(); + Bangle.buzz(300, 0.6).then(() => {}); + } catch (ex) { + // Simply ignore it... + } } From d5ccb4919c4911c075fe21958491b13b535586c7 Mon Sep 17 00:00:00 2001 From: David Peer Date: Mon, 19 Sep 2022 17:43:55 +0200 Subject: [PATCH 17/25] Updated readme --- apps/bwclk/README.md | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/apps/bwclk/README.md b/apps/bwclk/README.md index dfb9bf515..3a5061e81 100644 --- a/apps/bwclk/README.md +++ b/apps/bwclk/README.md @@ -4,9 +4,12 @@ A very minimalistic clock to mainly show date and time. ![](screenshot.png) ## Features -The BW clock provides many features and also 3rd party integrations: +The BW clock implements 3rd party integrations of other apps through the `clkinfo` module. +For example if you install the HomeAssistant app, this menu item will show up in BWClock +and additionally allows to send your triggers directly from the clock. Here are some +features that are supported: + - Bangle data such as steps, heart rate, battery or charging state. -- A timer can be set directly. *Requirement: Scheduler library* - Show agenda entries. A timer for an agenda entry can also be set by simply clicking in the middle of the screen. This can be used to not forget a meeting etc. Note that only one agenda-timer can be set at a time. *Requirement: Gadgetbridge calendar sync enabled* - Weather temperature as well as the wind speed can be shown. *Requirement: Weather app* - HomeAssistant triggers can be executed directly. *Requirement: HomeAssistant app* @@ -20,27 +23,29 @@ Note: If some apps are not installed (e.gt. weather app), then this menu item is - Your bangle uses the sys color settings so you can change the color too. ## Menu structure -2D menu allows you to display lots of different data including data from 3rd party apps and it's also possible to control things e.g. to set a timer or send a HomeAssistant trigger. +2D menu allows you to display lots of different data including data from 3rd party apps and it's also possible to control things e.g. to trigger HomeAssistant. -Simply click left / right to go through the menu entries such as Bangle, Timer etc. +Simply click left / right to go through the menu entries such as Bangle, Weather etc. and click up/down to move into this sub-menu. You can then click in the middle of the screen -to e.g. send a trigger via HomeAssistant once you selected it. +to e.g. send a trigger via HomeAssistant once you selected it. The actions really depend +on the app that provide this sub-menu through the `clkinfo` module. ``` - +5min - | - Bangle -- Timer[Optional] -- Agenda 1[Optional] -- Weather[Optional] -- HomeAssistant [Optional] - | | | | | - Bpm -5min Agenda 2 Temperature Trigger1 - | | | | - Steps ... ... ... + Bangle -- Agenda -- Weather -- HomeAssistant + | | | | + Battery Entry 1 Temperature Trigger1 + | | | | + Steps ... ... ... | - Battery + ... ``` ## Thanks to -Icons created by Flaticon +- Thanks to Gordon not only for the great BangleJs, but specifically also for the implementation of `clkinfo` which simplified the BWClock a lot and moved complexety to the apps where it should be located. +- Icons created by Flaticon ## Creator [David Peer](https://github.com/peerdavid) + +## Changes From 00783857ba333325967d3b048956d0d1a094325d Mon Sep 17 00:00:00 2001 From: David Peer Date: Mon, 19 Sep 2022 17:44:46 +0200 Subject: [PATCH 18/25] Minor change --- apps/bwclk/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/bwclk/README.md b/apps/bwclk/README.md index 3a5061e81..14e442ee4 100644 --- a/apps/bwclk/README.md +++ b/apps/bwclk/README.md @@ -42,7 +42,7 @@ on the app that provide this sub-menu through the `clkinfo` module. ## Thanks to -- Thanks to Gordon not only for the great BangleJs, but specifically also for the implementation of `clkinfo` which simplified the BWClock a lot and moved complexety to the apps where it should be located. +- Thanks to Gordon Williams not only for the great BangleJs, but specifically also for the implementation of `clkinfo` which simplified the BWClock a lot and moved complexety to the apps where it should be located. - Icons created by Flaticon ## Creator From bdb695c17fe074d83af8f7e7facebaeac1327bdd Mon Sep 17 00:00:00 2001 From: David Peer Date: Mon, 19 Sep 2022 17:46:13 +0200 Subject: [PATCH 19/25] Minor changes --- apps/bwclk/README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/apps/bwclk/README.md b/apps/bwclk/README.md index 14e442ee4..64483943f 100644 --- a/apps/bwclk/README.md +++ b/apps/bwclk/README.md @@ -47,5 +47,3 @@ on the app that provide this sub-menu through the `clkinfo` module. ## Creator [David Peer](https://github.com/peerdavid) - -## Changes From af315be7123ad0f1d0a554554e5398020c17a1a6 Mon Sep 17 00:00:00 2001 From: David Peer Date: Tue, 20 Sep 2022 18:38:17 +0200 Subject: [PATCH 20/25] Fix: On charge should show battery... --- apps/bwclk/app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/bwclk/app.js b/apps/bwclk/app.js index 15212ea21..ba77f2848 100644 --- a/apps/bwclk/app.js +++ b/apps/bwclk/app.js @@ -368,7 +368,7 @@ Bangle.on('charging',function(charging) { // Jump to battery settings.menuPosX = 0; - settings.menuPosY = 0; + settings.menuPosY = 1; draw(); }); From 96ae6140f0e3879d094f3b5b9108804f98ef3fe8 Mon Sep 17 00:00:00 2001 From: David Peer Date: Tue, 20 Sep 2022 18:45:01 +0200 Subject: [PATCH 21/25] Minor refactorings --- apps/bwclk/app.js | 102 +++++++++++++++++++++++----------------------- 1 file changed, 52 insertions(+), 50 deletions(-) diff --git a/apps/bwclk/app.js b/apps/bwclk/app.js index ba77f2848..c8c885ee1 100644 --- a/apps/bwclk/app.js +++ b/apps/bwclk/app.js @@ -1,18 +1,21 @@ -/************ +/************************************************ * Includes */ const locale = require('locale'); const storage = require('Storage'); const clock_info = require("clock_info"); -/************ - * Statics + +/************************************************ + * Globals */ const SETTINGS_FILE = "bwclk.setting.json"; const W = g.getWidth(); const H = g.getHeight(); +var lock_input = false; -/************ + +/************************************************ * Settings */ let settings = { @@ -28,9 +31,7 @@ for (const key in saved_settings) { settings[key] = saved_settings[key] } -var lock_input = false; - -/************ +/************************************************ * Assets */ // Manrope font @@ -82,6 +83,9 @@ function imgLock(){ } +/************************************************ + * Menu + */ // Custom bwItems menu - therefore, its added here and not in a clkinfo.js file. var bwItems = { name: null, @@ -141,22 +145,35 @@ menu.forEach((menuItm, x) => { }); +function canRunMenuItem(){ + if(settings.menuPosY == 0){ + return false; + } -/************ - * Helper - */ -function isFullscreen(){ - var s = settings.screen.toLowerCase(); - if(s == "dynamic"){ - return Bangle.isLocked() - } else { - return s == "full" + var menuEntry = menu[settings.menuPosX]; + var item = menuEntry.items[settings.menuPosY-1]; + return item.run !== undefined; +} + + +function runMenuItem(){ + if(settings.menuPosY == 0){ + return; + } + + var menuEntry = menu[settings.menuPosX]; + var item = menuEntry.items[settings.menuPosY-1]; + try{ + item.run(); + Bangle.buzz(300, 0.6).then(() => {}); + } catch (ex) { + // Simply ignore it... } } -/************ - * DRAW +/************************************************ + * Draw */ function draw() { // Queue draw again @@ -279,32 +296,6 @@ function drawMenuAndTime(){ } -function canRunItem(){ - if(settings.menuPosY == 0){ - return false; - } - - var menuEntry = menu[settings.menuPosX]; - var item = menuEntry.items[settings.menuPosY-1]; - return item.run !== undefined; -} - -function runItem(){ - if(settings.menuPosY == 0){ - return; - } - - var menuEntry = menu[settings.menuPosX]; - var item = menuEntry.items[settings.menuPosY-1]; - try{ - item.run(); - Bangle.buzz(300, 0.6).then(() => {}); - } catch (ex) { - // Simply ignore it... - } -} - - function drawLock(){ if(settings.showLock && Bangle.isLocked()){ g.setColor(g.theme.fg); @@ -322,9 +313,19 @@ function drawWidgets(){ } +function isFullscreen(){ + var s = settings.screen.toLowerCase(); + if(s == "dynamic"){ + return Bangle.isLocked() + } else { + return s == "full" + } +} -/* - * Draw timeout + + +/************************************************ + * Listener */ // timeout used to update every minute var drawTimeout; @@ -424,8 +425,8 @@ Bangle.on('touch', function(btn, e){ } if(is_center){ - if(canRunItem()){ - runItem(); + if(canRunMenuItem()){ + runMenuItem(); } } }); @@ -440,9 +441,10 @@ E.on("kill", function(){ }); -/* - * Draw clock the first time +/************************************************ + * Startup Clock */ + // The upper part is inverse i.e. light if dark and dark if light theme // is enabled. In order to draw the widgets correctly, we invert the // dark/light theme as well as the colors. From be4e289191950e85daafa969e5315dfa7f6f6cca Mon Sep 17 00:00:00 2001 From: David Peer Date: Tue, 20 Sep 2022 18:50:57 +0200 Subject: [PATCH 22/25] Updated readme --- apps/bwclk/README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/bwclk/README.md b/apps/bwclk/README.md index 64483943f..d869fa2cf 100644 --- a/apps/bwclk/README.md +++ b/apps/bwclk/README.md @@ -1,13 +1,13 @@ # BW Clock -A very minimalistic clock to mainly show date and time. +A very minimalistic clock. ![](screenshot.png) ## Features -The BW clock implements 3rd party integrations of other apps through the `clkinfo` module. -For example if you install the HomeAssistant app, this menu item will show up in BWClock -and additionally allows to send your triggers directly from the clock. Here are some -features that are supported: +The BW clock implements features that are exposed by other apps through the `clkinfo` module. +For example, if you install the HomeAssistant app, this menu item will be shown if you click right +and additionally allows you to send triggers directly from the clock (select triggers via up/down and +send via click center). Here are examples of other apps that are integrated: - Bangle data such as steps, heart rate, battery or charging state. - Show agenda entries. A timer for an agenda entry can also be set by simply clicking in the middle of the screen. This can be used to not forget a meeting etc. Note that only one agenda-timer can be set at a time. *Requirement: Gadgetbridge calendar sync enabled* From ceaae5614d09dda717df8fc35c60723b75c61f9e Mon Sep 17 00:00:00 2001 From: David Peer Date: Tue, 20 Sep 2022 18:53:46 +0200 Subject: [PATCH 23/25] Minor changes --- apps/agenda/agenda.clkinfo.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/agenda/agenda.clkinfo.js b/apps/agenda/agenda.clkinfo.js index 9e89b2ac8..a80c09002 100644 --- a/apps/agenda/agenda.clkinfo.js +++ b/apps/agenda/agenda.clkinfo.js @@ -12,7 +12,7 @@ agenda.forEach((entry, i) => { - var title = entry.title.slice(0,14); + var title = entry.title.slice(0,18); var date = new Date(entry.timestamp*1000); var dateStr = locale.date(date).replace(/\d\d\d\d/,""); dateStr += entry.durationInSeconds < 86400 ? "/ " + locale.time(date,1) : ""; From 8036d976b3e47d1672ecb1afeafaef98f08e6fb1 Mon Sep 17 00:00:00 2001 From: David Peer Date: Thu, 22 Sep 2022 18:25:42 +0200 Subject: [PATCH 24/25] Use this.interval insntead of interval. --- modules/clock_info.js | 23 ++++------------------- 1 file changed, 4 insertions(+), 19 deletions(-) diff --git a/modules/clock_info.js b/modules/clock_info.js index df35d4e22..d8068b69d 100644 --- a/modules/clock_info.js +++ b/modules/clock_info.js @@ -37,7 +37,6 @@ exports.load = function() { // info used for drawing... var hrm = "--"; var alt = "--"; - var interval = null; // callbacks (needed for easy removal of listeners) function batteryUpdateHandler() { bangleItems[0].emit("redraw"); } function stepUpdateHandler() { bangleItems[1].emit("redraw"); } @@ -49,12 +48,6 @@ exports.load = function() { bangleItems[3].emit("redraw"); }); } - function deleteInterval(inter){ - if(inter){ - clearInterval(inter); - } - delete inter; - } // actual items var items = [{ name: "Bangle", @@ -64,16 +57,8 @@ exports.load = function() { get : () => ({ text : E.getBattery() + "%", img : atob(Bangle.isCharging() ? "GBiBAAABgAADwAAHwAAPgACfAAHOAAPkBgHwDwP4Hwf8Pg/+fB//OD//kD//wD//4D//8D//4B//QB/+AD/8AH/4APnwAHAAACAAAA==" : "GBiBAAAAAAAAAAAAAAAAAAAAAD//+P///IAAAr//Ar//Ar//A7//A7//A7//A7//Ar//AoAAAv///D//+AAAAAAAAAAAAAAAAAAAAA==") }), - show : function() { - deleteInterval(interval); - interval = setInterval(()=>this.emit('redraw'), 60000); - Bangle.on("charging", batteryUpdateHandler); - batteryUpdateHandler(); - }, - hide : function() { - deleteInterval(interval); - Bangle.removeListener("charging", batteryUpdateHandler); - }, + show : function() { this.interval = setInterval(()=>this.emit('redraw'), 60000); Bangle.on("charging", batteryUpdateHandler); batteryUpdateHandler(); }, + hide : function() { clearInterval(this.interval); delete this.interval; Bangle.removeListener("charging", batteryUpdateHandler); }, }, { name : "Steps", get : () => ({ text : Bangle.getHealthStatus("day").steps, @@ -95,8 +80,8 @@ exports.load = function() { bangleItems.push({ name : "Altitude", get : () => ({ text : alt, img : atob("GBiBAAAAAAAAAAAAAAAAAAAAAAACAAAGAAAPAAEZgAOwwAPwQAZgYAwAMBgAGBAACDAADGAABv///////wAAAAAAAAAAAAAAAAAAAA==") }), - show : function() { deleteInterval(interval); interval = setInterval(altUpdateHandler, 60000); alt = "--"; altUpdateHandler(); }, - hide : function() { deleteInterval(interval); }, + show : function() { this.interval = setInterval(altUpdateHandler, 60000); alt = "--"; altUpdateHandler(); }, + hide : function() { clearInterval(this.interval); delete this.interval; }, }); } From 59d63885fa8b1ab2c384378d11234b88b9e7e926 Mon Sep 17 00:00:00 2001 From: David Peer Date: Thu, 22 Sep 2022 18:49:12 +0200 Subject: [PATCH 25/25] Advanced merge function of menu objects and items. --- modules/clock_info.js | 48 ++++++++++++++++++++++++++++--------------- 1 file changed, 31 insertions(+), 17 deletions(-) diff --git a/modules/clock_info.js b/modules/clock_info.js index d8068b69d..4d70f0013 100644 --- a/modules/clock_info.js +++ b/modules/clock_info.js @@ -2,9 +2,14 @@ var exports = {}; /* Module that allows for loading of clock 'info' displays that can be scrolled through on the clock face. -`load()` returns an array of menu items: +`load()` returns an array of menu objects, where each object contains a list of menu items: +* 'name' : text to display and identify menu object (e.g. weather) +* 'img' : a 24x24px image +* 'items' : menu items such as temperature, humidity, wind etc. -* 'item.name' : friendly name +Note that each item is an object with: + +* 'item.name' : friendly name to identify an item (e.g. temperature) * 'item.get' : function that resolves with: { 'text' : the text to display for this item @@ -20,14 +25,18 @@ See the bottom of this file for example usage... example.clkinfo.js : (function() { - return [ - { name : "Example", - get : () => ({ text : "Bangle.js", - img : atob("GBiBAAD+AAH+AAH+AAH+AAH/AAOHAAYBgAwAwBgwYBgwYBgwIBAwOBAwOBgYIBgMYBgAYAwAwAYBgAOHAAH/AAH+AAH+AAH+AAD+AA==") }), - show : () => {}, - hide : () => {} - } - ]; + return { + name: "Bangle", + img: atob("GBiBAAD+AAH+AAH+AAH+AAH/AAOHAAYBgAwAwBgwYBgwYBgwIBAwOBAwOBgYIBgMYBgAYAwAwAYBgAOHAAH/AAH+AAH+AAH+AAD+AA==") }), + items: [ + { name : "Item1", + get : () => ({ text : "TextOfItem1", + img : atob("GBiBAAD+AAH+AAH+AAH+AAH/AAOHAAYBgAwAwBgwYBgwYBgwIBAwOBAwOBgYIBgMYBgAYAwAwAYBgAOHAAH/AAH+AAH+AAH+AAD+AA==") }), + show : () => {}, + hide : () => {} + } + ] + }; }) // must not have a semi-colon! */ @@ -48,8 +57,8 @@ exports.load = function() { bangleItems[3].emit("redraw"); }); } - // actual items - var items = [{ + // actual menu + var menu = [{ name: "Bangle", img: atob("GBiBAf8B//4B//4B//4B//4A//x4//n+f/P/P+fPn+fPn+fP3+/Px+/Px+fn3+fzn+f/n/P/P/n+f/x4//4A//4B//4B//4B//8B/w=="), items: [ @@ -74,7 +83,7 @@ exports.load = function() { } ], }]; - var bangleItems = items[0].items; + var bangleItems = menu[0].items; if (Bangle.getPressure){ // Altimeter may not exist bangleItems.push({ name : "Altitude", get : () => ({ @@ -85,20 +94,25 @@ exports.load = function() { }); } - // now load extra data from a third party files + // In case there exists already a menu object b with the same name as the next + // object a, we append the items. Otherwise we add the new object a to the list. require("Storage").list(/clkinfo.js$/).forEach(fn => { - items = items.concat(eval(require("Storage").read(fn))()); + var a = eval(require("Storage").read(fn))(); + var b = menu.find(x => x.name === a.name) + if(b) b.items = b.items.concat(a.items); + else menu = menu.concat(a); }); // return it all! - return items; + return menu; }; // Code for testing /* g.clear(); -var items = exports.load(); // or require("clock_info").load() +var menu = exports.load(); // or require("clock_info").load() +var itemsFirstMenu = menu[0].items; items.forEach((itm,i) => { var y = i*24; console.log("Starting", itm.name);