From f627b860da269148017badadf080ce1610a69070 Mon Sep 17 00:00:00 2001 From: storm64 Date: Mon, 12 Sep 2022 23:09:33 +0200 Subject: [PATCH 001/110] [sleeplogalarm] First files --- apps/sleeplogalarm/ChangeLog | 1 + apps/sleeplogalarm/README.md | 47 ++++++++++++++++++++++++++++ apps/sleeplogalarm/app.png | Bin 0 -> 698 bytes apps/sleeplogalarm/metadata.json | 16 ++++++++++ apps/sleeplogalarm/settings.js | 52 +++++++++++++++++++++++++++++++ apps/sleeplogalarm/widget.js | 4 +++ 6 files changed, 120 insertions(+) create mode 100644 apps/sleeplogalarm/ChangeLog create mode 100644 apps/sleeplogalarm/README.md create mode 100644 apps/sleeplogalarm/app.png create mode 100644 apps/sleeplogalarm/metadata.json create mode 100644 apps/sleeplogalarm/settings.js create mode 100644 apps/sleeplogalarm/widget.js diff --git a/apps/sleeplogalarm/ChangeLog b/apps/sleeplogalarm/ChangeLog new file mode 100644 index 000000000..5560f00bc --- /dev/null +++ b/apps/sleeplogalarm/ChangeLog @@ -0,0 +1 @@ +0.01: New App! diff --git a/apps/sleeplogalarm/README.md b/apps/sleeplogalarm/README.md new file mode 100644 index 000000000..672c4238f --- /dev/null +++ b/apps/sleeplogalarm/README.md @@ -0,0 +1,47 @@ +# Sleep Log Alarm + +This widget searches for active alarms and raises the alarm event up to the defined time earlier, if in a light sleep phase. + +--- +### App Usage +--- + +#### Inside the settings: !!! dummy entries !!! + - __Thresholds__ submenu + Changes take effect from now on, not retrospective! + - __Max Awake__ | maximal awake duration + _10min_ / _20min_ / ... / __60min__ / ... / _120min_ + - __Min Consecutive__ | minimal consecutive sleep duration + _10min_ / _20min_ / ... / __30min__ / ... / _120min_ + - __Deep Sleep__ | deep sleep threshold + _30_ / _31_ / ... / __100__ / ... / _200_ + - __Light Sleep__ | light sleep threshold + _100_ / _110_ / ... / __200__ / ... / _400_ + - __Reset to Default__ | reset to bold values above + - __BreakToD__ | time of day to break view + _0:00_ / _1:00_ / ... / __12:00__ / ... / _23:00_ + - __App Timeout__ | app specific lock timeout + __0s__ / _10s_ / ... / _120s_ + - __Enabled__ | completely en-/disables the background service + __on__ / _off_ + +--- +### Worth Mentioning +--- + +#### To do list +- widget.js +- settings.js +- README.md + +#### Requests, Bugs and Feedback +Please leave requests and bug reports by raising an issue at [github.com/storm64/BangleApps](https://github.com/storm64/BangleApps) (or send me a [mail](mailto:banglejs@storm64.de)). + +#### Creator +Storm64 ([Mail](mailto:banglejs@storm64.de), [github](https://github.com/storm64)) + +#### Attributions +The app icon is downloaded from [https://icons8.com](https://icons8.com). + +#### License +[MIT License](LICENSE) diff --git a/apps/sleeplogalarm/app.png b/apps/sleeplogalarm/app.png new file mode 100644 index 0000000000000000000000000000000000000000..bb7f11f67bf96368c6c8994d43608a3c9ece108d GIT binary patch literal 698 zcmV;r0!96aP)>_62_vrVs7$x%)KEhY2bLH`8}|aP+4?loNZgNtQ$xdbF(5^0LHrv z*+n$Jo?TtG5znfDhWMwg>pnPhA64bntJ|$Z7122xCSpMsXp$@DCL257wkfKLqTb6Of7R0_aEmw-F2N`7O;DfXna3pU>Y z0M@gs%k^p^C2$Ye0)950Efu{>yq>Zp9zw{#ps}8TLDSP+NXwZdb@vg%IRJ!BR2F1v ztrChl1B^4EU9T=yX`_vGYC;HyCw zeu2ImiyxT3@-F?QwZq&%vuyl1->))54uWLrwWsTPj9&& zHGOc%+hA@$WdZo^)AJ3j-3%Zq5XJ^%YOO*nb_#d~{AfH&XzjFIc>XCYfq&KIZSXsZ zKc4t(wAhPlZ!AdKpR1K@o92-}iAUamQ3?G^crTVCpMl80uo-y+Mwhu^{gIh`P)0rj gk%5Sah=~82Kj4M5noGmPng9R*07*qoM6N<$f_3Oc+5i9m literal 0 HcmV?d00001 diff --git a/apps/sleeplogalarm/metadata.json b/apps/sleeplogalarm/metadata.json new file mode 100644 index 000000000..7b3c15818 --- /dev/null +++ b/apps/sleeplogalarm/metadata.json @@ -0,0 +1,16 @@ +{ + "id":"sleeplogalarm", + "name":"Sleep Log Alarm", + "shortName": "SleepLogAlarm", + "version": "0.01", + "description": "Enhance your morning and let your alarms wake you up when you are in light sleep.", + "icon": "app.png", + "type": "widget", + "tags": "tool,widget", + "supports": ["BANGLEJS2"], + "readme": "README.md", + "storage": [ + {"name": "sleeplogalarm.wid.js", "url": "widget.js"}, + {"name": "sleeplogalarm.settings.js", "url": "settings.js"} + ] +} diff --git a/apps/sleeplogalarm/settings.js b/apps/sleeplogalarm/settings.js new file mode 100644 index 000000000..c4f13d63f --- /dev/null +++ b/apps/sleeplogalarm/settings.js @@ -0,0 +1,52 @@ +(function(back) { + // define settings filename + var filename = "sleeplogalarm.json"; + + // define default vaules + var defaults = { + }; + + // assign loaded settings to default values + var settings = Object.assign(defaults, require("Storage").readJSON(filename, true) || {}); + + // write change to storage + function writeSetting() { + require("Storage").writeJSON(filename, settings); + } + + // show main menu + function showMain(selected) { + // set menu + var mainMenu = { + "": { + title: "Sleep Log Alarm", + selected: selected + }, + /*LANG*/"< Back": () => back(), + /*LANG*/"up to": { + value: settings.earlier, + step: 10, + min: 10, + max: 120, + wrap: true, + noList: true, + format: v => v + "min earlier", + onchange: v => { + settings.earlier = v; + writeSetting(); + } + }, + /*LANG*/"Enabled": { + value: settings.enabled, + onchange: v => { + settings.enabled = v; + writeSetting(); + } + } + }; + var menu = E.showMenu(mainMenu); + } + + // draw main menu + showMain(); +}) diff --git a/apps/sleeplogalarm/widget.js b/apps/sleeplogalarm/widget.js new file mode 100644 index 000000000..42e9bcd0a --- /dev/null +++ b/apps/sleeplogalarm/widget.js @@ -0,0 +1,4 @@ +// sleeplog.status values: +// undefined = service stopped, 0 = unknown, 1 = not worn, 2 = awake, 3 = light sleep, 4 = deep sleep +// sleeplog.consecutive values: +// undefined = service stopped, 0 = unknown, 1 = no consecutive sleep, 2 = consecutive sleep From 716b2e454aab6777a5bdfdcd9ce7b1197210c5af Mon Sep 17 00:00:00 2001 From: storm64 Date: Thu, 10 Nov 2022 01:18:02 +0100 Subject: [PATCH 002/110] [sleeplogalarm] Add triger, widget code --- apps/sleeplogalarm/trigger.js | 75 +++++++++++++++++++++++++++++++++++ apps/sleeplogalarm/widget.js | 59 +++++++++++++++++++++++++-- 2 files changed, 130 insertions(+), 4 deletions(-) create mode 100644 apps/sleeplogalarm/trigger.js diff --git a/apps/sleeplogalarm/trigger.js b/apps/sleeplogalarm/trigger.js new file mode 100644 index 000000000..d80a86f3d --- /dev/null +++ b/apps/sleeplogalarm/trigger.js @@ -0,0 +1,75 @@ +exports = function(now, tNow) { + // define settings + var settings = Object.assign({ + from: 4, // 0400 + to: 8, // 0800 + earlier: 6E4 * 30, + msgAsPrefix: true, + disableOnAlarm: false, // !!! not available if alarm is at the next day + msg: "...\n", + vibrate: "..", + as: true + }, require("Storage").readJSON("sleeplogalarm.settings.json", true) || {}); + + // calculate then date + var then = new Date(now + settings.earlier); + + // load library + var sched = require("sched"); + + // define function to return first active alarm in range to come + function firstActiveAlarm(allAlarms) { + return (sched.getActiveAlarms(allAlarms.filter( + // filter for active alarms, ... + a => a.on && !a.timer && + // after now+10s and in alarm range + a.t > tNow && a.t >= settings.from * 36E5 && a.t <= settings.to * 36E5 + ), then) || []).sort((a, b) => a.t > b.t)[0]; + } + + // read all alarms + var allAlarms = sched.getAlarms(); + + // find first active alarm + var alarm = firstActiveAlarm(allAlarms); + + // return if no alarm is found + if (!alarm) return; + + // disable early triggered alarm if set and now and then on the same day + if (settings.disableOnAlarm && now.getDate() === then.getDate()) { + // add indexes to find alarm to temporary disable + allAlarms = allAlarms.map((a, idx) => { + a.idx = idx; + return a; + }); + // get index of first active alarm + var idx = firstActiveAlarm(allAlarms).idx; + // set this alarms last to then + allAlarms[idx].last = then.getDate(); + // remove added indexes + allAlarms = allAlarms.map(a => { + delete a.idx; + return a; + }); + } + + // add new alarm for now with data from found alarm + allAlarms.push({ + id: "sleeplog", + appid: "sleeplog", + on: true, + t: (((now.getHours() * 60 + now.getMinutes()) * 60 + now.getSeconds()) * 1000), + dow: 127, + msg: settings.msg + (settings.msgAsPrefix ? alarm.msg || "" : ""), + vibrate: settings.vibrate || alarm.vibrate, + as: settings.as, + del: true + }); + + // write changes + sched.setAlarms(allAlarms); + + // trigger sched.js + load("sched.js"); +}; \ No newline at end of file diff --git a/apps/sleeplogalarm/widget.js b/apps/sleeplogalarm/widget.js index 42e9bcd0a..a7190768c 100644 --- a/apps/sleeplogalarm/widget.js +++ b/apps/sleeplogalarm/widget.js @@ -1,4 +1,55 @@ -// sleeplog.status values: -// undefined = service stopped, 0 = unknown, 1 = not worn, 2 = awake, 3 = light sleep, 4 = deep sleep -// sleeplog.consecutive values: -// undefined = service stopped, 0 = unknown, 1 = no consecutive sleep, 2 = consecutive sleep +// check if sleeplog is available and any alarm is active +if (typeof (global.sleeplog || {}).onChange === "object" && + (require("Storage").readJSON("sched.json", 1) || []).some(a => a.on && !a.timer)) { + + // read settings to calculate alarm range + var settings = Object.assign({ + enabled: true, + hide: false, + drawRange: true, + from: 4, // 0400 + to: 8, // 0800 + earlier: 6E4 * 30 + }, require("Storage").readJSON("sleeplogalarm.settings.json", true) || {}); + + // abort if not enabled in settings + if (!settings.enabled) return; + + // setup widget depending on settings + WIDGETS.sleeplogalarm = { + area: "tl", + width: 0, + from: settings.from, + to: settings.to, + earlier: settings.earlier, + draw: function() { + if (this.width) g.reset().setColor(1, 1, 0).drawImage(atob(""), this.x, this.y + this.width - 8); + if (this.width > 8) { + g.setFont().setFontAllign(); + g.drwaString(this.from, this.x + 6, this.y); + g.drwaString(this.to, this.x + 18, this.y); + } + } + }; + + // set widget width and draw + WIDGETS.sleeplogalarm.width = settings.hide ? 0 : settings.drawRange ? 24 : 8; + WIDGETS.sleeplogalarm.draw(); + + // add sleeplogalarm function to onChange + sleeplog.onChange.push(function(data) { + // abort if not changed from deep sleep to light sleep or awake + if (data.prevStatus !== 4 || !(data.status === 3 || data.status === 2)) return; + + // get now and calculate time of now + var now = new Date(); + var tNow = (now.getHours() * 3600000) + (now.getMinutes() * 60000) + (now.getSeconds() * 1000); + + // abort if now is outside the possible alarm range + if (tNow + WIDGETS.sleeplogalarm.earlier < WIDGETS.sleeplogalarm.from * 36E5 || + tNow + WIDGETS.sleeplogalarm.earlier >= WIDGETS.sleeplogalarm.to * 36E5) return; + + // execute trigger function + require("sleeplogalarm.trigger.js")(now, tNow); + }); +} From a07747ca2577309100fbbaa2541729573b263ef5 Mon Sep 17 00:00:00 2001 From: storm64 Date: Thu, 10 Nov 2022 13:12:22 +0100 Subject: [PATCH 003/110] [sleeplogalarm] Setup widget and app.png --- apps/sleeplogalarm/app.png | Bin 698 -> 8089 bytes apps/sleeplogalarm/metadata.json | 5 ++-- apps/sleeplogalarm/trigger.js | 6 ++--- apps/sleeplogalarm/widget.js | 38 +++++++++++++++++++------------ 4 files changed, 29 insertions(+), 20 deletions(-) diff --git a/apps/sleeplogalarm/app.png b/apps/sleeplogalarm/app.png index bb7f11f67bf96368c6c8994d43608a3c9ece108d..6efb22a3f666817408264ec02731f4ac13d1ffe8 100644 GIT binary patch literal 8089 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 delta 675 zcmV;U0$lx>Ke`2wBYyw}VoOIv0RI600RN!9r;`8x0&ht~K~!jg?U%o6Q&AMhKPOFG zv;_sbWislhe}R)IHI*dQb~iZGK^F&$gM$u&AP!v|%pYJad2Q1oK|48!OL1|C;39%j z6sgt4B=0yhf#l_--sIhv7>_5`V^`xngeecg(#ZDrw+& zqxn6skx*H5W}IzXv8)?N7jv^BS^&no4B16Azn)!Pwh_;&frj{}t?NEGb01aZ)~nmC zLlx0E8zy2w7if|z<|Z3E-?k~LilW}(f=Xd(Y4&K)xbdJ1G-=d)N7;CGzLkl1qIw;; z6C|#+42a6KUw?Zk>rl!%zH=0O=k$U#1HiF9=A?oKwP~QE&_kNjhD`$>1~jJ)n+Dc< zouHznph2w}NT@6VyQbp>c4A}hV$itO3^+5+HllgV>RMfueCcB8YtXnIC$T>EId$gE zPweTH%w<#xz(kjTJFZH8W5y}=q_hh*-vI#Dv#ZPXYJVana1Yo5em0&h6}?Nmp0Xt# zLdd|Nv7UiJ)6-o@%b6r~_YuN50EA6c7G!Fz5{fzlj5DC+OcK|9i*Sj(yZ$&z7WB22 zGs*BI?vHr}_ICb=PtRdo_aQL%sTPj9&&HGOc%+hA@$WdZo^)AJ3j-3%Zq5XJ^% zYOO*nb_#d~{AfH&XzjFIc>XCYfq&KIZSXsZKc4t(wAhPlZ!AdKpR1K@o92-}iAUam zQ3?G^crTVCpMl80uo-y+Mwhu^{gIh`P)0rjksN`Dh=_>)n?K-%w3 { diff --git a/apps/sleeplogalarm/widget.js b/apps/sleeplogalarm/widget.js index a7190768c..34453497b 100644 --- a/apps/sleeplogalarm/widget.js +++ b/apps/sleeplogalarm/widget.js @@ -7,37 +7,45 @@ if (typeof (global.sleeplog || {}).onChange === "object" && enabled: true, hide: false, drawRange: true, + color: g.theme.dark ? 65504 : 31, // yellow or blue from: 4, // 0400 to: 8, // 0800 - earlier: 6E4 * 30 + earlier: 30 }, require("Storage").readJSON("sleeplogalarm.settings.json", true) || {}); // abort if not enabled in settings if (!settings.enabled) return; - // setup widget depending on settings + // insert neccessary settings into widget WIDGETS.sleeplogalarm = { area: "tl", width: 0, + drawRange: settings.drawRange, + color: settings.color, from: settings.from, to: settings.to, earlier: settings.earlier, - draw: function() { - if (this.width) g.reset().setColor(1, 1, 0).drawImage(atob(""), this.x, this.y + this.width - 8); - if (this.width > 8) { - g.setFont().setFontAllign(); - g.drwaString(this.from, this.x + 6, this.y); - g.drwaString(this.to, this.x + 18, this.y); - } - } + draw: ()=>{} }; + // setup widget depending if not hidden + if (!settings.hide) { + WIDGETS.sleeplogalarm.width = 8; + WIDGETS.sleeplogalarm.draw = function() { + g.reset().setColor(this.color).drawImage(atob("BwoBD8SSSP4EEEDg"), this.x + 1, this.y); + if (this.drawRange) { + require("Font4x5Numeric").add(Graphics); + g.setFont("4x5Numeric").drawString(this.from, this.x + 1, this.y + 12); + g.setFontAlign(1, 1).drawString(this.to, this.x + this.width + 1, this.y + 23); + } + }; + } + // set widget width and draw - WIDGETS.sleeplogalarm.width = settings.hide ? 0 : settings.drawRange ? 24 : 8; WIDGETS.sleeplogalarm.draw(); // add sleeplogalarm function to onChange - sleeplog.onChange.push(function(data) { + sleeplog.onChange.sleeplogalarm = function(data) { // abort if not changed from deep sleep to light sleep or awake if (data.prevStatus !== 4 || !(data.status === 3 || data.status === 2)) return; @@ -46,10 +54,10 @@ if (typeof (global.sleeplog || {}).onChange === "object" && var tNow = (now.getHours() * 3600000) + (now.getMinutes() * 60000) + (now.getSeconds() * 1000); // abort if now is outside the possible alarm range - if (tNow + WIDGETS.sleeplogalarm.earlier < WIDGETS.sleeplogalarm.from * 36E5 || - tNow + WIDGETS.sleeplogalarm.earlier >= WIDGETS.sleeplogalarm.to * 36E5) return; + if (tNow + WIDGETS.sleeplogalarm.earlier * 6E4 < WIDGETS.sleeplogalarm.from * 36E5 || + tNow + WIDGETS.sleeplogalarm.earlier * 6E4 >= WIDGETS.sleeplogalarm.to * 36E5) return; // execute trigger function require("sleeplogalarm.trigger.js")(now, tNow); - }); + }; } From 57f06969988d7d1f01033ad3ca23f1e977af4dff Mon Sep 17 00:00:00 2001 From: storm64 Date: Thu, 10 Nov 2022 15:14:53 +0100 Subject: [PATCH 004/110] [sleeplogalarm] Add settings and dependency --- apps/sleeplogalarm/README.md | 20 +++-- apps/sleeplogalarm/metadata.json | 1 + apps/sleeplogalarm/settings.js | 128 ++++++++++++++++++++++++++++--- 3 files changed, 129 insertions(+), 20 deletions(-) diff --git a/apps/sleeplogalarm/README.md b/apps/sleeplogalarm/README.md index 672c4238f..42c2d6074 100644 --- a/apps/sleeplogalarm/README.md +++ b/apps/sleeplogalarm/README.md @@ -7,22 +7,22 @@ This widget searches for active alarms and raises the alarm event up to the defi --- #### Inside the settings: !!! dummy entries !!! - - __Thresholds__ submenu + - __Thresholds__ submenu Changes take effect from now on, not retrospective! - - __Max Awake__ | maximal awake duration + - __Max Awake__ | maximal awake duration _10min_ / _20min_ / ... / __60min__ / ... / _120min_ - - __Min Consecutive__ | minimal consecutive sleep duration + - __Min Consecutive__ | minimal consecutive sleep duration _10min_ / _20min_ / ... / __30min__ / ... / _120min_ - - __Deep Sleep__ | deep sleep threshold + - __Deep Sleep__ | deep sleep threshold _30_ / _31_ / ... / __100__ / ... / _200_ - - __Light Sleep__ | light sleep threshold - _100_ / _110_ / ... / __200__ / ... / _400_ + - __Light Sleep__ | light sleep threshold + _100_ / _110_ / ... / __200__ / ... / _400_ - __Reset to Default__ | reset to bold values above - - __BreakToD__ | time of day to break view + - __BreakToD__ | time of day to break view _0:00_ / _1:00_ / ... / __12:00__ / ... / _23:00_ - - __App Timeout__ | app specific lock timeout + - __App Timeout__ | app specific lock timeout __0s__ / _10s_ / ... / _120s_ - - __Enabled__ | completely en-/disables the background service + - __Enabled__ | completely en-/disables the background service __on__ / _off_ --- @@ -30,8 +30,6 @@ This widget searches for active alarms and raises the alarm event up to the defi --- #### To do list -- widget.js -- settings.js - README.md #### Requests, Bugs and Feedback diff --git a/apps/sleeplogalarm/metadata.json b/apps/sleeplogalarm/metadata.json index 3ea566acb..198d8e07a 100644 --- a/apps/sleeplogalarm/metadata.json +++ b/apps/sleeplogalarm/metadata.json @@ -8,6 +8,7 @@ "type": "widget", "tags": "tool,widget", "supports": ["BANGLEJS2"], + "dependencies": {"sleeplog": "app"}, "readme": "README.md", "storage": [ {"name": "sleeplogalarm.settings.js", "url": "settings.js"}, diff --git a/apps/sleeplogalarm/settings.js b/apps/sleeplogalarm/settings.js index c4f13d63f..38a1e5ab5 100644 --- a/apps/sleeplogalarm/settings.js +++ b/apps/sleeplogalarm/settings.js @@ -1,19 +1,66 @@ (function(back) { // define settings filename - var filename = "sleeplogalarm.json"; + var filename = "sleeplogalarm.settings.json"; - // define default vaules - var defaults = { - }; - - // assign loaded settings to default values - var settings = Object.assign(defaults, require("Storage").readJSON(filename, true) || {}); + // define settings + var settings = Object.assign({ + enabled: true, + hide: false, + drawRange: true, + color: g.theme.dark ? 65504 : 31, // yellow or blue + from: 4, // 0400 + to: 8, // 0800 + earlier: 30, + disableOnAlarm: false, // !!! not available if alarm is at the next day + msgAsPrefix: true, + msg: "...\n", + vibrate: "..", + as: true + }, require("Storage").readJSON(filename, true) || {}); // write change to storage function writeSetting() { require("Storage").writeJSON(filename, settings); } + // show widget menu + function showWidMenu() { + // set menu + var widgetMenu = { + "": { + title: "Widget Settings" + }, + /*LANG*/"< Back": () => showMain(7), + /*LANG*/"hide complete": { + value: settings.hide, + onchange: v => { + settings.hide = v; + writeSetting(); + } + }, + /*LANG*/"draw time range": { + value: settings.drawRange, + onchange: v => { + settings.drawRange = v; + writeSetting(); + } + }, + /*LANG*/"color": { + colors: [63488, 65504, 2016, 2047, 31, 63519, 0, 65535], + value: this.colors.indexOf(settings.color), + min: 0, + max: this.colors.length -1, + wrap: true, + format: v => ["red", "yellow", "green", "cyan", "blue", "magenta", "black", "white"][v], + onchange: v => { + settings.color = this.colors[v]; + writeSetting(); + } + } + }; + var menu = E.showMenu(widgetMenu); + } + // show main menu function showMain(selected) { // set menu @@ -23,19 +70,82 @@ selected: selected }, /*LANG*/"< Back": () => back(), - /*LANG*/"up to": { + /*LANG*/"from": { + value: settings.from, + min: 0, + max: 23, + wrap: true, + noList: true, + format: v => v + ":00", + onchange: v => { + settings.from = v; + writeSetting(); + } + }, + /*LANG*/"to": { + value: settings.to, + min: 1, + max: 24, + wrap: true, + noList: true, + format: v => v + ":00", + onchange: v => { + settings.to = v; + writeSetting(); + } + }, + /*LANG*/"erlier": { value: settings.earlier, step: 10, min: 10, max: 120, wrap: true, noList: true, - format: v => v + "min earlier", + format: v => v + "min", onchange: v => { settings.earlier = v; writeSetting(); } }, + /*LANG*/"disable on alarm": { + value: settings.disableOnAlarm, + onchange: v => { + settings.disableOnAlarm = v; + writeSetting(); + } + }, + /*LANG*/"message as prefix": { + value: settings.msgAsPrefix, + onchange: v => { + settings.msgAsPrefix = v; + writeSetting(); + } + }, + /*LANG*/"msg": { + value: settings.msg, + format: v => !v ? "" : v.length > 6 ? v.substring(0, 6)+"..." : v, + // setTimeout required to load after menu refresh + onchange: () => setTimeout(msg => { + if (require("Storage").read("textinput")) { + g.clear(); + require("textinput").input({text: msg}).then(result => { + settings.msg = result; + writeSetting(); + showMenu(7); + }); + } else { + E.showAlert(/*LANG*/"No keyboard app installed").then(() => showMenu(7)); + } + }), + }, + /*LANG*/"vibration pattern": require("buzz_menu.js").pattern( + settings.vibrate, + v => { + settings.vibrate = v; + writeSetting(); + } + ), + /*LANG*/"Widget Settings": () => showWidMenu(), /*LANG*/"Enabled": { value: settings.enabled, onchange: v => { From 9b8895a259430bada5e9f3f00e11db0af6250ab5 Mon Sep 17 00:00:00 2001 From: storm64 Date: Thu, 10 Nov 2022 16:52:35 +0100 Subject: [PATCH 005/110] [sleeplogalarm] Rewrite widget.js --- apps/sleeplogalarm/widget.js | 85 +++++++++++++++++++----------------- 1 file changed, 45 insertions(+), 40 deletions(-) diff --git a/apps/sleeplogalarm/widget.js b/apps/sleeplogalarm/widget.js index 34453497b..09f29e906 100644 --- a/apps/sleeplogalarm/widget.js +++ b/apps/sleeplogalarm/widget.js @@ -1,20 +1,16 @@ -// check if sleeplog is available and any alarm is active -if (typeof (global.sleeplog || {}).onChange === "object" && - (require("Storage").readJSON("sched.json", 1) || []).some(a => a.on && !a.timer)) { +// read settings to calculate alarm range +var settings = Object.assign({ + enabled: true, + hide: false, + drawRange: true, + color: g.theme.dark ? 65504 : 31, // yellow or blue + from: 4, // 0400 + to: 8, // 0800 + earlier: 30 +}, require("Storage").readJSON("sleeplogalarm.settings.json", true) || {}); - // read settings to calculate alarm range - var settings = Object.assign({ - enabled: true, - hide: false, - drawRange: true, - color: g.theme.dark ? 65504 : 31, // yellow or blue - from: 4, // 0400 - to: 8, // 0800 - earlier: 30 - }, require("Storage").readJSON("sleeplogalarm.settings.json", true) || {}); - - // abort if not enabled in settings - if (!settings.enabled) return; +// check if enabled in settings +if (settings.enabled) { // insert neccessary settings into widget WIDGETS.sleeplogalarm = { @@ -25,39 +21,48 @@ if (typeof (global.sleeplog || {}).onChange === "object" && from: settings.from, to: settings.to, earlier: settings.earlier, - draw: ()=>{} - }; - - // setup widget depending if not hidden - if (!settings.hide) { - WIDGETS.sleeplogalarm.width = 8; - WIDGETS.sleeplogalarm.draw = function() { + draw: function () { + // draw zzz g.reset().setColor(this.color).drawImage(atob("BwoBD8SSSP4EEEDg"), this.x + 1, this.y); + // draw alarm range times if enabled if (this.drawRange) { require("Font4x5Numeric").add(Graphics); g.setFont("4x5Numeric").drawString(this.from, this.x + 1, this.y + 12); g.setFontAlign(1, 1).drawString(this.to, this.x + this.width + 1, this.y + 23); } - }; - } + }, + reload: function () { + // abort if onChange is not available + if (typeof (global.sleeplog || {}).onChange === "object") return; - // set widget width and draw - WIDGETS.sleeplogalarm.draw(); + // abort if no alarm exists inside range + if (!(require("Storage").readJSON("sched.json", 1) || []) + .filter(a => a.on && !a.timer) + .some(a => a.t >= this.from * 36E5 && a.t < this.to * 36E5)) return; - // add sleeplogalarm function to onChange - sleeplog.onChange.sleeplogalarm = function(data) { - // abort if not changed from deep sleep to light sleep or awake - if (data.prevStatus !== 4 || !(data.status === 3 || data.status === 2)) return; + // set widget width if not hidden + if (!this.hidden) this.width = 8; - // get now and calculate time of now - var now = new Date(); - var tNow = (now.getHours() * 3600000) + (now.getMinutes() * 60000) + (now.getSeconds() * 1000); + // insert sleeplogalarm function to onChange + sleeplog.onChange.sleeplogalarm = function (data) { + // abort if not changed from deep sleep to light sleep or awake + if (data.prevStatus !== 4 || !(data.status === 3 || data.status === 2)) return; - // abort if now is outside the possible alarm range - if (tNow + WIDGETS.sleeplogalarm.earlier * 6E4 < WIDGETS.sleeplogalarm.from * 36E5 || - tNow + WIDGETS.sleeplogalarm.earlier * 6E4 >= WIDGETS.sleeplogalarm.to * 36E5) return; + // get cahed data, now and calculate time of now + var data = WIDGET.sleeplogalarm; + var now = new Date(); + var tNow = (((now.getHours() * 60 + now.getMinutes()) * 60 + now.getSeconds()) * 1000); - // execute trigger function - require("sleeplogalarm.trigger.js")(now, tNow); + // abort if now is outside the possible alarm range + if (tNow + data.earlier * 6E4 < data.from * 36E5 || + tNow + data.earlier * 6E4 >= data.to * 36E5) return; + + // execute trigger function + require("sleeplogalarm.trigger.js")(now, tNow); + }; + } }; -} + + // load widget + WIDGETS.sleeplogalarm.reload(); +}; \ No newline at end of file From 3b54d3b1a914270c20d97d6c1e42fa41adbbb842 Mon Sep 17 00:00:00 2001 From: storm64 Date: Thu, 10 Nov 2022 17:06:35 +0100 Subject: [PATCH 006/110] [sleeplogalarm] Correct typo --- apps/sleeplogalarm/widget.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/sleeplogalarm/widget.js b/apps/sleeplogalarm/widget.js index 09f29e906..741101222 100644 --- a/apps/sleeplogalarm/widget.js +++ b/apps/sleeplogalarm/widget.js @@ -65,4 +65,4 @@ if (settings.enabled) { // load widget WIDGETS.sleeplogalarm.reload(); -}; \ No newline at end of file +} \ No newline at end of file From 88468dc6c3677009afa1e78663623fab980a1156 Mon Sep 17 00:00:00 2001 From: storm64 Date: Thu, 10 Nov 2022 18:25:18 +0100 Subject: [PATCH 007/110] [sleeplogalarm] Include font in widget + edit settings --- apps/sleeplogalarm/settings.js | 46 ++++++++++++++++++---------------- apps/sleeplogalarm/widget.js | 15 +++++------ 2 files changed, 33 insertions(+), 28 deletions(-) diff --git a/apps/sleeplogalarm/settings.js b/apps/sleeplogalarm/settings.js index 38a1e5ab5..8b6bd96aa 100644 --- a/apps/sleeplogalarm/settings.js +++ b/apps/sleeplogalarm/settings.js @@ -12,8 +12,8 @@ to: 8, // 0800 earlier: 30, disableOnAlarm: false, // !!! not available if alarm is at the next day - msgAsPrefix: true, msg: "...\n", + msgAsPrefix: true, vibrate: "..", as: true }, require("Storage").readJSON(filename, true) || {}); @@ -23,6 +23,10 @@ require("Storage").writeJSON(filename, settings); } + // define color values and names + var colName = ["red", "yellow", "green", "cyan", "blue", "magenta", "black", "white"]; + var colVal = [63488, 65504, 2016, 2047, 31, 63519, 0, 65535]; + // show widget menu function showWidMenu() { // set menu @@ -46,14 +50,13 @@ } }, /*LANG*/"color": { - colors: [63488, 65504, 2016, 2047, 31, 63519, 0, 65535], - value: this.colors.indexOf(settings.color), + value: colVal.indexOf(settings.color), min: 0, - max: this.colors.length -1, + max: colVal.length -1, wrap: true, - format: v => ["red", "yellow", "green", "cyan", "blue", "magenta", "black", "white"][v], + format: v => colName[v], onchange: v => { - settings.color = this.colors[v]; + settings.color = colVal[v]; writeSetting(); } } @@ -70,7 +73,7 @@ selected: selected }, /*LANG*/"< Back": () => back(), - /*LANG*/"from": { + /*LANG*/"time from": { value: settings.from, min: 0, max: 23, @@ -82,7 +85,7 @@ writeSetting(); } }, - /*LANG*/"to": { + /*LANG*/"time to": { value: settings.to, min: 1, max: 24, @@ -114,31 +117,32 @@ writeSetting(); } }, - /*LANG*/"message as prefix": { - value: settings.msgAsPrefix, - onchange: v => { - settings.msgAsPrefix = v; - writeSetting(); - } - }, /*LANG*/"msg": { value: settings.msg, format: v => !v ? "" : v.length > 6 ? v.substring(0, 6)+"..." : v, // setTimeout required to load after menu refresh - onchange: () => setTimeout(msg => { + onchange: () => setTimeout((msg, cb) => { if (require("Storage").read("textinput")) { g.clear(); require("textinput").input({text: msg}).then(result => { settings.msg = result; writeSetting(); - showMenu(7); + cb(7); }); } else { - E.showAlert(/*LANG*/"No keyboard app installed").then(() => showMenu(7)); + E.showAlert(/*LANG*/"No keyboard app installed").then(() => cb(7)); } - }), + }, 0, settings.msg, showMain), }, - /*LANG*/"vibration pattern": require("buzz_menu.js").pattern( + /*LANG*/"msg:": { + value: settings.msgAsPrefix, + format: v => v ? "add as prefix" : "replace msg", + onchange: v => { + settings.msgAsPrefix = v; + writeSetting(); + } + }, + /*LANG*/"vibration pattern": require("buzz_menu").pattern( settings.vibrate, v => { settings.vibrate = v; @@ -159,4 +163,4 @@ // draw main menu showMain(); -}) +})() \ No newline at end of file diff --git a/apps/sleeplogalarm/widget.js b/apps/sleeplogalarm/widget.js index 741101222..083063318 100644 --- a/apps/sleeplogalarm/widget.js +++ b/apps/sleeplogalarm/widget.js @@ -1,5 +1,5 @@ // read settings to calculate alarm range -var settings = Object.assign({ +settings = Object.assign({ // if using var here settings will always be undefined enabled: true, hide: false, drawRange: true, @@ -26,14 +26,15 @@ if (settings.enabled) { g.reset().setColor(this.color).drawImage(atob("BwoBD8SSSP4EEEDg"), this.x + 1, this.y); // draw alarm range times if enabled if (this.drawRange) { - require("Font4x5Numeric").add(Graphics); - g.setFont("4x5Numeric").drawString(this.from, this.x + 1, this.y + 12); + // directly include Font4x5Numeric + g.setFontCustom(atob("CAZMA/H4PgvXoK1+DhPg7W4P1uCEPg/X4O1+AA=="), 46, atob("AgQEAgQEBAQEBAQE"), 5); + g.drawString(this.from, this.x + 1, this.y + 12); g.setFontAlign(1, 1).drawString(this.to, this.x + this.width + 1, this.y + 23); } }, reload: function () { // abort if onChange is not available - if (typeof (global.sleeplog || {}).onChange === "object") return; + if (typeof (global.sleeplog || {}).onChange !== "object") return; // abort if no alarm exists inside range if (!(require("Storage").readJSON("sched.json", 1) || []) @@ -49,13 +50,13 @@ if (settings.enabled) { if (data.prevStatus !== 4 || !(data.status === 3 || data.status === 2)) return; // get cahed data, now and calculate time of now - var data = WIDGET.sleeplogalarm; + var settings = WIDGET.sleeplogalarm; var now = new Date(); var tNow = (((now.getHours() * 60 + now.getMinutes()) * 60 + now.getSeconds()) * 1000); // abort if now is outside the possible alarm range - if (tNow + data.earlier * 6E4 < data.from * 36E5 || - tNow + data.earlier * 6E4 >= data.to * 36E5) return; + if (tNow + settings.earlier * 6E4 < settings.from * 36E5 || + tNow + settings.earlier * 6E4 >= settings.to * 36E5) return; // execute trigger function require("sleeplogalarm.trigger.js")(now, tNow); From f193e5d9a1ea80c19c6f96546c17f2f6a947d905 Mon Sep 17 00:00:00 2001 From: storm64 Date: Thu, 10 Nov 2022 23:16:00 +0100 Subject: [PATCH 008/110] [sleeplogalarm] Improve settings --- apps/sleeplogalarm/settings.js | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/apps/sleeplogalarm/settings.js b/apps/sleeplogalarm/settings.js index 8b6bd96aa..8719761dd 100644 --- a/apps/sleeplogalarm/settings.js +++ b/apps/sleeplogalarm/settings.js @@ -23,26 +23,26 @@ require("Storage").writeJSON(filename, settings); } - // define color values and names - var colName = ["red", "yellow", "green", "cyan", "blue", "magenta", "black", "white"]; - var colVal = [63488, 65504, 2016, 2047, 31, 63519, 0, 65535]; - // show widget menu function showWidMenu() { + // define color values and names + var colName = ["red", "yellow", "green", "cyan", "blue", "magenta", "black", "white"]; + var colVal = [63488, 65504, 2016, 2047, 31, 63519, 0, 65535]; + // set menu var widgetMenu = { "": { title: "Widget Settings" }, /*LANG*/"< Back": () => showMain(7), - /*LANG*/"hide complete": { + /*LANG*/"hide": { value: settings.hide, onchange: v => { settings.hide = v; writeSetting(); } }, - /*LANG*/"draw time range": { + /*LANG*/"time range": { value: settings.drawRange, onchange: v => { settings.drawRange = v; @@ -104,13 +104,13 @@ max: 120, wrap: true, noList: true, - format: v => v + "min", + format: v => v + /*LANG*/"min", onchange: v => { settings.earlier = v; writeSetting(); } }, - /*LANG*/"disable on alarm": { + /*LANG*/"disable alarm": { value: settings.disableOnAlarm, onchange: v => { settings.disableOnAlarm = v; @@ -134,22 +134,21 @@ } }, 0, settings.msg, showMain), }, - /*LANG*/"msg:": { + /*LANG*/"msg as prefix": { value: settings.msgAsPrefix, - format: v => v ? "add as prefix" : "replace msg", onchange: v => { settings.msgAsPrefix = v; writeSetting(); } }, - /*LANG*/"vibration pattern": require("buzz_menu").pattern( + /*LANG*/"vib pattern": require("buzz_menu").pattern( settings.vibrate, v => { settings.vibrate = v; writeSetting(); } ), - /*LANG*/"Widget Settings": () => showWidMenu(), + /*LANG*/"Widget": () => showWidMenu(), /*LANG*/"Enabled": { value: settings.enabled, onchange: v => { @@ -163,4 +162,4 @@ // draw main menu showMain(); -})() \ No newline at end of file +}) From 53aaf929ef680f0627b5e3036f60b8bd24fb57cf Mon Sep 17 00:00:00 2001 From: storm64 Date: Thu, 10 Nov 2022 23:56:03 +0100 Subject: [PATCH 009/110] [sleeplogalarm] Correct widget --- apps/sleeplogalarm/trigger.js | 2 +- apps/sleeplogalarm/widget.js | 11 ++++------- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/apps/sleeplogalarm/trigger.js b/apps/sleeplogalarm/trigger.js index 54135b649..cc4dd6f12 100644 --- a/apps/sleeplogalarm/trigger.js +++ b/apps/sleeplogalarm/trigger.js @@ -23,7 +23,7 @@ exports = function(now, tNow) { // filter for active alarms, ... a => a.on && !a.timer && // after now+10s and in alarm range - a.t > tNow && a.t >= settings.from * 36E5 && a.t <= settings.to * 36E5 + a.t > tNow && a.t >= settings.from * 36E5 && a.t < settings.to * 36E5 ), then) || []).sort((a, b) => a.t > b.t)[0]; } diff --git a/apps/sleeplogalarm/widget.js b/apps/sleeplogalarm/widget.js index 083063318..5ccc57cda 100644 --- a/apps/sleeplogalarm/widget.js +++ b/apps/sleeplogalarm/widget.js @@ -50,16 +50,13 @@ if (settings.enabled) { if (data.prevStatus !== 4 || !(data.status === 3 || data.status === 2)) return; // get cahed data, now and calculate time of now - var settings = WIDGET.sleeplogalarm; + var settings = WIDGETS.sleeplogalarm; var now = new Date(); var tNow = (((now.getHours() * 60 + now.getMinutes()) * 60 + now.getSeconds()) * 1000); - // abort if now is outside the possible alarm range - if (tNow + settings.earlier * 6E4 < settings.from * 36E5 || - tNow + settings.earlier * 6E4 >= settings.to * 36E5) return; - - // execute trigger function - require("sleeplogalarm.trigger.js")(now, tNow); + // execute trigger function if now is inside the alarm range + if (tNow + settings.earlier * 6E4 >= settings.from * 36E5 && + tNow < settings.to * 36E5) require("sleeplogalarm.trigger.js")(now, tNow); }; } }; From f253d344fb10a50c270a22e9f4d984bb84e7e40f Mon Sep 17 00:00:00 2001 From: storm64 Date: Fri, 11 Nov 2022 17:17:07 +0100 Subject: [PATCH 010/110] [sleeplogalarm] Reworking wid->lib ... --- apps/sleeplogalarm/lib.js | 133 +++++++++++++++++++++++++++++++ apps/sleeplogalarm/metadata.json | 2 +- apps/sleeplogalarm/settings.js | 7 ++ apps/sleeplogalarm/trigger.js | 75 ----------------- apps/sleeplogalarm/widget.js | 56 +++---------- 5 files changed, 150 insertions(+), 123 deletions(-) create mode 100644 apps/sleeplogalarm/lib.js delete mode 100644 apps/sleeplogalarm/trigger.js diff --git a/apps/sleeplogalarm/lib.js b/apps/sleeplogalarm/lib.js new file mode 100644 index 000000000..d7375f79a --- /dev/null +++ b/apps/sleeplogalarm/lib.js @@ -0,0 +1,133 @@ +// load library +var sched = require("sched"); + +// find next active alarm in range +function getNextAlarm(allAlarms, from, to, withId) { + if (withId) allAlarms = allAlarms.map((a, idx) => { + a.idx = idx; + return a; + }); + // return next + return sched.getActiveAlarms( + // filter for active alarms in range + allAlarms.filter(a => a.on && !a.timer && a.t >= from && a.t < to) + ).map(a => { + // add time to alarm + a.tTo = sched.getTimeToAlarm(a); + return a; + // sort to get next alarm first + }).sort((a, b) => a.tTo - b.tTo)[0] || {}; +} + +// calculate a time from its date +function dateToTime(date) { + return ((date.getHours() * 60 + date.getMinutes()) * 60 + date.getSeconds()) * 1000; +} + +exports = { + // function to read settings with defaults + getSettings: function() { + return Object.assign({ + enabled: true, + hide: false, + drawTime: true, + color: g.theme.dark ? 65504 : 31, // yellow or blue + from: 4, // 0400 + to: 8, // 0800 + earlier: 30, + msgAsPrefix: true, + disableOnAlarm: false, // !!! not available if alarm is at the next day + msg: "...\n", + vibrate: "..", + as: true + }, require("Storage").readJSON("sleeplogalarm.settings.json", true) || {}); + }, + + // widget reload function + widReload: function() { + // abort if onChange is not available + if (typeof (global.sleeplog || {}).onChange !== "object") return; + + // read settings to calculate alarm range + var settings = this.getSettings(); + + // set the alarm time + this.time = getNextAlarm(sched.getAlarms(), settings.from * 36E5, settings.to * 36E5).t; + + // abort if no alarm time could be found inside range + if (!this.time) return; + + // set widget width if not hidden + if (!this.hidden) this.width = 8; + + // insert sleeplogalarm function to onChange + sleeplog.onChange.sleeplogalarm = function (data) { + // abort if not changed from deep sleep to light sleep or awake + if (data.prevStatus !== 4 || !(data.status === 3 || data.status === 2)) return; + + // get settings from widget, now and calculate time of now + var settings = WIDGETS.sleeplogalarm; + var now = new Date(); + var tNow = dateToTime(now); + + // execute trigger function if inside the alarm range + if (tNow >= settings.time - settings.earlier * 6E4 && + tNow < settings.time) require("sleeplogalarm").trigger(now, tNow); + }; + }, + + // trigger function + trigger: function(now, tNow) { + // define settings + var settings = this.getSettings(); + + // calculate then date + var then = new Date(now + settings.earlier * 6E4); + + // read all alarms + var allAlarms = sched.getAlarms(); + + // find first active alarm + var alarm = firstActiveAlarm(allAlarms); + + // return if no alarm is found + if (!alarm) return; + + // disable early triggered alarm if set and now and then on the same day + if (settings.disableOnAlarm && now.getDate() === then.getDate()) { + // add indexes to find alarm to temporary disable + allAlarms = allAlarms.map((a, idx) => { + a.idx = idx; + return a; + }); + // get index of first active alarm + var idx = firstActiveAlarm(allAlarms).idx; + // set this alarms last to then + allAlarms[idx].last = then.getDate(); + // remove added indexes + allAlarms = allAlarms.map(a => { + delete a.idx; + return a; + }); + } + + // add new alarm for now with data from found alarm + allAlarms.push({ + id: "sleeplog", + appid: "sleeplog", + on: true, + t: (((now.getHours() * 60 + now.getMinutes()) * 60 + now.getSeconds()) * 1000), + dow: 127, + msg: settings.msg + (settings.msgAsPrefix ? alarm.msg || "" : ""), + vibrate: settings.vibrate || alarm.vibrate, + as: settings.as, + del: true + }); + + // write changes + sched.setAlarms(allAlarms); + + // trigger sched.js + load("sched.js"); + } +}; \ No newline at end of file diff --git a/apps/sleeplogalarm/metadata.json b/apps/sleeplogalarm/metadata.json index 198d8e07a..fc1d546da 100644 --- a/apps/sleeplogalarm/metadata.json +++ b/apps/sleeplogalarm/metadata.json @@ -11,8 +11,8 @@ "dependencies": {"sleeplog": "app"}, "readme": "README.md", "storage": [ + {"name": "sleeplogalarm", "url": "lib.js"}, {"name": "sleeplogalarm.settings.js", "url": "settings.js"}, - {"name": "sleeplogalarm.trigger.js", "url": "trigger.js"}, {"name": "sleeplogalarm.wid.js", "url": "widget.js"} ] } diff --git a/apps/sleeplogalarm/settings.js b/apps/sleeplogalarm/settings.js index 8719761dd..f6787f3bd 100644 --- a/apps/sleeplogalarm/settings.js +++ b/apps/sleeplogalarm/settings.js @@ -148,6 +148,13 @@ writeSetting(); } ), + /*LANG*/"auto snooze": { + value: settings.as, + onchange: v => { + settings.as = v; + writeSetting(); + } + }, /*LANG*/"Widget": () => showWidMenu(), /*LANG*/"Enabled": { value: settings.enabled, diff --git a/apps/sleeplogalarm/trigger.js b/apps/sleeplogalarm/trigger.js deleted file mode 100644 index cc4dd6f12..000000000 --- a/apps/sleeplogalarm/trigger.js +++ /dev/null @@ -1,75 +0,0 @@ -exports = function(now, tNow) { - // define settings - var settings = Object.assign({ - from: 4, // 0400 - to: 8, // 0800 - earlier: 30, - msgAsPrefix: true, - disableOnAlarm: false, // !!! not available if alarm is at the next day - msg: "...\n", - vibrate: "..", - as: true - }, require("Storage").readJSON("sleeplogalarm.settings.json", true) || {}); - - // calculate then date - var then = new Date(now + settings.earlier * 6E4); - - // load library - var sched = require("sched"); - - // define function to return first active alarm in range to come - function firstActiveAlarm(allAlarms) { - return (sched.getActiveAlarms(allAlarms.filter( - // filter for active alarms, ... - a => a.on && !a.timer && - // after now+10s and in alarm range - a.t > tNow && a.t >= settings.from * 36E5 && a.t < settings.to * 36E5 - ), then) || []).sort((a, b) => a.t > b.t)[0]; - } - - // read all alarms - var allAlarms = sched.getAlarms(); - - // find first active alarm - var alarm = firstActiveAlarm(allAlarms); - - // return if no alarm is found - if (!alarm) return; - - // disable early triggered alarm if set and now and then on the same day - if (settings.disableOnAlarm && now.getDate() === then.getDate()) { - // add indexes to find alarm to temporary disable - allAlarms = allAlarms.map((a, idx) => { - a.idx = idx; - return a; - }); - // get index of first active alarm - var idx = firstActiveAlarm(allAlarms).idx; - // set this alarms last to then - allAlarms[idx].last = then.getDate(); - // remove added indexes - allAlarms = allAlarms.map(a => { - delete a.idx; - return a; - }); - } - - // add new alarm for now with data from found alarm - allAlarms.push({ - id: "sleeplog", - appid: "sleeplog", - on: true, - t: (((now.getHours() * 60 + now.getMinutes()) * 60 + now.getSeconds()) * 1000), - dow: 127, - msg: settings.msg + (settings.msgAsPrefix ? alarm.msg || "" : ""), - vibrate: settings.vibrate || alarm.vibrate, - as: settings.as, - del: true - }); - - // write changes - sched.setAlarms(allAlarms); - - // trigger sched.js - load("sched.js"); -}; \ No newline at end of file diff --git a/apps/sleeplogalarm/widget.js b/apps/sleeplogalarm/widget.js index 5ccc57cda..d0e60b488 100644 --- a/apps/sleeplogalarm/widget.js +++ b/apps/sleeplogalarm/widget.js @@ -1,64 +1,26 @@ -// read settings to calculate alarm range -settings = Object.assign({ // if using var here settings will always be undefined - enabled: true, - hide: false, - drawRange: true, - color: g.theme.dark ? 65504 : 31, // yellow or blue - from: 4, // 0400 - to: 8, // 0800 - earlier: 30 -}, require("Storage").readJSON("sleeplogalarm.settings.json", true) || {}); - // check if enabled in settings -if (settings.enabled) { +if ((require("Storage").readJSON("sleeplogalarm.settings.json", true) || {enabled: true}).enabled) { // insert neccessary settings into widget WIDGETS.sleeplogalarm = { area: "tl", width: 0, - drawRange: settings.drawRange, + drawTime: settings.drawTime, color: settings.color, - from: settings.from, - to: settings.to, + time: 0, earlier: settings.earlier, draw: function () { // draw zzz g.reset().setColor(this.color).drawImage(atob("BwoBD8SSSP4EEEDg"), this.x + 1, this.y); - // draw alarm range times if enabled - if (this.drawRange) { + // draw time of alarm if enabled + if (this.drawTime && this.time) { // directly include Font4x5Numeric - g.setFontCustom(atob("CAZMA/H4PgvXoK1+DhPg7W4P1uCEPg/X4O1+AA=="), 46, atob("AgQEAgQEBAQEBAQE"), 5); - g.drawString(this.from, this.x + 1, this.y + 12); - g.setFontAlign(1, 1).drawString(this.to, this.x + this.width + 1, this.y + 23); + g.setFontCustom(atob("CAZMA/H4PgvXoK1+DhPg7W4P1uCEPg/X4O1+AA=="), 46, atob("AgQEAgQEBAQEBAQE"), 5).setFontAlign(1, 1); + g.drawString(0|(this.time / 36E5), this.x + this.width + 1, this.y + 12); + g.drawString(0|((this.time / 36E5)%1 * 60), this.x + this.width + 1, this.y + 23); } }, - reload: function () { - // abort if onChange is not available - if (typeof (global.sleeplog || {}).onChange !== "object") return; - - // abort if no alarm exists inside range - if (!(require("Storage").readJSON("sched.json", 1) || []) - .filter(a => a.on && !a.timer) - .some(a => a.t >= this.from * 36E5 && a.t < this.to * 36E5)) return; - - // set widget width if not hidden - if (!this.hidden) this.width = 8; - - // insert sleeplogalarm function to onChange - sleeplog.onChange.sleeplogalarm = function (data) { - // abort if not changed from deep sleep to light sleep or awake - if (data.prevStatus !== 4 || !(data.status === 3 || data.status === 2)) return; - - // get cahed data, now and calculate time of now - var settings = WIDGETS.sleeplogalarm; - var now = new Date(); - var tNow = (((now.getHours() * 60 + now.getMinutes()) * 60 + now.getSeconds()) * 1000); - - // execute trigger function if now is inside the alarm range - if (tNow + settings.earlier * 6E4 >= settings.from * 36E5 && - tNow < settings.to * 36E5) require("sleeplogalarm.trigger.js")(now, tNow); - }; - } + reload: require("sleeplogalarm").widReload() }; // load widget From e92bd01fc8b50cb7ed53d2e5f404c6705f7d9b4f Mon Sep 17 00:00:00 2001 From: storm64 Date: Sat, 12 Nov 2022 00:16:39 +0100 Subject: [PATCH 011/110] [sleeplogalarm] Finish transfer to lib --- apps/sleeplogalarm/lib.js | 34 +++++++++++----------------------- apps/sleeplogalarm/settings.js | 22 +++------------------- apps/sleeplogalarm/widget.js | 22 ++++++++++++++-------- 3 files changed, 28 insertions(+), 50 deletions(-) diff --git a/apps/sleeplogalarm/lib.js b/apps/sleeplogalarm/lib.js index d7375f79a..d5fb87a65 100644 --- a/apps/sleeplogalarm/lib.js +++ b/apps/sleeplogalarm/lib.js @@ -19,11 +19,6 @@ function getNextAlarm(allAlarms, from, to, withId) { }).sort((a, b) => a.tTo - b.tTo)[0] || {}; } -// calculate a time from its date -function dateToTime(date) { - return ((date.getHours() * 60 + date.getMinutes()) * 60 + date.getSeconds()) * 1000; -} - exports = { // function to read settings with defaults getSettings: function() { @@ -68,7 +63,7 @@ exports = { // get settings from widget, now and calculate time of now var settings = WIDGETS.sleeplogalarm; var now = new Date(); - var tNow = dateToTime(now); + var tNow = ((now.getHours() * 60 + now.getMinutes()) * 60 + now.getSeconds()) * 1000; // execute trigger function if inside the alarm range if (tNow >= settings.time - settings.earlier * 6E4 && @@ -78,32 +73,25 @@ exports = { // trigger function trigger: function(now, tNow) { - // define settings + // read settings var settings = this.getSettings(); - // calculate then date - var then = new Date(now + settings.earlier * 6E4); - // read all alarms var allAlarms = sched.getAlarms(); // find first active alarm - var alarm = firstActiveAlarm(allAlarms); + var alarm = getNextAlarm(sched.getAlarms(), settings.from * 36E5, settings.to * 36E5, settings.disableOnAlarm); // return if no alarm is found if (!alarm) return; - // disable early triggered alarm if set and now and then on the same day - if (settings.disableOnAlarm && now.getDate() === then.getDate()) { - // add indexes to find alarm to temporary disable - allAlarms = allAlarms.map((a, idx) => { - a.idx = idx; - return a; - }); - // get index of first active alarm - var idx = firstActiveAlarm(allAlarms).idx; - // set this alarms last to then - allAlarms[idx].last = then.getDate(); + // get date of the alarm + var aDate = new Date(now + alarm.tTo).getDate(); + + // disable earlier triggered alarm if set and on the same day + if (settings.disableOnAlarm && now.getDate() === aDate) { + // set alarms last to today + allAlarms[alarm.idx].last = aDate; // remove added indexes allAlarms = allAlarms.map(a => { delete a.idx; @@ -116,7 +104,7 @@ exports = { id: "sleeplog", appid: "sleeplog", on: true, - t: (((now.getHours() * 60 + now.getMinutes()) * 60 + now.getSeconds()) * 1000), + t: tNow, dow: 127, msg: settings.msg + (settings.msgAsPrefix ? alarm.msg || "" : ""), vibrate: settings.vibrate || alarm.vibrate, diff --git a/apps/sleeplogalarm/settings.js b/apps/sleeplogalarm/settings.js index f6787f3bd..2447a20aa 100644 --- a/apps/sleeplogalarm/settings.js +++ b/apps/sleeplogalarm/settings.js @@ -1,26 +1,10 @@ (function(back) { - // define settings filename - var filename = "sleeplogalarm.settings.json"; - - // define settings - var settings = Object.assign({ - enabled: true, - hide: false, - drawRange: true, - color: g.theme.dark ? 65504 : 31, // yellow or blue - from: 4, // 0400 - to: 8, // 0800 - earlier: 30, - disableOnAlarm: false, // !!! not available if alarm is at the next day - msg: "...\n", - msgAsPrefix: true, - vibrate: "..", - as: true - }, require("Storage").readJSON(filename, true) || {}); + // read settings + var settings = require("sleeplogalarm").getSettings(); // write change to storage function writeSetting() { - require("Storage").writeJSON(filename, settings); + require("Storage").writeJSON("sleeplogalarm.settings.json", settings); } // show widget menu diff --git a/apps/sleeplogalarm/widget.js b/apps/sleeplogalarm/widget.js index d0e60b488..ee5e06fcb 100644 --- a/apps/sleeplogalarm/widget.js +++ b/apps/sleeplogalarm/widget.js @@ -1,5 +1,7 @@ // check if enabled in settings if ((require("Storage").readJSON("sleeplogalarm.settings.json", true) || {enabled: true}).enabled) { + // read settings + var settings = require("sleeplogalarm").getSettings(); // insert neccessary settings into widget WIDGETS.sleeplogalarm = { @@ -11,18 +13,22 @@ if ((require("Storage").readJSON("sleeplogalarm.settings.json", true) || {enable earlier: settings.earlier, draw: function () { // draw zzz - g.reset().setColor(this.color).drawImage(atob("BwoBD8SSSP4EEEDg"), this.x + 1, this.y); - // draw time of alarm if enabled - if (this.drawTime && this.time) { - // directly include Font4x5Numeric - g.setFontCustom(atob("CAZMA/H4PgvXoK1+DhPg7W4P1uCEPg/X4O1+AA=="), 46, atob("AgQEAgQEBAQEBAQE"), 5).setFontAlign(1, 1); - g.drawString(0|(this.time / 36E5), this.x + this.width + 1, this.y + 12); - g.drawString(0|((this.time / 36E5)%1 * 60), this.x + this.width + 1, this.y + 23); - } + g.reset().setColor(settings.color).drawImage(atob("BwoBD8SSSP4EEEDg"), this.x + 1, this.y); + // call function to draw the time of alarm if a alarm is found + if (this.time) this.drawTime(this.time); }, + drawTime: () => {}, reload: require("sleeplogalarm").widReload() }; + // add function to draw the time of alarm if enabled + if (this.drawTime) WIDGETS.sleeplogalarm.drawTime = function(time) { + // directly include Font4x5Numeric + g.setFontCustom(atob("CAZMA/H4PgvXoK1+DhPg7W4P1uCEPg/X4O1+AA=="), 46, atob("AgQEAgQEBAQEBAQE"), 5).setFontAlign(1, 1); + g.drawString(0|(time / 36E5), this.x + this.width + 1, this.y + 12); + g.drawString(0|((time / 36E5)%1 * 60), this.x + this.width + 1, this.y + 23); + }; + // load widget WIDGETS.sleeplogalarm.reload(); } \ No newline at end of file From bc99316979698bf6d3f2274bccab02d67da8d000 Mon Sep 17 00:00:00 2001 From: storm64 Date: Sat, 12 Nov 2022 00:19:36 +0100 Subject: [PATCH 012/110] [sleeplogalarm] Clear dublicates in widget --- apps/sleeplogalarm/widget.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/apps/sleeplogalarm/widget.js b/apps/sleeplogalarm/widget.js index ee5e06fcb..a8bedaa13 100644 --- a/apps/sleeplogalarm/widget.js +++ b/apps/sleeplogalarm/widget.js @@ -7,8 +7,6 @@ if ((require("Storage").readJSON("sleeplogalarm.settings.json", true) || {enable WIDGETS.sleeplogalarm = { area: "tl", width: 0, - drawTime: settings.drawTime, - color: settings.color, time: 0, earlier: settings.earlier, draw: function () { From 111a194e573dd212c4e8541f1609581de9c417ef Mon Sep 17 00:00:00 2001 From: storm64 Date: Sat, 12 Nov 2022 01:42:31 +0100 Subject: [PATCH 013/110] [sleeplogalarm] Corrections, prevent retrigger --- apps/sleeplogalarm/lib.js | 25 +++++++++++++++---------- apps/sleeplogalarm/widget.js | 10 +++++----- 2 files changed, 20 insertions(+), 15 deletions(-) diff --git a/apps/sleeplogalarm/lib.js b/apps/sleeplogalarm/lib.js index d5fb87a65..7f513221f 100644 --- a/apps/sleeplogalarm/lib.js +++ b/apps/sleeplogalarm/lib.js @@ -7,16 +7,15 @@ function getNextAlarm(allAlarms, from, to, withId) { a.idx = idx; return a; }); - // return next - return sched.getActiveAlarms( - // filter for active alarms in range - allAlarms.filter(a => a.on && !a.timer && a.t >= from && a.t < to) - ).map(a => { - // add time to alarm + // return next active alarms in range + return allAlarms.filter( + a => a.on && !a.timer && a.t >= from && a.t < to + ).map(a => { // add time to alarm a.tTo = sched.getTimeToAlarm(a); return a; - // sort to get next alarm first - }).sort((a, b) => a.tTo - b.tTo)[0] || {}; + }).filter(a => a.tTo // filter non active alarms + // sort to get next alarm first + ).sort((a, b) => a.tTo - b.tTo)[0] || {}; } exports = { @@ -44,7 +43,7 @@ exports = { if (typeof (global.sleeplog || {}).onChange !== "object") return; // read settings to calculate alarm range - var settings = this.getSettings(); + var settings = exports.getSettings(); // set the alarm time this.time = getNextAlarm(sched.getAlarms(), settings.from * 36E5, settings.to * 36E5).t; @@ -55,6 +54,9 @@ exports = { // set widget width if not hidden if (!this.hidden) this.width = 8; + // abort if already alarmed for this alarm + if (sleeplog.onChange.sleeplogalarm == this.time) return; + // insert sleeplogalarm function to onChange sleeplog.onChange.sleeplogalarm = function (data) { // abort if not changed from deep sleep to light sleep or awake @@ -74,7 +76,7 @@ exports = { // trigger function trigger: function(now, tNow) { // read settings - var settings = this.getSettings(); + var settings = exports.getSettings(); // read all alarms var allAlarms = sched.getAlarms(); @@ -82,6 +84,9 @@ exports = { // find first active alarm var alarm = getNextAlarm(sched.getAlarms(), settings.from * 36E5, settings.to * 36E5, settings.disableOnAlarm); + // clear sleeplog.onChange function and set alarm time to prevent resetting for this alarm + sleeplog.onChange.sleeplogalarm = alarm.t; + // return if no alarm is found if (!alarm) return; diff --git a/apps/sleeplogalarm/widget.js b/apps/sleeplogalarm/widget.js index a8bedaa13..96f4e7740 100644 --- a/apps/sleeplogalarm/widget.js +++ b/apps/sleeplogalarm/widget.js @@ -1,7 +1,7 @@ // check if enabled in settings if ((require("Storage").readJSON("sleeplogalarm.settings.json", true) || {enabled: true}).enabled) { // read settings - var settings = require("sleeplogalarm").getSettings(); + settings = require("sleeplogalarm").getSettings(); // is undefined if used with var // insert neccessary settings into widget WIDGETS.sleeplogalarm = { @@ -13,17 +13,17 @@ if ((require("Storage").readJSON("sleeplogalarm.settings.json", true) || {enable // draw zzz g.reset().setColor(settings.color).drawImage(atob("BwoBD8SSSP4EEEDg"), this.x + 1, this.y); // call function to draw the time of alarm if a alarm is found - if (this.time) this.drawTime(this.time); + if (this.time) this.drawTime(this.time + 1); }, drawTime: () => {}, - reload: require("sleeplogalarm").widReload() + reload: require("sleeplogalarm").widReload }; // add function to draw the time of alarm if enabled - if (this.drawTime) WIDGETS.sleeplogalarm.drawTime = function(time) { + if (settings.drawTime) WIDGETS.sleeplogalarm.drawTime = function(time) { // directly include Font4x5Numeric g.setFontCustom(atob("CAZMA/H4PgvXoK1+DhPg7W4P1uCEPg/X4O1+AA=="), 46, atob("AgQEAgQEBAQEBAQE"), 5).setFontAlign(1, 1); - g.drawString(0|(time / 36E5), this.x + this.width + 1, this.y + 12); + g.drawString(0|(time / 36E5), this.x + this.width + 1, this.y + 17); g.drawString(0|((time / 36E5)%1 * 60), this.x + this.width + 1, this.y + 23); }; From 8d54208aded24279c2cfff3e238de828642b33a5 Mon Sep 17 00:00:00 2001 From: storm64 Date: Wed, 16 Nov 2022 23:24:43 +0100 Subject: [PATCH 014/110] [sleeplogalarm] Update using sleeplog.trigger --- apps/sleeplogalarm/lib.js | 39 +++++++++++++++++++-------------------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/apps/sleeplogalarm/lib.js b/apps/sleeplogalarm/lib.js index 7f513221f..ea19d04e2 100644 --- a/apps/sleeplogalarm/lib.js +++ b/apps/sleeplogalarm/lib.js @@ -39,8 +39,8 @@ exports = { // widget reload function widReload: function() { - // abort if onChange is not available - if (typeof (global.sleeplog || {}).onChange !== "object") return; + // abort if trigger object is not available + if (typeof (global.sleeplog || {}).trigger !== "object") return; // read settings to calculate alarm range var settings = exports.getSettings(); @@ -55,26 +55,22 @@ exports = { if (!this.hidden) this.width = 8; // abort if already alarmed for this alarm - if (sleeplog.onChange.sleeplogalarm == this.time) return; + if ((sleeplog.trigger.sleeplogalarm || {}).last == this.time) return; - // insert sleeplogalarm function to onChange - sleeplog.onChange.sleeplogalarm = function (data) { - // abort if not changed from deep sleep to light sleep or awake - if (data.prevStatus !== 4 || !(data.status === 3 || data.status === 2)) return; - - // get settings from widget, now and calculate time of now - var settings = WIDGETS.sleeplogalarm; - var now = new Date(); - var tNow = ((now.getHours() * 60 + now.getMinutes()) * 60 + now.getSeconds()) * 1000; - - // execute trigger function if inside the alarm range - if (tNow >= settings.time - settings.earlier * 6E4 && - tNow < settings.time) require("sleeplogalarm").trigger(now, tNow); + // insert sleeplogalarm conditions and function + sleeplog.trigger.sleeplogalarm = { + from: settings.time - settings.earlier * 6E4, + to: settings.time - 1, + fn: function (data) { + // execute trigger function if on light sleep or awake + if (data.status === 3 || data.status === 2) + require("sleeplogalarm").trigger(); + } }; }, // trigger function - trigger: function(now, tNow) { + trigger: function(tNow) { // read settings var settings = exports.getSettings(); @@ -84,12 +80,15 @@ exports = { // find first active alarm var alarm = getNextAlarm(sched.getAlarms(), settings.from * 36E5, settings.to * 36E5, settings.disableOnAlarm); - // clear sleeplog.onChange function and set alarm time to prevent resetting for this alarm - sleeplog.onChange.sleeplogalarm = alarm.t; + // clear sleeplog.trigger object and set alarm time to prevent resetting for this alarm + sleeplog.trigger.sleeplogalarm = {last: alarm.t}; // return if no alarm is found if (!alarm) return; + // get now + var now = new Date(); + // get date of the alarm var aDate = new Date(now + alarm.tTo).getDate(); @@ -109,7 +108,7 @@ exports = { id: "sleeplog", appid: "sleeplog", on: true, - t: tNow, + t: ((time.getHours() * 60 + time.getMinutes()) * 60 + time.getSeconds()) * 1000, dow: 127, msg: settings.msg + (settings.msgAsPrefix ? alarm.msg || "" : ""), vibrate: settings.vibrate || alarm.vibrate, From 550b95d9692304262314901bf8f1edbe5b8c594f Mon Sep 17 00:00:00 2001 From: storm64 Date: Thu, 17 Nov 2022 09:33:00 +0100 Subject: [PATCH 015/110] [sleeplogalarm] Correct times in sleeplog.trigger --- apps/sleeplogalarm/lib.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/sleeplogalarm/lib.js b/apps/sleeplogalarm/lib.js index ea19d04e2..7701d2624 100644 --- a/apps/sleeplogalarm/lib.js +++ b/apps/sleeplogalarm/lib.js @@ -59,8 +59,8 @@ exports = { // insert sleeplogalarm conditions and function sleeplog.trigger.sleeplogalarm = { - from: settings.time - settings.earlier * 6E4, - to: settings.time - 1, + from: this.time - settings.earlier * 6E4, + to: this.time - 1, fn: function (data) { // execute trigger function if on light sleep or awake if (data.status === 3 || data.status === 2) From 572020430773ce2f753bb964ff0d2bf5855bda14 Mon Sep 17 00:00:00 2001 From: storm64 Date: Thu, 17 Nov 2022 10:32:55 +0100 Subject: [PATCH 016/110] [sleeplogalarm] Correct t inside created alarm --- apps/sleeplogalarm/lib.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/sleeplogalarm/lib.js b/apps/sleeplogalarm/lib.js index 7701d2624..25bdfdbe4 100644 --- a/apps/sleeplogalarm/lib.js +++ b/apps/sleeplogalarm/lib.js @@ -70,7 +70,7 @@ exports = { }, // trigger function - trigger: function(tNow) { + trigger: function() { // read settings var settings = exports.getSettings(); @@ -108,7 +108,7 @@ exports = { id: "sleeplog", appid: "sleeplog", on: true, - t: ((time.getHours() * 60 + time.getMinutes()) * 60 + time.getSeconds()) * 1000, + t: ((now.getHours() * 60 + now.getMinutes()) * 60 + now.getSeconds()) * 1000, dow: 127, msg: settings.msg + (settings.msgAsPrefix ? alarm.msg || "" : ""), vibrate: settings.vibrate || alarm.vibrate, From 8800ba8fdaec6898be8fe015ab5c586f72473b9e Mon Sep 17 00:00:00 2001 From: storm64 Date: Thu, 17 Nov 2022 15:16:18 +0100 Subject: [PATCH 017/110] [sleeplogalarm] Reorder settings + filter for msg --- apps/sleeplogalarm/lib.js | 25 +++--- apps/sleeplogalarm/settings.js | 134 ++++++++++++++++++++------------- apps/sleeplogalarm/widget.js | 4 +- 3 files changed, 95 insertions(+), 68 deletions(-) diff --git a/apps/sleeplogalarm/lib.js b/apps/sleeplogalarm/lib.js index 25bdfdbe4..8beb64ffd 100644 --- a/apps/sleeplogalarm/lib.js +++ b/apps/sleeplogalarm/lib.js @@ -2,14 +2,14 @@ var sched = require("sched"); // find next active alarm in range -function getNextAlarm(allAlarms, from, to, withId) { +function getNextAlarm(allAlarms, from, to, msg, withId) { if (withId) allAlarms = allAlarms.map((a, idx) => { a.idx = idx; return a; }); // return next active alarms in range return allAlarms.filter( - a => a.on && !a.timer && a.t >= from && a.t < to + a => a.on && !a.timer && a.t >= from && a.t < to && (!msg || a.msg.includes(msg)) ).map(a => { // add time to alarm a.tTo = sched.getTimeToAlarm(a); return a; @@ -23,17 +23,18 @@ exports = { getSettings: function() { return Object.assign({ enabled: true, - hide: false, - drawTime: true, - color: g.theme.dark ? 65504 : 31, // yellow or blue - from: 4, // 0400 - to: 8, // 0800 earlier: 30, + filter_from: 0, + filter_to: 24, + filter_msg: "", + vibrate: "..", + msg: "...\n", msgAsPrefix: true, disableOnAlarm: false, // !!! not available if alarm is at the next day - msg: "...\n", - vibrate: "..", - as: true + as: true, + wid_hide: false, + wid_time: true, + wid_color: g.theme.dark ? 65504 : 31, // yellow or blue }, require("Storage").readJSON("sleeplogalarm.settings.json", true) || {}); }, @@ -46,7 +47,7 @@ exports = { var settings = exports.getSettings(); // set the alarm time - this.time = getNextAlarm(sched.getAlarms(), settings.from * 36E5, settings.to * 36E5).t; + this.time = getNextAlarm(sched.getAlarms(), settings.filter_from * 36E5, settings.filter_to * 36E5, settings,filter_msg).t; // abort if no alarm time could be found inside range if (!this.time) return; @@ -78,7 +79,7 @@ exports = { var allAlarms = sched.getAlarms(); // find first active alarm - var alarm = getNextAlarm(sched.getAlarms(), settings.from * 36E5, settings.to * 36E5, settings.disableOnAlarm); + var alarm = getNextAlarm(sched.getAlarms(), settings.filter_from * 36E5, settings.filter_to * 36E5, settings,filter_msg, settings.disableOnAlarm); // clear sleeplog.trigger object and set alarm time to prevent resetting for this alarm sleeplog.trigger.sleeplogalarm = {last: alarm.t}; diff --git a/apps/sleeplogalarm/settings.js b/apps/sleeplogalarm/settings.js index 2447a20aa..c62f6a273 100644 --- a/apps/sleeplogalarm/settings.js +++ b/apps/sleeplogalarm/settings.js @@ -7,6 +7,66 @@ require("Storage").writeJSON("sleeplogalarm.settings.json", settings); } + // read input from keyboard + function readInput(setting, retPos, cb) { + setTimeout((setting, retPos, cb) => { + if (require("Storage").read("textinput")) { + g.clear(); + require("textinput").input({text: settings[setting]}).then(result => { + settings[setting] = result; + writeSetting(); + cb(retPos); + }); + } else { + E.showAlert(/*LANG*/"No keyboard app installed").then(() => cb(retPos)); + } + }, 0, setting, retPos, cb); + } + + // show widget menu + function showFilterMenu() { + // set menu + var filterMenu = { + "": { + title: "Filter Alarm" + }, + /*LANG*/"< Back": () => showMain(2), + /*LANG*/"time from": { + value: settings.filter_from, + step: 0.25, + min: 0, + max: 23, + wrap: true, + noList: true, + format: v => 0|v + ":" + ("" + 0|(v%1 * 60)).padStart(2, "0"), + onchange: v => { + settings.filter_from = v; + writeSetting(); + } + }, + /*LANG*/"time to": { + value: settings.filter_to, + step: 0.25, + min: 1, + max: 24, + wrap: true, + noList: true, + format: v => 0|v + ":" + ("" + 0|(v%1 * 60)).padStart(2, "0"), + onchange: v => { + settings.filter_to = v; + writeSetting(); + } + }, + /*LANG*/"msg includes": { + value: settings.filter_msg, + format: v => !v ? "" : v.length > 6 ? v.substring(0, 6)+"..." : v, + // setTimeout required to load after menu refresh + onchange: () => readInput("filter_msg", 3, showFilterMenu) + } + }; + var menu = E.showMenu(filterMenu); + } + // show widget menu function showWidMenu() { // define color values and names @@ -18,29 +78,29 @@ "": { title: "Widget Settings" }, - /*LANG*/"< Back": () => showMain(7), + /*LANG*/"< Back": () => showMain(8), /*LANG*/"hide": { - value: settings.hide, + value: settings.wid_hide, onchange: v => { - settings.hide = v; + settings.wid_hide = v; writeSetting(); } }, - /*LANG*/"time range": { - value: settings.drawRange, + /*LANG*/"show time": { + value: settings.wid_time, onchange: v => { - settings.drawRange = v; + settings.wid_time = v; writeSetting(); } }, /*LANG*/"color": { - value: colVal.indexOf(settings.color), + value: colVal.indexOf(settings.wid_color), min: 0, max: colVal.length -1, wrap: true, format: v => colName[v], onchange: v => { - settings.color = colVal[v]; + settings.wid_color = colVal[v]; writeSetting(); } } @@ -57,30 +117,6 @@ selected: selected }, /*LANG*/"< Back": () => back(), - /*LANG*/"time from": { - value: settings.from, - min: 0, - max: 23, - wrap: true, - noList: true, - format: v => v + ":00", - onchange: v => { - settings.from = v; - writeSetting(); - } - }, - /*LANG*/"time to": { - value: settings.to, - min: 1, - max: 24, - wrap: true, - noList: true, - format: v => v + ":00", - onchange: v => { - settings.to = v; - writeSetting(); - } - }, /*LANG*/"erlier": { value: settings.earlier, step: 10, @@ -94,29 +130,19 @@ writeSetting(); } }, - /*LANG*/"disable alarm": { - value: settings.disableOnAlarm, - onchange: v => { - settings.disableOnAlarm = v; + /*LANG*/"Filter Alarm": () => showFilterMenu(), + /*LANG*/"vib pattern": require("buzz_menu").pattern( + settings.vibrate, + v => { + settings.vibrate = v; writeSetting(); } - }, + ), /*LANG*/"msg": { value: settings.msg, format: v => !v ? "" : v.length > 6 ? v.substring(0, 6)+"..." : v, // setTimeout required to load after menu refresh - onchange: () => setTimeout((msg, cb) => { - if (require("Storage").read("textinput")) { - g.clear(); - require("textinput").input({text: msg}).then(result => { - settings.msg = result; - writeSetting(); - cb(7); - }); - } else { - E.showAlert(/*LANG*/"No keyboard app installed").then(() => cb(7)); - } - }, 0, settings.msg, showMain), + onchange: () => readInput("msg", 4, showMain) }, /*LANG*/"msg as prefix": { value: settings.msgAsPrefix, @@ -125,13 +151,13 @@ writeSetting(); } }, - /*LANG*/"vib pattern": require("buzz_menu").pattern( - settings.vibrate, - v => { - settings.vibrate = v; + /*LANG*/"disable alarm": { + value: settings.disableOnAlarm, + onchange: v => { + settings.disableOnAlarm = v; writeSetting(); } - ), + }, /*LANG*/"auto snooze": { value: settings.as, onchange: v => { diff --git a/apps/sleeplogalarm/widget.js b/apps/sleeplogalarm/widget.js index 96f4e7740..991238140 100644 --- a/apps/sleeplogalarm/widget.js +++ b/apps/sleeplogalarm/widget.js @@ -11,7 +11,7 @@ if ((require("Storage").readJSON("sleeplogalarm.settings.json", true) || {enable earlier: settings.earlier, draw: function () { // draw zzz - g.reset().setColor(settings.color).drawImage(atob("BwoBD8SSSP4EEEDg"), this.x + 1, this.y); + g.reset().setColor(settings.wid_color).drawImage(atob("BwoBD8SSSP4EEEDg"), this.x + 1, this.y); // call function to draw the time of alarm if a alarm is found if (this.time) this.drawTime(this.time + 1); }, @@ -20,7 +20,7 @@ if ((require("Storage").readJSON("sleeplogalarm.settings.json", true) || {enable }; // add function to draw the time of alarm if enabled - if (settings.drawTime) WIDGETS.sleeplogalarm.drawTime = function(time) { + if (settings.wid_time) WIDGETS.sleeplogalarm.drawTime = function(time) { // directly include Font4x5Numeric g.setFontCustom(atob("CAZMA/H4PgvXoK1+DhPg7W4P1uCEPg/X4O1+AA=="), 46, atob("AgQEAgQEBAQEBAQE"), 5).setFontAlign(1, 1); g.drawString(0|(time / 36E5), this.x + this.width + 1, this.y + 17); From 67d6da813ec9d599274e285d32bcd2320992a19b Mon Sep 17 00:00:00 2001 From: storm64 Date: Thu, 17 Nov 2022 16:32:47 +0100 Subject: [PATCH 018/110] [sleeplogalarm] Correct typo --- apps/sleeplogalarm/lib.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/sleeplogalarm/lib.js b/apps/sleeplogalarm/lib.js index 8beb64ffd..f38945fb4 100644 --- a/apps/sleeplogalarm/lib.js +++ b/apps/sleeplogalarm/lib.js @@ -47,7 +47,7 @@ exports = { var settings = exports.getSettings(); // set the alarm time - this.time = getNextAlarm(sched.getAlarms(), settings.filter_from * 36E5, settings.filter_to * 36E5, settings,filter_msg).t; + this.time = getNextAlarm(sched.getAlarms(), settings.filter_from * 36E5, settings.filter_to * 36E5, settings.filter_msg).t; // abort if no alarm time could be found inside range if (!this.time) return; @@ -79,7 +79,7 @@ exports = { var allAlarms = sched.getAlarms(); // find first active alarm - var alarm = getNextAlarm(sched.getAlarms(), settings.filter_from * 36E5, settings.filter_to * 36E5, settings,filter_msg, settings.disableOnAlarm); + var alarm = getNextAlarm(sched.getAlarms(), settings.filter_from * 36E5, settings.filter_to * 36E5, settings.filter_msg, settings.disableOnAlarm); // clear sleeplog.trigger object and set alarm time to prevent resetting for this alarm sleeplog.trigger.sleeplogalarm = {last: alarm.t}; From 9def5a8ee3f427c7cbc440e761f93ece12835c9c Mon Sep 17 00:00:00 2001 From: storm64 Date: Thu, 17 Nov 2022 17:09:18 +0100 Subject: [PATCH 019/110] [sleeplogalarm] Don't show own alarm --- apps/sleeplogalarm/lib.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/sleeplogalarm/lib.js b/apps/sleeplogalarm/lib.js index f38945fb4..716c69c3d 100644 --- a/apps/sleeplogalarm/lib.js +++ b/apps/sleeplogalarm/lib.js @@ -9,7 +9,8 @@ function getNextAlarm(allAlarms, from, to, msg, withId) { }); // return next active alarms in range return allAlarms.filter( - a => a.on && !a.timer && a.t >= from && a.t < to && (!msg || a.msg.includes(msg)) + a => a.on && !a.timer && a.id !== "sleeplog" && + a.t >= from && a.t < to && (!msg || a.msg.includes(msg)) ).map(a => { // add time to alarm a.tTo = sched.getTimeToAlarm(a); return a; From c25750ebc1df501162113462cdd70b569bd3092b Mon Sep 17 00:00:00 2001 From: storm64 Date: Thu, 17 Nov 2022 17:44:36 +0100 Subject: [PATCH 020/110] [sleeplogalarm] Correct times display in settings --- apps/sleeplogalarm/settings.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/sleeplogalarm/settings.js b/apps/sleeplogalarm/settings.js index c62f6a273..fe774c3b2 100644 --- a/apps/sleeplogalarm/settings.js +++ b/apps/sleeplogalarm/settings.js @@ -38,7 +38,7 @@ max: 23, wrap: true, noList: true, - format: v => 0|v + ":" + ("" + 0|(v%1 * 60)).padStart(2, "0"), + format: v => (0|v) + ":" + ("" + (0|(v%1 * 60))).padStart(2, "0"), onchange: v => { settings.filter_from = v; writeSetting(); @@ -51,7 +51,7 @@ max: 24, wrap: true, noList: true, - format: v => 0|v + ":" + ("" + 0|(v%1 * 60)).padStart(2, "0"), + format: v => (0|v) + ":" + ("" + (0|(v%1 * 60))).padStart(2, "0"), onchange: v => { settings.filter_to = v; writeSetting(); From a49f902f027cffe2cd48d5243cbce7b11f5f625b Mon Sep 17 00:00:00 2001 From: storm64 Date: Thu, 17 Nov 2022 17:52:18 +0100 Subject: [PATCH 021/110] [sleeplogalarm] Adjust default filter times --- apps/sleeplogalarm/lib.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/sleeplogalarm/lib.js b/apps/sleeplogalarm/lib.js index 716c69c3d..739670673 100644 --- a/apps/sleeplogalarm/lib.js +++ b/apps/sleeplogalarm/lib.js @@ -25,8 +25,8 @@ exports = { return Object.assign({ enabled: true, earlier: 30, - filter_from: 0, - filter_to: 24, + filter_from: 3, + filter_to: 12, filter_msg: "", vibrate: "..", msg: "...\n", From 69d0890cfa86d3ee8654e24c1f2df052de9db6d9 Mon Sep 17 00:00:00 2001 From: storm64 Date: Fri, 18 Nov 2022 15:26:15 +0100 Subject: [PATCH 022/110] [sleeplogalarm] Alarm only once each alarm --- apps/sleeplogalarm/lib.js | 37 ++++++++++++++++++++++++++----------- 1 file changed, 26 insertions(+), 11 deletions(-) diff --git a/apps/sleeplogalarm/lib.js b/apps/sleeplogalarm/lib.js index 739670673..f899ae54e 100644 --- a/apps/sleeplogalarm/lib.js +++ b/apps/sleeplogalarm/lib.js @@ -2,15 +2,19 @@ var sched = require("sched"); // find next active alarm in range -function getNextAlarm(allAlarms, from, to, msg, withId) { +function getNextAlarm(allAlarms, fo, withId) { if (withId) allAlarms = allAlarms.map((a, idx) => { a.idx = idx; return a; }); - // return next active alarms in range + // return next active alarms in range, filter for + // active, not timer, not own alarm, + // after from, before to, includes msg + // not lastTime, not lastDay return allAlarms.filter( a => a.on && !a.timer && a.id !== "sleeplog" && - a.t >= from && a.t < to && (!msg || a.msg.includes(msg)) + a.t >= fo.from && a.t < fo.to && (!fo.msg || a.msg.includes(fo.msg)) && + fo.lastTime !== a.t && fo.lastDay !== a.last ).map(a => { // add time to alarm a.tTo = sched.getTimeToAlarm(a); return a; @@ -48,7 +52,13 @@ exports = { var settings = exports.getSettings(); // set the alarm time - this.time = getNextAlarm(sched.getAlarms(), settings.filter_from * 36E5, settings.filter_to * 36E5, settings.filter_msg).t; + this.time = getNextAlarm(sched.getAlarms(), { + from: settings.filter_from * 36E5, + to: settings.filter_to * 36E5, + msg: settings.filter_msg, + lastTime: settings.lastTime, + lastDay: settings.lastDay + }).t; // abort if no alarm time could be found inside range if (!this.time) return; @@ -56,9 +66,6 @@ exports = { // set widget width if not hidden if (!this.hidden) this.width = 8; - // abort if already alarmed for this alarm - if ((sleeplog.trigger.sleeplogalarm || {}).last == this.time) return; - // insert sleeplogalarm conditions and function sleeplog.trigger.sleeplogalarm = { from: this.time - settings.earlier * 6E4, @@ -80,10 +87,13 @@ exports = { var allAlarms = sched.getAlarms(); // find first active alarm - var alarm = getNextAlarm(sched.getAlarms(), settings.filter_from * 36E5, settings.filter_to * 36E5, settings.filter_msg, settings.disableOnAlarm); - - // clear sleeplog.trigger object and set alarm time to prevent resetting for this alarm - sleeplog.trigger.sleeplogalarm = {last: alarm.t}; + var alarm = getNextAlarm(sched.getAlarms(), { + from: settings.filter_from * 36E5, + to: settings.filter_to * 36E5, + msg: settings.filter_msg, + lastTime: settings.lastTime, + lastDay: settings.lastDay + }, settings.disableOnAlarm); // return if no alarm is found if (!alarm) return; @@ -118,6 +128,11 @@ exports = { del: true }); + // save time of alarm and this day to prevent triggering for the same alarm again + settings.lastTime = alarm.t; + settings.lastDay = now.getDay(); + require("Storage").writeJSON("sleeplogalarm.settings.json", settings); + // write changes sched.setAlarms(allAlarms); From 8c4c514059dd4daa83040509041f2c8189c77c47 Mon Sep 17 00:00:00 2001 From: storm64 Date: Fri, 18 Nov 2022 23:08:41 +0100 Subject: [PATCH 023/110] [sleeplogalarm] Add setting + explanations, icon --- apps/sleeplogalarm/ChangeLog | 1 + apps/sleeplogalarm/README.md | 49 +++++++++++++++++++------------ apps/sleeplogalarm/app.png | Bin 8089 -> 9048 bytes apps/sleeplogalarm/lib.js | 11 ++++--- apps/sleeplogalarm/metadata.json | 2 +- apps/sleeplogalarm/settings.js | 17 +++++++---- 6 files changed, 52 insertions(+), 28 deletions(-) diff --git a/apps/sleeplogalarm/ChangeLog b/apps/sleeplogalarm/ChangeLog index 5560f00bc..0030c8783 100644 --- a/apps/sleeplogalarm/ChangeLog +++ b/apps/sleeplogalarm/ChangeLog @@ -1 +1,2 @@ 0.01: New App! +0.02: Add "from Consec."-setting \ No newline at end of file diff --git a/apps/sleeplogalarm/README.md b/apps/sleeplogalarm/README.md index 42c2d6074..184eb4b53 100644 --- a/apps/sleeplogalarm/README.md +++ b/apps/sleeplogalarm/README.md @@ -1,27 +1,40 @@ # Sleep Log Alarm -This widget searches for active alarms and raises the alarm event up to the defined time earlier, if in a light sleep phase. +This widget searches for active alarms and raises an own alarm event up to the defined time earlier, if in light sleep or awake phase. Optional the earlier alarm will only be triggered if comming from or in consecutive sleep. The settings of the earlier alarm can be adjusted and it is possible to filter the targeting alarms by time and message. By default the time of the targeting alarm is displayed inside the widget which can be adjusted, too. --- -### App Usage +### Settings --- -#### Inside the settings: !!! dummy entries !!! - - __Thresholds__ submenu - Changes take effect from now on, not retrospective! - - __Max Awake__ | maximal awake duration - _10min_ / _20min_ / ... / __60min__ / ... / _120min_ - - __Min Consecutive__ | minimal consecutive sleep duration - _10min_ / _20min_ / ... / __30min__ / ... / _120min_ - - __Deep Sleep__ | deep sleep threshold - _30_ / _31_ / ... / __100__ / ... / _200_ - - __Light Sleep__ | light sleep threshold - _100_ / _110_ / ... / __200__ / ... / _400_ - - __Reset to Default__ | reset to bold values above - - __BreakToD__ | time of day to break view - _0:00_ / _1:00_ / ... / __12:00__ / ... / _23:00_ - - __App Timeout__ | app specific lock timeout - __0s__ / _10s_ / ... / _120s_ + - __earlier__ | duration to trigger alarm earlier + _10min_ / _20min_ / __30min__ / ... / _120min_ + - __from Consec.__ | only trigger if comming from consecutive sleep + _on_ / __off__ + - __vib pattern__ | vibration pattern for the earlier alarm + __..__ / ... + - __msg__ | customized message for the earlier alarm + __...__ / ... + - __msg as prefix__ | use the customized message as prefix to the original message or replace it comlpetely if disabled + __on__ / _off_ + - __disable alarm__ | if enabled the original alarm will be disabled + _on_ / __off__ + This feature does not work for alarms on the next day! + - __auto snooze__ | auto snooze option for the earlier alarm + __on__ / _off_ + - __Filter Alarm__ submenu + - __time from__ | exclude alarms before this time + _0:00_ / _0:15_ / ... / __3:00__ / ... / _24:00_ + - __time to__ | exclude alarms after this time + _0:00_ / _0:15_ / ... / __12:00__ / ... / _24:00_ + - __msg includes__ | include only alarms including this string in msg + __""__ / ... + - __Widget__ submenu + - __hide__ | completely hide the widget + _on_ / __off__ + - __show time__ | show the time of the targeting alarm + __on__ / _off_ + - __color__ | color of the widget + _red_ / __yellow__ / ... / _white_ - __Enabled__ | completely en-/disables the background service __on__ / _off_ diff --git a/apps/sleeplogalarm/app.png b/apps/sleeplogalarm/app.png index 6efb22a3f666817408264ec02731f4ac13d1ffe8..1a8e53865734de9ba90390a489ea54ddaa4a12ec 100644 GIT binary patch delta 5615 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 JPDHLkV1l9g&OHDC delta 4759 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 diff --git a/apps/sleeplogalarm/lib.js b/apps/sleeplogalarm/lib.js index f899ae54e..71210f98b 100644 --- a/apps/sleeplogalarm/lib.js +++ b/apps/sleeplogalarm/lib.js @@ -29,14 +29,15 @@ exports = { return Object.assign({ enabled: true, earlier: 30, - filter_from: 3, - filter_to: 12, - filter_msg: "", + fromConsec: false, vibrate: "..", msg: "...\n", msgAsPrefix: true, disableOnAlarm: false, // !!! not available if alarm is at the next day as: true, + filter_from: 3, + filter_to: 12, + filter_msg: "", wid_hide: false, wid_time: true, wid_color: g.theme.dark ? 65504 : 31, // yellow or blue @@ -72,7 +73,9 @@ exports = { to: this.time - 1, fn: function (data) { // execute trigger function if on light sleep or awake - if (data.status === 3 || data.status === 2) + // and if set if comming from consecutive + if ((data.status === 3 || data.status === 2) && !settings.fromConsec || + data.consecutive === 3 || data.prevConsecutive === 3) require("sleeplogalarm").trigger(); } }; diff --git a/apps/sleeplogalarm/metadata.json b/apps/sleeplogalarm/metadata.json index fc1d546da..1a37ffcbf 100644 --- a/apps/sleeplogalarm/metadata.json +++ b/apps/sleeplogalarm/metadata.json @@ -2,7 +2,7 @@ "id":"sleeplogalarm", "name":"Sleep Log Alarm", "shortName": "SleepLogAlarm", - "version": "0.01", + "version": "0.02", "description": "Enhance your morning and let your alarms wake you up when you are in light sleep.", "icon": "app.png", "type": "widget", diff --git a/apps/sleeplogalarm/settings.js b/apps/sleeplogalarm/settings.js index fe774c3b2..3a37b7274 100644 --- a/apps/sleeplogalarm/settings.js +++ b/apps/sleeplogalarm/settings.js @@ -30,12 +30,12 @@ "": { title: "Filter Alarm" }, - /*LANG*/"< Back": () => showMain(2), + /*LANG*/"< Back": () => showMain(8), /*LANG*/"time from": { value: settings.filter_from, step: 0.25, min: 0, - max: 23, + max: 24, wrap: true, noList: true, format: v => (0|v) + ":" + ("" + (0|(v%1 * 60))).padStart(2, "0"), @@ -47,7 +47,7 @@ /*LANG*/"time to": { value: settings.filter_to, step: 0.25, - min: 1, + min: 0, max: 24, wrap: true, noList: true, @@ -78,7 +78,7 @@ "": { title: "Widget Settings" }, - /*LANG*/"< Back": () => showMain(8), + /*LANG*/"< Back": () => showMain(9), /*LANG*/"hide": { value: settings.wid_hide, onchange: v => { @@ -130,7 +130,13 @@ writeSetting(); } }, - /*LANG*/"Filter Alarm": () => showFilterMenu(), + /*LANG*/"from Consec.": { + value: settings.fromConsec, + onchange: v => { + settings.fromConsec = v; + writeSetting(); + } + }, /*LANG*/"vib pattern": require("buzz_menu").pattern( settings.vibrate, v => { @@ -165,6 +171,7 @@ writeSetting(); } }, + /*LANG*/"Filter Alarm": () => showFilterMenu(), /*LANG*/"Widget": () => showWidMenu(), /*LANG*/"Enabled": { value: settings.enabled, From 7ef5152c17492acdcae407e5b9b1377e0e6a06d9 Mon Sep 17 00:00:00 2001 From: storm64 Date: Fri, 18 Nov 2022 23:31:10 +0100 Subject: [PATCH 024/110] [sleeplogalarm] Clear ToDo-list --- apps/sleeplogalarm/README.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/apps/sleeplogalarm/README.md b/apps/sleeplogalarm/README.md index 184eb4b53..73847d6f1 100644 --- a/apps/sleeplogalarm/README.md +++ b/apps/sleeplogalarm/README.md @@ -42,9 +42,6 @@ This widget searches for active alarms and raises an own alarm event up to the d ### Worth Mentioning --- -#### To do list -- README.md - #### Requests, Bugs and Feedback Please leave requests and bug reports by raising an issue at [github.com/storm64/BangleApps](https://github.com/storm64/BangleApps) (or send me a [mail](mailto:banglejs@storm64.de)). From ad7161cc93ddfe668d71a5045b240017b0402791 Mon Sep 17 00:00:00 2001 From: storm64 Date: Wed, 23 Nov 2022 18:11:42 +0100 Subject: [PATCH 025/110] [sleeplogalarm] Correct filter for last alarm --- apps/sleeplogalarm/ChangeLog | 3 ++- apps/sleeplogalarm/lib.js | 14 +++++++------- apps/sleeplogalarm/metadata.json | 2 +- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/apps/sleeplogalarm/ChangeLog b/apps/sleeplogalarm/ChangeLog index 0030c8783..48d9a161d 100644 --- a/apps/sleeplogalarm/ChangeLog +++ b/apps/sleeplogalarm/ChangeLog @@ -1,2 +1,3 @@ 0.01: New App! -0.02: Add "from Consec."-setting \ No newline at end of file +0.02: Add "from Consec."-setting +0.03: Correct how to ignore last triggered alarm \ No newline at end of file diff --git a/apps/sleeplogalarm/lib.js b/apps/sleeplogalarm/lib.js index 71210f98b..aaa97feed 100644 --- a/apps/sleeplogalarm/lib.js +++ b/apps/sleeplogalarm/lib.js @@ -8,13 +8,13 @@ function getNextAlarm(allAlarms, fo, withId) { return a; }); // return next active alarms in range, filter for - // active, not timer, not own alarm, - // after from, before to, includes msg - // not lastTime, not lastDay + // active && not timer && not own alarm && + // after from && before to && includes msg && + // lastDate not today || after lastTime return allAlarms.filter( a => a.on && !a.timer && a.id !== "sleeplog" && a.t >= fo.from && a.t < fo.to && (!fo.msg || a.msg.includes(fo.msg)) && - fo.lastTime !== a.t && fo.lastDay !== a.last + fo.lastDate !== new Date().getDate() || a.t > fo.lastTime ).map(a => { // add time to alarm a.tTo = sched.getTimeToAlarm(a); return a; @@ -58,7 +58,7 @@ exports = { to: settings.filter_to * 36E5, msg: settings.filter_msg, lastTime: settings.lastTime, - lastDay: settings.lastDay + lastDate: settings.lastDate }).t; // abort if no alarm time could be found inside range @@ -95,7 +95,7 @@ exports = { to: settings.filter_to * 36E5, msg: settings.filter_msg, lastTime: settings.lastTime, - lastDay: settings.lastDay + lastDate: settings.lastDate }, settings.disableOnAlarm); // return if no alarm is found @@ -133,7 +133,7 @@ exports = { // save time of alarm and this day to prevent triggering for the same alarm again settings.lastTime = alarm.t; - settings.lastDay = now.getDay(); + settings.lastDate = now.getDay(); require("Storage").writeJSON("sleeplogalarm.settings.json", settings); // write changes diff --git a/apps/sleeplogalarm/metadata.json b/apps/sleeplogalarm/metadata.json index 1a37ffcbf..813f0fe18 100644 --- a/apps/sleeplogalarm/metadata.json +++ b/apps/sleeplogalarm/metadata.json @@ -2,7 +2,7 @@ "id":"sleeplogalarm", "name":"Sleep Log Alarm", "shortName": "SleepLogAlarm", - "version": "0.02", + "version": "0.03", "description": "Enhance your morning and let your alarms wake you up when you are in light sleep.", "icon": "app.png", "type": "widget", From ec37f35622e595906d333be184ae7fb8072eca06 Mon Sep 17 00:00:00 2001 From: storm64 Date: Thu, 24 Nov 2022 13:29:52 +0100 Subject: [PATCH 026/110] [sleeplogalarm] Replace getDay with getDate --- apps/sleeplogalarm/lib.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/sleeplogalarm/lib.js b/apps/sleeplogalarm/lib.js index aaa97feed..3162c3f86 100644 --- a/apps/sleeplogalarm/lib.js +++ b/apps/sleeplogalarm/lib.js @@ -18,7 +18,7 @@ function getNextAlarm(allAlarms, fo, withId) { ).map(a => { // add time to alarm a.tTo = sched.getTimeToAlarm(a); return a; - }).filter(a => a.tTo // filter non active alarms + }).filter(a => a.tTo // filter non active alarms // sort to get next alarm first ).sort((a, b) => a.tTo - b.tTo)[0] || {}; } @@ -133,7 +133,7 @@ exports = { // save time of alarm and this day to prevent triggering for the same alarm again settings.lastTime = alarm.t; - settings.lastDate = now.getDay(); + settings.lastDate = now.getDate(); require("Storage").writeJSON("sleeplogalarm.settings.json", settings); // write changes From 3a45f155744e1a1887791073831ec3dbe33c88ba Mon Sep 17 00:00:00 2001 From: Hugh Barney Date: Sun, 27 Nov 2022 19:03:15 +0000 Subject: [PATCH 027/110] primtime lato, added debug feature --- apps/primetimelato/ChangeLog | 1 + apps/primetimelato/app.js | 28 ++++++++++++++++++++++++++-- apps/primetimelato/metadata.json | 4 ++-- apps/primetimelato/settings.js | 13 ++++++++++++- 4 files changed, 41 insertions(+), 5 deletions(-) diff --git a/apps/primetimelato/ChangeLog b/apps/primetimelato/ChangeLog index 46690e360..1be18255b 100644 --- a/apps/primetimelato/ChangeLog +++ b/apps/primetimelato/ChangeLog @@ -1,2 +1,3 @@ 0.01: first release 0.02: added option to buzz on prime, with settings +0.03: added option to debug settings and test fw 2.15.93 load speed ups diff --git a/apps/primetimelato/app.js b/apps/primetimelato/app.js index 817da7cda..b4b9d5bb9 100644 --- a/apps/primetimelato/app.js +++ b/apps/primetimelato/app.js @@ -2,7 +2,8 @@ const h = g.getHeight(); const w = g.getWidth(); const SETTINGS_FILE = "primetimelato.json"; let settings; - +let setStr = 'U'; + Graphics.prototype.setFontLato = function(scale) { // Actual height 41 (43 - 3) this.setFontCustom( @@ -28,6 +29,22 @@ Graphics.prototype.setFontLatoSmall = function(scale) { function loadSettings() { settings = require("Storage").readJSON(SETTINGS_FILE,1)||{}; settings.buzz_on_prime = (settings.buzz_on_prime === undefined ? false : settings.buzz_on_prime); + settings.debug = (settings.debug === undefined ? false : settings.debug); + + switch(settings.buzz_on_prime) { + case true: + setStr = 'T'; + break; + + case false: + setStr = 'F'; + break; + + case undefined: + default: + setStr = 'U'; + break; + } } // creates a list of prime factors of n and outputs them as a string, if n is prime outputs "Prime Time!" @@ -69,9 +86,16 @@ function draw() { g.setColor(0,0,0); g.fillRect(Bangle.appRect); + g.setColor(100,100,100); + + if (settings.debug) { + g.setFontLatoSmall(); + g.setFontAlign(0, 0); + g.drawString(setStr, w/2, h/4); + } + g.setFontLato(); g.setFontAlign(0, 0); - g.setColor(100,100,100); g.drawString(timeStr, w/2, h/2); g.setFontLatoSmall(); diff --git a/apps/primetimelato/metadata.json b/apps/primetimelato/metadata.json index 6b292c380..dd200e5d3 100644 --- a/apps/primetimelato/metadata.json +++ b/apps/primetimelato/metadata.json @@ -1,6 +1,6 @@ { "id": "primetimelato", - "name": "Prime Time Lato Clock", - "version": "0.02", + "name": "Prime Time Lato", + "version": "0.03", "type": "clock", "description": "A clock that tells you the primes of the time in the Lato font", "icon": "app.png", diff --git a/apps/primetimelato/settings.js b/apps/primetimelato/settings.js index 5550055eb..069c976c8 100644 --- a/apps/primetimelato/settings.js +++ b/apps/primetimelato/settings.js @@ -3,7 +3,8 @@ // initialize with default settings... let s = { - 'buzz_on_prime': true + 'buzz_on_prime': true, + 'debug': false } // ...and overwrite them with any saved values @@ -29,6 +30,16 @@ s.buzz_on_prime = v; save(); }, + }, + + 'Debug': { + value: !!s.debug, + onchange: v => { + s.debug = v; + save(); + }, } + + }) }) From beab5405c73af3d8bfb91b7b8293f34ff7d6d19e Mon Sep 17 00:00:00 2001 From: storm64 Date: Mon, 28 Nov 2022 00:08:21 +0100 Subject: [PATCH 028/110] [sleeplogalarm] Correct filtering improve settings --- apps/sleeplogalarm/ChangeLog | 3 +- apps/sleeplogalarm/README.md | 3 +- apps/sleeplogalarm/lib.js | 64 +++++++++++++++----------------- apps/sleeplogalarm/metadata.json | 2 +- apps/sleeplogalarm/settings.js | 63 ++++++++++++++++--------------- apps/sleeplogalarm/widget.js | 4 +- 6 files changed, 69 insertions(+), 70 deletions(-) diff --git a/apps/sleeplogalarm/ChangeLog b/apps/sleeplogalarm/ChangeLog index 48d9a161d..80f8bd7e4 100644 --- a/apps/sleeplogalarm/ChangeLog +++ b/apps/sleeplogalarm/ChangeLog @@ -1,3 +1,4 @@ 0.01: New App! 0.02: Add "from Consec."-setting -0.03: Correct how to ignore last triggered alarm \ No newline at end of file +0.03: Correct how to ignore last triggered alarm +0.04: Make "disable alarm" possible on next day; correct alarm filtering; improve settings \ No newline at end of file diff --git a/apps/sleeplogalarm/README.md b/apps/sleeplogalarm/README.md index 73847d6f1..29520dd09 100644 --- a/apps/sleeplogalarm/README.md +++ b/apps/sleeplogalarm/README.md @@ -17,8 +17,7 @@ This widget searches for active alarms and raises an own alarm event up to the d - __msg as prefix__ | use the customized message as prefix to the original message or replace it comlpetely if disabled __on__ / _off_ - __disable alarm__ | if enabled the original alarm will be disabled - _on_ / __off__ - This feature does not work for alarms on the next day! + _on_ / __off__ - __auto snooze__ | auto snooze option for the earlier alarm __on__ / _off_ - __Filter Alarm__ submenu diff --git a/apps/sleeplogalarm/lib.js b/apps/sleeplogalarm/lib.js index 3162c3f86..343e811af 100644 --- a/apps/sleeplogalarm/lib.js +++ b/apps/sleeplogalarm/lib.js @@ -9,18 +9,23 @@ function getNextAlarm(allAlarms, fo, withId) { }); // return next active alarms in range, filter for // active && not timer && not own alarm && - // after from && before to && includes msg && - // lastDate not today || after lastTime - return allAlarms.filter( + // after from && before to && includes msg + var ret = allAlarms.filter( a => a.on && !a.timer && a.id !== "sleeplog" && - a.t >= fo.from && a.t < fo.to && (!fo.msg || a.msg.includes(fo.msg)) && - fo.lastDate !== new Date().getDate() || a.t > fo.lastTime + a.t >= fo.from && a.t < fo.to && (!fo.msg || a.msg.includes(fo.msg)) ).map(a => { // add time to alarm a.tTo = sched.getTimeToAlarm(a); return a; }).filter(a => a.tTo // filter non active alarms // sort to get next alarm first - ).sort((a, b) => a.tTo - b.tTo)[0] || {}; + ).sort((a, b) => a.tTo - b.tTo); + // prevent triggering for an already triggered alarm again if available + if (fo.lastDate) { + var toLast = fo.lastDate - new Date().valueOf() + 1000; + if (toLast > 0) ret = ret.filter(a => a.tTo > toLast); + } + // return first entry + return ret[0] || {}; } exports = { @@ -35,12 +40,16 @@ exports = { msgAsPrefix: true, disableOnAlarm: false, // !!! not available if alarm is at the next day as: true, - filter_from: 3, - filter_to: 12, - filter_msg: "", - wid_hide: false, - wid_time: true, - wid_color: g.theme.dark ? 65504 : 31, // yellow or blue + filter: { + from: 3 * 36E5, + to: 12 * 36E5, + msg: "" + }, + wid: { + hide: false, + time: true, + color: g.theme.dark ? 65504 : 31 // yellow or blue + } }, require("Storage").readJSON("sleeplogalarm.settings.json", true) || {}); }, @@ -53,13 +62,7 @@ exports = { var settings = exports.getSettings(); // set the alarm time - this.time = getNextAlarm(sched.getAlarms(), { - from: settings.filter_from * 36E5, - to: settings.filter_to * 36E5, - msg: settings.filter_msg, - lastTime: settings.lastTime, - lastDate: settings.lastDate - }).t; + this.time = getNextAlarm(sched.getAlarms(), settings.filter).t; // abort if no alarm time could be found inside range if (!this.time) return; @@ -90,13 +93,7 @@ exports = { var allAlarms = sched.getAlarms(); // find first active alarm - var alarm = getNextAlarm(sched.getAlarms(), { - from: settings.filter_from * 36E5, - to: settings.filter_to * 36E5, - msg: settings.filter_msg, - lastTime: settings.lastTime, - lastDate: settings.lastDate - }, settings.disableOnAlarm); + var alarm = getNextAlarm(sched.getAlarms(), settings.filter, settings.disableOnAlarm); // return if no alarm is found if (!alarm) return; @@ -105,12 +102,12 @@ exports = { var now = new Date(); // get date of the alarm - var aDate = new Date(now + alarm.tTo).getDate(); + var aDate = new Date(now + alarm.tTo); - // disable earlier triggered alarm if set and on the same day - if (settings.disableOnAlarm && now.getDate() === aDate) { - // set alarms last to today - allAlarms[alarm.idx].last = aDate; + // disable earlier triggered alarm if set + if (settings.disableOnAlarm) { + // set alarms last to the day it would trigger + allAlarms[alarm.idx].last = aDate.getDate(); // remove added indexes allAlarms = allAlarms.map(a => { delete a.idx; @@ -131,9 +128,8 @@ exports = { del: true }); - // save time of alarm and this day to prevent triggering for the same alarm again - settings.lastTime = alarm.t; - settings.lastDate = now.getDate(); + // save date of the alarm to prevent triggering for the same alarm again + settings.filter.lastDate = aDate.valueOf(); require("Storage").writeJSON("sleeplogalarm.settings.json", settings); // write changes diff --git a/apps/sleeplogalarm/metadata.json b/apps/sleeplogalarm/metadata.json index 813f0fe18..1930a0ee3 100644 --- a/apps/sleeplogalarm/metadata.json +++ b/apps/sleeplogalarm/metadata.json @@ -2,7 +2,7 @@ "id":"sleeplogalarm", "name":"Sleep Log Alarm", "shortName": "SleepLogAlarm", - "version": "0.03", + "version": "0.04", "description": "Enhance your morning and let your alarms wake you up when you are in light sleep.", "icon": "app.png", "type": "widget", diff --git a/apps/sleeplogalarm/settings.js b/apps/sleeplogalarm/settings.js index 3a37b7274..1f3a13272 100644 --- a/apps/sleeplogalarm/settings.js +++ b/apps/sleeplogalarm/settings.js @@ -8,19 +8,16 @@ } // read input from keyboard - function readInput(setting, retPos, cb) { - setTimeout((setting, retPos, cb) => { + function readInput(v, cb) { + // setTimeout required to load after menu refresh + setTimeout((v, cb) => { if (require("Storage").read("textinput")) { g.clear(); - require("textinput").input({text: settings[setting]}).then(result => { - settings[setting] = result; - writeSetting(); - cb(retPos); - }); + require("textinput").input({text: v}).then(v => cb(v)); } else { - E.showAlert(/*LANG*/"No keyboard app installed").then(() => cb(retPos)); + E.showAlert(/*LANG*/"No keyboard app installed").then(() => cb()); } - }, 0, setting, retPos, cb); + }, 0, v, cb); } // show widget menu @@ -32,36 +29,39 @@ }, /*LANG*/"< Back": () => showMain(8), /*LANG*/"time from": { - value: settings.filter_from, - step: 0.25, + value: settings.filter.from / 6E4, + step: 10, min: 0, - max: 24, + max: 1440, wrap: true, noList: true, - format: v => (0|v) + ":" + ("" + (0|(v%1 * 60))).padStart(2, "0"), + format: v => (0|v/60) + ":" + ("" + (v%60)).padStart(2, "0"), onchange: v => { - settings.filter_from = v; + settings.filter.from = v * 6E4; writeSetting(); } }, /*LANG*/"time to": { - value: settings.filter_to, - step: 0.25, + value: settings.filter.to / 6E4, + step: 10, min: 0, - max: 24, + max: 1440, wrap: true, noList: true, - format: v => (0|v) + ":" + ("" + (0|(v%1 * 60))).padStart(2, "0"), + format: v => (0|v/60) + ":" + ("" + (v%60)).padStart(2, "0"), onchange: v => { - settings.filter_to = v; + settings.filter.to = v * 6E4; writeSetting(); } }, /*LANG*/"msg includes": { - value: settings.filter_msg, + value: settings.filter.msg, format: v => !v ? "" : v.length > 6 ? v.substring(0, 6)+"..." : v, - // setTimeout required to load after menu refresh - onchange: () => readInput("filter_msg", 3, showFilterMenu) + onchange: v => readInput(v, v => { + settings.filter.msg = v; + writeSetting(); + showFilterMenu(3); + }) } }; var menu = E.showMenu(filterMenu); @@ -80,27 +80,27 @@ }, /*LANG*/"< Back": () => showMain(9), /*LANG*/"hide": { - value: settings.wid_hide, + value: settings.wid.hide, onchange: v => { - settings.wid_hide = v; + settings.wid.hide = v; writeSetting(); } }, /*LANG*/"show time": { - value: settings.wid_time, + value: settings.wid.time, onchange: v => { - settings.wid_time = v; + settings.wid.time = v; writeSetting(); } }, /*LANG*/"color": { - value: colVal.indexOf(settings.wid_color), + value: colVal.indexOf(settings.wid.color), min: 0, max: colVal.length -1, wrap: true, format: v => colName[v], onchange: v => { - settings.wid_color = colVal[v]; + settings.wid.color = colVal[v]; writeSetting(); } } @@ -147,8 +147,11 @@ /*LANG*/"msg": { value: settings.msg, format: v => !v ? "" : v.length > 6 ? v.substring(0, 6)+"..." : v, - // setTimeout required to load after menu refresh - onchange: () => readInput("msg", 4, showMain) + onchange: v => readInput(v, v => { + settings.msg = v; + writeSetting(); + showMenu(4); + }) }, /*LANG*/"msg as prefix": { value: settings.msgAsPrefix, diff --git a/apps/sleeplogalarm/widget.js b/apps/sleeplogalarm/widget.js index 991238140..e3171751f 100644 --- a/apps/sleeplogalarm/widget.js +++ b/apps/sleeplogalarm/widget.js @@ -11,7 +11,7 @@ if ((require("Storage").readJSON("sleeplogalarm.settings.json", true) || {enable earlier: settings.earlier, draw: function () { // draw zzz - g.reset().setColor(settings.wid_color).drawImage(atob("BwoBD8SSSP4EEEDg"), this.x + 1, this.y); + g.reset().setColor(settings.wid.color).drawImage(atob("BwoBD8SSSP4EEEDg"), this.x + 1, this.y); // call function to draw the time of alarm if a alarm is found if (this.time) this.drawTime(this.time + 1); }, @@ -20,7 +20,7 @@ if ((require("Storage").readJSON("sleeplogalarm.settings.json", true) || {enable }; // add function to draw the time of alarm if enabled - if (settings.wid_time) WIDGETS.sleeplogalarm.drawTime = function(time) { + if (settings.wid.time) WIDGETS.sleeplogalarm.drawTime = function(time) { // directly include Font4x5Numeric g.setFontCustom(atob("CAZMA/H4PgvXoK1+DhPg7W4P1uCEPg/X4O1+AA=="), 46, atob("AgQEAgQEBAQEBAQE"), 5).setFontAlign(1, 1); g.drawString(0|(time / 36E5), this.x + this.width + 1, this.y + 17); From 4283fa2d9d16b3d59625517431d29ea3de72b8b5 Mon Sep 17 00:00:00 2001 From: storm64 Date: Mon, 28 Nov 2022 21:54:21 +0100 Subject: [PATCH 029/110] [sleeplogalarm] Add dependency in README --- apps/sleeplogalarm/README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/sleeplogalarm/README.md b/apps/sleeplogalarm/README.md index 29520dd09..09a30b7eb 100644 --- a/apps/sleeplogalarm/README.md +++ b/apps/sleeplogalarm/README.md @@ -1,6 +1,8 @@ # Sleep Log Alarm -This widget searches for active alarms and raises an own alarm event up to the defined time earlier, if in light sleep or awake phase. Optional the earlier alarm will only be triggered if comming from or in consecutive sleep. The settings of the earlier alarm can be adjusted and it is possible to filter the targeting alarms by time and message. By default the time of the targeting alarm is displayed inside the widget which can be adjusted, too. +This widget searches for active alarms and raises an own alarm event up to the defined time earlier, if in light sleep or awake phase. Optional the earlier alarm will only be triggered if comming from or in consecutive sleep. The settings of the earlier alarm can be adjusted and it is possible to filter the targeting alarms by time and message. By default the time of the targeting alarm is displayed inside the widget which can be adjusted, too. + +_This widget does not detect sleep by its own and requires the [sleeplog](/apps/?id=sleeplog) app to be installed._ --- ### Settings From 59c745a743512ed1b4bb16a3d62142f38610c17e Mon Sep 17 00:00:00 2001 From: storm64 Date: Wed, 30 Nov 2022 22:05:38 +0100 Subject: [PATCH 030/110] [sleeplogalarm] Add sched dependency --- apps/sleeplogalarm/README.md | 2 +- apps/sleeplogalarm/metadata.json | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/apps/sleeplogalarm/README.md b/apps/sleeplogalarm/README.md index 09a30b7eb..005377fb1 100644 --- a/apps/sleeplogalarm/README.md +++ b/apps/sleeplogalarm/README.md @@ -2,7 +2,7 @@ This widget searches for active alarms and raises an own alarm event up to the defined time earlier, if in light sleep or awake phase. Optional the earlier alarm will only be triggered if comming from or in consecutive sleep. The settings of the earlier alarm can be adjusted and it is possible to filter the targeting alarms by time and message. By default the time of the targeting alarm is displayed inside the widget which can be adjusted, too. -_This widget does not detect sleep by its own and requires the [sleeplog](/apps/?id=sleeplog) app to be installed._ +_This widget does not detect sleep on its own and can not create alarms. It requires the [sleeplog](/apps/?id=sleeplog) app and any alarm app that uses [sched](/apps/?id=sched) to be installed._ --- ### Settings diff --git a/apps/sleeplogalarm/metadata.json b/apps/sleeplogalarm/metadata.json index 1930a0ee3..235c1ecc1 100644 --- a/apps/sleeplogalarm/metadata.json +++ b/apps/sleeplogalarm/metadata.json @@ -8,7 +8,10 @@ "type": "widget", "tags": "tool,widget", "supports": ["BANGLEJS2"], - "dependencies": {"sleeplog": "app"}, + "dependencies": [ + {"scheduler": "type"}, + {"sleeplog": "app"} + ], "readme": "README.md", "storage": [ {"name": "sleeplogalarm", "url": "lib.js"}, From 439ecd703d5207b0f01d22f1c198b795328419ee Mon Sep 17 00:00:00 2001 From: storm64 Date: Wed, 30 Nov 2022 22:31:55 +0100 Subject: [PATCH 031/110] [sleeplogalarm] Correct dependencies in metadata --- apps/sleeplogalarm/metadata.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/sleeplogalarm/metadata.json b/apps/sleeplogalarm/metadata.json index 235c1ecc1..fd85507e6 100644 --- a/apps/sleeplogalarm/metadata.json +++ b/apps/sleeplogalarm/metadata.json @@ -8,10 +8,10 @@ "type": "widget", "tags": "tool,widget", "supports": ["BANGLEJS2"], - "dependencies": [ - {"scheduler": "type"}, - {"sleeplog": "app"} - ], + "dependencies": { + "scheduler": "type", + "sleeplog": "app" + }, "readme": "README.md", "storage": [ {"name": "sleeplogalarm", "url": "lib.js"}, From 6b6dc4b14e861e53aef4b3f40f846301ff0c4f9f Mon Sep 17 00:00:00 2001 From: Martin Boonk Date: Thu, 17 Nov 2022 18:17:37 +0100 Subject: [PATCH 032/110] bthrm - Show internal values if replacing HRM --- apps/bthrm/bthrm.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/apps/bthrm/bthrm.js b/apps/bthrm/bthrm.js index fadf2a5d8..84fce927c 100644 --- a/apps/bthrm/bthrm.js +++ b/apps/bthrm/bthrm.js @@ -91,7 +91,12 @@ function onHrm(e) { var settings = require('Storage').readJSON("bthrm.json", true) || {}; Bangle.on('BTHRM', onBtHrm); -Bangle.on('HRM', onHrm); + +if (settings.replace){ + Bangle.on('HRM_int', onHrm); +} else { + Bangle.on('HRM', onHrm); +} Bangle.setHRMPower(1,'bthrm'); if (!(settings.startWithHrm)){ From 1530ed39154de83e0e64e2fee49bd255f300f74e Mon Sep 17 00:00:00 2001 From: Martin Boonk Date: Thu, 1 Dec 2022 22:49:02 +0100 Subject: [PATCH 033/110] bthrm - Reimplement viewer app with layout --- apps/bthrm/bthrm.js | 191 ++++++++++++++++++++++++++++++++------------ 1 file changed, 139 insertions(+), 52 deletions(-) diff --git a/apps/bthrm/bthrm.js b/apps/bthrm/bthrm.js index 84fce927c..05bf323a5 100644 --- a/apps/bthrm/bthrm.js +++ b/apps/bthrm/bthrm.js @@ -1,5 +1,9 @@ var intervalInt; var intervalBt; +var intervalAgg; + +const BPM_FONT_SIZE="19%"; +const VALUE_TIMEOUT=3000; var BODY_LOCS = { 0: 'Other', @@ -7,40 +11,123 @@ var BODY_LOCS = { 2: 'Wrist', 3: 'Finger', 4: 'Hand', - 5: 'Ear Lobe', + 5: 'Earlobe', 6: 'Foot', +}; + +var Layout = require("Layout"); + +function border(l,c) { + g.setColor(c).drawLine(l.x+l.w*0.05, l.y-4, l.x+l.w*0.95, l.y-4); + c++; } -function clear(y){ - g.reset(); - g.clearRect(0,y,g.getWidth(),y+75); -} - -function draw(y, type, event) { - clear(y); - var px = g.getWidth()/2; - var str = event.bpm + ""; - g.reset(); - g.setFontAlign(0,0); - g.setFontVector(40).drawString(str,px,y+20); - str = "Event: " + type; - if (type === "HRM") { - str += " Confidence: " + event.confidence; - g.setFontVector(12).drawString(str,px,y+40); - str = " Source: " + (event.src ? event.src : "internal"); - g.setFontVector(12).drawString(str,px,y+50); +function getRow(id, text, additionalInfo){ + let additional = []; + let l = { + type:"h", c: [ + { + type:"v", + width: g.getWidth()*0.4, + c: [ + {type:"txt", halign:1, font:"8%", label:text, id:id+"text" }, + {type:"txt", halign:1, font:BPM_FONT_SIZE, label:"--", id:id, bgCol: g.theme.bg } + ] + },{ + type:undefined, fillx:1 + },{ + type:"v", + valign: -1, + width: g.getWidth()*0.45, + c: additional + },{ + type:undefined, width:g.getWidth()*0.05 + } + ] + }; + for (let i of additionalInfo){ + let label = {type:"txt", font:"6x8", label:i + ":" }; + let value = {type:"txt", font:"6x8", label:"--", id:id + i }; + additional.push({type:"h", halign:-1, c:[ label, {type:undefined, fillx:1}, value ]}); } - if (type === "BTHRM"){ - if (event.battery) str += " Bat: " + (event.battery ? event.battery : ""); - g.setFontVector(12).drawString(str,px,y+40); - str= ""; - if (event.location) str += "Loc: " + BODY_LOCS[event.location]; - if (event.rr && event.rr.length > 0) str += " RR: " + event.rr.join(","); - g.setFontVector(12).drawString(str,px,y+50); - str= ""; - if (event.contact) str += " Contact: " + event.contact; - if (event.energy) str += " kJoule: " + event.energy.toFixed(0); - g.setFontVector(12).drawString(str,px,y+60); + + return l; +} + +var layout = new Layout( { + type:"v", c: [ + getRow("int", "INT", ["Confidence"]), + getRow("agg", "HRM", ["Confidence", "Source"]), + getRow("bt", "BT", ["Battery","Location","Contact", "RR", "Energy"]), + { type:undefined, height:8 } //dummy to protect debug output + ] +}, { + lazy:true +}); + +var int,agg,bt; +var firstEvent = true; + +var drawTimeout; +function draw(){ + + if (drawTimeout) clearTimeout(drawTimeout); + drawTimeout = setTimeout(function() { + drawTimeout = undefined; + draw(); + }, 1000); + + if (!(int || agg || bt)) return; + + if (firstEvent) { + g.clearRect(Bangle.appRect); + firstEvent = false; + } + + if (int){ + layout.int.label = int.bpm; + if (!isNaN(int.confidence)) layout.intConfidence.label = int.confidence; + } else { + layout.int.label = "--"; + layout.intConfidence.label = "--"; + } + + if (agg){ + layout.agg.label = agg.bpm; + if (!isNaN(agg.confidence)) layout.aggConfidence.label = agg.confidence; + if (agg.src) layout.aggSource.label = agg.src; + } else { + layout.agg.label = "--"; + layout.aggConfidence.label = "--"; + layout.aggSource.label = "--"; + } + + if (bt) { + layout.bt.label = bt.bpm; + if (bt.battery) layout.btBattery.label = bt.battery; + if (bt.rr) layout.btRR.label = bt.rr.join(","); + if (bt.location) layout.btLocation.label = BODY_LOCS[bt.location]; + if (bt.contact !== undefined) layout.btContact.label = bt.contact ? "Yes":"No"; + if (bt.energy) layout.btEnergy.label = bt.energy.toFixed(0) + "kJ"; + } else { + layout.bt.label = "--"; + layout.btBattery.label = "--"; + layout.btRR.label = "--"; + layout.btLocation.label = "--"; + layout.btContact.label = "--"; + layout.btEnergy.label = "--"; + } + + layout.update(); + layout.render(); + let first = true; + for (let c of layout.l.c){ + if (first) { + first = false; + continue; + } + if (c.type && c.type == "h") + border(c,g.theme.fg); } } @@ -57,11 +144,7 @@ function showStatusInfo(txt) { } function onBtHrm(e) { - if (firstEventBt){ - clear(24); - firstEventBt = false; - } - draw(100, "BTHRM", e); + bt = e; if (e.bpm === 0){ Bangle.buzz(100,0.2); } @@ -69,34 +152,37 @@ function onBtHrm(e) { clearInterval(intervalBt); } intervalBt = setInterval(()=>{ - clear(100); - }, 2000); + bt = undefined; + }, VALUE_TIMEOUT); } -function onHrm(e) { - if (firstEventInt){ - clear(24); - firstEventInt = false; - } - draw(24, "HRM", e); +function onInt(e) { + int = e; if (intervalInt){ clearInterval(intervalInt); } intervalInt = setInterval(()=>{ - clear(24); - }, 2000); + int = undefined; + }, VALUE_TIMEOUT); +} + +function onAgg(e) { + agg = e; + if (intervalAgg){ + clearInterval(intervalAgg); + } + intervalAgg = setInterval(()=>{ + agg = undefined; + }, VALUE_TIMEOUT); } var settings = require('Storage').readJSON("bthrm.json", true) || {}; Bangle.on('BTHRM', onBtHrm); +Bangle.on('HRM_int', onInt); +Bangle.on('HRM', onAgg); -if (settings.replace){ - Bangle.on('HRM_int', onHrm); -} else { - Bangle.on('HRM', onHrm); -} Bangle.setHRMPower(1,'bthrm'); if (!(settings.startWithHrm)){ @@ -108,10 +194,11 @@ Bangle.loadWidgets(); Bangle.drawWidgets(); if (Bangle.setBTHRMPower){ g.reset().setFont("6x8",2).setFontAlign(0,0); - g.drawString("Please wait...",g.getWidth()/2,g.getHeight()/2 - 24); + g.drawString("Please wait...",g.getWidth()/2,g.getHeight()/2); + draw(); } else { g.reset().setFont("6x8",2).setFontAlign(0,0); - g.drawString("BTHRM disabled",g.getWidth()/2,g.getHeight()/2 + 32); + g.drawString("BTHRM disabled",g.getWidth()/2,g.getHeight()/2); } E.on('kill', ()=>Bangle.setBTHRMPower(0,'bthrm')); From 48815b249eb197d4b957d8709cee1edec710d320 Mon Sep 17 00:00:00 2001 From: Erik Andresen Date: Fri, 2 Dec 2022 19:38:51 +0100 Subject: [PATCH 034/110] kbswipe: Support input of numbers To switch between the input of alphabetic and numeric characters tap the widget which displays either "123" or "ABC" closes #1820 --- apps/kbswipe/ChangeLog | 1 + apps/kbswipe/README.md | 2 + apps/kbswipe/lib.js | 130 ++++++++++++++++++++++++++----------- apps/kbswipe/metadata.json | 2 +- 4 files changed, 96 insertions(+), 39 deletions(-) diff --git a/apps/kbswipe/ChangeLog b/apps/kbswipe/ChangeLog index 1804c4a89..05be810cc 100644 --- a/apps/kbswipe/ChangeLog +++ b/apps/kbswipe/ChangeLog @@ -3,3 +3,4 @@ 0.03: Positioning of marker now takes the height of the widget field into account. 0.04: Fix issue if going back without typing. 0.05: Keep drag-function in ram, hopefully improving performance and input reliability somewhat. +0.06: Support input of numbers diff --git a/apps/kbswipe/README.md b/apps/kbswipe/README.md index 3f5575777..1508061d1 100644 --- a/apps/kbswipe/README.md +++ b/apps/kbswipe/README.md @@ -4,6 +4,8 @@ A library that provides the ability to input text by swiping PalmOS Graffiti-sty To get a legend of available characters, just tap the screen. +To switch between the input of alphabetic and numeric characters tap the widget which displays either "123" or "ABC". + ![](key.png) ## Usage diff --git a/apps/kbswipe/lib.js b/apps/kbswipe/lib.js index fe5f7e977..861d046cb 100644 --- a/apps/kbswipe/lib.js +++ b/apps/kbswipe/lib.js @@ -1,47 +1,67 @@ +const INPUT_MODE_ALPHA = 0; +const INPUT_MODE_NUM = 1; + /* To make your own strokes, type: Bangle.on('stroke',print) on the left of the IDE, then do a stroke and copy out the Uint8Array line */ -exports.getStrokes = function(cb) { - cb("a", new Uint8Array([58, 159, 58, 155, 62, 144, 69, 127, 77, 106, 86, 90, 94, 77, 101, 68, 108, 62, 114, 59, 121, 59, 133, 61, 146, 70, 158, 88, 169, 107, 176, 124, 180, 135, 183, 144, 185, 152])); - cb("b", new Uint8Array([51, 47, 51, 77, 56, 123, 60, 151, 65, 163, 68, 164, 68, 144, 67, 108, 67, 76, 72, 43, 104, 51, 121, 74, 110, 87, 109, 95, 131, 117, 131, 140, 109, 152, 88, 157])); - cb("c", new Uint8Array([153, 62, 150, 62, 145, 62, 136, 62, 123, 62, 106, 65, 85, 70, 65, 75, 50, 82, 42, 93, 37, 106, 36, 119, 36, 130, 40, 140, 49, 147, 61, 153, 72, 156, 85, 157, 106, 158, 116, 158])); - cb("d", new Uint8Array([57, 178, 57, 176, 55, 171, 52, 163, 50, 154, 49, 146, 47, 135, 45, 121, 44, 108, 44, 97, 44, 85, 44, 75, 44, 66, 44, 58, 44, 48, 44, 38, 46, 31, 48, 26, 58, 21, 75, 20, 99, 26, 120, 35, 136, 51, 144, 70, 144, 88, 137, 110, 124, 131, 106, 145, 88, 153])); - cb("e", new Uint8Array([150, 72, 141, 69, 114, 68, 79, 69, 48, 77, 32, 81, 31, 85, 46, 91, 73, 95, 107, 100, 114, 103, 83, 117, 58, 134, 66, 143, 105, 148, 133, 148, 144, 148])); - cb("f", new Uint8Array([157, 52, 155, 52, 148, 52, 137, 52, 124, 52, 110, 52, 96, 52, 83, 52, 74, 52, 67, 52, 61, 52, 57, 52, 55, 52, 52, 52, 52, 54, 52, 58, 52, 64, 54, 75, 58, 97, 59, 117, 60, 130])); - cb("g", new Uint8Array([160, 66, 153, 62, 129, 58, 90, 56, 58, 57, 38, 65, 31, 86, 43, 125, 69, 152, 116, 166, 145, 154, 146, 134, 112, 116, 85, 108, 97, 106, 140, 106, 164, 106])); - cb("h", new Uint8Array([58, 50, 58, 55, 58, 64, 58, 80, 58, 102, 58, 122, 58, 139, 58, 153, 58, 164, 58, 171, 58, 177, 58, 179, 58, 181, 58, 180, 58, 173, 58, 163, 59, 154, 61, 138, 64, 114, 68, 95, 72, 84, 80, 79, 91, 79, 107, 82, 123, 93, 137, 111, 145, 130, 149, 147, 150, 154, 150, 159])); - cb("i", new Uint8Array([89, 48, 89, 49, 89, 51, 89, 55, 89, 60, 89, 68, 89, 78, 89, 91, 89, 103, 89, 114, 89, 124, 89, 132, 89, 138, 89, 144, 89, 148, 89, 151, 89, 154, 89, 156, 89, 157, 89, 158])); - cb("j", new Uint8Array([130, 57, 130, 61, 130, 73, 130, 91, 130, 113, 130, 133, 130, 147, 130, 156, 130, 161, 130, 164, 130, 166, 129, 168, 127, 168, 120, 168, 110, 168, 91, 167, 81, 167, 68, 167])); - cb("k", new Uint8Array([149, 63, 147, 68, 143, 76, 136, 89, 126, 106, 114, 123, 100, 136, 86, 147, 72, 153, 57, 155, 45, 152, 36, 145, 29, 131, 26, 117, 26, 104, 27, 93, 30, 86, 35, 80, 45, 77, 62, 80, 88, 96, 113, 116, 130, 131, 140, 142, 145, 149, 148, 153])); - cb("l", new Uint8Array([42, 55, 42, 59, 42, 69, 44, 87, 44, 107, 44, 128, 44, 143, 44, 156, 44, 163, 44, 167, 44, 169, 45, 170, 49, 170, 59, 169, 76, 167, 100, 164, 119, 162, 139, 160, 163, 159])); - cb("m", new Uint8Array([49, 165, 48, 162, 46, 156, 44, 148, 42, 138, 42, 126, 42, 113, 43, 101, 45, 91, 47, 82, 49, 75, 51, 71, 54, 70, 57, 70, 61, 74, 69, 81, 75, 91, 84, 104, 94, 121, 101, 132, 103, 137, 106, 130, 110, 114, 116, 92, 125, 75, 134, 65, 139, 62, 144, 66, 148, 83, 151, 108, 155, 132, 157, 149])); - cb("n", new Uint8Array([50, 165, 50, 160, 50, 153, 50, 140, 50, 122, 50, 103, 50, 83, 50, 65, 50, 52, 50, 45, 50, 43, 52, 52, 57, 67, 66, 90, 78, 112, 93, 131, 104, 143, 116, 152, 127, 159, 135, 160, 141, 150, 148, 125, 154, 96, 158, 71, 161, 56, 162, 49])); - cb("o", new Uint8Array([107, 58, 104, 58, 97, 61, 87, 68, 75, 77, 65, 88, 58, 103, 54, 116, 53, 126, 55, 135, 61, 143, 75, 149, 91, 150, 106, 148, 119, 141, 137, 125, 143, 115, 146, 104, 146, 89, 142, 78, 130, 70, 116, 65, 104, 62])); - cb("p", new Uint8Array([52, 59, 52, 64, 54, 73, 58, 88, 61, 104, 65, 119, 67, 130, 69, 138, 71, 145, 71, 147, 71, 148, 71, 143, 70, 133, 68, 120, 67, 108, 67, 97, 67, 89, 68, 79, 72, 67, 83, 60, 99, 58, 118, 58, 136, 63, 146, 70, 148, 77, 145, 84, 136, 91, 121, 95, 106, 97, 93, 97, 82, 97])); - cb("q", new Uint8Array([95, 59, 93, 59, 88, 59, 79, 59, 68, 61, 57, 67, 50, 77, 48, 89, 48, 103, 50, 117, 55, 130, 65, 140, 76, 145, 85, 146, 94, 144, 101, 140, 105, 136, 106, 127, 106, 113, 100, 98, 92, 86, 86, 79, 84, 75, 84, 72, 91, 69, 106, 67, 126, 67, 144, 67, 158, 67, 168, 67, 173, 67, 177, 67])); - cb("r", new Uint8Array([53, 49, 53, 62, 53, 91, 53, 127, 53, 146, 53, 147, 53, 128, 53, 94, 53, 69, 62, 44, 82, 42, 94, 50, 92, 68, 82, 85, 77, 93, 80, 102, 95, 119, 114, 134, 129, 145, 137, 150])); - cb("s", new Uint8Array([159, 72, 157, 70, 155, 68, 151, 66, 145, 63, 134, 60, 121, 58, 108, 56, 96, 55, 83, 55, 73, 55, 64, 56, 57, 60, 52, 65, 49, 71, 49, 76, 50, 81, 55, 87, 71, 94, 94, 100, 116, 104, 131, 108, 141, 114, 145, 124, 142, 135, 124, 146, 97, 153, 70, 157, 52, 158])); - cb("t", new Uint8Array([45, 55, 48, 55, 55, 55, 72, 55, 96, 55, 120, 55, 136, 55, 147, 55, 152, 55, 155, 55, 157, 55, 158, 56, 158, 60, 156, 70, 154, 86, 151, 102, 150, 114, 148, 125, 148, 138, 148, 146])); - cb("u", new Uint8Array([35, 52, 35, 59, 35, 73, 35, 90, 36, 114, 38, 133, 42, 146, 49, 153, 60, 157, 73, 158, 86, 156, 100, 152, 112, 144, 121, 131, 127, 114, 132, 97, 134, 85, 135, 73, 136, 61, 136, 56])); - cb("v", new Uint8Array([36, 55, 37, 59, 40, 68, 45, 83, 51, 100, 58, 118, 64, 132, 69, 142, 71, 149, 73, 156, 76, 158, 77, 160, 77, 159, 80, 151, 82, 137, 84, 122, 86, 111, 90, 91, 91, 78, 91, 68, 91, 63, 92, 61, 97, 61, 111, 61, 132, 61, 150, 61, 162, 61])); - cb("w", new Uint8Array([33, 58, 34, 81, 39, 127, 44, 151, 48, 161, 52, 162, 57, 154, 61, 136, 65, 115, 70, 95, 76, 95, 93, 121, 110, 146, 119, 151, 130, 129, 138, 84, 140, 56, 140, 45])); - cb("x", new Uint8Array([56, 63, 56, 67, 57, 74, 60, 89, 66, 109, 74, 129, 85, 145, 96, 158, 107, 164, 117, 167, 128, 164, 141, 155, 151, 140, 159, 122, 166, 105, 168, 89, 170, 81, 170, 73, 169, 66, 161, 63, 141, 68, 110, 83, 77, 110, 55, 134, 47, 145])); - cb("y", new Uint8Array([42, 56, 42, 70, 48, 97, 62, 109, 85, 106, 109, 90, 126, 65, 134, 47, 137, 45, 137, 75, 127, 125, 98, 141, 70, 133, 65, 126, 92, 137, 132, 156, 149, 166])); - cb("z", new Uint8Array([29, 62, 35, 62, 43, 62, 63, 62, 87, 62, 110, 62, 125, 62, 134, 62, 138, 62, 136, 63, 122, 68, 103, 77, 85, 91, 70, 107, 59, 120, 50, 132, 47, 138, 43, 143, 41, 148, 42, 151, 53, 155, 80, 157, 116, 158, 146, 158, 163, 158])); +exports.getStrokes = function(mode, cb) { + if (mode === INPUT_MODE_ALPHA) { + cb("a", new Uint8Array([58, 159, 58, 155, 62, 144, 69, 127, 77, 106, 86, 90, 94, 77, 101, 68, 108, 62, 114, 59, 121, 59, 133, 61, 146, 70, 158, 88, 169, 107, 176, 124, 180, 135, 183, 144, 185, 152])); + cb("b", new Uint8Array([51, 47, 51, 77, 56, 123, 60, 151, 65, 163, 68, 164, 68, 144, 67, 108, 67, 76, 72, 43, 104, 51, 121, 74, 110, 87, 109, 95, 131, 117, 131, 140, 109, 152, 88, 157])); + cb("c", new Uint8Array([153, 62, 150, 62, 145, 62, 136, 62, 123, 62, 106, 65, 85, 70, 65, 75, 50, 82, 42, 93, 37, 106, 36, 119, 36, 130, 40, 140, 49, 147, 61, 153, 72, 156, 85, 157, 106, 158, 116, 158])); + cb("d", new Uint8Array([57, 178, 57, 176, 55, 171, 52, 163, 50, 154, 49, 146, 47, 135, 45, 121, 44, 108, 44, 97, 44, 85, 44, 75, 44, 66, 44, 58, 44, 48, 44, 38, 46, 31, 48, 26, 58, 21, 75, 20, 99, 26, 120, 35, 136, 51, 144, 70, 144, 88, 137, 110, 124, 131, 106, 145, 88, 153])); + cb("e", new Uint8Array([150, 72, 141, 69, 114, 68, 79, 69, 48, 77, 32, 81, 31, 85, 46, 91, 73, 95, 107, 100, 114, 103, 83, 117, 58, 134, 66, 143, 105, 148, 133, 148, 144, 148])); + cb("f", new Uint8Array([157, 52, 155, 52, 148, 52, 137, 52, 124, 52, 110, 52, 96, 52, 83, 52, 74, 52, 67, 52, 61, 52, 57, 52, 55, 52, 52, 52, 52, 54, 52, 58, 52, 64, 54, 75, 58, 97, 59, 117, 60, 130])); + cb("g", new Uint8Array([160, 66, 153, 62, 129, 58, 90, 56, 58, 57, 38, 65, 31, 86, 43, 125, 69, 152, 116, 166, 145, 154, 146, 134, 112, 116, 85, 108, 97, 106, 140, 106, 164, 106])); + cb("h", new Uint8Array([58, 50, 58, 55, 58, 64, 58, 80, 58, 102, 58, 122, 58, 139, 58, 153, 58, 164, 58, 171, 58, 177, 58, 179, 58, 181, 58, 180, 58, 173, 58, 163, 59, 154, 61, 138, 64, 114, 68, 95, 72, 84, 80, 79, 91, 79, 107, 82, 123, 93, 137, 111, 145, 130, 149, 147, 150, 154, 150, 159])); + cb("i", new Uint8Array([89, 48, 89, 49, 89, 51, 89, 55, 89, 60, 89, 68, 89, 78, 89, 91, 89, 103, 89, 114, 89, 124, 89, 132, 89, 138, 89, 144, 89, 148, 89, 151, 89, 154, 89, 156, 89, 157, 89, 158])); + cb("j", new Uint8Array([130, 57, 130, 61, 130, 73, 130, 91, 130, 113, 130, 133, 130, 147, 130, 156, 130, 161, 130, 164, 130, 166, 129, 168, 127, 168, 120, 168, 110, 168, 91, 167, 81, 167, 68, 167])); + cb("k", new Uint8Array([149, 63, 147, 68, 143, 76, 136, 89, 126, 106, 114, 123, 100, 136, 86, 147, 72, 153, 57, 155, 45, 152, 36, 145, 29, 131, 26, 117, 26, 104, 27, 93, 30, 86, 35, 80, 45, 77, 62, 80, 88, 96, 113, 116, 130, 131, 140, 142, 145, 149, 148, 153])); + cb("l", new Uint8Array([42, 55, 42, 59, 42, 69, 44, 87, 44, 107, 44, 128, 44, 143, 44, 156, 44, 163, 44, 167, 44, 169, 45, 170, 49, 170, 59, 169, 76, 167, 100, 164, 119, 162, 139, 160, 163, 159])); + cb("m", new Uint8Array([49, 165, 48, 162, 46, 156, 44, 148, 42, 138, 42, 126, 42, 113, 43, 101, 45, 91, 47, 82, 49, 75, 51, 71, 54, 70, 57, 70, 61, 74, 69, 81, 75, 91, 84, 104, 94, 121, 101, 132, 103, 137, 106, 130, 110, 114, 116, 92, 125, 75, 134, 65, 139, 62, 144, 66, 148, 83, 151, 108, 155, 132, 157, 149])); + cb("n", new Uint8Array([50, 165, 50, 160, 50, 153, 50, 140, 50, 122, 50, 103, 50, 83, 50, 65, 50, 52, 50, 45, 50, 43, 52, 52, 57, 67, 66, 90, 78, 112, 93, 131, 104, 143, 116, 152, 127, 159, 135, 160, 141, 150, 148, 125, 154, 96, 158, 71, 161, 56, 162, 49])); + cb("o", new Uint8Array([107, 58, 104, 58, 97, 61, 87, 68, 75, 77, 65, 88, 58, 103, 54, 116, 53, 126, 55, 135, 61, 143, 75, 149, 91, 150, 106, 148, 119, 141, 137, 125, 143, 115, 146, 104, 146, 89, 142, 78, 130, 70, 116, 65, 104, 62])); + cb("p", new Uint8Array([52, 59, 52, 64, 54, 73, 58, 88, 61, 104, 65, 119, 67, 130, 69, 138, 71, 145, 71, 147, 71, 148, 71, 143, 70, 133, 68, 120, 67, 108, 67, 97, 67, 89, 68, 79, 72, 67, 83, 60, 99, 58, 118, 58, 136, 63, 146, 70, 148, 77, 145, 84, 136, 91, 121, 95, 106, 97, 93, 97, 82, 97])); + cb("q", new Uint8Array([95, 59, 93, 59, 88, 59, 79, 59, 68, 61, 57, 67, 50, 77, 48, 89, 48, 103, 50, 117, 55, 130, 65, 140, 76, 145, 85, 146, 94, 144, 101, 140, 105, 136, 106, 127, 106, 113, 100, 98, 92, 86, 86, 79, 84, 75, 84, 72, 91, 69, 106, 67, 126, 67, 144, 67, 158, 67, 168, 67, 173, 67, 177, 67])); + cb("r", new Uint8Array([53, 49, 53, 62, 53, 91, 53, 127, 53, 146, 53, 147, 53, 128, 53, 94, 53, 69, 62, 44, 82, 42, 94, 50, 92, 68, 82, 85, 77, 93, 80, 102, 95, 119, 114, 134, 129, 145, 137, 150])); + cb("s", new Uint8Array([159, 72, 157, 70, 155, 68, 151, 66, 145, 63, 134, 60, 121, 58, 108, 56, 96, 55, 83, 55, 73, 55, 64, 56, 57, 60, 52, 65, 49, 71, 49, 76, 50, 81, 55, 87, 71, 94, 94, 100, 116, 104, 131, 108, 141, 114, 145, 124, 142, 135, 124, 146, 97, 153, 70, 157, 52, 158])); + cb("t", new Uint8Array([45, 55, 48, 55, 55, 55, 72, 55, 96, 55, 120, 55, 136, 55, 147, 55, 152, 55, 155, 55, 157, 55, 158, 56, 158, 60, 156, 70, 154, 86, 151, 102, 150, 114, 148, 125, 148, 138, 148, 146])); + cb("u", new Uint8Array([35, 52, 35, 59, 35, 73, 35, 90, 36, 114, 38, 133, 42, 146, 49, 153, 60, 157, 73, 158, 86, 156, 100, 152, 112, 144, 121, 131, 127, 114, 132, 97, 134, 85, 135, 73, 136, 61, 136, 56])); + cb("v", new Uint8Array([36, 55, 37, 59, 40, 68, 45, 83, 51, 100, 58, 118, 64, 132, 69, 142, 71, 149, 73, 156, 76, 158, 77, 160, 77, 159, 80, 151, 82, 137, 84, 122, 86, 111, 90, 91, 91, 78, 91, 68, 91, 63, 92, 61, 97, 61, 111, 61, 132, 61, 150, 61, 162, 61])); + cb("w", new Uint8Array([33, 58, 34, 81, 39, 127, 44, 151, 48, 161, 52, 162, 57, 154, 61, 136, 65, 115, 70, 95, 76, 95, 93, 121, 110, 146, 119, 151, 130, 129, 138, 84, 140, 56, 140, 45])); + cb("x", new Uint8Array([56, 63, 56, 67, 57, 74, 60, 89, 66, 109, 74, 129, 85, 145, 96, 158, 107, 164, 117, 167, 128, 164, 141, 155, 151, 140, 159, 122, 166, 105, 168, 89, 170, 81, 170, 73, 169, 66, 161, 63, 141, 68, 110, 83, 77, 110, 55, 134, 47, 145])); + cb("y", new Uint8Array([42, 56, 42, 70, 48, 97, 62, 109, 85, 106, 109, 90, 126, 65, 134, 47, 137, 45, 137, 75, 127, 125, 98, 141, 70, 133, 65, 126, 92, 137, 132, 156, 149, 166])); + cb("z", new Uint8Array([29, 62, 35, 62, 43, 62, 63, 62, 87, 62, 110, 62, 125, 62, 134, 62, 138, 62, 136, 63, 122, 68, 103, 77, 85, 91, 70, 107, 59, 120, 50, 132, 47, 138, 43, 143, 41, 148, 42, 151, 53, 155, 80, 157, 116, 158, 146, 158, 163, 158])); + } else if (mode === INPUT_MODE_NUM) { + cb("0", new Uint8Array([105, 63, 97, 63, 80, 63, 62, 64, 52, 69, 47, 79, 47, 94, 48, 111, 55, 125, 74, 138, 100, 141, 126, 137, 148, 129, 158, 119, 161, 107, 161, 98, 159, 92, 154, 87, 149, 82])); + cb("1", new Uint8Array([123, 59, 123, 60, 123, 63, 123, 67, 123, 70, 122, 73, 121, 78, 119, 83, 118, 91, 117, 100, 116, 108, 115, 117, 114, 126, 113, 135, 112, 143, 111, 149, 111, 155, 110, 159])); + cb("2", new Uint8Array([61, 99, 61, 94, 61, 88, 61, 80, 65, 71, 73, 66, 83, 62, 97, 62, 109, 62, 126, 62, 141, 62, 149, 65, 151, 74, 151, 87, 150, 95, 143, 108, 130, 118, 117, 127, 100, 138, 84, 146, 67, 151, 55, 157, 52, 159, 73, 159, 117, 159, 163, 159, 183, 159])); + cb("3", new Uint8Array([69, 62, 78, 56, 98, 49, 121, 49, 141, 54, 149, 58, 150, 65, 148, 74, 143, 82, 126, 92, 114, 98, 119, 100, 135, 105, 143, 117, 142, 135, 123, 149, 105, 155])); + cb("4", new Uint8Array([78, 45, 78, 47, 78, 50, 78, 56, 78, 64, 78, 75, 78, 88, 78, 103, 78, 119, 78, 132, 78, 144, 78, 148, 80, 149, 84, 149, 96, 149, 112, 148, 127, 147, 144, 144, 163, 140, 175, 137])); + cb("5", new Uint8Array([142, 49, 134, 47, 121, 44, 104, 44, 88, 45, 75, 46, 68, 48, 64, 52, 64, 59, 64, 73, 64, 86, 64, 100, 67, 105, 82, 105, 106, 105, 130, 105, 143, 105, 149, 105, 151, 110, 148, 125, 138, 144, 118, 157, 92, 164, 76, 165, 65, 165, 60, 165])); + cb("6", new Uint8Array([161, 47, 151, 47, 133, 47, 108, 48, 85, 52, 65, 59, 53, 72, 46, 89, 44, 107, 49, 133, 71, 151, 100, 156, 118, 152, 120, 141, 108, 132, 84, 127, 70, 126])); + cb("7", new Uint8Array([43, 53, 53, 49, 72, 45, 96, 40, 116, 38, 129, 38, 138, 38, 144, 38, 147, 39, 149, 47, 143, 75, 127, 121, 114, 147, 107, 158, 104, 162, 98, 168, 93, 171])); + cb("8", new Uint8Array([148, 66, 135, 58, 113, 49, 97, 43, 84, 40, 74, 40, 66, 43, 62, 47, 62, 51, 67, 61, 84, 75, 101, 88, 111, 101, 113, 115, 110, 135, 98, 149, 84, 156, 73, 157, 63, 157, 58, 154, 52, 144, 52, 133, 54, 122, 65, 111, 81, 100, 97, 92, 110, 86, 121, 81, 129, 80, 137, 80, 145, 79, 151, 78])); + cb("9", new Uint8Array([146, 57, 146, 52, 146, 46, 143, 42, 135, 41, 123, 41, 107, 45, 92, 49, 83, 53, 78, 62, 89, 82, 110, 94, 126, 94, 139, 88, 147, 81, 151, 74, 152, 75, 152, 80, 152, 88, 152, 101, 152, 121, 152, 140, 152, 154, 152, 165, 152, 171])); + } cb("\b", new Uint8Array([183, 103, 182, 103, 180, 103, 176, 103, 169, 103, 159, 103, 147, 103, 133, 103, 116, 103, 101, 103, 85, 103, 73, 103, 61, 103, 52, 103, 38, 103, 34, 103, 29, 103, 27, 103, 26, 103, 25, 103, 24, 103])); cb(" ", new Uint8Array([39, 118, 40, 118, 41, 118, 44, 118, 47, 118, 52, 118, 58, 118, 66, 118, 74, 118, 84, 118, 94, 118, 104, 117, 114, 116, 123, 116, 130, 116, 144, 116, 149, 116, 154, 116, 158, 116, 161, 116, 163, 116])); }; exports.input = function(options) { options = options||{}; + let input_mode = INPUT_MODE_ALPHA; var text = options.text; if ("string"!=typeof text) text=""; -Bangle.strokes = {}; -exports.getStrokes( (id,s) => Bangle.strokes[id] = Unistroke.new(s) ); + function setupStrokes() { + Bangle.strokes = {}; + exports.getStrokes(input_mode, (id,s) => Bangle.strokes[id] = Unistroke.new(s) ); + } + setupStrokes(); var flashToggle = false; const R = Bangle.appRect; @@ -49,6 +69,7 @@ exports.getStrokes( (id,s) => Bangle.strokes[id] = Unistroke.new(s) ); var Rx2; var Ry1; var Ry2; + let flashInterval; function findMarker(strArr) { if (strArr.length == 0) { @@ -101,10 +122,13 @@ exports.getStrokes( (id,s) => Bangle.strokes[id] = Unistroke.new(s) ); */ function show() { + if (flashInterval) clearInterval(flashInterval); + flashInterval = undefined; + g.reset(); g.clearRect(R).setColor("#f00"); var n=0; - exports.getStrokes((id,s) => { + exports.getStrokes(input_mode, (id,s) => { var x = n%6; var y = (n-x)/6; s = g.transformVertices(s, {scale:0.16, x:R.x+x*30-4, y:R.y+y*30-4}); @@ -119,22 +143,47 @@ exports.getStrokes( (id,s) => Bangle.strokes[id] = Unistroke.new(s) ); if (!flashInterval) flashInterval = setInterval(() => { flashToggle = !flashToggle; - draw(); + draw(false); }, 1000); if (o.stroke!==undefined) { var ch = o.stroke; if (ch=="\b") text = text.slice(0,-1); else text += ch; - g.clearRect(R); + g.clearRect(R); } flashToggle = true; - draw(); + draw(false); } + + // Switches between alphabetic and numeric input + function cycleInput() { + input_mode++; + if (input_mode > INPUT_MODE_NUM) input_mode = 0; + setupStrokes(); + show(); + Bangle.drawWidgets(); + } + Bangle.on('stroke',strokeHandler); g.reset().clearRect(R); show(); draw(false); - var flashInterval; + + // Create Widget to switch between alphabetic and numeric input + WIDGETS.kbswipe={ + area:"tl", + width: 36, // 3 chars 6*2 px/char + draw: function() { + g.reset(); + g.setFont("6x8:2x3"); + g.setColor("#f00"); + if (input_mode === INPUT_MODE_ALPHA) { + g.drawString("123", this.x, this.y); + } else if (input_mode === INPUT_MODE_NUM) { + g.drawString("ABC", this.x, this.y); + } + } + }; return new Promise((resolve,reject) => { var l;//last event @@ -142,11 +191,16 @@ exports.getStrokes( (id,s) => Bangle.strokes[id] = Unistroke.new(s) ); "ram"; if (l) g.reset().setColor("#f00").drawLine(l.x,l.y,e.x,e.y); l = e.b ? e : 0; - },touch:() => { - if (flashInterval) clearInterval(flashInterval); - flashInterval = undefined; - show(); + },touch:(n,e) => { + if (WIDGETS.kbswipe && e.x>=WIDGETS.kbswipe.x && e.x=WIDGETS.kbswipe.y && e.y<=WIDGETS.kbswipe.y+24) { + // touch inside widget + cycleInput(); + } else { + show(); + } }, back:()=>{ + delete WIDGETS.kbswipe; Bangle.removeListener("stroke", strokeHandler); if (flashInterval) clearInterval(flashInterval); Bangle.setUI(); diff --git a/apps/kbswipe/metadata.json b/apps/kbswipe/metadata.json index 59622cb96..5e290e1dd 100644 --- a/apps/kbswipe/metadata.json +++ b/apps/kbswipe/metadata.json @@ -1,6 +1,6 @@ { "id": "kbswipe", "name": "Swipe keyboard", - "version":"0.05", + "version":"0.06", "description": "A library for text input via PalmOS style swipe gestures (beta!)", "icon": "app.png", "type":"textinput", From 39860e9bb281a343859d11522fab337f02c3ec40 Mon Sep 17 00:00:00 2001 From: Erik Andresen Date: Fri, 2 Dec 2022 20:40:15 +0100 Subject: [PATCH 035/110] kbswipe: Support uppercase input --- apps/kbswipe/lib.js | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/apps/kbswipe/lib.js b/apps/kbswipe/lib.js index 861d046cb..451cc21b4 100644 --- a/apps/kbswipe/lib.js +++ b/apps/kbswipe/lib.js @@ -35,6 +35,7 @@ exports.getStrokes = function(mode, cb) { cb("x", new Uint8Array([56, 63, 56, 67, 57, 74, 60, 89, 66, 109, 74, 129, 85, 145, 96, 158, 107, 164, 117, 167, 128, 164, 141, 155, 151, 140, 159, 122, 166, 105, 168, 89, 170, 81, 170, 73, 169, 66, 161, 63, 141, 68, 110, 83, 77, 110, 55, 134, 47, 145])); cb("y", new Uint8Array([42, 56, 42, 70, 48, 97, 62, 109, 85, 106, 109, 90, 126, 65, 134, 47, 137, 45, 137, 75, 127, 125, 98, 141, 70, 133, 65, 126, 92, 137, 132, 156, 149, 166])); cb("z", new Uint8Array([29, 62, 35, 62, 43, 62, 63, 62, 87, 62, 110, 62, 125, 62, 134, 62, 138, 62, 136, 63, 122, 68, 103, 77, 85, 91, 70, 107, 59, 120, 50, 132, 47, 138, 43, 143, 41, 148, 42, 151, 53, 155, 80, 157, 116, 158, 146, 158, 163, 158])); + cb("SHIFT", new Uint8Array([106, 184, 106, 182, 106, 175, 106, 165, 106, 151, 106, 135, 106, 120, 106, 106, 106, 95, 106, 87, 106, 82, 106, 78, 106, 73, 106, 70, 106, 68, 106, 66, 106, 64])); } else if (mode === INPUT_MODE_NUM) { cb("0", new Uint8Array([105, 63, 97, 63, 80, 63, 62, 64, 52, 69, 47, 79, 47, 94, 48, 111, 55, 125, 74, 138, 100, 141, 126, 137, 148, 129, 158, 119, 161, 107, 161, 98, 159, 92, 154, 87, 149, 82])); cb("1", new Uint8Array([123, 59, 123, 60, 123, 63, 123, 67, 123, 70, 122, 73, 121, 78, 119, 83, 118, 91, 117, 100, 116, 108, 115, 117, 114, 126, 113, 135, 112, 143, 111, 149, 111, 155, 110, 159])); @@ -70,6 +71,7 @@ exports.input = function(options) { var Ry1; var Ry2; let flashInterval; + let shift = false; function findMarker(strArr) { if (strArr.length == 0) { @@ -148,7 +150,8 @@ exports.input = function(options) { if (o.stroke!==undefined) { var ch = o.stroke; if (ch=="\b") text = text.slice(0,-1); - else text += ch; + else if (ch==="SHIFT") { shift=!shift; Bangle.drawWidgets(); } + else text += shift ? ch.toUpperCase() : ch; g.clearRect(R); } flashToggle = true; @@ -159,6 +162,7 @@ exports.input = function(options) { function cycleInput() { input_mode++; if (input_mode > INPUT_MODE_NUM) input_mode = 0; + shift = false; setupStrokes(); show(); Bangle.drawWidgets(); @@ -172,15 +176,15 @@ exports.input = function(options) { // Create Widget to switch between alphabetic and numeric input WIDGETS.kbswipe={ area:"tl", - width: 36, // 3 chars 6*2 px/char + width: 36, // 3 chars, 6*2 px/char draw: function() { g.reset(); g.setFont("6x8:2x3"); g.setColor("#f00"); if (input_mode === INPUT_MODE_ALPHA) { - g.drawString("123", this.x, this.y); + g.drawString(shift ? "ABC" : "abc", this.x, this.y); } else if (input_mode === INPUT_MODE_NUM) { - g.drawString("ABC", this.x, this.y); + g.drawString("123", this.x, this.y); } } }; From e77a5f973c535bbfc2a755ceebdd4dc13c3f82e0 Mon Sep 17 00:00:00 2001 From: Martin Boonk Date: Fri, 2 Dec 2022 19:10:26 +0100 Subject: [PATCH 036/110] bthrm - Emit copies of events when changing --- apps/bthrm/lib.js | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/apps/bthrm/lib.js b/apps/bthrm/lib.js index f5e0e1e5b..a792167ca 100644 --- a/apps/bthrm/lib.js +++ b/apps/bthrm/lib.js @@ -553,14 +553,15 @@ exports.enable = () => { if (settings.replace){ // register a listener for original HRM events and emit as HRM_int - Bangle.on("HRM", (e) => { - e.modified = true; + Bangle.on("HRM", (o) => { + let e = Object.assign({},o); log("Emitting HRM_int", e); Bangle.emit("HRM_int", e); if (fallbackActive){ // if fallback to internal HRM is active, emit as HRM_R to which everyone listens - log("Emitting HRM_R(int)", e); - Bangle.emit("HRM_R", e); + o.src = "int"; + log("Emitting HRM_R(int)", o); + Bangle.emit("HRM_R", o); } }); @@ -576,6 +577,13 @@ exports.enable = () => { if (name == "HRM") o("HRM_R", cb); else o(name, cb); })(Bangle.removeListener); + } else { + Bangle.on("HRM", (o)=>{ + o.src = "int"; + let e = Object.assign({},o); + log("Emitting HRM_int", e); + Bangle.emit("HRM_int", e); + }); } Bangle.origSetHRMPower = Bangle.setHRMPower; From 85c2f92e0aa816ce8c47f46ea077ae82548b7d90 Mon Sep 17 00:00:00 2001 From: Martin Boonk Date: Fri, 2 Dec 2022 19:15:03 +0100 Subject: [PATCH 037/110] bthrm - Bump version --- apps/bthrm/ChangeLog | 1 + apps/bthrm/metadata.json | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/bthrm/ChangeLog b/apps/bthrm/ChangeLog index 99cf0c670..000c5e3f8 100644 --- a/apps/bthrm/ChangeLog +++ b/apps/bthrm/ChangeLog @@ -40,3 +40,4 @@ 0.16: Set powerdownRequested correctly on BTHRM power on Additional logging on errors Add debug option for disabling active scanning +0.17: New GUI based on layout library diff --git a/apps/bthrm/metadata.json b/apps/bthrm/metadata.json index 18c34ea33..0977fd755 100644 --- a/apps/bthrm/metadata.json +++ b/apps/bthrm/metadata.json @@ -2,7 +2,7 @@ "id": "bthrm", "name": "Bluetooth Heart Rate Monitor", "shortName": "BT HRM", - "version": "0.16", + "version": "0.17", "description": "Overrides Bangle.js's build in heart rate monitor with an external Bluetooth one.", "icon": "app.png", "type": "app", From ddbbef2bf814eb254d9fd3969f5c05ddb4e70da1 Mon Sep 17 00:00:00 2001 From: Martin Boonk Date: Fri, 2 Dec 2022 23:50:14 +0100 Subject: [PATCH 038/110] bthrm - Change from timeouts to timestamps for resetting values --- apps/bthrm/bthrm.js | 55 +++++++++------------------------------------ 1 file changed, 11 insertions(+), 44 deletions(-) diff --git a/apps/bthrm/bthrm.js b/apps/bthrm/bthrm.js index 05bf323a5..e163dd8b7 100644 --- a/apps/bthrm/bthrm.js +++ b/apps/bthrm/bthrm.js @@ -1,7 +1,3 @@ -var intervalInt; -var intervalBt; -var intervalAgg; - const BPM_FONT_SIZE="19%"; const VALUE_TIMEOUT=3000; @@ -19,7 +15,6 @@ var Layout = require("Layout"); function border(l,c) { g.setColor(c).drawLine(l.x+l.w*0.05, l.y-4, l.x+l.w*0.95, l.y-4); - c++; } function getRow(id, text, additionalInfo){ @@ -68,23 +63,17 @@ var layout = new Layout( { var int,agg,bt; var firstEvent = true; -var drawTimeout; function draw(){ - - if (drawTimeout) clearTimeout(drawTimeout); - drawTimeout = setTimeout(function() { - drawTimeout = undefined; - draw(); - }, 1000); - if (!(int || agg || bt)) return; - + if (firstEvent) { g.clearRect(Bangle.appRect); firstEvent = false; } - - if (int){ + + let now = Date.now(); + + if (int && int.time > (now - VALUE_TIMEOUT)){ layout.int.label = int.bpm; if (!isNaN(int.confidence)) layout.intConfidence.label = int.confidence; } else { @@ -92,7 +81,7 @@ function draw(){ layout.intConfidence.label = "--"; } - if (agg){ + if (agg && agg.time > (now - VALUE_TIMEOUT)){ layout.agg.label = agg.bpm; if (!isNaN(agg.confidence)) layout.aggConfidence.label = agg.confidence; if (agg.src) layout.aggSource.label = agg.src; @@ -102,7 +91,7 @@ function draw(){ layout.aggSource.label = "--"; } - if (bt) { + if (bt && bt.time > (now - VALUE_TIMEOUT)) { layout.bt.label = bt.bpm; if (bt.battery) layout.btBattery.label = bt.battery; if (bt.rr) layout.btRR.label = bt.rr.join(","); @@ -131,9 +120,6 @@ function draw(){ } } -var firstEventBt = true; -var firstEventInt = true; - // This can get called for the boot code to show what's happening function showStatusInfo(txt) { @@ -145,38 +131,19 @@ function showStatusInfo(txt) { function onBtHrm(e) { bt = e; - if (e.bpm === 0){ - Bangle.buzz(100,0.2); - } - if (intervalBt){ - clearInterval(intervalBt); - } - intervalBt = setInterval(()=>{ - bt = undefined; - }, VALUE_TIMEOUT); + bt.time = Date.now(); } function onInt(e) { int = e; - if (intervalInt){ - clearInterval(intervalInt); - } - intervalInt = setInterval(()=>{ - int = undefined; - }, VALUE_TIMEOUT); + int.time = Date.now(); } function onAgg(e) { agg = e; - if (intervalAgg){ - clearInterval(intervalAgg); - } - intervalAgg = setInterval(()=>{ - agg = undefined; - }, VALUE_TIMEOUT); + agg.time = Date.now(); } - var settings = require('Storage').readJSON("bthrm.json", true) || {}; Bangle.on('BTHRM', onBtHrm); @@ -195,7 +162,7 @@ Bangle.drawWidgets(); if (Bangle.setBTHRMPower){ g.reset().setFont("6x8",2).setFontAlign(0,0); g.drawString("Please wait...",g.getWidth()/2,g.getHeight()/2); - draw(); + setInterval(draw, 1000); } else { g.reset().setFont("6x8",2).setFontAlign(0,0); g.drawString("BTHRM disabled",g.getWidth()/2,g.getHeight()/2); From 6324ffb378a77d8debd64cf28443946786016092 Mon Sep 17 00:00:00 2001 From: Erik Andresen Date: Sun, 4 Dec 2022 10:56:20 +0100 Subject: [PATCH 039/110] kbswipe: Bug fixes --- apps/kbswipe/lib.js | 71 ++++++++++++++++++++++++++++----------------- 1 file changed, 44 insertions(+), 27 deletions(-) diff --git a/apps/kbswipe/lib.js b/apps/kbswipe/lib.js index 451cc21b4..edc50817a 100644 --- a/apps/kbswipe/lib.js +++ b/apps/kbswipe/lib.js @@ -1,5 +1,5 @@ -const INPUT_MODE_ALPHA = 0; -const INPUT_MODE_NUM = 1; +exports.INPUT_MODE_ALPHA = 0; +exports.INPUT_MODE_NUM = 1; /* To make your own strokes, type: @@ -8,7 +8,7 @@ Bangle.on('stroke',print) on the left of the IDE, then do a stroke and copy out the Uint8Array line */ exports.getStrokes = function(mode, cb) { - if (mode === INPUT_MODE_ALPHA) { + if (mode === exports.INPUT_MODE_ALPHA) { cb("a", new Uint8Array([58, 159, 58, 155, 62, 144, 69, 127, 77, 106, 86, 90, 94, 77, 101, 68, 108, 62, 114, 59, 121, 59, 133, 61, 146, 70, 158, 88, 169, 107, 176, 124, 180, 135, 183, 144, 185, 152])); cb("b", new Uint8Array([51, 47, 51, 77, 56, 123, 60, 151, 65, 163, 68, 164, 68, 144, 67, 108, 67, 76, 72, 43, 104, 51, 121, 74, 110, 87, 109, 95, 131, 117, 131, 140, 109, 152, 88, 157])); cb("c", new Uint8Array([153, 62, 150, 62, 145, 62, 136, 62, 123, 62, 106, 65, 85, 70, 65, 75, 50, 82, 42, 93, 37, 106, 36, 119, 36, 130, 40, 140, 49, 147, 61, 153, 72, 156, 85, 157, 106, 158, 116, 158])); @@ -35,18 +35,18 @@ exports.getStrokes = function(mode, cb) { cb("x", new Uint8Array([56, 63, 56, 67, 57, 74, 60, 89, 66, 109, 74, 129, 85, 145, 96, 158, 107, 164, 117, 167, 128, 164, 141, 155, 151, 140, 159, 122, 166, 105, 168, 89, 170, 81, 170, 73, 169, 66, 161, 63, 141, 68, 110, 83, 77, 110, 55, 134, 47, 145])); cb("y", new Uint8Array([42, 56, 42, 70, 48, 97, 62, 109, 85, 106, 109, 90, 126, 65, 134, 47, 137, 45, 137, 75, 127, 125, 98, 141, 70, 133, 65, 126, 92, 137, 132, 156, 149, 166])); cb("z", new Uint8Array([29, 62, 35, 62, 43, 62, 63, 62, 87, 62, 110, 62, 125, 62, 134, 62, 138, 62, 136, 63, 122, 68, 103, 77, 85, 91, 70, 107, 59, 120, 50, 132, 47, 138, 43, 143, 41, 148, 42, 151, 53, 155, 80, 157, 116, 158, 146, 158, 163, 158])); - cb("SHIFT", new Uint8Array([106, 184, 106, 182, 106, 175, 106, 165, 106, 151, 106, 135, 106, 120, 106, 106, 106, 95, 106, 87, 106, 82, 106, 78, 106, 73, 106, 70, 106, 68, 106, 66, 106, 64])); - } else if (mode === INPUT_MODE_NUM) { - cb("0", new Uint8Array([105, 63, 97, 63, 80, 63, 62, 64, 52, 69, 47, 79, 47, 94, 48, 111, 55, 125, 74, 138, 100, 141, 126, 137, 148, 129, 158, 119, 161, 107, 161, 98, 159, 92, 154, 87, 149, 82])); - cb("1", new Uint8Array([123, 59, 123, 60, 123, 63, 123, 67, 123, 70, 122, 73, 121, 78, 119, 83, 118, 91, 117, 100, 116, 108, 115, 117, 114, 126, 113, 135, 112, 143, 111, 149, 111, 155, 110, 159])); - cb("2", new Uint8Array([61, 99, 61, 94, 61, 88, 61, 80, 65, 71, 73, 66, 83, 62, 97, 62, 109, 62, 126, 62, 141, 62, 149, 65, 151, 74, 151, 87, 150, 95, 143, 108, 130, 118, 117, 127, 100, 138, 84, 146, 67, 151, 55, 157, 52, 159, 73, 159, 117, 159, 163, 159, 183, 159])); - cb("3", new Uint8Array([69, 62, 78, 56, 98, 49, 121, 49, 141, 54, 149, 58, 150, 65, 148, 74, 143, 82, 126, 92, 114, 98, 119, 100, 135, 105, 143, 117, 142, 135, 123, 149, 105, 155])); - cb("4", new Uint8Array([78, 45, 78, 47, 78, 50, 78, 56, 78, 64, 78, 75, 78, 88, 78, 103, 78, 119, 78, 132, 78, 144, 78, 148, 80, 149, 84, 149, 96, 149, 112, 148, 127, 147, 144, 144, 163, 140, 175, 137])); - cb("5", new Uint8Array([142, 49, 134, 47, 121, 44, 104, 44, 88, 45, 75, 46, 68, 48, 64, 52, 64, 59, 64, 73, 64, 86, 64, 100, 67, 105, 82, 105, 106, 105, 130, 105, 143, 105, 149, 105, 151, 110, 148, 125, 138, 144, 118, 157, 92, 164, 76, 165, 65, 165, 60, 165])); - cb("6", new Uint8Array([161, 47, 151, 47, 133, 47, 108, 48, 85, 52, 65, 59, 53, 72, 46, 89, 44, 107, 49, 133, 71, 151, 100, 156, 118, 152, 120, 141, 108, 132, 84, 127, 70, 126])); - cb("7", new Uint8Array([43, 53, 53, 49, 72, 45, 96, 40, 116, 38, 129, 38, 138, 38, 144, 38, 147, 39, 149, 47, 143, 75, 127, 121, 114, 147, 107, 158, 104, 162, 98, 168, 93, 171])); - cb("8", new Uint8Array([148, 66, 135, 58, 113, 49, 97, 43, 84, 40, 74, 40, 66, 43, 62, 47, 62, 51, 67, 61, 84, 75, 101, 88, 111, 101, 113, 115, 110, 135, 98, 149, 84, 156, 73, 157, 63, 157, 58, 154, 52, 144, 52, 133, 54, 122, 65, 111, 81, 100, 97, 92, 110, 86, 121, 81, 129, 80, 137, 80, 145, 79, 151, 78])); - cb("9", new Uint8Array([146, 57, 146, 52, 146, 46, 143, 42, 135, 41, 123, 41, 107, 45, 92, 49, 83, 53, 78, 62, 89, 82, 110, 94, 126, 94, 139, 88, 147, 81, 151, 74, 152, 75, 152, 80, 152, 88, 152, 101, 152, 121, 152, 140, 152, 154, 152, 165, 152, 171])); + cb("SHIFT", new Uint8Array([100, 160, 100, 50])); + } else if (mode === exports.INPUT_MODE_NUM) { + cb("0", new Uint8Array([127, 67, 125, 67, 121, 67, 111, 67, 98, 67, 83, 68, 72, 70, 64, 74, 58, 79, 54, 86, 51, 96, 50, 107, 50, 116, 50, 125, 53, 132, 59, 141, 66, 146, 75, 150, 93, 155, 112, 157, 132, 154, 147, 146, 158, 126, 160, 113, 159, 103, 155, 94, 149, 89, 142, 85])); + cb("1", new Uint8Array([100, 50, 100, 160])); + cb("2", new Uint8Array([63, 80, 65, 78, 68, 75, 72, 71, 79, 67, 87, 62, 97, 59, 106, 58, 115, 58, 122, 58, 126, 61, 128, 66, 129, 72, 127, 84, 123, 100, 115, 116, 110, 126, 103, 136, 95, 146, 93, 149, 98, 150, 114, 150, 136, 150, 154, 150])); + cb("3", new Uint8Array([100, 62, 102, 62, 105, 62, 109, 62, 114, 62, 121, 62, 127, 62, 131, 62, 135, 62, 137, 63, 138, 66, 138, 68, 138, 70, 137, 72, 135, 74, 133, 77, 132, 79, 129, 81, 126, 84, 123, 86, 119, 86, 122, 90, 129, 93, 142, 101, 150, 107, 154, 117, 154, 126, 150, 135, 142, 142, 131, 147, 122, 150])); + cb("4", new Uint8Array([93, 61, 93, 63, 93, 68, 93, 75, 93, 84, 93, 93, 93, 101, 93, 113, 93, 126, 93, 137, 93, 144, 93, 149, 93, 151, 93, 154, 93, 156, 94, 157, 96, 157, 103, 157, 120, 157, 141, 157, 161, 157, 176, 157, 182, 157, 185, 157])); + cb("5", new Uint8Array([151, 57, 144, 55, 130, 55, 110, 56, 94, 59, 83, 61, 78, 69, 78, 78, 78, 86, 78, 93, 83, 100, 103, 103, 127, 106, 143, 114, 148, 128, 141, 142, 125, 152, 107, 159, 90, 162, 81, 163])); + cb("6", new Uint8Array([147, 35, 145, 35, 141, 36, 136, 38, 130, 42, 123, 47, 115, 51, 106, 57, 97, 64, 88, 73, 81, 82, 76, 89, 73, 95, 71, 101, 70, 108, 70, 114, 70, 118, 71, 124, 74, 131, 80, 137, 87, 140, 96, 143, 103, 143, 108, 141, 113, 138, 116, 134, 118, 127, 118, 120, 118, 114, 116, 107, 113, 103, 109, 100])); + cb("7", new Uint8Array([66, 69, 69, 69, 75, 67, 83, 66, 95, 66, 108, 63, 121, 61, 132, 61, 141, 61, 147, 61, 151, 61, 154, 61, 156, 61, 158, 61, 160, 61, 162, 61, 162, 63, 161, 67, 156, 85, 147, 112, 137, 135, 129, 151, 124, 158])); + cb("8", new Uint8Array([148, 59, 145, 55, 137, 52, 125, 52, 112, 52, 100, 54, 92, 56, 84, 60, 81, 66, 81, 76, 90, 82, 109, 90, 128, 98, 136, 106, 137, 121, 126, 140, 107, 151, 92, 151, 81, 143, 81, 122, 92, 94, 108, 75, 124, 65])); + cb("9", new Uint8Array([129, 72, 127, 72, 125, 72, 122, 72, 117, 72, 111, 72, 104, 74, 100, 77, 95, 79, 94, 81, 94, 83, 94, 87, 96, 90, 101, 92, 105, 94, 111, 94, 115, 94, 121, 92, 130, 89, 136, 85, 140, 82, 144, 79, 146, 79, 147, 83, 149, 97, 149, 118, 149, 135, 149, 149, 149, 158])); } cb("\b", new Uint8Array([183, 103, 182, 103, 180, 103, 176, 103, 169, 103, 159, 103, 147, 103, 133, 103, 116, 103, 101, 103, 85, 103, 73, 103, 61, 103, 52, 103, 38, 103, 34, 103, 29, 103, 27, 103, 26, 103, 25, 103, 24, 103])); cb(" ", new Uint8Array([39, 118, 40, 118, 41, 118, 44, 118, 47, 118, 52, 118, 58, 118, 66, 118, 74, 118, 84, 118, 94, 118, 104, 117, 114, 116, 123, 116, 130, 116, 144, 116, 149, 116, 154, 116, 158, 116, 161, 116, 163, 116])); @@ -54,7 +54,7 @@ exports.getStrokes = function(mode, cb) { exports.input = function(options) { options = options||{}; - let input_mode = INPUT_MODE_ALPHA; + let input_mode = exports.INPUT_MODE_ALPHA; var text = options.text; if ("string"!=typeof text) text=""; @@ -72,6 +72,7 @@ exports.input = function(options) { var Ry2; let flashInterval; let shift = false; + let lastDrag; function findMarker(strArr) { if (strArr.length == 0) { @@ -140,6 +141,20 @@ exports.input = function(options) { }); } + function isInside(rect, e) { + return e.x>=rect.x && e.x=rect.y && e.y<=rect.y+rect.h; + } + + function isStrokeInAppRect(stroke, rect) { + for(let i=0; i < stroke.length; i+=2) { + if (!isInside(rect, {x: stroke[i], y: stroke[i+1]})) { + return false; + } + } + return true; + } + function strokeHandler(o) { //print(o); if (!flashInterval) @@ -147,13 +162,14 @@ exports.input = function(options) { flashToggle = !flashToggle; draw(false); }, 1000); - if (o.stroke!==undefined) { + if (o.stroke!==undefined && o.xy.length >= 6 && isStrokeInAppRect(o.xy, R)) { var ch = o.stroke; if (ch=="\b") text = text.slice(0,-1); else if (ch==="SHIFT") { shift=!shift; Bangle.drawWidgets(); } else text += shift ? ch.toUpperCase() : ch; - g.clearRect(R); } + lastDrag = undefined; + g.clearRect(R); flashToggle = true; draw(false); } @@ -161,7 +177,7 @@ exports.input = function(options) { // Switches between alphabetic and numeric input function cycleInput() { input_mode++; - if (input_mode > INPUT_MODE_NUM) input_mode = 0; + if (input_mode > exports.INPUT_MODE_NUM) input_mode = 0; shift = false; setupStrokes(); show(); @@ -181,26 +197,27 @@ exports.input = function(options) { g.reset(); g.setFont("6x8:2x3"); g.setColor("#f00"); - if (input_mode === INPUT_MODE_ALPHA) { + if (input_mode === exports.INPUT_MODE_ALPHA) { g.drawString(shift ? "ABC" : "abc", this.x, this.y); - } else if (input_mode === INPUT_MODE_NUM) { + } else if (input_mode === exports.INPUT_MODE_NUM) { g.drawString("123", this.x, this.y); } } }; return new Promise((resolve,reject) => { - var l;//last event Bangle.setUI({mode:"custom", drag:e=>{ "ram"; - if (l) g.reset().setColor("#f00").drawLine(l.x,l.y,e.x,e.y); - l = e.b ? e : 0; + if (isInside(R, e)) { + if (lastDrag) g.reset().setColor("#f00").drawLine(lastDrag.x,lastDrag.y,e.x,e.y); + lastDrag = e.b ? e : 0; + } },touch:(n,e) => { - if (WIDGETS.kbswipe && e.x>=WIDGETS.kbswipe.x && e.x=WIDGETS.kbswipe.y && e.y<=WIDGETS.kbswipe.y+24) { + if (WIDGETS.kbswipe && isInside({x: WIDGETS.kbswipe.x, y: WIDGETS.kbswipe.y, w: WIDGETS.kbswipe.width, h: 24}, e)) { // touch inside widget cycleInput(); - } else { + } else if (isInside(R, e)) { + // touch inside app area show(); } }, back:()=>{ From 2183b53524b0162fa4a692531a386687a630688a Mon Sep 17 00:00:00 2001 From: Erik Andresen Date: Sun, 4 Dec 2022 11:46:12 +0100 Subject: [PATCH 040/110] kbswipe: Redo some patterns --- apps/kbswipe/lib.js | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/apps/kbswipe/lib.js b/apps/kbswipe/lib.js index edc50817a..981dc80db 100644 --- a/apps/kbswipe/lib.js +++ b/apps/kbswipe/lib.js @@ -31,22 +31,22 @@ exports.getStrokes = function(mode, cb) { cb("t", new Uint8Array([45, 55, 48, 55, 55, 55, 72, 55, 96, 55, 120, 55, 136, 55, 147, 55, 152, 55, 155, 55, 157, 55, 158, 56, 158, 60, 156, 70, 154, 86, 151, 102, 150, 114, 148, 125, 148, 138, 148, 146])); cb("u", new Uint8Array([35, 52, 35, 59, 35, 73, 35, 90, 36, 114, 38, 133, 42, 146, 49, 153, 60, 157, 73, 158, 86, 156, 100, 152, 112, 144, 121, 131, 127, 114, 132, 97, 134, 85, 135, 73, 136, 61, 136, 56])); cb("v", new Uint8Array([36, 55, 37, 59, 40, 68, 45, 83, 51, 100, 58, 118, 64, 132, 69, 142, 71, 149, 73, 156, 76, 158, 77, 160, 77, 159, 80, 151, 82, 137, 84, 122, 86, 111, 90, 91, 91, 78, 91, 68, 91, 63, 92, 61, 97, 61, 111, 61, 132, 61, 150, 61, 162, 61])); - cb("w", new Uint8Array([33, 58, 34, 81, 39, 127, 44, 151, 48, 161, 52, 162, 57, 154, 61, 136, 65, 115, 70, 95, 76, 95, 93, 121, 110, 146, 119, 151, 130, 129, 138, 84, 140, 56, 140, 45])); + cb("w", new Uint8Array([25, 46, 25, 82, 25, 119, 33, 143, 43, 153, 60, 147, 73, 118, 75, 91, 76, 88, 85, 109, 96, 134, 107, 143, 118, 137, 129, 112, 134, 81, 134, 64, 134, 55])); cb("x", new Uint8Array([56, 63, 56, 67, 57, 74, 60, 89, 66, 109, 74, 129, 85, 145, 96, 158, 107, 164, 117, 167, 128, 164, 141, 155, 151, 140, 159, 122, 166, 105, 168, 89, 170, 81, 170, 73, 169, 66, 161, 63, 141, 68, 110, 83, 77, 110, 55, 134, 47, 145])); cb("y", new Uint8Array([42, 56, 42, 70, 48, 97, 62, 109, 85, 106, 109, 90, 126, 65, 134, 47, 137, 45, 137, 75, 127, 125, 98, 141, 70, 133, 65, 126, 92, 137, 132, 156, 149, 166])); cb("z", new Uint8Array([29, 62, 35, 62, 43, 62, 63, 62, 87, 62, 110, 62, 125, 62, 134, 62, 138, 62, 136, 63, 122, 68, 103, 77, 85, 91, 70, 107, 59, 120, 50, 132, 47, 138, 43, 143, 41, 148, 42, 151, 53, 155, 80, 157, 116, 158, 146, 158, 163, 158])); cb("SHIFT", new Uint8Array([100, 160, 100, 50])); } else if (mode === exports.INPUT_MODE_NUM) { - cb("0", new Uint8Array([127, 67, 125, 67, 121, 67, 111, 67, 98, 67, 83, 68, 72, 70, 64, 74, 58, 79, 54, 86, 51, 96, 50, 107, 50, 116, 50, 125, 53, 132, 59, 141, 66, 146, 75, 150, 93, 155, 112, 157, 132, 154, 147, 146, 158, 126, 160, 113, 159, 103, 155, 94, 149, 89, 142, 85])); + cb("0", new Uint8Array([82, 50, 76, 50, 67, 50, 59, 50, 50, 51, 43, 57, 38, 68, 34, 83, 33, 95, 33, 108, 34, 121, 42, 136, 57, 148, 72, 155, 85, 157, 98, 155, 110, 149, 120, 139, 128, 127, 134, 119, 137, 114, 138, 107, 138, 98, 138, 88, 138, 77, 137, 71, 134, 65, 128, 60, 123, 58])); cb("1", new Uint8Array([100, 50, 100, 160])); - cb("2", new Uint8Array([63, 80, 65, 78, 68, 75, 72, 71, 79, 67, 87, 62, 97, 59, 106, 58, 115, 58, 122, 58, 126, 61, 128, 66, 129, 72, 127, 84, 123, 100, 115, 116, 110, 126, 103, 136, 95, 146, 93, 149, 98, 150, 114, 150, 136, 150, 154, 150])); - cb("3", new Uint8Array([100, 62, 102, 62, 105, 62, 109, 62, 114, 62, 121, 62, 127, 62, 131, 62, 135, 62, 137, 63, 138, 66, 138, 68, 138, 70, 137, 72, 135, 74, 133, 77, 132, 79, 129, 81, 126, 84, 123, 86, 119, 86, 122, 90, 129, 93, 142, 101, 150, 107, 154, 117, 154, 126, 150, 135, 142, 142, 131, 147, 122, 150])); - cb("4", new Uint8Array([93, 61, 93, 63, 93, 68, 93, 75, 93, 84, 93, 93, 93, 101, 93, 113, 93, 126, 93, 137, 93, 144, 93, 149, 93, 151, 93, 154, 93, 156, 94, 157, 96, 157, 103, 157, 120, 157, 141, 157, 161, 157, 176, 157, 182, 157, 185, 157])); - cb("5", new Uint8Array([151, 57, 144, 55, 130, 55, 110, 56, 94, 59, 83, 61, 78, 69, 78, 78, 78, 86, 78, 93, 83, 100, 103, 103, 127, 106, 143, 114, 148, 128, 141, 142, 125, 152, 107, 159, 90, 162, 81, 163])); - cb("6", new Uint8Array([147, 35, 145, 35, 141, 36, 136, 38, 130, 42, 123, 47, 115, 51, 106, 57, 97, 64, 88, 73, 81, 82, 76, 89, 73, 95, 71, 101, 70, 108, 70, 114, 70, 118, 71, 124, 74, 131, 80, 137, 87, 140, 96, 143, 103, 143, 108, 141, 113, 138, 116, 134, 118, 127, 118, 120, 118, 114, 116, 107, 113, 103, 109, 100])); - cb("7", new Uint8Array([66, 69, 69, 69, 75, 67, 83, 66, 95, 66, 108, 63, 121, 61, 132, 61, 141, 61, 147, 61, 151, 61, 154, 61, 156, 61, 158, 61, 160, 61, 162, 61, 162, 63, 161, 67, 156, 85, 147, 112, 137, 135, 129, 151, 124, 158])); - cb("8", new Uint8Array([148, 59, 145, 55, 137, 52, 125, 52, 112, 52, 100, 54, 92, 56, 84, 60, 81, 66, 81, 76, 90, 82, 109, 90, 128, 98, 136, 106, 137, 121, 126, 140, 107, 151, 92, 151, 81, 143, 81, 122, 92, 94, 108, 75, 124, 65])); - cb("9", new Uint8Array([129, 72, 127, 72, 125, 72, 122, 72, 117, 72, 111, 72, 104, 74, 100, 77, 95, 79, 94, 81, 94, 83, 94, 87, 96, 90, 101, 92, 105, 94, 111, 94, 115, 94, 121, 92, 130, 89, 136, 85, 140, 82, 144, 79, 146, 79, 147, 83, 149, 97, 149, 118, 149, 135, 149, 149, 149, 158])); + cb("2", new Uint8Array([40, 88, 40, 83, 40, 76, 43, 71, 47, 64, 55, 59, 64, 55, 73, 50, 80, 47, 91, 44, 104, 44, 117, 45, 128, 50, 135, 57, 142, 63, 145, 74, 145, 84, 140, 94, 129, 112, 108, 133, 87, 149, 71, 159, 58, 165, 52, 169, 55, 169, 63, 169, 77, 169, 89, 169, 100, 169, 110, 169, 116, 169])); + cb("3", new Uint8Array([52, 58, 65, 49, 83, 42, 100, 42, 118, 47, 136, 58, 143, 71, 135, 88, 125, 99, 114, 101, 119, 101, 132, 110, 142, 121, 145, 137, 139, 152, 122, 164, 106, 168, 92, 168, 74, 168, 55, 168])); + cb("4", new Uint8Array([37, 58, 37, 60, 37, 64, 37, 69, 37, 75, 37, 86, 37, 96, 37, 105, 37, 112, 37, 117, 37, 122, 37, 126, 37, 128, 38, 129, 40, 129, 45, 129, 48, 129, 53, 129, 67, 129, 85, 129, 104, 129, 119, 129, 129, 129, 136, 129])); + cb("5", new Uint8Array([142, 60, 119, 60, 79, 60, 45, 60, 37, 64, 37, 86, 37, 103, 47, 107, 66, 106, 81, 103, 97, 103, 116, 103, 129, 108, 131, 130, 122, 152, 101, 168, 85, 172, 70, 172, 59, 172])); + cb("6", new Uint8Array([128, 56, 110, 56, 81, 56, 58, 61, 47, 77, 41, 101, 41, 123, 41, 154, 50, 168, 71, 169, 98, 169, 123, 161, 131, 141, 129, 124, 117, 117, 102, 117, 92, 117, 85, 118, 77, 125])); + cb("7", new Uint8Array([47, 38, 48, 38, 53, 38, 66, 38, 85, 38, 103, 38, 117, 38, 125, 38, 129, 38, 134, 41, 135, 47, 135, 54, 135, 66, 131, 93, 124, 126, 116, 149, 109, 161, 105, 168])); + cb("8", new Uint8Array([122, 61, 102, 61, 83, 61, 60, 61, 47, 62, 45, 78, 58, 99, 84, 112, 105, 122, 118, 134, 121, 149, 113, 165, 86, 171, 59, 171, 47, 164, 45, 144, 50, 132, 57, 125, 67, 117, 78, 109, 87, 102, 96, 94, 105, 86, 113, 85])); + cb("9", new Uint8Array([122, 58, 117, 55, 112, 51, 104, 51, 95, 51, 86, 51, 77, 51, 68, 51, 60, 51, 54, 56, 47, 64, 46, 77, 46, 89, 46, 96, 51, 103, 64, 109, 74, 110, 83, 110, 94, 107, 106, 102, 116, 94, 124, 84, 127, 79, 128, 78, 128, 94, 128, 123, 128, 161, 128, 175])); } cb("\b", new Uint8Array([183, 103, 182, 103, 180, 103, 176, 103, 169, 103, 159, 103, 147, 103, 133, 103, 116, 103, 101, 103, 85, 103, 73, 103, 61, 103, 52, 103, 38, 103, 34, 103, 29, 103, 27, 103, 26, 103, 25, 103, 24, 103])); cb(" ", new Uint8Array([39, 118, 40, 118, 41, 118, 44, 118, 47, 118, 52, 118, 58, 118, 66, 118, 74, 118, 84, 118, 94, 118, 104, 117, 114, 116, 123, 116, 130, 116, 144, 116, 149, 116, 154, 116, 158, 116, 161, 116, 163, 116])); @@ -146,7 +146,7 @@ exports.input = function(options) { && e.y>=rect.y && e.y<=rect.y+rect.h; } - function isStrokeInAppRect(stroke, rect) { + function isStrokeInside(rect, stroke) { for(let i=0; i < stroke.length; i+=2) { if (!isInside(rect, {x: stroke[i], y: stroke[i+1]})) { return false; @@ -162,7 +162,7 @@ exports.input = function(options) { flashToggle = !flashToggle; draw(false); }, 1000); - if (o.stroke!==undefined && o.xy.length >= 6 && isStrokeInAppRect(o.xy, R)) { + if (o.stroke!==undefined && o.xy.length >= 6 && isStrokeInside(R, o.xy)) { var ch = o.stroke; if (ch=="\b") text = text.slice(0,-1); else if (ch==="SHIFT") { shift=!shift; Bangle.drawWidgets(); } From 999e47a55012040ac390de81908e1daefc5c6acf Mon Sep 17 00:00:00 2001 From: Hugh Barney Date: Sun, 4 Dec 2022 14:24:45 +0000 Subject: [PATCH 041/110] Updted slopeclkpp README --- apps/slopeclockpp/ChangeLog | 1 + apps/slopeclockpp/README.md | 2 ++ apps/slopeclockpp/metadata.json | 2 +- 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/slopeclockpp/ChangeLog b/apps/slopeclockpp/ChangeLog index 9ae4ccc96..eef1840ea 100644 --- a/apps/slopeclockpp/ChangeLog +++ b/apps/slopeclockpp/ChangeLog @@ -6,3 +6,4 @@ Allowed black/white background (as that can look nice too) 0.05: Images in clkinfo are optional now 0.06: Added support for locale based time +0.07: README file update as UI interaction was not easy to understand diff --git a/apps/slopeclockpp/README.md b/apps/slopeclockpp/README.md index 9352db685..8aad8467b 100644 --- a/apps/slopeclockpp/README.md +++ b/apps/slopeclockpp/README.md @@ -10,6 +10,8 @@ to change (top right or bottom left). It should change color showing it is selected. * Swipe up or down to cycle through the info screens that can be displayed + when you have finnised tap again towards the centre of the screen to unselect. + * Swipe left or right to change the type of info screens displayed (by default there is only one type of data so this will have no effect) diff --git a/apps/slopeclockpp/metadata.json b/apps/slopeclockpp/metadata.json index bebed4b71..3243d389a 100644 --- a/apps/slopeclockpp/metadata.json +++ b/apps/slopeclockpp/metadata.json @@ -1,6 +1,6 @@ { "id": "slopeclockpp", "name": "Slope Clock ++", - "version":"0.06", + "version":"0.07", "description": "A clock where hours and minutes are divided by a sloping line. When the minute changes, the numbers slide off the screen. This is a clone of the original Slope Clock which shows extra information and allows the colors to be selected.", "icon": "app.png", "screenshots": [{"url":"screenshot.png"}], From fa70e5354c6df1485b546900123022c2a5a930a4 Mon Sep 17 00:00:00 2001 From: David Peer Date: Sun, 4 Dec 2022 16:42:24 +0100 Subject: [PATCH 042/110] aiclock -- support clkinfo module and updated icons of some clkinfos... --- apps/aiclock/ChangeLog | 1 + apps/aiclock/README.md | 4 +- apps/aiclock/aiclock.app.js | 285 +++++++++++++++++++++++++++++++----- apps/aiclock/impl.png | Bin 2743 -> 2597 bytes apps/aiclock/impl_2.png | Bin 0 -> 2459 bytes apps/aiclock/impl_3.png | Bin 0 -> 2487 bytes apps/aiclock/metadata.json | 6 +- apps/ha/ChangeLog | 3 +- apps/ha/ha.clkinfo.js | 2 +- apps/ha/metadata.json | 2 +- apps/smpltmr/ChangeLog | 3 +- apps/smpltmr/clkinfo.js | 3 +- apps/smpltmr/metadata.json | 2 +- apps/weather/ChangeLog | 1 + apps/weather/clkinfo.js | 2 +- apps/weather/metadata.json | 2 +- core | 2 +- modules/clock_info.js | 2 +- 18 files changed, 270 insertions(+), 50 deletions(-) create mode 100644 apps/aiclock/impl_2.png create mode 100644 apps/aiclock/impl_3.png diff --git a/apps/aiclock/ChangeLog b/apps/aiclock/ChangeLog index 96b389f6e..fb5aed3e3 100644 --- a/apps/aiclock/ChangeLog +++ b/apps/aiclock/ChangeLog @@ -2,3 +2,4 @@ 0.02: Design improvements and fixes. 0.03: Indicate battery level through line occurrence. 0.04: Use widget_utils module. +0.05: Support for clkinfo. \ No newline at end of file diff --git a/apps/aiclock/README.md b/apps/aiclock/README.md index 9e23de3a6..31dd5aa29 100644 --- a/apps/aiclock/README.md +++ b/apps/aiclock/README.md @@ -10,7 +10,9 @@ The original output of stable diffusion is shown here: My implementation is shown below. Note that horizontal lines occur randomly, but the probability is correlated with the battery level. So if your screen contains only -a few lines its time to charge your bangle again ;) +a few lines its time to charge your bangle again ;) Also note that the upper text +implementes the clkinfo module and can be configured via touch left/right/up/down. +Touch at the center to trigger the selected action. ![](impl.png) diff --git a/apps/aiclock/aiclock.app.js b/apps/aiclock/aiclock.app.js index 5d4e98fcd..b5bb30b9d 100644 --- a/apps/aiclock/aiclock.app.js +++ b/apps/aiclock/aiclock.app.js @@ -1,6 +1,14 @@ -/** +/************************************************ * AI Clock */ + const storage = require('Storage'); + const clock_info = require("clock_info"); + + + + /************************************************ + * Assets + */ require("Font7x11Numeric7Seg").add(Graphics); Graphics.prototype.setFontGochiHand = function(scale) { // Actual height 27 (29 - 3) @@ -13,7 +21,7 @@ Graphics.prototype.setFontGochiHand = function(scale) { return this; } -/* +/************************************************ * Set some important constants such as width, height and center */ var W = g.getWidth(),R=W/2; @@ -21,6 +29,120 @@ var H = g.getHeight(); var cx = W/2; var cy = H/2; var drawTimeout; +var lock_input = false; + + +/************************************************ + * SETTINGS + */ +const SETTINGS_FILE = "aiclock.setting.json"; +let settings = { + menuPosX: 0, + menuPosY: 0, +}; +let saved_settings = storage.readJSON(SETTINGS_FILE, 1) || settings; +for (const key in saved_settings) { + settings[key] = saved_settings[key] +} + + +/************************************************ + * Menu + */ +function getDate(){ + var date = new Date(); + return ("0"+date.getDate()).substr(-2) + "/" + ("0"+(date.getMonth()+1)).substr(-2) +} + + +// Custom clockItems menu - therefore, its added here and not in a clkinfo.js file. +var clockItems = { + name: getDate(), + img: null, + items: [ + { name: "Week", + get: () => ({ text: "Week " + weekOfYear(), img: null}), + show: function() { clockItems.items[0].emit("redraw"); }, + hide: function () {} + }, + ] + }; + +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); +} + + + +// Load menu +var menu = clock_info.load(); +menu = menu.concat(clockItems); + + + // 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) => { + menuItm.items.forEach((item, y) => { + function drawItem() { + // 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(); + + // After drawing the item, we enable inputs again... + lock_input = false; + + var info = item.get(); + drawMenuItem(info.text, info.img); + } + + item.on('redraw', drawItem); + }) + }); + + + function canRunMenuItem(){ + if(settings.menuPosY == 0){ + return false; + } + + 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{ + var ret = item.run(); + if(ret){ + Bangle.buzz(300, 0.6); + } + } catch (ex) { + // Simply ignore it... + } + } + /* * Based on the great multi clock from https://github.com/jeffmer/BangleApps/ @@ -76,7 +198,50 @@ function toAngle(a){ return a } + +function drawMenuItem(text, image){ + if(text == null){ + drawTime(); + return + } + // image = atob("GBiBAAD+AAH+AAH+AAH+AAH/AAOHAAYBgAwAwBgwYBgwYBgwIBAwOBAwOBgYIBgMYBgAYAwAwAYBgAOHAAH/AAH+AAH+AAH+AAD+AA=="); + + text = String(text); + + g.reset().setBgColor("#fff").setColor("#000"); + g.setFontAlign(0,0); + g.setFont("Vector", 20); + + var imgWidth = image == null ? 0 : 24; + var strWidth = g.stringWidth(text); + var strHeight = text.split('\n').length > 1 ? 40 : Math.max(24, imgWidth+2); + var w = imgWidth + strWidth; + + g.clearRect(cx-w/2-8, 40-strHeight/2-1, cx+w/2+4, 40+strHeight/2) + + // Draw right line as designed by stable diffusion + g.drawLine(cx+w/2+5, 40-strHeight/2-1, cx+w/2+5, 40+strHeight/2); + g.drawLine(cx+w/2+6, 40-strHeight/2-1, cx+w/2+6, 40+strHeight/2); + g.drawLine(cx+w/2+7, 40-strHeight/2-1, cx+w/2+7, 40+strHeight/2); + + // And finally the text + g.drawString(text, cx+imgWidth/2, 42); + g.drawString(text, cx+1+imgWidth/2, 41); + + if(image != null) { + var scale = image.width ? imgWidth / image.width : 1; + g.drawImage(image, W/2 + -strWidth/2-4 - parseInt(imgWidth/2), 41-12, {scale: scale}); + } + + drawTime(); +} + + function drawTime(){ + // Draw digital time first + drawDigits(); + + // And now the analog time var drawHourHand = g.drawRotRect.bind(g,8,12,R-38); var drawMinuteHand = g.drawRotRect.bind(g,6,12,R-12 ); @@ -90,13 +255,6 @@ function drawTime(){ h += date.getMinutes()/60.0; h = parseInt(h*360/12); - // Draw minute and hour bg - g.setColor(g.theme.bg); - drawHourHand(toAngle(h-3)); - drawHourHand(toAngle(h+3)); - drawMinuteHand(toAngle(m-2)); - drawMinuteHand(toAngle(m+3)); - // Draw minute and hour fg g.setColor(g.theme.fg); drawHourHand(h); @@ -104,28 +262,6 @@ function drawTime(){ } - -function drawDate(){ - var date = new Date(); - g.setFontAlign(0,0); - g.setFontGochiHand(); - - var text = ("0"+date.getDate()).substr(-2) + "/" + ("0"+(date.getMonth()+1)).substr(-2); - var w = g.stringWidth(text); - g.setColor(g.theme.bg); - g.fillRect(cx-w/2-4, 20, cx+w/2+4, 40+12); - - g.setColor(g.theme.fg); - // Draw right line as designed by stable diffusion - g.drawLine(cx+w/2+5, 20, cx+w/2+5, 40+12); - g.drawLine(cx+w/2+6, 20, cx+w/2+6, 40+12); - g.drawLine(cx+w/2+7, 20, cx+w/2+7, 40+12); - - // And finally the text - g.drawString(text, cx, 40); -} - - function drawDigits(){ var date = new Date(); @@ -156,20 +292,35 @@ function drawDigits(){ } +function drawDate(){ + 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 + lock_input = true; + var item = menuEntry.items[settings.menuPosY-1]; + item.show(); +} + + + + function draw(){ // Queue draw in one minute queueDraw(); - g.reset(); g.clearRect(0, 0, g.getWidth(), g.getHeight()); - g.setColor(1,1,1); + drawBackground(); drawDate(); - drawDigits(); - drawTime(); drawCircle(Bangle.isLocked()); } @@ -190,6 +341,68 @@ Bangle.on('lock', function(isLocked) { drawCircle(isLocked); }); +Bangle.on('touch', function(btn, e){ + var left = parseInt(g.getWidth() * 0.22); + var right = g.getWidth() - left; + var upper = parseInt(g.getHeight() * 0.22); + var lower = g.getHeight() - upper; + + var is_upper = e.y < upper; + var is_lower = e.y > lower; + var is_left = e.x < left && !is_upper && !is_lower; + 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); + + draw(); + } + + if(is_upper){ + Bangle.buzz(40, 0.6); + settings.menuPosY = settings.menuPosY-1; + settings.menuPosY = settings.menuPosY < 0 ? menu[settings.menuPosX].items.length : settings.menuPosY; + + draw(); + } + + if(is_right){ + Bangle.buzz(40, 0.6); + settings.menuPosX = (settings.menuPosX+1) % menu.length; + settings.menuPosY = 0; + draw(); + } + + if(is_left){ + Bangle.buzz(40, 0.6); + settings.menuPosY = 0; + settings.menuPosX = settings.menuPosX-1; + settings.menuPosX = settings.menuPosX < 0 ? menu.length-1 : settings.menuPosX; + draw(); + } + + if(is_center){ + if(canRunMenuItem()){ + runMenuItem(); + } + } +}); + + +E.on("kill", function(){ + try{ + storage.write(SETTINGS_FILE, settings); + } catch(ex){ + // If this fails, we still kill the app... + } +}); + /* * Some helpers @@ -203,7 +416,6 @@ function queueDraw() { } - /* * Lets start widgets, listen for btn etc. */ @@ -216,6 +428,7 @@ Bangle.loadWidgets(); * area to the top bar doesn't get cleared. */ require('widget_utils').hide(); + // Clear the screen once, at startup and draw clock g.setTheme({bg:"#fff",fg:"#000",dark:false}).clear(); draw(); diff --git a/apps/aiclock/impl.png b/apps/aiclock/impl.png index 92374b68059bb87f00feb41525d8b6dcb9d91c87..8a9e43e2deabf9a80b9cc59b763db5bf3bf15a47 100644 GIT binary patch delta 2576 zcmV+r3h(u|6{QrAFnz3oV3Pw}!|Il@oGsit1w=6C~Hdwp<%<2gc z^s$ApoK*e%{{H@c_(6f93j6?Y(aMqbR{;P9gwhHCaOv`q{Lkm}VFreSvI+oj+0v2t zcLt^d143m5n1L%-kK8$hfPvZy(1B~$Z~5#2czFbB3jn~i>wmX=_5i#*0<{GI;M(Bv<17Kqr z=)gw7CYz@RxPSWZM(YX8W*DdYsBcC+OW(vv-65mk<4D~b0e~m!4Zst{{eNfxo~ZFm zfGdwCd+rfeAOL<4;O(tFMU*ziz9diViE?~HM*|lfFM9oDXW*W&qoM=wznG0`84c_? zUP*wpmq@MMU!oWe@3VE`XyBsbMFU+9U@MeXd+9QK?tjhz9F3$cUMYZkFnV8W$)z1n zq#65|Q!8fcbOFg#27m)M z+(?(*d^O$eJVNx+Z^e_q+`G2cZhwER{S|PM|CKfX91O4|wDh`k*|z}PiY0*pz=1$y z{1XGx<$p{9RC+xc;A1>(_v>BiTQ`ZLaW$LjN*AqfESCCcr9Mt6-F!$RhG&G(j0wBV zC}^$j9|5}-Ld{zBXx(G^Du9mw9E%}=-@93|bo9yqYu0%WlD2nw%_&50*-rp`HCnW0 z;MQi_*V8(&Xm$Kv+}2p4#e|zUtx`%mFO1spVSnT%&T^^tc5CTWq!m}nOSA(^N&ewawj*2dIEa@bp=YPKZ_Z~KA zA4Igq4bA3~8o+tuXzZQkbi0-8z?M##QFKqWq)jzzoukdbvsR1Gs{x)>RExk7wi3M3 z6@OtQ2LK*XPwRjGH?u0;8g%?&R;`RBS;zrUIVanA~Ex*DNQvOOeEc>(H5)$ zOCC@FfCt3G^?3yV`1u-;!GHpMfAWlM}GmTdQ zOgDDYP|)qQ00VJB8XYOW8ekxH5K+wK^#B8LF(QrWE&(tQ8>uK{z6`)XT!>0Ts!IV3 z#0D~om@Wq}5Emg+nI?~tl|o^bQvm?ZSr@WWDgeMrp)kv-z>+g?s}z>cPi+2thJPXl z&;Wd>0}$tc(vk%LpVR_k3qH@=0&t@SBM@tR89(B{2jB}WH6V_b0gy)({Cohoqv0J8 zb3-@=F#rqt0r41Mv%LXWsqh^jGg2svaXdNNjx_CVc%VQI1$YuSp$@%{unEpjoB{wG zr{y=2=5hwaaiTK=8@25I0zpHp9)HBl!g?VASg+OB@(N&0=RLpG6~q9nFA4zbwE|$H zR(F^Kuu)|?uu-td<^XII7=Vp}O*RK$qrd=c6l}6N02>7cV54A@%>mdbFaR3`n{3X5 zj6i`cM`=9Fh!GxuV|4rzMFTPL#)%HVaayV%2Hse~nSq^p&iHsGPvGpu0DoY+X5A-p z&TwBh0Jf_Kz;@04ctmz#;Pn*(fPK1!Lkz&aLIAK&x4*nbyDI1t<91z?+AA=ce*b^K}`g@mN>iXZ^|P#J+ZMtA^@(a{_QfX$LM9RN5+ zM^_XecFFc1CjcJT&>aDQ-G9>kdk+80ZSS~>0}+6DK)mf+;s87*V1zdi`&9&Bzjk4s z0PL3%fc@HqdIGUeP5}1l7VZVWK1umThEF%Vk|+ScNeV$4J_P{SryE{L6krBUQix+3 z%)|Pk0I*)G+bjWCFEs$`wYt?3h;?!UuuiAjtpHdjIRNW)dc+EdWq;WLSk~wA3NZld>W5Y556f)gJk|XG7&O%iWbDFe09O8OKDF3hL#dN&f^9a| z|Mv2czT)2UmGbnifAjO?BXwaI8ewH%f{0d4$BXKIuJ1Hh-EnpV4tgyHO;&*PcQ= zH9|;mNd?iqZUJa^2iE31!!A9*+KzA*rwYJP>+8W`0a%-lWdqFscaO;oZ1{DinoILt z9oTY|WdT?VTbdb|QwaU<eQeKg-(}6!9P9cJC;;evbJ6`4)*t+IO`}6>N z7khPy8@cq2_-fXn?WmeqBQ~0uIZLi(06upr?Z2f$YUAv7QoNDZJy0BB^Z2*&Ed_A) zW3&+8uy)9!ed{c=RexaZH$6OsmI^ll+*RJvds<%a zou2G*0NA3a(zePegy!Lha>;+pdYeLmO`Ff``vL8m)6c-(yYy86Zs~J3z*^X5*rf;9 zyXdC?w!)+Bcvc;(dF=7E`HYM{*0uEP(*sBd{|CU41I|D!I`BW@S-UU*4?x#)r326Fz*}VL zK?vu-!9Z)nW$VBi5L!TK*W0~Q7rw>J2oa(3MT}}4*eZqglI=N#I6tYoiqZQ#g=XVP z4@az;SnSh3O13OU(@92v8S(7_DBW0jHR$QFzkkLE5ut7;#<>Gq{@p54)B$`{*NMod zmCI2lZ;5(qV#HtS%Sc@xlyMa``t~2tP5z~|Fs5Y1P5Gw;bOVkzOS~tclP11juXV$`r zJAbA?8i2EZ7Gg|hyk{wpW(Ee}StTa!9SWowA?{c#@9{nb0Qh}1U1~)Dyi~d0x7gQy z7UF%SVnrv;v$$lrA61{|_Zq!t()@0agG200{s|MNUMnLSTX!S;Yqc delta 2723 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 literal 0 HcmV?d00001 diff --git a/apps/aiclock/impl_3.png b/apps/aiclock/impl_3.png new file mode 100644 index 0000000000000000000000000000000000000000..c2a036d14b24b0ac1cc982f108f92039254b97f9 GIT binary patch literal 2487 zcmai0X*AUP8~@IX8QG9x(IOhMg~=AlGJ`BB{O6u?-`yAg=bUGG^Ld_go;}gh!dOgrzc2tm%+$olny;Dv z@GcZzR@6?p@D(h?+Sm}3cgfEJAQWV3WMD&fS)j9ni_VA|-P_suGLkbwSAFyR$uIW} zs=8Tz{)z`mejG~v{T?@;Pa4|~^sSIASlyG5qODQ@5QbNgpzi7Q!xGSOOGg;M_#b?Y zI4+ug1yIa}jhBHaqF8!kdvkN*{DrF`>lO->^|hAhRp7*FZ5APlHP!BXE)^VGmRWQL zfV&X${VS}lDLzUTKv6$jS&;w}FwQ{&9%nnVLV@y@P)CA+|3bdY6#NInL~&m2aJhCZ zn>*dAXa5qS!0MjDfzwC4>vAYD-(|MI?$mqbi^P;IcUW^Gh(|CNPbv>1;&7vE>K3Z~p^l6Q~p_5!pN4Rwqt2*S#aTZsKvvIN` zQ-GXt&@UKS;JK}qpy$kaGrMc-*x7(4WZ*N4;kTr0?I4*r4rYGgit>u<^C@S%6Jt(K z)<7D9ZA>w2JUR-HoCZ)fsX+NqPZJ<#eoA{7Zqj{XY}b(Q$P$KV5Qc0bk=o7-;4Wdi zLY8#VjW5rQn0ZK>W4lgt#hzcdl~>H}v@d0;b-?PrtGoL=t`QX=nms(-Q46aZh>xn> zIvK$bAHW>t?BrFZ^j{YyMgQ*QY!mX==DZpK=4Xm4{ZS*Egba*odRIsqCsV(*6Cyoz zSieAe`gkE;#&=NWx_{WOkgk`QKRR)CRgyH{lO`@d`{?Vj zK7c#bc)$&WXDw;$rOC&F@A(dl)? z$W!RF3pYwFxqDB}1k)*2agcLpbetPEEm7AK1DC2~DMy56b5Rs}>}o5FeD|-e ztM-T} z$TLItve--1^h`7yg84GG2(0*B3H#;Ykk$CL4U4Q%!4^3%KQK><>x)?utsG6IG=92{+}CvX?{u`+MpD8Uk1jYqKvb$|1K%^FQZGePf*fFE zrxy?9C}b0s22kh?AfGZz)D#+u-`9JGEy3>!i38AV$6hd|xwUVL$@g|pYm6M(|Ki3; zFjz6fP#(EMz zk5)em&i?uMdN552_+7rM3s3lgVpH$E_+fFUxUJp_I0=l|<>>z$Py;S}OAfcKAr3GC zfsZiJO$T%%#zCMarCMJULOy?eH~5xw;wjKVvye-USk_8^cq2gk(m6l+C&Hyu_;-Q} zGLXh|7fnt}MOl3hi3#Df zgK3kV3KNT84)5Nh3j2w2TcejY6GloBkzsNahT+Fa_1q4^-=uPvpMH}{vgy`IN4oQ_ z*=MQk_+MYjO6$l*fV%VA{RZ zk1oEggUq4`j4I|OT^Q2H3sN+mGiyPm;)}U(W)GFYs5(XlI+0h!Qlt0_dQoe6f@qm~ z_C+5?6uSAwZVt*v>GV+V;BYiO;CD2%H|PvgrK~Tp7m>SVdjh?&zb#FCWKkuTZVIz+ zv{_8NxTAX7Q44Kv*VQ<01r2oLWwI5BXL!x%K}U(lT&R?l__m*FE15TPS#PfFBInX{ zC!ROOr8aA~apE6!ooql|>n@xQNk$O+)Qv|jqX*L_0-gvblQ@4g5~sop4qf*X_UcKU31U&$<_ioG|f#2dMKr6#(3>Jb9>`?pYzyRp@8 zmc1n?9=hR~Sw0S18Ev{F=`DRccw~5KQA?G8|N1hf7LyrK){vqF*K+qq_NXaVwOp(z zK0G1BKdVWN!R9+Ei{-7^By$*l^zX2L<&{GH5<$l;U16Y{JKir1c>QYw8VZ!TsJbvD zXnMA_nj|>3sc_911_JzJwkBY8tlI=T01<{=Tgd+h@;oMQ+ka;FxJo$x69cB_EsV+y HiLw6!gEO)t literal 0 HcmV?d00001 diff --git a/apps/aiclock/metadata.json b/apps/aiclock/metadata.json index 0da23e8ca..1c3c68609 100644 --- a/apps/aiclock/metadata.json +++ b/apps/aiclock/metadata.json @@ -3,7 +3,7 @@ "name": "AI Clock", "shortName":"AI Clock", "icon": "aiclock.png", - "version":"0.04", + "version":"0.05", "readme": "README.md", "supports": ["BANGLEJS2"], "description": "A watch face that was designed by an AI (stable diffusion) and implemented by a human.", @@ -11,7 +11,9 @@ "tags": "clock", "screenshots": [ {"url":"orig.png"}, - {"url":"impl.png"} + {"url":"impl.png"}, + {"url":"impl_2.png"}, + {"url":"impl_3.png"}, ], "storage": [ {"name":"aiclock.app.js","url":"aiclock.app.js"}, diff --git a/apps/ha/ChangeLog b/apps/ha/ChangeLog index a4865be3f..f9ca3c16d 100644 --- a/apps/ha/ChangeLog +++ b/apps/ha/ChangeLog @@ -2,4 +2,5 @@ 0.02: Includeas the ha.lib.js library that can be used by other apps or clocks. 0.03: Added clkinfo for clocks. 0.04: Feedback if clkinfo run is called. -0.05: Clkinfo improvements. \ No newline at end of file +0.05: Clkinfo improvements. +0.06: Updated clkinfo icon. \ No newline at end of file diff --git a/apps/ha/ha.clkinfo.js b/apps/ha/ha.clkinfo.js index 1b1e468d7..d6a0f72a0 100644 --- a/apps/ha/ha.clkinfo.js +++ b/apps/ha/ha.clkinfo.js @@ -4,7 +4,7 @@ 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=="), + img: atob("GBiBAAAAAAAAAAAAAAAYAAA+AAB+AADD4AHb4APD4Afn8A/n+BxmOD0mnA0ksAwAMA+B8A/D8A/n8A/n8A/n8A/n8AAAAAAAAAAAAA=="), items: [] }; diff --git a/apps/ha/metadata.json b/apps/ha/metadata.json index fad052544..089450f55 100644 --- a/apps/ha/metadata.json +++ b/apps/ha/metadata.json @@ -1,7 +1,7 @@ { "id": "ha", "name": "HomeAssistant", - "version": "0.05", + "version": "0.06", "description": "Integrates your BangleJS into HomeAssistant.", "icon": "ha.png", "type": "app", diff --git a/apps/smpltmr/ChangeLog b/apps/smpltmr/ChangeLog index b09100f50..805e8546f 100644 --- a/apps/smpltmr/ChangeLog +++ b/apps/smpltmr/ChangeLog @@ -1,4 +1,5 @@ 0.01: Release 0.02: Rewrite with new interface 0.03: Added clock infos to expose timer functionality to clocks. -0.04: Improvements of clock infos. \ No newline at end of file +0.04: Improvements of clock infos. +0.05: Updated clkinfo icon. \ No newline at end of file diff --git a/apps/smpltmr/clkinfo.js b/apps/smpltmr/clkinfo.js index 1a63a9b7e..c16e6127e 100644 --- a/apps/smpltmr/clkinfo.js +++ b/apps/smpltmr/clkinfo.js @@ -63,10 +63,9 @@ } catch(ex){ } } - var img = atob("GBiBAeAAB+AAB/v/3/v/3/v/3/v/3/v/n/n/H/z+P/48//85//+b//+b//8p//4E//yCP/kBH/oAn/oAX/oAX/oAX/oAX+AAB+AABw==") var smpltmrItems = { name: "Timer", - img: img, + img: atob("GBiBAAB+AAB+AAAYAAAYAAB+AA3/sA+B8A4AcAwMMBgPGBgPmDAPjDAPzDAPzDP/zDP/zDH/jBn/mBj/GAw8MA4AcAeB4AH/gAB+AA=="), items: [ { name: null, diff --git a/apps/smpltmr/metadata.json b/apps/smpltmr/metadata.json index ce526d1ba..2191902de 100644 --- a/apps/smpltmr/metadata.json +++ b/apps/smpltmr/metadata.json @@ -2,7 +2,7 @@ "id": "smpltmr", "name": "Simple Timer", "shortName": "Simple Timer", - "version": "0.04", + "version": "0.05", "description": "A very simple app to start a timer.", "icon": "app.png", "tags": "tool,alarm,timer,clkinfo", diff --git a/apps/weather/ChangeLog b/apps/weather/ChangeLog index aefb903b9..1b6c1b9b5 100644 --- a/apps/weather/ChangeLog +++ b/apps/weather/ChangeLog @@ -17,3 +17,4 @@ 0.18: Added hasRange to clkinfo. 0.19: Added weather condition to clkinfo. 0.20: Added weather condition with temperature to clkinfo. +0.21: Updated clkinfo icon. \ No newline at end of file diff --git a/apps/weather/clkinfo.js b/apps/weather/clkinfo.js index 339ff39c3..3cdd31c59 100644 --- a/apps/weather/clkinfo.js +++ b/apps/weather/clkinfo.js @@ -28,7 +28,7 @@ //FIXME ranges are somehow arbitrary var weatherItems = { name: "Weather", - img: atob("GBiBAf+///u5//n7//8f/9wHP8gDf/gB//AB/7AH/5AcP/AQH/DwD/uAD84AD/4AA/wAAfAAAfAAAfAAAfgAA/////+bP/+zf/+zfw=="), + img: atob("GBiBAABAAARGAAYEAADgACP4wDf8gAf+AA/+AE/4AG/jwA/v4A8P8AR/8DH/8AH//AP//g///g///g///gf//AAAAABkwABMgABMgA=="), items: [ { name: "conditionWithTemperature", diff --git a/apps/weather/metadata.json b/apps/weather/metadata.json index dd8b6c293..500eac012 100644 --- a/apps/weather/metadata.json +++ b/apps/weather/metadata.json @@ -1,7 +1,7 @@ { "id": "weather", "name": "Weather", - "version": "0.20", + "version": "0.21", "description": "Show Gadgetbridge weather report", "icon": "icon.png", "screenshots": [{"url":"screenshot.png"}], diff --git a/core b/core index 3a953179b..764197500 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit 3a953179b7bb9f574d4e77d5f34b6b7deee1e884 +Subproject commit 76419750083a88ee7a569db3975ae1bdd6dc155a diff --git a/modules/clock_info.js b/modules/clock_info.js index 238888b1c..50968311e 100644 --- a/modules/clock_info.js +++ b/modules/clock_info.js @@ -77,7 +77,7 @@ exports.load = function() { // 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=="), + img: atob("GBiBAAD+AAH+AAH+AAH+AAH/AAOHAAYBgAwAwBgwYBgwYBgwIBAwOBAwOBgYIBgMYBgAYAwAwAYBgAOHAAH/AAH+AAH+AAH+AAD+AA=="), items: [ { name : "Battery", hasRange : true, From 3673a0d7cf33eea9efc9d14e2eb701e8b16afb98 Mon Sep 17 00:00:00 2001 From: David Peer Date: Sun, 4 Dec 2022 16:43:41 +0100 Subject: [PATCH 043/110] Fixed json file --- apps/aiclock/metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/aiclock/metadata.json b/apps/aiclock/metadata.json index 1c3c68609..1dcda427f 100644 --- a/apps/aiclock/metadata.json +++ b/apps/aiclock/metadata.json @@ -13,7 +13,7 @@ {"url":"orig.png"}, {"url":"impl.png"}, {"url":"impl_2.png"}, - {"url":"impl_3.png"}, + {"url":"impl_3.png"} ], "storage": [ {"name":"aiclock.app.js","url":"aiclock.app.js"}, From 8016e8ec5333ec8fe5ef4b8ea95b4a7428513bf6 Mon Sep 17 00:00:00 2001 From: Martin Boonk Date: Fri, 2 Dec 2022 23:53:32 +0100 Subject: [PATCH 044/110] bthrm - Correctly handle 0 values --- apps/bthrm/bthrm.js | 6 +++--- apps/bthrm/metadata.json | 1 + apps/bthrm/screen.png | Bin 0 -> 3702 bytes 3 files changed, 4 insertions(+), 3 deletions(-) create mode 100644 apps/bthrm/screen.png diff --git a/apps/bthrm/bthrm.js b/apps/bthrm/bthrm.js index e163dd8b7..b07e7bd37 100644 --- a/apps/bthrm/bthrm.js +++ b/apps/bthrm/bthrm.js @@ -93,11 +93,11 @@ function draw(){ if (bt && bt.time > (now - VALUE_TIMEOUT)) { layout.bt.label = bt.bpm; - if (bt.battery) layout.btBattery.label = bt.battery; + if (!isNaN(bt.battery)) layout.btBattery.label = bt.battery + "%"; if (bt.rr) layout.btRR.label = bt.rr.join(","); - if (bt.location) layout.btLocation.label = BODY_LOCS[bt.location]; + if (!isNaN(bt.location)) layout.btLocation.label = BODY_LOCS[bt.location]; if (bt.contact !== undefined) layout.btContact.label = bt.contact ? "Yes":"No"; - if (bt.energy) layout.btEnergy.label = bt.energy.toFixed(0) + "kJ"; + if (!isNaN(bt.energy)) layout.btEnergy.label = bt.energy.toFixed(0) + "kJ"; } else { layout.bt.label = "--"; layout.btBattery.label = "--"; diff --git a/apps/bthrm/metadata.json b/apps/bthrm/metadata.json index 0977fd755..fea274ff3 100644 --- a/apps/bthrm/metadata.json +++ b/apps/bthrm/metadata.json @@ -5,6 +5,7 @@ "version": "0.17", "description": "Overrides Bangle.js's build in heart rate monitor with an external Bluetooth one.", "icon": "app.png", + "screenshots": [{"url":"screen.png"}], "type": "app", "tags": "health,bluetooth,hrm,bthrm", "supports": ["BANGLEJS","BANGLEJS2"], diff --git a/apps/bthrm/screen.png b/apps/bthrm/screen.png new file mode 100644 index 0000000000000000000000000000000000000000..6b6b8522758de6d8a330fbe6184b59517f74360a GIT binary patch literal 3702 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 literal 0 HcmV?d00001 From 90e603b49d1b6fdc55cfc4d4cc3edd3e4389f7f9 Mon Sep 17 00:00:00 2001 From: Erik Andresen Date: Sun, 4 Dec 2022 19:44:17 +0100 Subject: [PATCH 045/110] kbswipe: Redo some patterns --- apps/kbswipe/ChangeLog | 2 +- apps/kbswipe/README.md | 2 ++ apps/kbswipe/lib.js | 10 +++++----- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/apps/kbswipe/ChangeLog b/apps/kbswipe/ChangeLog index 05be810cc..568db372e 100644 --- a/apps/kbswipe/ChangeLog +++ b/apps/kbswipe/ChangeLog @@ -3,4 +3,4 @@ 0.03: Positioning of marker now takes the height of the widget field into account. 0.04: Fix issue if going back without typing. 0.05: Keep drag-function in ram, hopefully improving performance and input reliability somewhat. -0.06: Support input of numbers +0.06: Support input of numbers and uppercase characters. diff --git a/apps/kbswipe/README.md b/apps/kbswipe/README.md index 1508061d1..c4c3fbd99 100644 --- a/apps/kbswipe/README.md +++ b/apps/kbswipe/README.md @@ -6,6 +6,8 @@ To get a legend of available characters, just tap the screen. To switch between the input of alphabetic and numeric characters tap the widget which displays either "123" or "ABC". +To switch between lowercase and uppercase characters do an up swipe. + ![](key.png) ## Usage diff --git a/apps/kbswipe/lib.js b/apps/kbswipe/lib.js index 981dc80db..75a434999 100644 --- a/apps/kbswipe/lib.js +++ b/apps/kbswipe/lib.js @@ -24,7 +24,7 @@ exports.getStrokes = function(mode, cb) { cb("m", new Uint8Array([49, 165, 48, 162, 46, 156, 44, 148, 42, 138, 42, 126, 42, 113, 43, 101, 45, 91, 47, 82, 49, 75, 51, 71, 54, 70, 57, 70, 61, 74, 69, 81, 75, 91, 84, 104, 94, 121, 101, 132, 103, 137, 106, 130, 110, 114, 116, 92, 125, 75, 134, 65, 139, 62, 144, 66, 148, 83, 151, 108, 155, 132, 157, 149])); cb("n", new Uint8Array([50, 165, 50, 160, 50, 153, 50, 140, 50, 122, 50, 103, 50, 83, 50, 65, 50, 52, 50, 45, 50, 43, 52, 52, 57, 67, 66, 90, 78, 112, 93, 131, 104, 143, 116, 152, 127, 159, 135, 160, 141, 150, 148, 125, 154, 96, 158, 71, 161, 56, 162, 49])); cb("o", new Uint8Array([107, 58, 104, 58, 97, 61, 87, 68, 75, 77, 65, 88, 58, 103, 54, 116, 53, 126, 55, 135, 61, 143, 75, 149, 91, 150, 106, 148, 119, 141, 137, 125, 143, 115, 146, 104, 146, 89, 142, 78, 130, 70, 116, 65, 104, 62])); - cb("p", new Uint8Array([52, 59, 52, 64, 54, 73, 58, 88, 61, 104, 65, 119, 67, 130, 69, 138, 71, 145, 71, 147, 71, 148, 71, 143, 70, 133, 68, 120, 67, 108, 67, 97, 67, 89, 68, 79, 72, 67, 83, 60, 99, 58, 118, 58, 136, 63, 146, 70, 148, 77, 145, 84, 136, 91, 121, 95, 106, 97, 93, 97, 82, 97])); + cb("p", new Uint8Array([29, 47, 29, 55, 29, 75, 29, 110, 29, 145, 29, 165, 29, 172, 29, 164, 30, 149, 37, 120, 50, 91, 61, 74, 72, 65, 85, 61, 103, 61, 118, 63, 126, 69, 129, 76, 130, 87, 126, 98, 112, 108, 97, 114, 87, 116])); cb("q", new Uint8Array([95, 59, 93, 59, 88, 59, 79, 59, 68, 61, 57, 67, 50, 77, 48, 89, 48, 103, 50, 117, 55, 130, 65, 140, 76, 145, 85, 146, 94, 144, 101, 140, 105, 136, 106, 127, 106, 113, 100, 98, 92, 86, 86, 79, 84, 75, 84, 72, 91, 69, 106, 67, 126, 67, 144, 67, 158, 67, 168, 67, 173, 67, 177, 67])); cb("r", new Uint8Array([53, 49, 53, 62, 53, 91, 53, 127, 53, 146, 53, 147, 53, 128, 53, 94, 53, 69, 62, 44, 82, 42, 94, 50, 92, 68, 82, 85, 77, 93, 80, 102, 95, 119, 114, 134, 129, 145, 137, 150])); cb("s", new Uint8Array([159, 72, 157, 70, 155, 68, 151, 66, 145, 63, 134, 60, 121, 58, 108, 56, 96, 55, 83, 55, 73, 55, 64, 56, 57, 60, 52, 65, 49, 71, 49, 76, 50, 81, 55, 87, 71, 94, 94, 100, 116, 104, 131, 108, 141, 114, 145, 124, 142, 135, 124, 146, 97, 153, 70, 157, 52, 158])); @@ -33,17 +33,17 @@ exports.getStrokes = function(mode, cb) { cb("v", new Uint8Array([36, 55, 37, 59, 40, 68, 45, 83, 51, 100, 58, 118, 64, 132, 69, 142, 71, 149, 73, 156, 76, 158, 77, 160, 77, 159, 80, 151, 82, 137, 84, 122, 86, 111, 90, 91, 91, 78, 91, 68, 91, 63, 92, 61, 97, 61, 111, 61, 132, 61, 150, 61, 162, 61])); cb("w", new Uint8Array([25, 46, 25, 82, 25, 119, 33, 143, 43, 153, 60, 147, 73, 118, 75, 91, 76, 88, 85, 109, 96, 134, 107, 143, 118, 137, 129, 112, 134, 81, 134, 64, 134, 55])); cb("x", new Uint8Array([56, 63, 56, 67, 57, 74, 60, 89, 66, 109, 74, 129, 85, 145, 96, 158, 107, 164, 117, 167, 128, 164, 141, 155, 151, 140, 159, 122, 166, 105, 168, 89, 170, 81, 170, 73, 169, 66, 161, 63, 141, 68, 110, 83, 77, 110, 55, 134, 47, 145])); - cb("y", new Uint8Array([42, 56, 42, 70, 48, 97, 62, 109, 85, 106, 109, 90, 126, 65, 134, 47, 137, 45, 137, 75, 127, 125, 98, 141, 70, 133, 65, 126, 92, 137, 132, 156, 149, 166])); + cb("y", new Uint8Array([30, 41, 30, 46, 30, 52, 30, 63, 30, 79, 33, 92, 38, 100, 47, 104, 54, 107, 66, 105, 79, 94, 88, 82, 92, 74, 94, 77, 96, 98, 96, 131, 94, 151, 91, 164, 85, 171, 75, 171, 71, 162, 74, 146, 84, 130, 95, 119, 106, 113])); cb("z", new Uint8Array([29, 62, 35, 62, 43, 62, 63, 62, 87, 62, 110, 62, 125, 62, 134, 62, 138, 62, 136, 63, 122, 68, 103, 77, 85, 91, 70, 107, 59, 120, 50, 132, 47, 138, 43, 143, 41, 148, 42, 151, 53, 155, 80, 157, 116, 158, 146, 158, 163, 158])); cb("SHIFT", new Uint8Array([100, 160, 100, 50])); } else if (mode === exports.INPUT_MODE_NUM) { cb("0", new Uint8Array([82, 50, 76, 50, 67, 50, 59, 50, 50, 51, 43, 57, 38, 68, 34, 83, 33, 95, 33, 108, 34, 121, 42, 136, 57, 148, 72, 155, 85, 157, 98, 155, 110, 149, 120, 139, 128, 127, 134, 119, 137, 114, 138, 107, 138, 98, 138, 88, 138, 77, 137, 71, 134, 65, 128, 60, 123, 58])); cb("1", new Uint8Array([100, 50, 100, 160])); - cb("2", new Uint8Array([40, 88, 40, 83, 40, 76, 43, 71, 47, 64, 55, 59, 64, 55, 73, 50, 80, 47, 91, 44, 104, 44, 117, 45, 128, 50, 135, 57, 142, 63, 145, 74, 145, 84, 140, 94, 129, 112, 108, 133, 87, 149, 71, 159, 58, 165, 52, 169, 55, 169, 63, 169, 77, 169, 89, 169, 100, 169, 110, 169, 116, 169])); - cb("3", new Uint8Array([52, 58, 65, 49, 83, 42, 100, 42, 118, 47, 136, 58, 143, 71, 135, 88, 125, 99, 114, 101, 119, 101, 132, 110, 142, 121, 145, 137, 139, 152, 122, 164, 106, 168, 92, 168, 74, 168, 55, 168])); + cb("2", new Uint8Array([40, 79, 46, 74, 56, 66, 68, 58, 77, 49, 87, 45, 100, 45, 111, 46, 119, 50, 128, 58, 133, 71, 130, 88, 120, 106, 98, 128, 69, 150, 50, 162, 42, 167, 43, 168, 58, 169, 78, 170, 93, 170, 103, 170, 109, 170])); + cb("3", new Uint8Array([47, 65, 51, 60, 57, 56, 65, 51, 74, 47, 84, 45, 93, 45, 102, 45, 109, 46, 122, 51, 129, 58, 130, 65, 127, 74, 120, 85, 112, 92, 107, 96, 112, 101, 117, 105, 125, 113, 128, 123, 127, 134, 122, 145, 108, 156, 91, 161, 70, 163, 55, 163])); cb("4", new Uint8Array([37, 58, 37, 60, 37, 64, 37, 69, 37, 75, 37, 86, 37, 96, 37, 105, 37, 112, 37, 117, 37, 122, 37, 126, 37, 128, 38, 129, 40, 129, 45, 129, 48, 129, 53, 129, 67, 129, 85, 129, 104, 129, 119, 129, 129, 129, 136, 129])); cb("5", new Uint8Array([142, 60, 119, 60, 79, 60, 45, 60, 37, 64, 37, 86, 37, 103, 47, 107, 66, 106, 81, 103, 97, 103, 116, 103, 129, 108, 131, 130, 122, 152, 101, 168, 85, 172, 70, 172, 59, 172])); - cb("6", new Uint8Array([128, 56, 110, 56, 81, 56, 58, 61, 47, 77, 41, 101, 41, 123, 41, 154, 50, 168, 71, 169, 98, 169, 123, 161, 131, 141, 129, 124, 117, 117, 102, 117, 92, 117, 85, 118, 77, 125])); + cb("6", new Uint8Array([136, 54, 135, 49, 129, 47, 114, 47, 89, 54, 66, 66, 50, 81, 39, 95, 35, 109, 34, 128, 38, 145, 52, 158, 81, 164, 114, 157, 133, 139, 136, 125, 132, 118, 120, 115, 102, 117, 85, 123])); cb("7", new Uint8Array([47, 38, 48, 38, 53, 38, 66, 38, 85, 38, 103, 38, 117, 38, 125, 38, 129, 38, 134, 41, 135, 47, 135, 54, 135, 66, 131, 93, 124, 126, 116, 149, 109, 161, 105, 168])); cb("8", new Uint8Array([122, 61, 102, 61, 83, 61, 60, 61, 47, 62, 45, 78, 58, 99, 84, 112, 105, 122, 118, 134, 121, 149, 113, 165, 86, 171, 59, 171, 47, 164, 45, 144, 50, 132, 57, 125, 67, 117, 78, 109, 87, 102, 96, 94, 105, 86, 113, 85])); cb("9", new Uint8Array([122, 58, 117, 55, 112, 51, 104, 51, 95, 51, 86, 51, 77, 51, 68, 51, 60, 51, 54, 56, 47, 64, 46, 77, 46, 89, 46, 96, 51, 103, 64, 109, 74, 110, 83, 110, 94, 107, 106, 102, 116, 94, 124, 84, 127, 79, 128, 78, 128, 94, 128, 123, 128, 161, 128, 175])); From 141eb9b90bebf93f8d701a16f25308bdca16db9f Mon Sep 17 00:00:00 2001 From: Martin Boonk Date: Sun, 4 Dec 2022 18:40:10 +0100 Subject: [PATCH 046/110] widget_utils - Allow setting a time for auto hideout --- modules/widget_utils.js | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/modules/widget_utils.js b/modules/widget_utils.js index 3440a01d2..33fd303f9 100644 --- a/modules/widget_utils.js +++ b/modules/widget_utils.js @@ -29,6 +29,7 @@ exports.show = function() { /// Remove any intervals/handlers/etc that we might have added. Does NOT re-show widgets that were hidden exports.cleanup = function() { + delete exports.autohide; delete Bangle.appRect; if (exports.swipeHandler) { Bangle.removeListener("swipe", exports.swipeHandler); @@ -50,11 +51,13 @@ exports.cleanup = function() { /** Put widgets offscreen, and allow them to be swiped back onscreen with a downwards swipe. Use .show to undo. +First parameter controls automatic hiding time, 0 equals not hiding at all. +Default value is 2000ms until hiding. Bangle.js 2 only at the moment. */ -exports.swipeOn = function() { +exports.swipeOn = function(autohide) { exports.cleanup(); if (!global.WIDGETS) return; - + exports.autohide=autohide===undefined?2000:autohide; /* TODO: maybe when widgets are offscreen we don't even store them in an offscreen buffer? */ @@ -125,11 +128,13 @@ exports.swipeOn = function() { clearTimeout(exports.hideTimeout); delete exports.hideTimeout; } - if (ud>0 && offset<0) anim(4, function() { + let cb; + if (exports.autohide > 0) cb = function() { exports.hideTimeout = setTimeout(function() { anim(-4); - }, 2000); - }); + }, exports.autohide); + } + if (ud>0 && offset<0) anim(4, cb); if (ud<0 && offset>-24) anim(-4); }; From dba3511e2ab5dad72f5bc008dba91af934287713 Mon Sep 17 00:00:00 2001 From: Martin Boonk Date: Sun, 4 Dec 2022 18:52:43 +0100 Subject: [PATCH 047/110] imageclock - Disable auto hide of widgets --- apps/imageclock/app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/imageclock/app.js b/apps/imageclock/app.js index 90c6163cd..374e73070 100644 --- a/apps/imageclock/app.js +++ b/apps/imageclock/app.js @@ -627,7 +627,7 @@ s.pl = {}; Bangle.drawWidgets = ()=>{}; Bangle.loadWidgets(); Bangle.drawWidgets = orig; - require("widget_utils").swipeOn(); + require("widget_utils").swipeOn(0); Bangle.drawWidgets(); } }).catch((e)=>{ From 2df4ba30f5928720257e9743141e17b736de1379 Mon Sep 17 00:00:00 2001 From: Martin Boonk Date: Sun, 4 Dec 2022 21:13:10 +0100 Subject: [PATCH 048/110] gpstrek - Workaround minifier issue --- apps/gpstrek/ChangeLog | 1 + apps/gpstrek/app.js | 6 ++++-- apps/gpstrek/metadata.json | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/apps/gpstrek/ChangeLog b/apps/gpstrek/ChangeLog index c36c23c72..849088c64 100644 --- a/apps/gpstrek/ChangeLog +++ b/apps/gpstrek/ChangeLog @@ -13,3 +13,4 @@ Reconstruct battery voltage by using calibrated batFullVoltage Averaging for smoothing compass headings Save state if route or waypoint has been chosen +0.09: Workaround a minifier issue allowing to install gpstrek with minification enabled diff --git a/apps/gpstrek/app.js b/apps/gpstrek/app.js index b3ec79fd2..1f46ae2b4 100644 --- a/apps/gpstrek/app.js +++ b/apps/gpstrek/app.js @@ -259,7 +259,8 @@ let getCompassSlice = function(compassDataSource){ if (compassDataSource.getPoints){ - for (let p of compassDataSource.getPoints()){ + let points = compassDataSource.getPoints(); //storing this in a variable works around a minifier bug causing a problem in the next line: for(let a of a.getPoints()) + for (let p of points){ g.reset(); var bpos = p.bearing - lastDrawnValue; if (bpos>180) bpos -=360; @@ -285,7 +286,8 @@ let getCompassSlice = function(compassDataSource){ } } if (compassDataSource.getMarkers){ - for (let m of compassDataSource.getMarkers()){ + let markers = compassDataSource.getMarkers(); //storing this in a variable works around a minifier bug causing a problem in the next line: for(let a of a.getMarkers()) + for (let m of markers){ g.reset(); g.setColor(m.fillcolor); let mpos = m.xpos * width; diff --git a/apps/gpstrek/metadata.json b/apps/gpstrek/metadata.json index 3e27a3247..2e2e481af 100644 --- a/apps/gpstrek/metadata.json +++ b/apps/gpstrek/metadata.json @@ -1,7 +1,7 @@ { "id": "gpstrek", "name": "GPS Trekking", - "version": "0.08", + "version": "0.09", "description": "Helper for tracking the status/progress during hiking. Do NOT depend on this for navigation!", "icon": "icon.png", "screenshots": [{"url":"screen1.png"},{"url":"screen2.png"},{"url":"screen3.png"},{"url":"screen4.png"}], From 72bbc3a406a47934f83126410167da2dde8663ec Mon Sep 17 00:00:00 2001 From: m-p-3 Date: Sun, 4 Dec 2022 21:24:33 -0500 Subject: [PATCH 049/110] Bump version 0.01 -> 0.02 --- apps/messageicons/metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/messageicons/metadata.json b/apps/messageicons/metadata.json index eb907f893..b6ce34f88 100644 --- a/apps/messageicons/metadata.json +++ b/apps/messageicons/metadata.json @@ -1,7 +1,7 @@ { "id": "messageicons", "name": "Message Icons", - "version": "0.01", + "version": "0.02", "description": "Library containing a list of icons and colors for apps", "icon": "app.png", "type": "module", From 768e2cb8f3001287883dc7e05a35e2a842bbcb7c Mon Sep 17 00:00:00 2001 From: m-p-3 Date: Sun, 4 Dec 2022 21:26:22 -0500 Subject: [PATCH 050/110] Update Changelog --- apps/messageicons/ChangeLog | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/messageicons/ChangeLog b/apps/messageicons/ChangeLog index 52a4b35a7..fefc6ee6e 100644 --- a/apps/messageicons/ChangeLog +++ b/apps/messageicons/ChangeLog @@ -1 +1,2 @@ 0.01: Moved message icons from messages into standalone library +0.02: Added several new icons and colors From 596a2be1f8b69cd8bf0cb9b7a9c64f12959fb6ef Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Mon, 5 Dec 2022 10:09:40 +0000 Subject: [PATCH 051/110] Update README.md --- apps/slopeclockpp/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/slopeclockpp/README.md b/apps/slopeclockpp/README.md index 8aad8467b..c9e9d523d 100644 --- a/apps/slopeclockpp/README.md +++ b/apps/slopeclockpp/README.md @@ -10,7 +10,7 @@ to change (top right or bottom left). It should change color showing it is selected. * Swipe up or down to cycle through the info screens that can be displayed - when you have finnised tap again towards the centre of the screen to unselect. + when you have finished tap again towards the centre of the screen to unselect. * Swipe left or right to change the type of info screens displayed (by default there is only one type of data so this will have no effect) From 67071d3722f169e45f0da4ed7c21cad9e716d855 Mon Sep 17 00:00:00 2001 From: thyttan <6uuxstm66@mozmail.com⁩> Date: Fri, 2 Dec 2022 22:45:10 +0100 Subject: [PATCH 052/110] android - autotranslate some strings --- apps/android/ChangeLog | 3 ++- apps/android/boot.js | 4 ++-- apps/android/metadata.json | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/apps/android/ChangeLog b/apps/android/ChangeLog index e4a3e9de0..86dbdb649 100644 --- a/apps/android/ChangeLog +++ b/apps/android/ChangeLog @@ -16,4 +16,5 @@ 0.16: Bangle.http now fails immediately if there is no Bluetooth connection (fix #2152) 0.17: Now kick off Calendar sync as soon as connected to Gadgetbridge 0.18: Use new message library - If connected to Gadgetbridge, allow GPS forwarding from phone (Gadgetbridge code still not merged) \ No newline at end of file + If connected to Gadgetbridge, allow GPS forwarding from phone (Gadgetbridge code still not merged) +0.19: Add automatic translation for a couple of strings. diff --git a/apps/android/boot.js b/apps/android/boot.js index 8e75241e7..e1e5b028b 100644 --- a/apps/android/boot.js +++ b/apps/android/boot.js @@ -57,7 +57,7 @@ t:event.cmd=="incoming"?"add":"remove", id:"call", src:"Phone", positive:true, negative:true, - title:event.name||"Call", body:"Incoming call\n"+event.number}); + title:event.name||/*LANG*/"Call", body:/*LANG*/"Incoming call\n"+event.number}); require("messages").pushMessage(event); }, "alarm" : function() { @@ -148,7 +148,7 @@ Bangle.http = (url,options)=>{ options = options||{}; if (!NRF.getSecurityStatus().connected) - return Promise.reject("Not connected to Bluetooth"); + return Promise.reject(/*LANG*/"Not connected to Bluetooth"); if (Bangle.httpRequest === undefined) Bangle.httpRequest={}; if (options.id === undefined) { diff --git a/apps/android/metadata.json b/apps/android/metadata.json index 45c08a75a..d5a45edb7 100644 --- a/apps/android/metadata.json +++ b/apps/android/metadata.json @@ -2,7 +2,7 @@ "id": "android", "name": "Android Integration", "shortName": "Android", - "version": "0.18", + "version": "0.19", "description": "Display notifications/music/etc sent from the Gadgetbridge app on Android. This replaces the old 'Gadgetbridge' Bangle.js widget.", "icon": "app.png", "tags": "tool,system,messages,notifications,gadgetbridge", From 6522e0311da0a767245884eb30918df6547df52e Mon Sep 17 00:00:00 2001 From: thyttan <6uuxstm66@mozmail.com⁩> Date: Fri, 2 Dec 2022 23:06:38 +0100 Subject: [PATCH 053/110] files - autotranslate strings --- apps/files/ChangeLog | 3 ++- apps/files/files.js | 54 ++++++++++++++++++++-------------------- apps/files/metadata.json | 2 +- 3 files changed, 30 insertions(+), 29 deletions(-) diff --git a/apps/files/ChangeLog b/apps/files/ChangeLog index 1908f7e5c..4622e6f0f 100644 --- a/apps/files/ChangeLog +++ b/apps/files/ChangeLog @@ -3,4 +3,5 @@ 0.04: Add functionality to sort apps manually or alphabetically ascending/descending. 0.05: Tweaks to help with memory usage 0.06: Reduce memory usage -0.07: Allow negative numbers when manual-sorting \ No newline at end of file +0.07: Allow negative numbers when manual-sorting +0.08: Automatic translation of strings. diff --git a/apps/files/files.js b/apps/files/files.js index e81e9589f..2f7b5c9a1 100644 --- a/apps/files/files.js +++ b/apps/files/files.js @@ -3,20 +3,20 @@ const store = require('Storage'); function showMainMenu() { const mainmenu = { '': { - 'title': 'App Manager', + 'title': /*LANG*/'App Manager', }, '< Back': ()=> {load();}, - 'Sort Apps': () => showSortAppsMenu(), - 'Manage Apps': ()=> showApps(), - 'Compact': () => { - E.showMessage('Compacting...'); + /*LANG*/'Sort Apps': () => showSortAppsMenu(), + /*LANG*/'Manage Apps': ()=> showApps(), + /*LANG*/'Compact': () => { + E.showMessage(/*LANG*/'Compacting...'); try { store.compact(); } catch (e) { } showMainMenu(); }, - 'Free': { + /*LANG*/'Free': { value: undefined, format: (v) => { return store.getFree(); @@ -65,13 +65,13 @@ function eraseData(info) { }); } function eraseApp(app, files,data) { - E.showMessage('Erasing\n' + app.name + '...'); + E.showMessage(/*LANG*/'Erasing\n' + app.name + '...'); var info = store.readJSON(app.id + ".info", 1)||{}; if (files) eraseFiles(info); if (data) eraseData(info); } function eraseOne(app, files,data){ - E.showPrompt('Erase\n'+app.name+'?').then((v) => { + E.showPrompt(/*LANG*/'Erase\n'+app.name+'?').then((v) => { if (v) { Bangle.buzz(100, 1); eraseApp(app, files, data); @@ -82,7 +82,7 @@ function eraseOne(app, files,data){ }); } function eraseAll(apps, files,data) { - E.showPrompt('Erase all?').then((v) => { + E.showPrompt(/*LANG*/'Erase all?').then((v) => { if (v) { Bangle.buzz(100, 1); apps.forEach(app => eraseApp(app, files, data)); @@ -99,11 +99,11 @@ function showAppMenu(app) { '< Back': () => showApps(), }; if (app.hasData) { - appmenu['Erase Completely'] = () => eraseOne(app, true, true); - appmenu['Erase App,Keep Data'] = () => eraseOne(app, true, false); - appmenu['Only Erase Data'] = () => eraseOne(app, false, true); + appmenu[/*LANG*/'Erase Completely'] = () => eraseOne(app, true, true); + appmenu[/*LANG*/'Erase App,Keep Data'] = () => eraseOne(app, true, false); + appmenu[/*LANG*/'Only Erase Data'] = () => eraseOne(app, false, true); } else { - appmenu['Erase'] = () => eraseOne(app, true, false); + appmenu[/*LANG*/'Erase'] = () => eraseOne(app, true, false); } E.showMenu(appmenu); } @@ -111,7 +111,7 @@ function showAppMenu(app) { function showApps() { const appsmenu = { '': { - 'title': 'Apps', + 'title': /*LANG*/'Apps', }, '< Back': () => showMainMenu(), }; @@ -128,17 +128,17 @@ function showApps() { menu[app.name] = () => showAppMenu(app); return menu; }, appsmenu); - appsmenu['Erase All'] = () => { + appsmenu[/*LANG*/'Erase All'] = () => { E.showMenu({ - '': {'title': 'Erase All'}, - 'Erase Everything': () => eraseAll(list, true, true), - 'Erase Apps,Keep Data': () => eraseAll(list, true, false), - 'Only Erase Data': () => eraseAll(list, false, true), + '': {'title': /*LANG*/'Erase All'}, + /*LANG*/'Erase Everything': () => eraseAll(list, true, true), + /*LANG*/'Erase Apps,Keep Data': () => eraseAll(list, true, false), + /*LANG*/'Only Erase Data': () => eraseAll(list, false, true), '< Back': () => showApps(), }); }; } else { - appsmenu['...No Apps...'] = { + appsmenu[/*LANG*/'...No Apps...'] = { value: undefined, format: ()=> '', onchange: ()=> {} @@ -150,16 +150,16 @@ function showApps() { function showSortAppsMenu() { const sorterMenu = { '': { - 'title': 'App Sorter', + 'title': /*LANG*/'App Sorter', }, '< Back': () => showMainMenu(), - 'Sort: manually': ()=> showSortAppsManually(), - 'Sort: alph. ASC': () => { - E.showMessage('Sorting:\nAlphabetically\nascending ...'); + /*LANG*/'Sort: manually': ()=> showSortAppsManually(), + /*LANG*/'Sort: alph. ASC': () => { + E.showMessage(/*LANG*/'Sorting:\nAlphabetically\nascending ...'); sortAlphabet(false); }, 'Sort: alph. DESC': () => { - E.showMessage('Sorting:\nAlphabetically\ndescending ...'); + E.showMessage(/*LANG*/'Sorting:\nAlphabetically\ndescending ...'); sortAlphabet(true); } }; @@ -169,7 +169,7 @@ function showSortAppsMenu() { function showSortAppsManually() { const appsSorterMenu = { '': { - 'title': 'Sort: manually', + 'title': /*LANG*/'Sort: manually', }, '< Back': () => showSortAppsMenu(), }; @@ -186,7 +186,7 @@ function showSortAppsManually() { return menu; }, appsSorterMenu); } else { - appsSorterMenu['...No Apps...'] = { + appsSorterMenu[/*LANG*/'...No Apps...'] = { value: undefined, format: ()=> '', onchange: ()=> {} diff --git a/apps/files/metadata.json b/apps/files/metadata.json index ac73a7717..a53f914e6 100644 --- a/apps/files/metadata.json +++ b/apps/files/metadata.json @@ -1,7 +1,7 @@ { "id": "files", "name": "App Manager", - "version": "0.07", + "version": "0.08", "description": "Show currently installed apps, free space, and allow their deletion from the watch", "icon": "files.png", "tags": "tool,system,files", From db38c197015b4e3e4e93f19b82f70d3e0271c7df Mon Sep 17 00:00:00 2001 From: thyttan <6uuxstm66@mozmail.com⁩> Date: Fri, 2 Dec 2022 23:15:20 +0100 Subject: [PATCH 054/110] recorder - autotranslate more strings --- apps/recorder/ChangeLog | 1 + apps/recorder/app.js | 6 +++--- apps/recorder/metadata.json | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/apps/recorder/ChangeLog b/apps/recorder/ChangeLog index 3cf5d8372..a4d0b7e88 100644 --- a/apps/recorder/ChangeLog +++ b/apps/recorder/ChangeLog @@ -23,3 +23,4 @@ 0.17: Use default Bangle formatter for booleans 0.18: Improve widget load speed, allow currently recording track to be plotted in openstmap 0.19: Fix track plotting code +0.20: Automatic translation of some more strings. diff --git a/apps/recorder/app.js b/apps/recorder/app.js index 9006d2236..8dcc4c3ed 100644 --- a/apps/recorder/app.js +++ b/apps/recorder/app.js @@ -61,7 +61,7 @@ function showMainMenu() { setTimeout(function() { E.showMenu(); WIDGETS["recorder"].setRecording(v).then(function() { - print("Complete"); + print(/*LANG*/"Complete"); loadSettings(); print(settings.recording); showMainMenu(); @@ -96,7 +96,7 @@ function showMainMenu() { }; var recorders = WIDGETS["recorder"].getRecorders(); Object.keys(recorders).forEach(id=>{ - mainmenu["Log "+recorders[id]().name] = menuRecord(id); + mainmenu[/*LANG*/"Log "+recorders[id]().name] = menuRecord(id); }); delete recorders; return E.showMenu(mainmenu); @@ -404,7 +404,7 @@ function viewTrack(filename, info) { title: title, miny: min, maxy: max, - xlabel : x=>Math.round(x*dur/(60*infn.length))+" min" // minutes + xlabel : x=>Math.round(x*dur/(60*infn.length))+/*LANG*/" min" // minutes }); g.setFont("6x8",2); g.setFontAlign(0,0,3); diff --git a/apps/recorder/metadata.json b/apps/recorder/metadata.json index bbc08e0ef..91ceaf86e 100644 --- a/apps/recorder/metadata.json +++ b/apps/recorder/metadata.json @@ -2,7 +2,7 @@ "id": "recorder", "name": "Recorder", "shortName": "Recorder", - "version": "0.19", + "version": "0.20", "description": "Record GPS position, heart rate and more in the background, then download to your PC.", "icon": "app.png", "tags": "tool,outdoors,gps,widget", From fb721b00a72a32a0de2359caa00a689f4f2519fa Mon Sep 17 00:00:00 2001 From: thyttan <6uuxstm66@mozmail.com⁩> Date: Fri, 2 Dec 2022 23:19:35 +0100 Subject: [PATCH 055/110] hrm - autotranslate strings --- apps/hrm/ChangeLog | 1 + apps/hrm/heartrate.js | 6 +++--- apps/hrm/metadata.json | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/apps/hrm/ChangeLog b/apps/hrm/ChangeLog index 62956e8cd..b55ba8930 100644 --- a/apps/hrm/ChangeLog +++ b/apps/hrm/ChangeLog @@ -8,3 +8,4 @@ 0.08: Don't force backlight on/watch unlocked on Bangle 2 0.09: Grey out BPM until confidence is over 50% 0.10: Autoscale raw graph to maximum value seen +0.11: Automatic translation of strings. diff --git a/apps/hrm/heartrate.js b/apps/hrm/heartrate.js index 386341e6d..2e5a720e5 100644 --- a/apps/hrm/heartrate.js +++ b/apps/hrm/heartrate.js @@ -37,7 +37,7 @@ function updateHrm(){ var px = g.getWidth()/2; g.setFontAlign(0,-1); g.clearRect(0,24,g.getWidth(),80); - g.setFont("6x8").drawString("Confidence "+(hrmInfo.confidence || "--")+"%", px, 70); + g.setFont("6x8").drawString(/*LANG*/"Confidence "+(hrmInfo.confidence || "--")+"%", px, 70); updateScale(); @@ -46,7 +46,7 @@ function updateHrm(){ g.setFontVector(40).setColor(hrmInfo.confidence > 50 ? g.theme.fg : "#888").drawString(str,px,45); px += g.stringWidth(str)/2; g.setFont("6x8").setColor(g.theme.fg); - g.drawString("BPM",px+15,45); + g.drawString(/*LANG*/"BPM",px+15,45); } function updateScale(){ @@ -101,7 +101,7 @@ Bangle.loadWidgets(); Bangle.drawWidgets(); g.setColor(g.theme.fg); g.reset().setFont("6x8",2).setFontAlign(0,-1); -g.drawString("Please wait...",g.getWidth()/2,g.getHeight()/2 - 16); +g.drawString(/*LANG*/"Please wait...",g.getWidth()/2,g.getHeight()/2 - 16); countDown(); diff --git a/apps/hrm/metadata.json b/apps/hrm/metadata.json index c5a5f4f4d..f254b5d23 100644 --- a/apps/hrm/metadata.json +++ b/apps/hrm/metadata.json @@ -1,7 +1,7 @@ { "id": "hrm", "name": "Heart Rate Monitor", - "version": "0.10", + "version": "0.11", "description": "Measure your heart rate and see live sensor data", "icon": "heartrate.png", "tags": "health", From ee21d0bb4820aad91baf567d7f1ad54d642f7aae Mon Sep 17 00:00:00 2001 From: thyttan <6uuxstm66@mozmail.com⁩> Date: Fri, 2 Dec 2022 23:30:08 +0100 Subject: [PATCH 056/110] weather - autotranslate strings --- apps/weather/ChangeLog | 4 +++- apps/weather/app.js | 22 +++++++++++----------- apps/weather/metadata.json | 2 +- 3 files changed, 15 insertions(+), 13 deletions(-) diff --git a/apps/weather/ChangeLog b/apps/weather/ChangeLog index 1b6c1b9b5..359cb8635 100644 --- a/apps/weather/ChangeLog +++ b/apps/weather/ChangeLog @@ -17,4 +17,6 @@ 0.18: Added hasRange to clkinfo. 0.19: Added weather condition to clkinfo. 0.20: Added weather condition with temperature to clkinfo. -0.21: Updated clkinfo icon. \ No newline at end of file +0.21: Updated clkinfo icon. +0.22: Automatic translation of strings, some left untranslated. +>>>>>>> b37fcacd1 (weather - autotranslate strings) diff --git a/apps/weather/app.js b/apps/weather/app.js index f63b226b9..8988c5002 100644 --- a/apps/weather/app.js +++ b/apps/weather/app.js @@ -16,10 +16,10 @@ var layout = new Layout({type:"v", bgCol: g.theme.bg, c: [ {type: "txt", font: "12%", valign: -1, id: "tempUnit", label: "°C"}, ]}, {filly: 1}, - {type: "txt", font: "6x8", pad: 2, halign: 1, label: "Humidity"}, + {type: "txt", font: "6x8", pad: 2, halign: 1, label: /*LANG*/"Humidity"}, {type: "txt", font: "9%", pad: 2, halign: 1, id: "hum", label: "000%"}, {filly: 1}, - {type: "txt", font: "6x8", pad: 2, halign: -1, label: "Wind"}, + {type: "txt", font: "6x8", pad: 2, halign: -1, label: /*LANG*/"Wind"}, {type: "h", halign: -1, c: [ {type: "txt", font: "9%", pad: 2, id: "wind", label: "00"}, {type: "txt", font: "6x8", pad: 2, valign: -1, id: "windUnit", label: "km/h"}, @@ -27,22 +27,22 @@ var layout = new Layout({type:"v", bgCol: g.theme.bg, c: [ ]}, ]}, {filly: 1}, - {type: "txt", font: "9%", wrap: true, height: g.getHeight()*0.18, fillx: 1, id: "cond", label: "Weather condition"}, + {type: "txt", font: "9%", wrap: true, height: g.getHeight()*0.18, fillx: 1, id: "cond", label: /*LANG*/"Weather condition"}, {filly: 1}, {type: "h", c: [ {type: "txt", font: "6x8", pad: 4, id: "loc", label: "Toronto"}, {fillx: 1}, - {type: "txt", font: "6x8", pad: 4, id: "updateTime", label: "15 minutes ago"}, + {type: "txt", font: "6x8", pad: 4, id: "updateTime", label: /*LANG*/"15 minutes ago"}, ]}, {filly: 1}, ]}, {lazy: true}); function formatDuration(millis) { let pluralize = (n, w) => n + " " + w + (n == 1 ? "" : "s"); - if (millis < 60000) return "< 1 minute"; - if (millis < 3600000) return pluralize(Math.floor(millis/60000), "minute"); - if (millis < 86400000) return pluralize(Math.floor(millis/3600000), "hour"); - return pluralize(Math.floor(millis/86400000), "day"); + if (millis < 60000) return /*LANG*/"< 1 minute"; + if (millis < 3600000) return pluralize(Math.floor(millis/60000), /*LANG*/"minute"); + if (millis < 86400000) return pluralize(Math.floor(millis/3600000), /*LANG*/"hour"); + return pluralize(Math.floor(millis/86400000), /*LANG*/"day"); } function draw() { @@ -57,7 +57,7 @@ function draw() { layout.windUnit.label = wind[2] + " " + (current.wrose||'').toUpperCase(); layout.cond.label = current.txt.charAt(0).toUpperCase()+(current.txt||'').slice(1); layout.loc.label = current.loc; - layout.updateTime.label = `${formatDuration(Date.now() - current.time)} ago`; + layout.updateTime.label = `${formatDuration(Date.now() - current.time)} ago`; // How to autotranslate this and similar? layout.update(); layout.render(); } @@ -77,9 +77,9 @@ function update() { } else { layout.forgetLazyState(); if (NRF.getSecurityStatus().connected) { - E.showMessage("Weather\nunknown\n\nIs Gadgetbridge\nweather\nreporting set\nup on your\nphone?"); + E.showMessage(/*LANG*/"Weather\nunknown\n\nIs Gadgetbridge\nweather\nreporting set\nup on your\nphone?"); } else { - E.showMessage("Weather\nunknown\n\nGadgetbridge\nnot connected"); + E.showMessage(/*LANG*/"Weather\nunknown\n\nGadgetbridge\nnot connected"); NRF.on("connect", update); } } diff --git a/apps/weather/metadata.json b/apps/weather/metadata.json index 500eac012..7fefb7685 100644 --- a/apps/weather/metadata.json +++ b/apps/weather/metadata.json @@ -1,7 +1,7 @@ { "id": "weather", "name": "Weather", - "version": "0.21", + "version": "0.22", "description": "Show Gadgetbridge weather report", "icon": "icon.png", "screenshots": [{"url":"screenshot.png"}], From 946f77d7b59f469f87556d2b5e21e2d1da76a1f3 Mon Sep 17 00:00:00 2001 From: Erik Andresen Date: Mon, 5 Dec 2022 18:06:17 +0100 Subject: [PATCH 057/110] sleepphasealarm Support javascript command to execute as defined in scheduler 'js' configuration --- apps/sleepphasealarm/ChangeLog | 1 + apps/sleepphasealarm/app.js | 3 +++ apps/sleepphasealarm/metadata.json | 2 +- 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/apps/sleepphasealarm/ChangeLog b/apps/sleepphasealarm/ChangeLog index 80b2e554b..795c62fa2 100644 --- a/apps/sleepphasealarm/ChangeLog +++ b/apps/sleepphasealarm/ChangeLog @@ -12,3 +12,4 @@ Add setting to disable scheduler alarm 0.10: Fix: Do not wake when falling asleep 0.11: Minor tweaks +0.12: Support javascript command to execute as defined in scheduler 'js' configuration diff --git a/apps/sleepphasealarm/app.js b/apps/sleepphasealarm/app.js index a5193b244..90cd32c7e 100644 --- a/apps/sleepphasealarm/app.js +++ b/apps/sleepphasealarm/app.js @@ -173,6 +173,9 @@ if (nextAlarmDate !== undefined) { setTimeout(load, 1000); } else if (measure && now >= minAlarm && swest === false) { addLog(now, "alarm"); + if (nextAlarmConfig.js) { + eval(nextAlarmConfig.js); // run nextAlarmConfig.js if set + } buzz(); measure = false; if (config.settings.disableAlarm) { diff --git a/apps/sleepphasealarm/metadata.json b/apps/sleepphasealarm/metadata.json index fd3366812..ced99062f 100644 --- a/apps/sleepphasealarm/metadata.json +++ b/apps/sleepphasealarm/metadata.json @@ -2,7 +2,7 @@ "id": "sleepphasealarm", "name": "SleepPhaseAlarm", "shortName": "SleepPhaseAlarm", - "version": "0.11", + "version": "0.12", "description": "Uses the accelerometer to estimate sleep and wake states with the principle of Estimation of Stationary Sleep-segments (ESS, see https://ubicomp.eti.uni-siegen.de/home/datasets/ichi14/index.html.en). This app will read the next alarm from the alarm application and will wake you up to 30 minutes early at the best guessed time when you are almost already awake.", "icon": "app.png", "tags": "alarm", From ae6d53ffc397439e24d732c633af01206e2a8008 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Mon, 5 Dec 2022 17:09:09 +0000 Subject: [PATCH 058/110] bootloader 0.55: Add toLocalISOString polyfill for pre-2v15 firmwares + Only add boot info comments if settings.bootDebug was set + If settings.bootDebug is set, output timing for each section of .boot0 --- apps/boot/ChangeLog | 3 ++ apps/boot/bootupdate.js | 72 ++++++++++++++++++++++++++--------------- apps/boot/metadata.json | 2 +- 3 files changed, 50 insertions(+), 27 deletions(-) diff --git a/apps/boot/ChangeLog b/apps/boot/ChangeLog index 0eaf517d9..780d9cc7d 100644 --- a/apps/boot/ChangeLog +++ b/apps/boot/ChangeLog @@ -61,3 +61,6 @@ 0.52: Ensure heading patch for pre-2v15.68 firmware applies to getCompass 0.53: Add polyfills for pre-2v15.135 firmware for Bangle.load and Bangle.showClock 0.54: Fix for invalid version comparison in polyfill +0.55: Add toLocalISOString polyfill for pre-2v15 firmwares + Only add boot info comments if settings.bootDebug was set + If settings.bootDebug is set, output timing for each section of .boot0 diff --git a/apps/boot/bootupdate.js b/apps/boot/bootupdate.js index ad58437ec..112dfeba8 100644 --- a/apps/boot/bootupdate.js +++ b/apps/boot/bootupdate.js @@ -1,16 +1,22 @@ /* This rewrites boot0.js based on current settings. If settings changed then it recalculates, but this avoids us doing a whole bunch of reconfiguration most of the time. */ +{ // execute in our own scope so we don't have to free variables... E.showMessage(/*LANG*/"Updating boot0..."); -var s = require('Storage').readJSON('setting.json',1)||{}; -var BANGLEJS2 = process.env.HWVERSION==2; // Is Bangle.js 2 -var FWVERSION = parseFloat(process.env.VERSION.replace("v","").replace(/\.(\d\d)$/,".0$1")); -var boot = "", bootPost = ""; +let s = require('Storage').readJSON('setting.json',1)||{}; +const BANGLEJS2 = process.env.HWVERSION==2; // Is Bangle.js 2 +const FWVERSION = parseFloat(process.env.VERSION.replace("v","").replace(/\.(\d\d)$/,".0$1")); +const DEBUG = s.bootDebug; // we can set this to enable debugging output in boot0 +let boot = "", bootPost = ""; +if (DEBUG) { + boot += "var _tm=Date.now()\n"; + bootPost += "delete _tm;"; +} if (require('Storage').hash) { // new in 2v11 - helps ensure files haven't changed - var CRC = E.CRC32(require('Storage').read('setting.json'))+require('Storage').hash(/\.boot\.js/)+E.CRC32(process.env.GIT_COMMIT); + let CRC = E.CRC32(require('Storage').read('setting.json'))+require('Storage').hash(/\.boot\.js/)+E.CRC32(process.env.GIT_COMMIT); boot += `if (E.CRC32(require('Storage').read('setting.json'))+require('Storage').hash(/\\.boot\\.js/)+E.CRC32(process.env.GIT_COMMIT)!=${CRC})`; } else { - var CRC = E.CRC32(require('Storage').read('setting.json'))+E.CRC32(require('Storage').list(/\.boot\.js/))+E.CRC32(process.env.GIT_COMMIT); + let CRC = E.CRC32(require('Storage').read('setting.json'))+E.CRC32(require('Storage').list(/\.boot\.js/))+E.CRC32(process.env.GIT_COMMIT); boot += `if (E.CRC32(require('Storage').read('setting.json'))+E.CRC32(require('Storage').list(/\\.boot\\.js/))+E.CRC32(process.env.GIT_COMMIT)!=${CRC})`; } boot += ` { eval(require('Storage').read('bootupdate.js')); throw "Storage Updated!"}\n`; @@ -88,14 +94,25 @@ delete Bangle.showClock; if (!Bangle.showClock) boot += `Bangle.showClock = ()=>{load(".bootcde")};\n`; delete Bangle.load; if (!Bangle.load) boot += `Bangle.load = load;\n`; +let date = new Date(); +delete date.toLocalISOString; // toLocalISOString was only introduced in 2v15 +if (!date.toLocalISOString) boot += `Date.prototype.toLocalISOString = function() { + var o = this.getTimezoneOffset(); + var d = new Date(this.getTime() - o*60000); + var sign = o>0?"-":"+"; + o = Math.abs(o); + return d.toISOString().slice(0,-1)+sign+Math.floor(o/60).toString().padStart(2,0)+(o%60).toString().padStart(2,0); +};\n`; +// show timings +if (DEBUG) boot += `print(".boot0",0|(Date.now()-_tm),"ms");_tm=Date.now();\n` // ================================================== BOOT.JS // Append *.boot.js files // These could change bleServices/bleServiceOptions if needed -var bootFiles = require('Storage').list(/\.boot\.js$/).sort((a,b)=>{ - var getPriority = /.*\.(\d+)\.boot\.js$/; - var aPriority = a.match(getPriority); - var bPriority = b.match(getPriority); +let bootFiles = require('Storage').list(/\.boot\.js$/).sort((a,b)=>{ + let getPriority = /.*\.(\d+)\.boot\.js$/; + let aPriority = a.match(getPriority); + let bPriority = b.match(getPriority); if (aPriority && bPriority){ return parseInt(aPriority[1]) - parseInt(bPriority[1]); } else if (aPriority && !bPriority){ @@ -106,14 +123,16 @@ var bootFiles = require('Storage').list(/\.boot\.js$/).sort((a,b)=>{ return a==b ? 0 : (a>b ? 1 : -1); }); // precalculate file size -var fileSize = boot.length + bootPost.length; +let fileSize = boot.length + bootPost.length; bootFiles.forEach(bootFile=>{ // match the size of data we're adding below in bootFiles.forEach - fileSize += 2+bootFile.length+1+require('Storage').read(bootFile).length+2; + if (DEBUG) fileSize += 2+bootFile.length+1; // `//${bootFile}\n` comment + fileSize += require('Storage').read(bootFile).length+2; // boot code plus ";\n" + if (DEBUG) fileSize += 48+E.toJS(bootFile).length; // `print(${E.toJS(bootFile)},0|(Date.now()-_tm),"ms");_tm=Date.now();\n` }); // write file in chunks (so as not to use up all RAM) require('Storage').write('.boot0',boot,0,fileSize); -var fileOffset = boot.length; +let fileOffset = boot.length; bootFiles.forEach(bootFile=>{ // we add a semicolon so if the file is wrapped in (function(){ ... }() // with no semicolon we don't end up with (function(){ ... }()(function(){ ... }() @@ -122,16 +141,18 @@ bootFiles.forEach(bootFile=>{ // "//"+bootFile+"\n"+require('Storage').read(bootFile)+";\n"; // but we need to do this without ever loading everything into RAM as some // boot files seem to be getting pretty big now. - require('Storage').write('.boot0',"//"+bootFile+"\n",fileOffset); - fileOffset+=2+bootFile.length+1; - var bf = require('Storage').read(bootFile); + if (DEBUG) { + require('Storage').write('.boot0',`//${bootFile}\n`,fileOffset); + fileOffset+=2+bootFile.length+1; + } + let bf = require('Storage').read(bootFile); // we can't just write 'bf' in one go because at least in 2v13 and earlier // Espruino wants to read the whole file into RAM first, and on Bangle.js 1 // it can be too big (especially BTHRM). - var bflen = bf.length; - var bfoffset = 0; + let bflen = bf.length; + let bfoffset = 0; while (bflen) { - var bfchunk = Math.min(bflen, 2048); + let bfchunk = Math.min(bflen, 2048); require('Storage').write('.boot0',bf.substr(bfoffset, bfchunk),fileOffset); fileOffset+=bfchunk; bfoffset+=bfchunk; @@ -139,15 +160,14 @@ bootFiles.forEach(bootFile=>{ } require('Storage').write('.boot0',";\n",fileOffset); fileOffset+=2; + if (DEBUG) { + require('Storage').write('.boot0',`print(${E.toJS(bootFile)},0|(Date.now()-_tm),"ms");_tm=Date.now();\n`,fileOffset); + fileOffset += 48+E.toJS(bootFile).length + } }); require('Storage').write('.boot0',bootPost,fileOffset); - -delete boot; -delete bootPost; -delete bootFiles; -delete fileSize; -delete fileOffset; E.showMessage(/*LANG*/"Reloading..."); -eval(require('Storage').read('.boot0')); +} // .bootcde should be run automatically after if required, since // we normally get called automatically from '.boot0' +eval(require('Storage').read('.boot0')); diff --git a/apps/boot/metadata.json b/apps/boot/metadata.json index bd39beb7f..455563a16 100644 --- a/apps/boot/metadata.json +++ b/apps/boot/metadata.json @@ -1,7 +1,7 @@ { "id": "boot", "name": "Bootloader", - "version": "0.54", + "version": "0.55", "description": "This is needed by Bangle.js to automatically load the clock, menu, widgets and settings", "icon": "bootloader.png", "type": "bootloader", From b47725568c7d08636cdef5a3486276568dcb7bde Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Mon, 5 Dec 2022 17:09:22 +0000 Subject: [PATCH 059/110] Not sure how, but core got set to earlier commit --- core | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core b/core index 764197500..3a953179b 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit 76419750083a88ee7a569db3975ae1bdd6dc155a +Subproject commit 3a953179b7bb9f574d4e77d5f34b6b7deee1e884 From 7114d646bc14dc422d239c41f80d6a9f63ba6d3a Mon Sep 17 00:00:00 2001 From: Hugh Barney Date: Mon, 5 Dec 2022 20:31:58 +0000 Subject: [PATCH 060/110] Prime Lato: changed to a prime icon --- apps/primetimelato/ChangeLog | 1 + apps/primetimelato/icon.js | 2 +- apps/primetimelato/metadata.json | 4 ++-- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/apps/primetimelato/ChangeLog b/apps/primetimelato/ChangeLog index 1be18255b..7781e93a1 100644 --- a/apps/primetimelato/ChangeLog +++ b/apps/primetimelato/ChangeLog @@ -1,3 +1,4 @@ 0.01: first release 0.02: added option to buzz on prime, with settings 0.03: added option to debug settings and test fw 2.15.93 load speed ups +0.04: changed icon diff --git a/apps/primetimelato/icon.js b/apps/primetimelato/icon.js index 06f93e2ef..7c8d5380b 100644 --- a/apps/primetimelato/icon.js +++ b/apps/primetimelato/icon.js @@ -1 +1 @@ -require("heatshrink").decompress(atob("mEwwIdah/wAof//4ECgYFB4AFBg4FB8AFBj/wh/4AoM/wEB/gFBvwCEBAU/AQP4gfAj8AgPwAoMPwED8AFBg/AAYIBDA4ngg4TB4EBApkPKgJSBJQIFTMgIFCJIIFDKoIFEvgFBGoMAnw7DP4IFEh+BAoItBg+DNIQwBMIaeCKoKxCPoIzCEgKVHUIqtFXIrFFaIrdFdIwAV")) +require("heatshrink").decompress(atob("mEw4X/AAIHB8cYttrJf4AR1gKJgdYBZMCBZdcBZMNsALKuALJhNABZMFwALJmvAAwkOqvAmtAkwSF83+uEV4EMOIpZBznWII5NB7mXGo5BB7Z0HkpBB6x0HFYXVNA4rC6pcFAANXDQhSFqgaEBZGYaBLfIaAUBBZUJNQ4jCm+cHZPcBZFXgdwzELBg1W/PAy/rBY3VPAOVTY863kAnaPHAH4A/ADAA==")) diff --git a/apps/primetimelato/metadata.json b/apps/primetimelato/metadata.json index dd200e5d3..400220b10 100644 --- a/apps/primetimelato/metadata.json +++ b/apps/primetimelato/metadata.json @@ -1,6 +1,6 @@ { "id": "primetimelato", - "name": "Prime Time Lato", - "version": "0.03", + "name": "Prime Lato", + "version": "0.04", "type": "clock", "description": "A clock that tells you the primes of the time in the Lato font", "icon": "app.png", From d06e4c5a5ec25c357e148568b89154ff2db7f0bc Mon Sep 17 00:00:00 2001 From: Erik Andresen Date: Mon, 5 Dec 2022 21:34:20 +0100 Subject: [PATCH 061/110] gallery: Do not invert image colors --- apps/gallery/ChangeLog | 3 ++- apps/gallery/app.js | 6 +++--- apps/gallery/metadata.json | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/apps/gallery/ChangeLog b/apps/gallery/ChangeLog index 76db22053..0167bc1f9 100644 --- a/apps/gallery/ChangeLog +++ b/apps/gallery/ChangeLog @@ -1,2 +1,3 @@ 0.01: New app! -0.02: Submitted to app loader \ No newline at end of file +0.02: Submitted to app loader +0.03: Do not invert colors diff --git a/apps/gallery/app.js b/apps/gallery/app.js index ca9392f13..6fb2bdf49 100644 --- a/apps/gallery/app.js +++ b/apps/gallery/app.js @@ -35,7 +35,7 @@ function drawImage(fileName) { Bangle.setLCDBrightness(1); // Full brightness image = eval(storage.read(fileName)); // Sadly, the only reasonable way to do this - g.clear().reset().drawImage(image, 88, 88, { rotate: angle }); + g.clear().reset().setBgColor(0).setColor("#fff").drawImage(image, 88, 88, { rotate: angle }); } setWatch(info => { @@ -44,9 +44,9 @@ setWatch(info => { else angle = 0; Bangle.buzz(); - g.clear().reset().drawImage(image, 88, 88, { rotate: angle }) + g.clear().reset().setBgColor(0).setColor("#fff").drawImage(image, 88, 88, { rotate: angle }) } }, BTN1, { repeat: true }); // We don't load the widgets because there is no reasonable way to unload them -drawMenu(); \ No newline at end of file +drawMenu(); diff --git a/apps/gallery/metadata.json b/apps/gallery/metadata.json index 0dc8d1613..00ac42075 100644 --- a/apps/gallery/metadata.json +++ b/apps/gallery/metadata.json @@ -1,7 +1,7 @@ { "id": "gallery", "name": "Gallery", - "version": "0.02", + "version": "0.03", "description": "A gallery that lets you view images uploaded with the IDE (see README)", "readme": "README.md", "icon": "icon.png", From 350e0057f417752faa91f62b35eb54a522e56e7a Mon Sep 17 00:00:00 2001 From: thyttan <6uuxstm66@mozmail.com⁩> Date: Sat, 12 Nov 2022 23:29:27 +0100 Subject: [PATCH 062/110] podadrem - compatibility with Fastload Utils --- apps/podadrem/ChangeLog | 1 + apps/podadrem/app.js | 90 +++++++++++++++++++++---------------- apps/podadrem/metadata.json | 2 +- 3 files changed, 53 insertions(+), 40 deletions(-) diff --git a/apps/podadrem/ChangeLog b/apps/podadrem/ChangeLog index c26e40c0e..837ef7941 100644 --- a/apps/podadrem/ChangeLog +++ b/apps/podadrem/ChangeLog @@ -4,3 +4,4 @@ Addict. 0.04: New layout. 0.05: Add widget field, tweak layout. +0.06: Add compatibility with Fastload Utils. diff --git a/apps/podadrem/app.js b/apps/podadrem/app.js index b04d80b17..0e32847ef 100644 --- a/apps/podadrem/app.js +++ b/apps/podadrem/app.js @@ -1,3 +1,4 @@ +{ /* Bluetooth.println(JSON.stringify({t:"intent", action:"", flags:["flag1", "flag2",...], categories:["category1","category2",...], mimetype:"", data:"", package:"", class:"", target:"", extra:{someKey:"someValueOrString"}})); @@ -65,13 +66,14 @@ Since v2020.16 com.bambuna.podcastaddict.service.player.togglespeed – This will toggle the Playback speed for the episode currently playing (alternate between selected speed and 1.0x). */ -var R; -var backToMenu = false; -var dark = g.theme.dark; // bool +let R; +let widgetUtils = require("widget_utils"); +let backToMenu = false; +let dark = g.theme.dark; // bool // The main layout of the app -function gfx() { - //Bangle.drawWidgets(); +let gfx = function() { + widgetUtils.hide(); R = Bangle.appRect; marigin = 8; // g.drawString(str, x, y, solid) @@ -106,10 +108,10 @@ function gfx() { g.setFontAlign(1, 1, 0); g.drawString("Speed", R.x + R.w - 2*marigin, R.y + R.h - 2*marigin); -} +}; // Touch handler for main layout -function touchHandler(_, xy) { +let touchHandler = function(_, xy) { x = xy.x; y = xy.y; len = (R.w { - if (ud) Bangle.musicControl(ud>0 ? "volumedown" : "volumeup"); - } + {mode : "updown", + remove : ()=>{ + Bangle.removeListener("touch", touchHandler); + Bangle.removeListener("swipe", swipeHandler); + clearWatch(buttonHandler); + widgetUtils.show(); + } + }, + ud => { + if (ud) Bangle.musicControl(ud>0 ? "volumedown" : "volumeup"); + } ); Bangle.on("touch", touchHandler); Bangle.on("swipe", swipeHandler); -} + let buttonHandler = setWatch(()=>{load();}, BTN, {edge:'falling'}); +}; /* The functions for interacting with Android and the Podcast Addict app */ -pkg = "com.bambuna.podcastaddict"; -standardCls = pkg + ".receiver.PodcastAddictPlayerReceiver"; -updateCls = pkg + ".receiver.PodcastAddictBroadcastReceiver"; -speed = 1.0; +let pkg = "com.bambuna.podcastaddict"; +let standardCls = pkg + ".receiver.PodcastAddictPlayerReceiver"; +let updateCls = pkg + ".receiver.PodcastAddictBroadcastReceiver"; +let speed = 1.0; -simpleSearch = ""; +let simpleSearch = ""; -function simpleSearchTerm() { // input a simple search term without tags, overrides search with tags (artist and track) +let simpleSearchTerm = function() { // input a simple search term without tags, overrides search with tags (artist and track) require("textinput").input({ text: simpleSearch }).then(result => { @@ -189,9 +199,9 @@ function simpleSearchTerm() { // input a simple search term without tags, overri }).then(() => { E.showMenu(searchMenu); }); -} +}; -function searchPlayWOTags() { //make a search and play using entered terms +let searchPlayWOTags = function() { //make a search and play using entered terms searchString = simpleSearch; Bluetooth.println(JSON.stringify({ t: "intent", @@ -203,9 +213,9 @@ function searchPlayWOTags() { //make a search and play using entered terms }, flags: ["FLAG_ACTIVITY_NEW_TASK"] })); -} +}; -function gadgetbridgeWake() { +let gadgetbridgeWake = function() { Bluetooth.println(JSON.stringify({ t: "intent", target: "activity", @@ -213,15 +223,15 @@ function gadgetbridgeWake() { package: "gadgetbridge", class: "nodomain.freeyourgadget.gadgetbridge.activities.WakeActivity" })); -} +}; // For stringing together the action for Podcast Addict to perform -function actFn(actName, activOrServ) { +let actFn = function(actName, activOrServ) { return "com.bambuna.podcastaddict." + (activOrServ == "service" ? "service." : "") + actName; -} +}; // Send the intent message to Gadgetbridge -function btMsg(activOrServ, cls, actName, xtra) { +let btMsg = function(activOrServ, cls, actName, xtra) { Bluetooth.println(JSON.stringify({ t: "intent", @@ -231,10 +241,10 @@ function btMsg(activOrServ, cls, actName, xtra) { target: "broadcastreceiver", extra: xtra })); -} +}; // Get back to the main layout -function backToGfx() { +let backToGfx = function() { E.showMenu(); g.clear(); g.reset(); @@ -243,10 +253,10 @@ function backToGfx() { setUI(); gfx(); backToMenu = false; -} +}; // Podcast Addict Menu -var paMenu = { +let paMenu = { "": { title: " ", back: backToGfx @@ -271,7 +281,7 @@ var paMenu = { }; -var controlMenu = { +let controlMenu = { "": { title: " ", back: () => {if (backToMenu) E.showMenu(paMenu); @@ -310,7 +320,7 @@ var controlMenu = { }, }; -var speedMenu = { +let speedMenu = { "": { title: " ", back: () => {if (backToMenu) E.showMenu(paMenu); @@ -333,7 +343,7 @@ var speedMenu = { //"Slower" : ()=>{speed-=0.1; speed=((speed<0.1)?0.1:speed); btMsg("service",standardCls,"player.customspeed",{arg1:speed});}, }; -var searchMenu = { +let searchMenu = { "": { title: " ", @@ -356,7 +366,7 @@ var searchMenu = { "Simpler search and play" : searchPlayWOTags, }; -var navigationMenu = { +let navigationMenu = { "": { title: " ", back: () => {if (backToMenu) E.showMenu(paMenu); @@ -372,4 +382,6 @@ var navigationMenu = { Bangle.loadWidgets(); setUI(); +widgetUtils.hide(); gfx(); +} diff --git a/apps/podadrem/metadata.json b/apps/podadrem/metadata.json index 929269762..3d49dfdbd 100644 --- a/apps/podadrem/metadata.json +++ b/apps/podadrem/metadata.json @@ -2,7 +2,7 @@ "id": "podadrem", "name": "Podcast Addict Remote", "shortName": "PA Remote", - "version": "0.05", + "version": "0.06", "description": "Control Podcast Addict on your android device.", "readme": "README.md", "type": "app", From 22b97ac96298d4d8680624f377f6029e88aef799 Mon Sep 17 00:00:00 2001 From: Hugh Barney Date: Mon, 5 Dec 2022 20:41:42 +0000 Subject: [PATCH 063/110] Prime Lato: changed to a prime icon --- apps/primetimelato/README.md | 2 +- apps/primetimelato/app.png | Bin 710 -> 1455 bytes 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/primetimelato/README.md b/apps/primetimelato/README.md index 924a6fae6..0ffd5a3fa 100644 --- a/apps/primetimelato/README.md +++ b/apps/primetimelato/README.md @@ -1,4 +1,4 @@ -# Prime Time Lato (clock) +# Prime Lato (clock) A watchface that displays time and its prime factors in the Lato font. For example when the time is 21:05, the prime factors are 5,421. diff --git a/apps/primetimelato/app.png b/apps/primetimelato/app.png index 2a84c62a07e71744a3721a4a7f8e3caa3721d71c..e5762b97cbfbc9ecfb0bf3c51c5c83947529359f 100644 GIT binary patch literal 1455 zcmV;g1yK5lP)Px)X-PyuRA@u(SZPR&q@sG*rwZs8B@N2Nw22BC;h zKhgv-C6^zHC{z-emQ)BWC>bf`R%EUSfq|mt9%`Hm?=Yh?-#70xLkjc!aeU{#_nz}C z=Xvg!tgf!EViTK*k-$HWo-qRdH~`r25%}`u3!I#suw%y#wZ7WW1bTaW5f&B(Yin!7 z#>V2>wQJbEeY*;g4Nc(ErAsI;FUQKtiU9ul^=o)}d2J2?Gcz;r_4UQ4PoD%}e}8|} z)zx9wu3ejhz{igtar*RW{P^($rlzLI$;m-hR+jjzY#TC#m@-vWRY*%q!`$2)9336; z>eVZ_ySuL|xI z=L{|;@~}d_J}6Kv{-BO9sx3y4jnoq8q<|4 zR}|V_U0tmfw8n&2^M&jb8W|ZuL_`F-y1HOyW`^9{T->~QQ{$Pbsj0Ys|31vk%|%f% zo%pw-qeCU#94p6CE8bij$z!nQ{tAz2MHBJ3?0VWwHpodGiK=fq@Ed78VwYXlPQ3g@pxN zxNt#8BG-6(dyCH;&h%xn2;}GIt9Xx*P*=PXxbg9E#Kgql?c2BFR#j0^A*5HICW`=D zI+a6N;{FQ^WtIfS#>U{_-~i6}E-o(m#4qnsf9%*XusP9KxZl2g(+KAG@87t7{ko!Q zu{*O1>)W)B02S!Kfdd#E926Kh9=v$*VjUi-9ymfU=Otse<%pnf)0)8Y@-p`A+b49K zcIwnAG&VM>#WOoQi<2i$;{E&gLT*VaI5-$DU%u2ge(h6;AXuNwxOMB6;vD{FbMfLu@juD1OLI+BRFs&1copQ7N&>tRN&>(r zG9sLhxNhwbD2IqF0`2YX@bU2h6^5SQy?Zyp!^4HfvuL}!yM=7B!SOrFD7*E~pFhPK zf+pDd`g*WV%F4=c=FAz5*F|lJ$RfZ(=FHDYlqMA@KXaVmSj{V-t*x#2o&`?=)PH5$ zxpSwe2NwF@nk)i5jN?H`NeP}me~yWX3E|QG`}Yf3O-xK&hlfhV`z^b&ot+(cUF1kj zMf<IZDlYK6plC9#C2_7H34NN*1f&$wCm3D!(usgB2N~)e zBLPEsR@;4z5zy9ChFWKgfT29A?Y_ncXzM9MtusczP@dIx-#_QO0-mUQetiG{002ov JPDHLkV1k&)$d>>B literal 710 zcmV;%0y+JOP)Px%fJsC_R9Hvtm^+TbFc5|(bXUD~@YEpQpp&!1vedHBEsjPT^cG zM;ybcdbe!c0b3UI$(&QzDXb~rLc)cF3yHL2;5Q1RAQ}#bY@%AN((!nFiCZidxfVfv zq8@m6zu)su!T0{Zv>2;NWb5I8d`y=R4S}elv5oT zp@7cHvoaD^fhBfzqXILTObFX76JR{ETrNp=IeN$>g@uvANx-k1=n7-f;;h%}JSysL zCJB~1XHvi?g~U6+dIzBR{eF)eohZ9Tz)=(9)udA$MNK+2bW#IGKE=$J^n=tSX-$t| zbzi6hOL`P&gasz8WR#?^Fjg3b;uemmED^O32&9AUmcGzol?iP_O(r z;Iv2Ke=3Yr)#-G?>I~TgUpu8*)7!rp1#1eQPN#>@ut-yCZq?hLLR$ewZGe(d77XNN zwYb;YpTZi~5=joEw%u;GwApOJ599iWa%m^o%Pg&_OR|)WrYo3fC#-~osWThTIba(q sW){O~!&=J{S%8WU7sF|*{dEfe0H(cp6H7fzivR!s07*qoM6N<$f*j~OtpET3 From b124bfade5ff3da2eaf5b3bec10d728cdd1690ff Mon Sep 17 00:00:00 2001 From: thyttan <6uuxstm66@mozmail.com⁩> Date: Sat, 12 Nov 2022 22:35:23 +0100 Subject: [PATCH 064/110] spotrem - compatibility with Fastload Utils --- apps/spotrem/ChangeLog | 1 + apps/spotrem/app.js | 160 ++++++++++++++++++++----------------- apps/spotrem/metadata.json | 2 +- 3 files changed, 87 insertions(+), 76 deletions(-) diff --git a/apps/spotrem/ChangeLog b/apps/spotrem/ChangeLog index 8e3d8b652..f54b4a0fa 100644 --- a/apps/spotrem/ChangeLog +++ b/apps/spotrem/ChangeLog @@ -3,3 +3,4 @@ 0.03: change handling of intent extras. 0.04: New layout. 0.05: Add widgets field. Tweak layout. +0.06: Make compatible with Fastload Utils app. diff --git a/apps/spotrem/app.js b/apps/spotrem/app.js index 7e76d84bc..d66b466d2 100644 --- a/apps/spotrem/app.js +++ b/apps/spotrem/app.js @@ -1,21 +1,23 @@ +{ /* Bluetooth.println(JSON.stringify({t:"intent", action:"", flags:["flag1", "flag2",...], categories:["category1","category2",...], mimetype:"", data:"", package:"", class:"", target:"", extra:{someKey:"someValueOrString"}})); */ -var R; -var backToMenu = false; -var isPaused = true; -var dark = g.theme.dark; // bool +let R; +let widgetUtils = require("widget_utils"); +let backToMenu = false; +let isPaused = true; +let dark = g.theme.dark; // bool // The main layout of the app -function gfx() { - //Bangle.drawWidgets(); +let gfx = function() { + widgetUtils.hide(); R = Bangle.appRect; marigin = 8; // g.drawString(str, x, y, solid) g.clearRect(R); g.reset(); - + if (dark) {g.setColor(0x07E0);} else {g.setColor(0x03E0);} // Green on dark theme, DarkGreen on light theme. g.setFont("4x6:2"); g.setFontAlign(1, 0, 0); @@ -44,10 +46,10 @@ function gfx() { g.setFontAlign(1, 1, 0); g.drawString("Saved", R.x + R.w - 2*marigin, R.y + R.h - 2*marigin); -} +}; // Touch handler for main layout -function touchHandler(_, xy) { +let touchHandler = function(_, xy) { x = xy.x; y = xy.y; len = (R.w { - if (ud) Bangle.musicControl(ud>0 ? "volumedown" : "volumeup"); - } + {mode : "updown", + remove : ()=>{ + Bangle.removeListener("touch", touchHandler); + Bangle.removeListener("swipe", swipeHandler); + clearWatch(buttonHandler); + widgetUtils.show(); + } + }, + ud => { + if (ud) Bangle.musicControl(ud>0 ? "volumedown" : "volumeup"); + } ); Bangle.on("touch", touchHandler); Bangle.on("swipe", swipeHandler); -} - - + let buttonHandler = setWatch(()=>{load();}, BTN, {edge:'falling'}); +}; // Get back to the main layout -function backToGfx() { +let backToGfx = function() { E.showMenu(); g.clear(); g.reset(); @@ -122,109 +130,109 @@ function backToGfx() { setUI(); gfx(); backToMenu = false; -} +}; /* The functions for interacting with Android and the Spotify app */ simpleSearch = ""; -function simpleSearchTerm() { // input a simple search term without tags, overrides search with tags (artist and track) +let simpleSearchTerm = function() { // input a simple search term without tags, overrides search with tags (artist and track) require("textinput").input({text:simpleSearch}).then(result => {simpleSearch = result;}).then(() => {E.showMenu(searchMenu);}); -} +}; artist = ""; -function artistSearchTerm() { // input artist to search for +let artistSearchTerm = function() { // input artist to search for require("textinput").input({text:artist}).then(result => {artist = result;}).then(() => {E.showMenu(searchMenu);}); -} +}; track = ""; -function trackSearchTerm() { // input track to search for +let trackSearchTerm = function() { // input track to search for require("textinput").input({text:track}).then(result => {track = result;}).then(() => {E.showMenu(searchMenu);}); -} +}; album = ""; -function albumSearchTerm() { // input album to search for +let albumSearchTerm = function() { // input album to search for require("textinput").input({text:album}).then(result => {album = result;}).then(() => {E.showMenu(searchMenu);}); -} +}; -function searchPlayWOTags() {//make a spotify search and play using entered terms +let searchPlayWOTags = function() {//make a spotify search and play using entered terms searchString = simpleSearch; Bluetooth.println(JSON.stringify({t:"intent", action:"android.media.action.MEDIA_PLAY_FROM_SEARCH", categories:["android.intent.category.DEFAULT"], package:"com.spotify.music", target:"activity", extra:{query:searchString}, flags:["FLAG_ACTIVITY_NEW_TASK"]})); -} +}; -function searchPlayWTags() {//make a spotify search and play using entered terms +let searchPlayWTags = function() {//make a spotify search and play using entered terms searchString = (artist=="" ? "":("artist:\""+artist+"\"")) + ((artist!="" && track!="") ? " ":"") + (track=="" ? "":("track:\""+track+"\"")) + (((artist!="" && album!="") || (track!="" && album!="")) ? " ":"") + (album=="" ? "":(" album:\""+album+"\"")); Bluetooth.println(JSON.stringify({t:"intent", action:"android.media.action.MEDIA_PLAY_FROM_SEARCH", categories:["android.intent.category.DEFAULT"], package:"com.spotify.music", target:"activity", extra:{query:searchString}, flags:["FLAG_ACTIVITY_NEW_TASK"]})); -} +}; -function playVreden() {//Play the track "Vreden" by Sara Parkman via spotify uri-link +let playVreden = function() {//Play the track "Vreden" by Sara Parkman via spotify uri-link Bluetooth.println(JSON.stringify({t:"intent", action:"android.intent.action.VIEW", categories:["android.intent.category.DEFAULT"], package:"com.spotify.music", data:"spotify:track:5QEFFJ5tAeRlVquCUNpAJY:play", target:"activity" , flags:["FLAG_ACTIVITY_NEW_TASK", "FLAG_ACTIVITY_NO_ANIMATION"/*, "FLAG_ACTIVITY_CLEAR_TOP", "FLAG_ACTIVITY_PREVIOUS_IS_TOP"*/]})); -} +}; -function playVredenAlternate() {//Play the track "Vreden" by Sara Parkman via spotify uri-link +let playVredenAlternate = function() {//Play the track "Vreden" by Sara Parkman via spotify uri-link Bluetooth.println(JSON.stringify({t:"intent", action:"android.intent.action.VIEW", categories:["android.intent.category.DEFAULT"], package:"com.spotify.music", data:"spotify:track:5QEFFJ5tAeRlVquCUNpAJY:play", target:"activity" , flags:["FLAG_ACTIVITY_NEW_TASK"]})); -} +}; -function searchPlayVreden() {//Play the track "Vreden" by Sara Parkman via search and play +let searchPlayVreden = function() {//Play the track "Vreden" by Sara Parkman via search and play Bluetooth.println(JSON.stringify({t:"intent", action:"android.media.action.MEDIA_PLAY_FROM_SEARCH", categories:["android.intent.category.DEFAULT"], package:"com.spotify.music", target:"activity", extra:{query:'artist:"Sara Parkman" track:"Vreden"'}, flags:["FLAG_ACTIVITY_NEW_TASK"]})); -} +}; -function openAlbum() {//Play EP "The Blue Room" by Coldplay +let openAlbum = function() {//Play EP "The Blue Room" by Coldplay Bluetooth.println(JSON.stringify({t:"intent", action:"android.intent.action.VIEW", categories:["android.intent.category.DEFAULT"], package:"com.spotify.music", data:"spotify:album:3MVb2CWB36x7VwYo5sZmf2", target:"activity", flags:["FLAG_ACTIVITY_NEW_TASK"]})); -} +}; -function searchPlayAlbum() {//Play EP "The Blue Room" by Coldplay via search and play +let searchPlayAlbum = function() {//Play EP "The Blue Room" by Coldplay via search and play Bluetooth.println(JSON.stringify({t:"intent", action:"android.media.action.MEDIA_PLAY_FROM_SEARCH", categories:["android.intent.category.DEFAULT"], package:"com.spotify.music", target:"activity", extra:{query:'album:"The blue room" artist:"Coldplay"', "android.intent.extra.focus":"vnd.android.cursor.item/album"}, flags:["FLAG_ACTIVITY_NEW_TASK"]})); -} +}; -function spotifyWidget(action) { +let spotifyWidget = function(action) { Bluetooth.println(JSON.stringify({t:"intent", action:("com.spotify.mobile.android.ui.widget."+action), package:"com.spotify.music", target:"broadcastreceiver"})); -} +}; -function gadgetbridgeWake() { +let gadgetbridgeWake = function() { Bluetooth.println(JSON.stringify({t:"intent", target:"activity", flags:["FLAG_ACTIVITY_NEW_TASK", "FLAG_ACTIVITY_CLEAR_TASK", "FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS", "FLAG_ACTIVITY_NO_ANIMATION"], package:"gadgetbridge", class:"nodomain.freeyourgadget.gadgetbridge.activities.WakeActivity"})); -} +}; -function spotifyPlaylistDW() { +let spotifyPlaylistDW = function() { Bluetooth.println(JSON.stringify({t:"intent", action:"android.intent.action.VIEW", categories:["android.intent.category.DEFAULT"], package:"com.spotify.music", data:"spotify:user:spotify:playlist:37i9dQZEVXcRfaeEbxXIgb:play", target:"activity" , flags:["FLAG_ACTIVITY_NEW_TASK", "FLAG_ACTIVITY_NO_ANIMATION"/*, "FLAG_ACTIVITY_CLEAR_TOP", "FLAG_ACTIVITY_PREVIOUS_IS_TOP"*/]})); -} +}; -function spotifyPlaylistDM1() { +let spotifyPlaylistDM1 = function() { Bluetooth.println(JSON.stringify({t:"intent", action:"android.intent.action.VIEW", categories:["android.intent.category.DEFAULT"], package:"com.spotify.music", data:"spotify:user:spotify:playlist:37i9dQZF1E365VyzxE0mxF:play", target:"activity" , flags:["FLAG_ACTIVITY_NEW_TASK", "FLAG_ACTIVITY_NO_ANIMATION"/*, "FLAG_ACTIVITY_CLEAR_TOP", "FLAG_ACTIVITY_PREVIOUS_IS_TOP"*/]})); -} +}; -function spotifyPlaylistDM2() { +let spotifyPlaylistDM2 = function() { Bluetooth.println(JSON.stringify({t:"intent", action:"android.intent.action.VIEW", categories:["android.intent.category.DEFAULT"], package:"com.spotify.music", data:"spotify:user:spotify:playlist:37i9dQZF1E38LZHLFnrM61:play", target:"activity" , flags:["FLAG_ACTIVITY_NEW_TASK", "FLAG_ACTIVITY_NO_ANIMATION"/*, "FLAG_ACTIVITY_CLEAR_TOP", "FLAG_ACTIVITY_PREVIOUS_IS_TOP"*/]})); -} +}; -function spotifyPlaylistDM3() { +let spotifyPlaylistDM3 = function() { Bluetooth.println(JSON.stringify({t:"intent", action:"android.intent.action.VIEW", categories:["android.intent.category.DEFAULT"], package:"com.spotify.music", data:"spotify:user:spotify:playlist:37i9dQZF1E36RU87qzgBFP:play", target:"activity" , flags:["FLAG_ACTIVITY_NEW_TASK", "FLAG_ACTIVITY_NO_ANIMATION"/*, "FLAG_ACTIVITY_CLEAR_TOP", "FLAG_ACTIVITY_PREVIOUS_IS_TOP"*/]})); -} +}; -function spotifyPlaylistDM4() { +let spotifyPlaylistDM4 = function() { Bluetooth.println(JSON.stringify({t:"intent", action:"android.intent.action.VIEW", categories:["android.intent.category.DEFAULT"], package:"com.spotify.music", data:"spotify:user:spotify:playlist:37i9dQZF1E396gGyCXEBFh:play", target:"activity" , flags:["FLAG_ACTIVITY_NEW_TASK", "FLAG_ACTIVITY_NO_ANIMATION"/*, "FLAG_ACTIVITY_CLEAR_TOP", "FLAG_ACTIVITY_PREVIOUS_IS_TOP"*/]})); -} +}; -function spotifyPlaylistDM5() { +let spotifyPlaylistDM5 = function() { Bluetooth.println(JSON.stringify({t:"intent", action:"android.intent.action.VIEW", categories:["android.intent.category.DEFAULT"], package:"com.spotify.music", data:"spotify:user:spotify:playlist:37i9dQZF1E37a0Tt6CKJLP:play", target:"activity" , flags:["FLAG_ACTIVITY_NEW_TASK", "FLAG_ACTIVITY_NO_ANIMATION"/*, "FLAG_ACTIVITY_CLEAR_TOP", "FLAG_ACTIVITY_PREVIOUS_IS_TOP"*/]})); -} +}; -function spotifyPlaylistDM6() { +let spotifyPlaylistDM6 = function() { Bluetooth.println(JSON.stringify({t:"intent", action:"android.intent.action.VIEW", categories:["android.intent.category.DEFAULT"], package:"com.spotify.music", data:"spotify:user:spotify:playlist:37i9dQZF1E36UIQLQK79od:play", target:"activity" , flags:["FLAG_ACTIVITY_NEW_TASK", "FLAG_ACTIVITY_NO_ANIMATION"/*, "FLAG_ACTIVITY_CLEAR_TOP", "FLAG_ACTIVITY_PREVIOUS_IS_TOP"*/]})); -} +}; -function spotifyPlaylistDD() { +let spotifyPlaylistDD = function() { Bluetooth.println(JSON.stringify({t:"intent", action:"android.intent.action.VIEW", categories:["android.intent.category.DEFAULT"], package:"com.spotify.music", data:"spotify:user:spotify:playlist:37i9dQZF1EfWFiI7QfIAKq:play", target:"activity" , flags:["FLAG_ACTIVITY_NEW_TASK", "FLAG_ACTIVITY_NO_ANIMATION"/*, "FLAG_ACTIVITY_CLEAR_TOP", "FLAG_ACTIVITY_PREVIOUS_IS_TOP"*/]})); -} +}; -function spotifyPlaylistRR() { +let spotifyPlaylistRR = function() { Bluetooth.println(JSON.stringify({t:"intent", action:"android.intent.action.VIEW", categories:["android.intent.category.DEFAULT"], package:"com.spotify.music", data:"spotify:user:spotify:playlist:37i9dQZEVXbs0XkE2V8sMO:play", target:"activity" , flags:["FLAG_ACTIVITY_NEW_TASK", "FLAG_ACTIVITY_NO_ANIMATION"/*, "FLAG_ACTIVITY_CLEAR_TOP", "FLAG_ACTIVITY_PREVIOUS_IS_TOP"*/]})); -} +}; // Spotify Remote Menu -var spotifyMenu = { - "" : { title : " ", +let spotifyMenu = { + "" : { title : " Menu ", back: backToGfx }, "Controls" : ()=>{E.showMenu(controlMenu);}, "Search and play" : ()=>{E.showMenu(searchMenu);}, @@ -234,8 +242,8 @@ var spotifyMenu = { }; -var controlMenu = { - "" : { title : " ", +let controlMenu = { + "" : { title : " Controls ", back: () => {if (backToMenu) E.showMenu(spotifyMenu); if (!backToMenu) backToGfx();} }, "Play" : ()=>{Bangle.musicControl("play");}, @@ -246,8 +254,8 @@ var controlMenu = { "Messages Music Controls" : ()=>{load("messagesmusic.app.js");}, }; -var searchMenu = { - "" : { title : " ", +let searchMenu = { + "" : { title : " Search ", back: () => {if (backToMenu) E.showMenu(spotifyMenu); if (!backToMenu) backToGfx();} }, "Search term w/o tags" : ()=>{simpleSearchTerm();}, @@ -258,8 +266,8 @@ var searchMenu = { "Execute search and play with tags" : ()=>{searchPlayWTags();}, }; -var savedMenu = { - "" : { title : " ", +let savedMenu = { + "" : { title : " Saved ", back: () => {if (backToMenu) E.showMenu(spotifyMenu); if (!backToMenu) backToGfx();} }, "Play Discover Weekly" : ()=>{spotifyPlaylistDW();}, @@ -278,4 +286,6 @@ var savedMenu = { Bangle.loadWidgets(); setUI(); +widgetUtils.hide(); gfx(); +} diff --git a/apps/spotrem/metadata.json b/apps/spotrem/metadata.json index a0261ba13..ac891f1cc 100644 --- a/apps/spotrem/metadata.json +++ b/apps/spotrem/metadata.json @@ -1,7 +1,7 @@ { "id": "spotrem", "name": "Remote for Spotify", - "version": "0.05", + "version": "0.06", "description": "Control spotify on your android device.", "readme": "README.md", "type": "app", From 684c54e884788b3ad897959cc6689e176d82af7e Mon Sep 17 00:00:00 2001 From: thyttan <6uuxstm66@mozmail.com⁩> Date: Mon, 5 Dec 2022 22:26:35 +0100 Subject: [PATCH 065/110] rebase on latest changes --- apps/swscroll/ChangeLog | 1 + apps/swscroll/boot.js | 94 ++++++++++++++++++++----------------- apps/swscroll/metadata.json | 2 +- 3 files changed, 52 insertions(+), 45 deletions(-) diff --git a/apps/swscroll/ChangeLog b/apps/swscroll/ChangeLog index c650baf72..c5fc9dcb4 100644 --- a/apps/swscroll/ChangeLog +++ b/apps/swscroll/ChangeLog @@ -1 +1,2 @@ 0.01: Inital release. +0.02: Rebasing on latest changes to showScroller_Q3 (https://github.com/espruino/Espruino/commit/2d3c34ef7c2b9fe2118e816aacd2e096adb99596). diff --git a/apps/swscroll/boot.js b/apps/swscroll/boot.js index fc5650cad..2b1b00de3 100644 --- a/apps/swscroll/boot.js +++ b/apps/swscroll/boot.js @@ -1,13 +1,14 @@ -E.showScroller = (function(options) { +E.showScroller = (function(options) { /* options = { h = height c = # of items scroll = initial scroll position scrollMin = minimum scroll amount (can be negative) draw = function(idx, rect) - select = function(idx) + remove = function() + select = function(idx, touch) } - + returns { draw = draw all drawItem(idx) = draw specific item @@ -15,46 +16,13 @@ E.showScroller = (function(options) { */ if (!options) return Bangle.setUI(); // remove existing handlers -var menuShowing = false; -var R = Bangle.appRect; -var Y = Bangle.appRect.y; -var n = Math.ceil(R.h/options.h); -var menuScrollMin = 0|options.scrollMin; -var menuScrollMax = options.h*options.c - R.h; -if (menuScrollMax { - g.reset().clearRect(R.x,R.y,R.x2,R.y2); - g.setClipRect(R.x,R.y,R.x2,R.y2); - var a = YtoIdx(R.y); - var b = Math.min(YtoIdx(R.y2),options.c-1); - for (var i=a;i<=b;i++) - options.draw(i, {x:R.x,y:idxToY(i),w:R.w,h:options.h}); - g.setClipRect(0,0,g.getWidth()-1,g.getHeight()-1); -}, drawItem : i => { - var y = idxToY(i); - g.reset().setClipRect(R.x,y,R.x2,y+options.h); - options.draw(i, {x:R.x,y:y,w:R.w,h:options.h}); - g.setClipRect(0,0,g.getWidth()-1,g.getHeight()-1); -}}; -var rScroll = s.scroll&~1; // rendered menu scroll (we only shift by 2 because of dither) -s.draw(); // draw the full scroller -g.flip(); // force an update now to make this snappier Bangle.setUI({ mode : "custom", back : options.back, - swipe : (hor,ver)=>{ + remove : options.remove, + swipe : (_,UD)=>{ pixels = 120; - var dy = ver*pixels; + var dy = UD*pixels; if (s.scroll - dy > menuScrollMax) dy = s.scroll - menuScrollMax-8; // Makes it so the last 'page' has the same position as previous pages. This should be done dynamically (change the static 8 to be a variable) so the offset is correct even when no widget field or title field is present. if (s.scroll - dy < menuScrollMin) @@ -66,7 +34,7 @@ Bangle.setUI({ if (!dy || options.c<=3) return; //options.c<=3 should maybe be dynamic, so 3 would be replaced by a variable dependent on R=Bangle.appRect. It's here so we don't try to scroll if all entries fit in the app rectangle. g.reset().setClipRect(R.x,R.y,R.x2,R.y2); g.scroll(0,dy); - var d = ver*pixels; + var d = UD*pixels; if (d < 0) { g.setClipRect(R.x,R.y2-(1-d),R.x2,R.y2); let i = YtoIdx(R.y2-(1-d)); @@ -92,9 +60,47 @@ Bangle.setUI({ }, touch : (_,e)=>{ if (e.y=0) && i=0) && i { + g.reset().clearRect(R.x,R.y,R.x2,R.y2); + g.setClipRect(R.x,R.y,R.x2,R.y2); + var a = YtoIdx(R.y); + var b = Math.min(YtoIdx(R.y2),options.c-1); + for (var i=a;i<=b;i++) + options.draw(i, {x:R.x,y:idxToY(i),w:R.w,h:options.h}); + g.setClipRect(0,0,g.getWidth()-1,g.getHeight()-1); +}, drawItem : i => { + var y = idxToY(i); + g.reset().setClipRect(R.x,y,R.x2,y+options.h); + options.draw(i, {x:R.x,y:y,w:R.w,h:options.h}); + g.setClipRect(0,0,g.getWidth()-1,g.getHeight()-1); +}}; +var rScroll = s.scroll&~1; // rendered menu scroll (we only shift by 2 because of dither) +s.draw(); // draw the full scroller +g.flip(); // force an update now to make this snappier return s; -}); +}) diff --git a/apps/swscroll/metadata.json b/apps/swscroll/metadata.json index cb345054e..4edbfa2ba 100644 --- a/apps/swscroll/metadata.json +++ b/apps/swscroll/metadata.json @@ -1,7 +1,7 @@ { "id": "swscroll", "name": "Swipe menus", - "version": "0.01", + "version": "0.02", "description": "Replace built in E.showScroller to act on swipe instead of drag. Navigate menus in discrete steps instead of a continuous motion.", "readme": "README.md", "icon": "app.png", From 341517881bd70657522385f49912ec8d0fd9cc22 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Tue, 6 Dec 2022 09:41:54 +0000 Subject: [PATCH 066/110] update docs to put the best solution at the top --- modules/README.md | 49 ++++++++++++++++++++++++++--------------------- 1 file changed, 27 insertions(+), 22 deletions(-) diff --git a/modules/README.md b/modules/README.md index 3f8e90b06..fcb403bd5 100644 --- a/modules/README.md +++ b/modules/README.md @@ -18,28 +18,6 @@ so you may see the error "Module not found" in the IDE when sendin To fix this you have three options: -### Host your own App Loader and upload from that - -This is reasonably easy to set up, but it's more difficult to make changes and upload: - -* Follow the steps here to set up your own App Loader: https://www.espruino.com/Bangle.js+App+Loader -* Make changes to that repository -* Refresh and upload your app from the app loader (you can have the IDE connected - at the same time so you can see any error messages) - -### Upload the module to the Bangle's internal storage - -This allows you to develop both the app and module very quickly, but the app is -uploaded in a slightly different way to what you'd get when you use the App Loader -or the method below: - -* Load the module's source file in the Web IDE -* Click the down-arrow below the upload button, then `Storage` -* Click `New File`, type `your_module_name` as the name (with no `.js` extension), click `Ok` -* Now Click the `Upload` icon. - -You can now upload the app direct from the IDE. You can even leave a second Web IDE window open -(one for the app, one for the module) to allow you to change the module. ### Change the Web IDE search path to include Bangle.js modules @@ -56,3 +34,30 @@ The next time you upload your app, the module will automatically be included. **Note:** You can optionally use `https://raw.githubusercontent.com/espruino/BangleApps/master/modules|https://www.espruino.com/modules` as the module URL to pull in modules direct from the development app loader (which could be slightly newer than the ones on https://banglejs.com/apps) + + +### Host your own App Loader and upload from that + +This is reasonably easy to set up, but it's more difficult to make changes and upload: + +* Follow the steps here to set up your own App Loader: https://www.espruino.com/Bangle.js+App+Loader +* Make changes to that repository +* Refresh and upload your app from the app loader (you can have the IDE connected + at the same time so you can see any error messages) + + +### Upload the module to the Bangle's internal storage + +This allows you to develop both the app and module very quickly, but the app is +uploaded in a slightly different way to what you'd get when you use the App Loader +or the method below: + +* Load the module's source file in the Web IDE +* Click the down-arrow below the upload button, then `Storage` +* Click `New File`, type `your_module_name` as the name (with no `.js` extension), click `Ok` +* Now Click the `Upload` icon. + +You can now upload the app direct from the IDE. You can even leave a second Web IDE window open +(one for the app, one for the module) to allow you to change the module. + + From 3e5c0538a9776014a7f99d8c3521d1372dde8a90 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Tue, 6 Dec 2022 10:25:32 +0000 Subject: [PATCH 067/110] Support for provides_widgets entry in metadata, and try and tag existing widgets Support for 'default' tag and add it to apps that we expect would be used by default with the Bangle split widalarm out of alarm fixes https://github.com/espruino/BangleApps/issues/2353 --- README.md | 5 ++++- apps/alarm/ChangeLog | 2 +- apps/alarm/metadata.json | 9 ++++----- apps/launch/metadata.json | 1 + apps/messagegui/metadata.json | 1 + apps/messageicons/metadata.json | 1 + apps/messages/metadata.json | 6 +++++- apps/sched/metadata.json | 2 ++ apps/widalarm/ChangeLog | 1 + apps/widalarm/app.png | Bin 0 -> 6229 bytes apps/widalarm/metadata.json | 15 +++++++++++++++ apps/{alarm => widalarm}/widget.js | 0 apps/widalarmeta/metadata.json | 1 + apps/widbat/metadata.json | 2 ++ apps/widbata/metadata.json | 1 + apps/widbatpc/metadata.json | 1 + apps/widbatv/metadata.json | 1 + apps/widbt/metadata.json | 2 ++ apps/widbt_notify/metadata.json | 3 ++- apps/widbthide/metadata.json | 1 + apps/widmessages/metadata.json | 2 ++ bin/sanitycheck.js | 6 +++--- core | 2 +- defaultapps_banglejs2.json | 2 +- 24 files changed, 53 insertions(+), 14 deletions(-) create mode 100644 apps/widalarm/ChangeLog create mode 100644 apps/widalarm/app.png create mode 100644 apps/widalarm/metadata.json rename apps/{alarm => widalarm}/widget.js (100%) diff --git a/README.md b/README.md index 1058787bb..fed13a358 100644 --- a/README.md +++ b/README.md @@ -282,8 +282,11 @@ and which gives information about the app for the Launcher. "dependencies" : { "notify":"type" } // optional, app 'types' we depend on (see "type" above) "dependencies" : { "messages":"app" } // optional, depend on a specific app ID // for instance this will use notify/notifyfs is they exist, or will pull in 'notify' - "dependencies" : { "messageicons":"module" } // optional, depend on a specific library to be used with 'require' + "dependencies" : { "messageicons":"module" } // optional, depend on a specific library to be used with 'require' - see provides_modules + "dependencies" : { "message":"widget" } // optional, depend on a specific type of widget - see provides_widgets "provides_modules" : ["messageicons"] // optional, this app provides a module that can be used with 'require' + "provides_widgets" : ["battery"] // optional, this app provides a type of widget - 'alarm/battery/bluetooth/pedometer/message' + "default" : true, // set if an app is the default implementer of something (a widget/module/etc) "readme": "README.md", // if supplied, a link to a markdown-style text file // that contains more information about this app (usage, etc) // A 'Read more...' link will be added under the app diff --git a/apps/alarm/ChangeLog b/apps/alarm/ChangeLog index 6ce6147ca..9994d33d9 100644 --- a/apps/alarm/ChangeLog +++ b/apps/alarm/ChangeLog @@ -36,4 +36,4 @@ 0.33: Allow hiding timers&alarms 0.34: Add "Confirm" option to alarm/timer edit menus 0.35: Add automatic translation of more strings - +0.36: alarm widget moved out of app diff --git a/apps/alarm/metadata.json b/apps/alarm/metadata.json index a02985851..dbf090774 100644 --- a/apps/alarm/metadata.json +++ b/apps/alarm/metadata.json @@ -2,17 +2,16 @@ "id": "alarm", "name": "Alarms & Timers", "shortName": "Alarms", - "version": "0.35", + "version": "0.36", "description": "Set alarms and timers on your Bangle", "icon": "app.png", - "tags": "tool,alarm,widget", + "tags": "tool,alarm", "supports": [ "BANGLEJS", "BANGLEJS2" ], "readme": "README.md", - "dependencies": { "scheduler":"type" }, + "dependencies": { "scheduler":"type", "alarm":"widget" }, "storage": [ { "name": "alarm.app.js", "url": "app.js" }, - { "name": "alarm.img", "url": "app-icon.js", "evaluate": true }, - { "name": "alarm.wid.js", "url": "widget.js" } + { "name": "alarm.img", "url": "app-icon.js", "evaluate": true } ], "screenshots": [ { "url": "screenshot-1.png" }, diff --git a/apps/launch/metadata.json b/apps/launch/metadata.json index 4d0270e37..85fcdd02f 100644 --- a/apps/launch/metadata.json +++ b/apps/launch/metadata.json @@ -7,6 +7,7 @@ "readme": "README.md", "icon": "app.png", "type": "launch", + "default": true, "tags": "tool,system,launcher", "supports": ["BANGLEJS","BANGLEJS2"], "storage": [ diff --git a/apps/messagegui/metadata.json b/apps/messagegui/metadata.json index b3e70d5d4..f3798f645 100644 --- a/apps/messagegui/metadata.json +++ b/apps/messagegui/metadata.json @@ -9,6 +9,7 @@ "supports": ["BANGLEJS","BANGLEJS2"], "dependencies" : { "messageicons":"module" }, "provides_modules": ["messagegui"], + "default": true, "readme": "README.md", "storage": [ {"name":"messagegui","url":"lib.js"}, diff --git a/apps/messageicons/metadata.json b/apps/messageicons/metadata.json index b6ce34f88..b621c55b9 100644 --- a/apps/messageicons/metadata.json +++ b/apps/messageicons/metadata.json @@ -8,6 +8,7 @@ "tags": "tool,system", "supports": ["BANGLEJS","BANGLEJS2"], "provides_modules" : ["messageicons"], + "default": true, "storage": [ {"name":"messageicons","url":"lib.js"} ] diff --git a/apps/messages/metadata.json b/apps/messages/metadata.json index 8bcf3da25..27e771975 100644 --- a/apps/messages/metadata.json +++ b/apps/messages/metadata.json @@ -8,7 +8,11 @@ "tags": "tool,system", "supports": ["BANGLEJS","BANGLEJS2"], "provides_modules" : ["messages"], - "dependencies" : { "messagegui":"module","messagewidget":"module" }, + "dependencies" : { + "messagegui":"module", + "message":"widget" + }, + "default": true, "readme": "README.md", "storage": [ {"name":"messages","url":"lib.js"}, diff --git a/apps/sched/metadata.json b/apps/sched/metadata.json index a457d0f44..a266d11f8 100644 --- a/apps/sched/metadata.json +++ b/apps/sched/metadata.json @@ -7,6 +7,8 @@ "type": "scheduler", "tags": "tool,system,alarm", "supports": ["BANGLEJS","BANGLEJS2"], + "provides_modules" : ["sched"], + "default" : true, "readme": "README.md", "storage": [ {"name":"sched.boot.js","url":"boot.js"}, diff --git a/apps/widalarm/ChangeLog b/apps/widalarm/ChangeLog new file mode 100644 index 000000000..63568a9bd --- /dev/null +++ b/apps/widalarm/ChangeLog @@ -0,0 +1 @@ +0.01: Moved out of 'alarm' app diff --git a/apps/widalarm/app.png b/apps/widalarm/app.png new file mode 100644 index 0000000000000000000000000000000000000000..a859dd2ef1768b0b260b996ef41920607c080913 GIT binary patch literal 6229 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 literal 0 HcmV?d00001 diff --git a/apps/widalarm/metadata.json b/apps/widalarm/metadata.json new file mode 100644 index 000000000..b91457138 --- /dev/null +++ b/apps/widalarm/metadata.json @@ -0,0 +1,15 @@ +{ + "id": "widalarm", + "name": "Alarms Widget", + "version": "0.01", + "description": "Displays an alarm icon in the widgets bar if any alarm is active", + "icon": "app.png", + "type": "widget", + "tags": "tool,alarm,widget", + "supports": [ "BANGLEJS", "BANGLEJS2" ], + "provides_widgets" : ["alarm"], + "default" : true, + "storage": [ + { "name": "widalarm.wid.js", "url": "widget.js" } + ] +} diff --git a/apps/alarm/widget.js b/apps/widalarm/widget.js similarity index 100% rename from apps/alarm/widget.js rename to apps/widalarm/widget.js diff --git a/apps/widalarmeta/metadata.json b/apps/widalarmeta/metadata.json index b6d8bd62b..ef9f55ba8 100644 --- a/apps/widalarmeta/metadata.json +++ b/apps/widalarmeta/metadata.json @@ -8,6 +8,7 @@ "type": "widget", "tags": "widget", "supports": ["BANGLEJS","BANGLEJS2"], + "provides_widgets" : ["alarm"], "screenshots" : [ { "url":"screenshot.png" } ], "storage": [ {"name":"widalarmeta.wid.js","url":"widget.js"} diff --git a/apps/widbat/metadata.json b/apps/widbat/metadata.json index 0f040396f..993310eb2 100644 --- a/apps/widbat/metadata.json +++ b/apps/widbat/metadata.json @@ -6,6 +6,8 @@ "icon": "widget.png", "type": "widget", "tags": "widget,battery", + "provides_widgets" : ["battery"], + "default" : true, "supports": ["BANGLEJS","BANGLEJS2"], "storage": [ {"name":"widbat.wid.js","url":"widget.js"} diff --git a/apps/widbata/metadata.json b/apps/widbata/metadata.json index 26968a7d7..ddc901e80 100644 --- a/apps/widbata/metadata.json +++ b/apps/widbata/metadata.json @@ -10,6 +10,7 @@ "readme": "README.md", "description": "Shows the current battery level status in the top right using the clocks colour theme", "tags": "widget,battery", + "provides_widgets" : ["battery"], "storage": [ {"name":"widbata.wid.js","url":"widbata.wid.js"} ] diff --git a/apps/widbatpc/metadata.json b/apps/widbatpc/metadata.json index 7da4e3e0c..953f8d345 100644 --- a/apps/widbatpc/metadata.json +++ b/apps/widbatpc/metadata.json @@ -7,6 +7,7 @@ "icon": "widget.png", "type": "widget", "tags": "widget,battery", + "provides_widgets" : ["battery"], "supports": ["BANGLEJS","BANGLEJS2"], "readme": "README.md", "screenshots": [{"url":"widbatpc.full.jpg"},{"url":"widbatpc.part.jpg"}], diff --git a/apps/widbatv/metadata.json b/apps/widbatv/metadata.json index 37cf6197b..d4ef28315 100644 --- a/apps/widbatv/metadata.json +++ b/apps/widbatv/metadata.json @@ -6,6 +6,7 @@ "icon": "widget.png", "type": "widget", "tags": "widget,battery", + "provides_widgets" : ["battery"], "supports": ["BANGLEJS","BANGLEJS2"], "storage": [ {"name":"widbatv.wid.js","url":"widget.js"} diff --git a/apps/widbt/metadata.json b/apps/widbt/metadata.json index e2d5082a5..1623db7a1 100644 --- a/apps/widbt/metadata.json +++ b/apps/widbt/metadata.json @@ -6,6 +6,8 @@ "icon": "widget.png", "type": "widget", "tags": "widget,bluetooth", + "provides_widgets" : ["bluetooth"], + "default" : true, "supports": ["BANGLEJS","BANGLEJS2"], "storage": [ {"name":"widbt.wid.js","url":"widget.js"} diff --git a/apps/widbt_notify/metadata.json b/apps/widbt_notify/metadata.json index 36905a340..5e3f15af2 100644 --- a/apps/widbt_notify/metadata.json +++ b/apps/widbt_notify/metadata.json @@ -6,6 +6,7 @@ "icon": "widget.png", "type": "widget", "tags": "widget,bluetooth", + "provides_widgets" : ["bluetooth"], "supports": ["BANGLEJS","BANGLEJS2"], "storage": [ {"name":"widbt_notify.wid.js","url":"widget.js"}, @@ -13,5 +14,5 @@ ], "data": [ {"name":"widbt_notify.json"} - ] + ] } diff --git a/apps/widbthide/metadata.json b/apps/widbthide/metadata.json index 59b13adb4..e3ac5cd54 100644 --- a/apps/widbthide/metadata.json +++ b/apps/widbthide/metadata.json @@ -6,6 +6,7 @@ "icon": "widget.png", "type": "widget", "tags": "widget,bluetooth", + "provides_widgets" : ["bluetooth"], "supports": ["BANGLEJS","BANGLEJS2"], "storage": [ {"name":"widbthide.wid.js","url":"widget.js"} diff --git a/apps/widmessages/metadata.json b/apps/widmessages/metadata.json index 0c3ac7e05..080e19273 100644 --- a/apps/widmessages/metadata.json +++ b/apps/widmessages/metadata.json @@ -10,6 +10,8 @@ "screenshots": [{"url": "screenshot.gif"}], "dependencies" : { "messageicons":"module" }, "provides_modules" : ["messagewidget"], + "provides_widgets" : ["message"], + "default" : true, "readme": "README.md", "storage": [ {"name":"messagewidget","url":"lib.js"}, diff --git a/bin/sanitycheck.js b/bin/sanitycheck.js index 0a4765d9c..5af6f1aa1 100755 --- a/bin/sanitycheck.js +++ b/bin/sanitycheck.js @@ -76,7 +76,7 @@ const APP_KEYS = [ 'id', 'name', 'shortName', 'version', 'icon', 'screenshots', 'description', 'tags', 'type', 'sortorder', 'readme', 'custom', 'customConnect', 'interface', 'storage', 'data', 'supports', 'allow_emulator', - 'dependencies', 'provides_modules' + 'dependencies', 'provides_modules', 'provides_widgets', "default" ]; const STORAGE_KEYS = ['name', 'url', 'content', 'evaluate', 'noOverwite', 'supports', 'noOverwrite']; const DATA_KEYS = ['name', 'wildcard', 'storageFile', 'url', 'content', 'evaluate']; @@ -168,8 +168,8 @@ apps.forEach((app,appIdx) => { if (app.dependencies) { if (("object"==typeof app.dependencies) && !Array.isArray(app.dependencies)) { Object.keys(app.dependencies).forEach(dependency => { - if (!["type","app","module"].includes(app.dependencies[dependency])) - ERROR(`App ${app.id} 'dependencies' must all be tagged 'type/app/module' right now`, {file:metadataFile}); + if (!["type","app","module","widget"].includes(app.dependencies[dependency])) + ERROR(`App ${app.id} 'dependencies' must all be tagged 'type/app/module/widget' right now`, {file:metadataFile}); if (app.dependencies[dependency]=="type" && !METADATA_TYPES.includes(dependency)) ERROR(`App ${app.id} 'type' dependency must be one of `+METADATA_TYPES, {file:metadataFile}); }); diff --git a/core b/core index 3a953179b..2a89ea64f 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit 3a953179b7bb9f574d4e77d5f34b6b7deee1e884 +Subproject commit 2a89ea64f7874b9264572f68836fe8ecd0a6b191 diff --git a/defaultapps_banglejs2.json b/defaultapps_banglejs2.json index 04bd44504..f96f81f60 100644 --- a/defaultapps_banglejs2.json +++ b/defaultapps_banglejs2.json @@ -1 +1 @@ -["boot","launch","antonclk","health","setting","about","widbat","widbt","widlock","widid"] +["boot","launch","antonclk","health","setting","about","alarm","widbat","widbt","widlock","widid"] From cee04a21bf06522f0cd03760f3d966d412ceb740 Mon Sep 17 00:00:00 2001 From: Erik Andresen Date: Tue, 6 Dec 2022 11:45:50 +0100 Subject: [PATCH 068/110] sleepphasealarm: Do not run buzz() when 'js' is set --- apps/sleepphasealarm/app.js | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/apps/sleepphasealarm/app.js b/apps/sleepphasealarm/app.js index 90cd32c7e..bcb6ddac8 100644 --- a/apps/sleepphasealarm/app.js +++ b/apps/sleepphasealarm/app.js @@ -173,16 +173,17 @@ if (nextAlarmDate !== undefined) { setTimeout(load, 1000); } else if (measure && now >= minAlarm && swest === false) { addLog(now, "alarm"); + measure = false; if (nextAlarmConfig.js) { eval(nextAlarmConfig.js); // run nextAlarmConfig.js if set - } - buzz(); - measure = false; - if (config.settings.disableAlarm) { - // disable alarm for scheduler - nextAlarmConfig.last = now.getDate(); - require("Storage").writeJSON("sched.json", alarms); - } + } else { + buzz(); + if (config.settings.disableAlarm) { + // disable alarm for scheduler + nextAlarmConfig.last = now.getDate(); + require('Storage').writeJSON('sched.json', alarms); + } + } } }); }; From 224b4560cbf6ee73b4b7ebae7e2934542a609d81 Mon Sep 17 00:00:00 2001 From: Erik Andresen Date: Tue, 6 Dec 2022 11:48:02 +0100 Subject: [PATCH 069/110] sleepphasealarm: format --- apps/sleepphasealarm/app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/sleepphasealarm/app.js b/apps/sleepphasealarm/app.js index bcb6ddac8..ba8bff9b2 100644 --- a/apps/sleepphasealarm/app.js +++ b/apps/sleepphasealarm/app.js @@ -183,7 +183,7 @@ if (nextAlarmDate !== undefined) { nextAlarmConfig.last = now.getDate(); require('Storage').writeJSON('sched.json', alarms); } - } + } } }); }; From 02cdc9fc93062e1ab1e1ba5c9245cd930553f006 Mon Sep 17 00:00:00 2001 From: thyttan <6uuxstm66@mozmail.com⁩> Date: Tue, 6 Dec 2022 12:20:52 +0100 Subject: [PATCH 070/110] remove only specific listeners --- apps/spotrem/ChangeLog | 2 ++ apps/spotrem/app.js | 19 +++++++++---------- apps/spotrem/metadata.json | 2 +- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/apps/spotrem/ChangeLog b/apps/spotrem/ChangeLog index f54b4a0fa..a92ed3de2 100644 --- a/apps/spotrem/ChangeLog +++ b/apps/spotrem/ChangeLog @@ -4,3 +4,5 @@ 0.04: New layout. 0.05: Add widgets field. Tweak layout. 0.06: Make compatible with Fastload Utils app. +0.07: Remove just the specific listeners to not interfere with Quick Launch +when fastloading. diff --git a/apps/spotrem/app.js b/apps/spotrem/app.js index d66b466d2..a0cba3a4d 100644 --- a/apps/spotrem/app.js +++ b/apps/spotrem/app.js @@ -57,8 +57,8 @@ let touchHandler = function(_, xy) { // doing ab-1 instead of a>b. if ((R.x-1 Date: Tue, 6 Dec 2022 12:43:32 +0100 Subject: [PATCH 071/110] remove only specific listeners --- apps/podadrem/ChangeLog | 2 ++ apps/podadrem/app.js | 16 +++++++--------- apps/podadrem/metadata.json | 2 +- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/apps/podadrem/ChangeLog b/apps/podadrem/ChangeLog index 837ef7941..3c68f15ac 100644 --- a/apps/podadrem/ChangeLog +++ b/apps/podadrem/ChangeLog @@ -5,3 +5,5 @@ Addict. 0.04: New layout. 0.05: Add widget field, tweak layout. 0.06: Add compatibility with Fastload Utils. +0.07: Remove just the specific listeners to not interfere with Quick Launch +when fastloading. diff --git a/apps/podadrem/app.js b/apps/podadrem/app.js index 0e32847ef..8e59a2464 100644 --- a/apps/podadrem/app.js +++ b/apps/podadrem/app.js @@ -116,11 +116,11 @@ let touchHandler = function(_, xy) { y = xy.y; len = (R.wb-1 instead of a>b. + // doing ab-1 instead of a>=b. if ((R.x-1 Date: Tue, 6 Dec 2022 12:50:23 +0100 Subject: [PATCH 072/110] remove unnecessary removeListener --- apps/spotrem/app.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/apps/spotrem/app.js b/apps/spotrem/app.js index a0cba3a4d..f9046c4a6 100644 --- a/apps/spotrem/app.js +++ b/apps/spotrem/app.js @@ -125,8 +125,6 @@ let backToGfx = function() { E.showMenu(); g.clear(); g.reset(); - Bangle.removeListener("touch", touchHandler); - Bangle.removeListener("swipe", swipeHandler); setUI(); gfx(); backToMenu = false; From 4b58d6a2e0067700dc22b3377558c4ce686e0cc9 Mon Sep 17 00:00:00 2001 From: thyttan <6uuxstm66@mozmail.com⁩> Date: Tue, 6 Dec 2022 13:03:47 +0100 Subject: [PATCH 073/110] shorten prepended info re intents --- apps/podadrem/app.js | 67 +++----------------------------------------- 1 file changed, 4 insertions(+), 63 deletions(-) diff --git a/apps/podadrem/app.js b/apps/podadrem/app.js index 8e59a2464..9c9ed8b04 100644 --- a/apps/podadrem/app.js +++ b/apps/podadrem/app.js @@ -1,69 +1,10 @@ { /* -Bluetooth.println(JSON.stringify({t:"intent", action:"", flags:["flag1", "flag2",...], categories:["category1","category2",...], mimetype:"", data:"", package:"", class:"", target:"", extra:{someKey:"someValueOrString"}})); + Bluetooth.println(JSON.stringify({t:"intent", action:"", flags:["flag1", "flag2",...], categories:["category1","category2",...], mimetype:"", data:"", package:"", class:"", target:"", extra:{someKey:"someValueOrString"}})); -Podcast Addict is developed by Xavier Guillemane and can be downloaded on Google Play Store: https://play.google.com/store/apps/details?id=com.bambuna.podcastaddict&hl=en_US&gl=US - -Podcast Addict can be controlled through the sending of remote commands called 'Intents'. -Some 3rd parties apps specialized in task automation will then allow you to control Podcast Addict. For example, you will be able to wake up to the sound of your playlist or to start automatically playing when some NFC tag has been detected. -In Tasker, you just need to copy/paste one of the following intent in the task Action field ("Misc" action type then select "Send Itent") . -If you prefer Automate It, you can use the Podcast Addict plugin that will save you some configuration time (https://play.google.com/store/apps/details?id=com.smarterapps.podcastaddictplugin ) -Before using an intent make sure to set the following: -Package: com.bambuna.podcastaddict -Class (UPDATE intent only): com.bambuna.podcastaddict.receiver.PodcastAddictBroadcastReceiver -Class (every other intent): com.bambuna.podcastaddict.receiver.PodcastAddictPlayerReceiver -Here are the supported commands (Intents) : -com.bambuna.podcastaddict.service.player.toggle – Toggle the playlist -com.bambuna.podcastaddict.service.player.stop – Stop the player and release its resources -com.bambuna.podcastaddict.service.player.play – Start playing the playlist -com.bambuna.podcastaddict.service.player.pause – Pause the playlist -com.bambuna.podcastaddict.service.player.nexttrack – Start playing next track -com.bambuna.podcastaddict.service.player.previoustrack – Start playing previous track -com.bambuna.podcastaddict.service.player.jumpforward – Jump 30s forward -com.bambuna.podcastaddict.service.player.jumpbackward – Jump 15s backward -com.bambuna.podcastaddict.service.player.1xspeed - Disable the variable playback speed -com.bambuna.podcastaddict.service.player.1.5xspeed – Force the playback speed at 1.5x -com.bambuna.podcastaddict.service.player.2xspeed – Force the playback speed at 2.0x -com.bambuna.podcastaddict.service.player.stoptimer – Disable the timer -com.bambuna.podcastaddict.service.player.15mntimer – Set the timer at 15 minutes -com.bambuna.podcastaddict.service.player.30mntimer – Set the timer at 30 minutes -com.bambuna.podcastaddict.service.player.60mntimer – Set the timer at 1 hour -com.bambuna.podcastaddict.service.update – Trigger podcasts update -com.bambuna.podcastaddict.openmainscreen – Open the app on the Main screen -com.bambuna.podcastaddict.openplaylist – Open the app on the Playlist screen -com.bambuna.podcastaddict.openplayer – Open the app on the Player screen -com.bambuna.podcastaddict.opennewepisodes – Open the app on the New episodes screen -com.bambuna.podcastaddict.opendownloadedepisodes – Open the app on the Downloaded episodes screen -com.bambuna.podcastaddict.service.player.playfirstepisode – Start playing the first episode in the playlist -com.bambuna.podcastaddict.service.player.customspeed – Select playback speed -In order to use this intent you need to pass a float argument called "arg1". Valid values are within [0.1, 5.0] -com.bambuna.podcastaddict.service.player.customtimer – Start a custom timer -In order to use this intent you need to pass an int argument called "arg1" containing the number of minutes. Valid values are within [1, 1440] -com.bambuna.podcastaddict.service.player.deletecurrentskipnexttrack – Delete the current episode and skip to the next one. It behaves the same way as long pressing on the player >| button, but doesn't display any confirmation popup. -com.bambuna.podcastaddict.service.player.deletecurrentskipprevioustrack – Delete the current episode and skip to the previous one. It behaves the same way as long pressing on the player |< button, but doesn't display any confirmation popup. -com.bambuna.podcastaddict.service.player.boostVolume – Toggle the Volume Boost audio effect -You can pass a, optional boolean argument called "arg1" in order to create a ON or OFF button for the volume boost. Without this parameter the app will just toggle the current value -com.bambuna.podcastaddict.service.player.quickBookmark – Creates a bookmark at the current playback position so you can easily retrieve it later. -com.bambuna.podcastaddict.service.download.pause – Pause downloads -com.bambuna.podcastaddict.service.download.resume – Resume downloads -com.bambuna.podcastaddict.service. download.toggle – Toggle downloads -com.bambuna.podcastaddict.service.player.favorite – Mark the current episode playing as favorite. -com.bambuna.podcastaddict.openplaylist – Open the app on the Playlist screen -You can pass an optional string argument called "arg1" in order to select the playlist to open. Without this parameter the app will open the current playlist -Here's how it works: -##AUDIO## will open the Audio playlist screen -##VIDEO## will open the Video playlist screen -##RADIO## will open the Radio screen -Any other argument will be used as a CATEGORY name. The app will then open this category under the playlist CUSTOM tab -You can pass an optional boolean argument called "arg2" in order to select if the app UI should be opened. Without this parameter the playlist will be displayed -You can pass an optional boolean argument called "arg3" in order to select if the app should start playing the selected playlist. Without this parameter the playback won't start -Since v2020.3 -com.bambuna.podcastaddict.service.full_backup – Trigger a full backup of the app data (relies on the app automatic backup settings for the folder and the # of backup to keep) -This task takes a lot of resources and might take up to a minute to complete, so please avoid using the app at the same time -Since v2020.15 -com.bambuna.podcastaddict.service.player.toggletimer – This will toggle the Sleep Timer using the last duration and parameter used in the app. -Since v2020.16 -com.bambuna.podcastaddict.service.player.togglespeed – This will toggle the Playback speed for the episode currently playing (alternate between selected speed and 1.0x). + Podcast Addict is developed by Xavier Guillemane and can be downloaded on Google Play Store: https://play.google.com/store/apps/details?id=com.bambuna.podcastaddict&hl=en_US&gl=US + + How to use intents to control Podcast Addict: https://podcastaddict.com/faq/130 */ let R; From 8fca0579ce4c46df67175e1e1f379b610d2e4caa Mon Sep 17 00:00:00 2001 From: Erik Andresen Date: Tue, 6 Dec 2022 14:33:15 +0100 Subject: [PATCH 074/110] noteify: Remove duplicate alarm widget --- apps/noteify/ChangeLog | 1 + apps/noteify/metadata.json | 5 ++--- apps/noteify/widget.js | 8 -------- lang/de_DE.json | 4 ++-- 4 files changed, 5 insertions(+), 13 deletions(-) delete mode 100644 apps/noteify/widget.js diff --git a/apps/noteify/ChangeLog b/apps/noteify/ChangeLog index d7bc46dcd..a37a66731 100644 --- a/apps/noteify/ChangeLog +++ b/apps/noteify/ChangeLog @@ -1,2 +1,3 @@ 0.01: Initial version 0.02: Use default Bangle formatter for booleans +0.03: Drop duplicate alarm widget diff --git a/apps/noteify/metadata.json b/apps/noteify/metadata.json index fbd5a88f1..850628c46 100644 --- a/apps/noteify/metadata.json +++ b/apps/noteify/metadata.json @@ -1,7 +1,7 @@ { "id": "noteify", "name": "Noteify", - "version": "0.02", + "version": "0.03", "description": "Write notes using an onscreen keyboard and use them as custom messages for alarms or timers.", "icon": "app.png", "tags": "tool,alarm", @@ -9,8 +9,7 @@ "readme": "README.md", "storage": [ {"name":"noteify.app.js","url":"app.js"}, - {"name":"noteify.img","url":"app-icon.js","evaluate":true}, - {"name":"noteify.wid.js","url":"widget.js"} + {"name":"noteify.img","url":"app-icon.js","evaluate":true} ], "data": [{"name":"noteify.json"}], "dependencies": {"scheduler":"type","textinput":"type"}, diff --git a/apps/noteify/widget.js b/apps/noteify/widget.js deleted file mode 100644 index 052ac9ebd..000000000 --- a/apps/noteify/widget.js +++ /dev/null @@ -1,8 +0,0 @@ -WIDGETS["alarm"]={area:"tl",width:0,draw:function() { - if (this.width) g.reset().drawImage(atob("GBgBAAAAAAAAABgADhhwDDwwGP8YGf+YMf+MM//MM//MA//AA//AA//AA//AA//AA//AB//gD//wD//wAAAAADwAABgAAAAAAAAA"),this.x,this.y); - },reload:function() { - // don't include library here as we're trying to use as little RAM as possible - WIDGETS["alarm"].width = (require('Storage').readJSON('sched.json',1)||[]).some(alarm=>alarm.on&&(alarm.hidden!==false)) ? 24 : 0; - } -}; -WIDGETS["alarm"].reload(); diff --git a/lang/de_DE.json b/lang/de_DE.json index ef22b588f..84f29a6c2 100644 --- a/lang/de_DE.json +++ b/lang/de_DE.json @@ -20,7 +20,7 @@ "On": "Ein", "Off": "Aus", "Ok": "OK", - "New Timer": "Neuer Kurzzeitwecker", + "New Timer": "Neuer Timer", "(repeat)": "(Wiederholung)", "music": "Musik", "Keep Msgs": "Nachrichten behalten", @@ -148,7 +148,7 @@ "Whitelist": "Whitelist", "Select Clock": "Uhr auswählen", "Disable": "Deaktivieren", - "Timer": "Kurzzeitwecker", + "Timer": "Timer", "Error in settings": "Fehler in den Einstellungen", "Set Time": "Zeit einstellen", "ALARM": "ALARM", From 80ea9d910c669546199d0db98ab3a83cb5b87ee3 Mon Sep 17 00:00:00 2001 From: thyttan <6uuxstm66@mozmail.com⁩> Date: Tue, 6 Dec 2022 17:02:44 +0100 Subject: [PATCH 075/110] adjust some sv_SE translations --- lang/sv_SE.json | 92 ++++++++++++++++++++++++------------------------- 1 file changed, 46 insertions(+), 46 deletions(-) diff --git a/lang/sv_SE.json b/lang/sv_SE.json index 6e0f30fa4..2c2ff5acf 100644 --- a/lang/sv_SE.json +++ b/lang/sv_SE.json @@ -6,34 +6,34 @@ "Hours": "Timmar", "Minutes": "Minuter", "Enabled": "Aktiverad", - "New Alarm": "Ny alarm", + "New Alarm": "Nytt larm", "Save": "Spara", "Back": "Tillbaka", "Repeat": "Upprepning", "Delete": "Radera", - "ALARM!": "ALURH!", + "ALARM!": "LARM!", "Sleep": "Sömn", "circle 3": "cirkel 3", "circle 1": "cirkel 1", "music": "musik", "week": "vecka", "Keep Msgs": "Behåll meddelanden", - "Auto snooze": "Automatisk snooze", + "Auto snooze": "Auto-snooza", "step length": "steglängd", "Circle": "Cirkel", "data": "uppgifter", - "colorize icon": "färglägga ikonen", - "min. confidence": "Min. förtroende", - "show widgets": "visa widgets", + "colorize icon": "färglägg ikon", + "min. confidence": "min. konfidens", + "show widgets": "visa widgetar", "valid period": "giltig period", "Heartrate": "Hjärtfrekvens", - "distance goal": "mål för distans", + "distance goal": "distansmål", "circle 4": "cirkel 4", "circle count": "antal cirklar", "minimum": "minimum", "maximum": "maximal", "New Timer": "Ny timer", - "battery warn": "batteri varning", + "battery warn": "batterivarning", "heartrate": "hjärtfrekvens", "circle 2": "cirkel 2", "(repeat)": "(upprepning)", @@ -42,30 +42,30 @@ "No Messages": "Inga meddelanden", "Show clocks": "Visa klockor", "STEPS": "STEG", - "TAP right top/bottom": "TAP höger upp/ner", + "TAP right top/bottom": "KNACKA höger upp/ner", "View Message": "Visa meddelande", "Mark Unread": "Markera oläst", - "Are you sure": "Är du säker på att", + "Are you sure": "Är du säker", "Delete all messages": "Radera alla meddelanden", - "Record Run": "Rekordkörning", + "Record Run": "Spåra löprunda", "Unread timer": "Oläst timer", "Vibration": "Vibrationer", - "Utils": "Användaruppgifter", + "Utils": "Verktyg", "Quiet Mode": "Tyst läge", "Passkey BETA": "Passkey BETA", "Dark BW": "Mörk BW", - "BTNs 1:startlap 2:exit 3:reset": "BTN 1:startlap 2:exit 3:reset", - "start&lap/reset, BTN1: EXIT": "start&lap/återställning, BTN1: EXIT", + "BTNs 1:startlap 2:exit 3:reset": "BTN 1:starta varv 2:lämna 3:återställ", + "start&lap/reset, BTN1: EXIT": "starta&varv/återställ, BTN1: LÄMNA", "BLE": "BLE", "Programmable": "Programmerbar", - "Launcher Settings": "Inställningar för lanseringen", - "Vector font size": "Vektor teckensnittsstorlek", + "Launcher Settings": "Inställningar för launchern", + "Vector font size": "Storlek vektortypsnitt", "Font": "Typsnitt", "Yes\ndefinitely": "Ja\ndefinitivt", "App Source\nNot found": "App-källa\nEj funnen", - "Make Connectable": "Gör det möjligt att ansluta", + "Make Connectable": "Gör anslutningsbar", "HID": "HID", - "Bluetooth": "Bluetooth", + "Bluetooth": "Blåtand", "Apps": "Appar", "Piezo": "Piezo", "LCD": "LCD", @@ -73,46 +73,46 @@ "Light BW": "Ljus BW", "Background": "Bakgrund", "Remove": "Ta bort", - "Highlight BG": "Markera BG", + "Highlight BG": "Markering BG", "Customize": "Anpassa", - "Highlight FG": "Highlight FG", + "Highlight FG": "Markering FG", "Background 2": "Bakgrund 2", "LCD Brightness": "Ljusstyrka på LCD-skärmen", "Add Device": "Lägg till enhet", - "Wake on BTN1": "Vakna på BTN1", - "Wake on BTN2": "Vakna på BTN2", - "Twist Timeout": "Twist Timeout", + "Wake on BTN1": "Vakna av BTN1", + "Wake on BTN2": "Vakna av BTN2", + "Twist Timeout": "Vridning Timeout", "Wake on Touch": "Vakna vid beröring", "LCD Timeout": "LCD Timeout", "Foreground": "Förgrund", - "Connect device\nto add to\nwhitelist": "Anslut enhet\nför att lägga till\nvitlista", - "Wake on FaceUp": "Vakna på FaceUp", + "Connect device\nto add to\nwhitelist": "Anslut enhet\nför att lägga till\ni vitlistan", + "Wake on FaceUp": "Skärm upp väcker", "Twist Threshold": "Tröskelvärde för vridning", - "Wake on BTN3": "Wake på BTN3", + "Wake on BTN3": "Vakna av BTN3", "Clock Style": "Klockstil", "Time Zone": "Tidszon", "Twist Max Y": "Vridning Max Y", - "Stay Connectable": "Håll dig tillgänglig", - "This will remove everything": "Detta kommer att ta bort allt", + "Stay Connectable": "Håll anslutningsbar", + "This will remove everything": "Detta kommer ta bort allt", "Turn Off": "Stäng av", "Connectable": "Anslutningsbar", - "Flattening battery - this can take hours.\nLong-press button to cancel": "Platta batterier - detta kan ta flera timmar.\nTryck länge på knappen för att avbryta", - "Reset to Defaults": "Återställ till standardvärden", + "Flattening battery - this can take hours.\nLong-press button to cancel": "Töm batteri - detta kan ta flera timmar.\nTryck länge på knappen för att avbryta", + "Reset to Defaults": "Återställ standardvärden", "Utilities": "Verktyg", - "Flatten Battery": "Platta batterier", - "Debug Info": "Info om felsökning", - "Reset Settings": "Återställa inställningar", - "Wake on Twist": "Väckning på Twist", - "Compact Storage": "Kompakt förvaring", + "Flatten Battery": "Töm batteri", + "Debug Info": "Felsökningsinfo", + "Reset Settings": "Återställ inställningar", + "Wake on Twist": "Vakna av vridning", + "Compact Storage": "Komprimera lagring", "Log": "Logg", "Rewrite Settings": "Omskrivning av inställningar", - "Compacting...\nTakes approx\n1 minute": "Komprimering...\nTar ca.\n1 minut", + "Compacting...\nTakes approx\n1 minute": "Komprimerar...\nTar ca.\n1 minut", "Storage": "Lagring", "Second": "Andra", "App Settings": "App-inställningar", "Invalid settings": "Ogiltiga inställningar", - "Minute": "Protokoll", - "Sleep Phase Alarm": "Larm om sömnfas", + "Minute": "Minut", + "Sleep Phase Alarm": "Sömnfaslarm", "No app has settings": "Ingen app har inställningar", "Hour": "Timme", "No Clocks Found": "Inga klockor hittades", @@ -124,16 +124,16 @@ "TIMER": "TIMER", "on": "på", "OFF": "OFF", - "Side": "Sidan", + "Side": "Sida", "Sort Order": "Sortering", "Left": "Vänster", "Right": "Höger", "Reset All": "Återställ alla", - "Widgets": "Widgets", + "Widgets": "Widgetar", "goal": "mål", "Vibrate": "Vibrera", "Message": "Meddelande", - "Beep": "Piper", + "Beep": "Pip", "Disable": "Inaktivera", "Select Clock": "Välj klocka", "Locale": "Lokalisering", @@ -145,14 +145,14 @@ "Timer": "Timer", "BACK": "TILLBAKA", "Error in settings": "Fel i inställningarna", - "Whitelist": "Whitelist", - "ALARM": "ALARM", + "Whitelist": "Vitlista", + "ALARM": "LARM", "Hide": "Dölj", "Connected": "Ansluten", "Show": "Visa", "On": "På", "Ok": "Ok", - "No": "Ingen", + "No": "Nej", "Settings": "Inställningar", "steps": "steg", "back": "tillbaka", @@ -162,7 +162,7 @@ "Loading": "Laddar", "Music": "Musik", "color": "färg", - "off": "off", + "off": "av", "Off": "Av", "Theme": "Tema", "one": "ett", @@ -197,4 +197,4 @@ "ten to *$2": "tio i *$2", "five to *$2": "fem i *$2" } -} \ No newline at end of file +} From b29a2c4d0b9d10b4d66c41a402c051236ecc2f68 Mon Sep 17 00:00:00 2001 From: Hugh Barney Date: Tue, 6 Dec 2022 23:12:14 +0000 Subject: [PATCH 076/110] Added simplestpp, basic clock with fast load and clock_info support --- apps/simplestpp/README.md | 54 ++++++++++++++++ apps/simplestpp/app.js | 108 ++++++++++++++++++++++++++++++++ apps/simplestpp/app.png | Bin 0 -> 994 bytes apps/simplestpp/icon.js | 1 + apps/simplestpp/metadata.json | 16 +++++ apps/simplestpp/screenshot1.png | Bin 0 -> 2411 bytes apps/simplestpp/screenshot2.png | Bin 0 -> 2444 bytes apps/simplestpp/screenshot3.png | Bin 0 -> 2622 bytes 8 files changed, 179 insertions(+) create mode 100644 apps/simplestpp/README.md create mode 100644 apps/simplestpp/app.js create mode 100644 apps/simplestpp/app.png create mode 100644 apps/simplestpp/icon.js create mode 100644 apps/simplestpp/metadata.json create mode 100644 apps/simplestpp/screenshot1.png create mode 100644 apps/simplestpp/screenshot2.png create mode 100644 apps/simplestpp/screenshot3.png diff --git a/apps/simplestpp/README.md b/apps/simplestpp/README.md new file mode 100644 index 000000000..4b459bda1 --- /dev/null +++ b/apps/simplestpp/README.md @@ -0,0 +1,54 @@ +# Simplest++ Clock + +The simplest working clock, with fast load and clock_info + +![](screenshot1.png) +![](screenshot2.png) +![](screenshot3.png) + + +Simplest++ has 1 clock info menu that is displayed as a single line at the bottom of the screen. + +This provides a working demo of how to use the clock_info modules. + + +## Usage + +* When the screen is unlocked, tap at the bottom of the csreen on the information text. + It should change color showing it is selected. + +* Swipe up or down to cycle through the info screens that can be displayed + when you have finished tap again towards the centre of the screen to unselect. + +* Swipe left or right to change the type of info screens displayed (by default + there is only one type of data so this will have no effect) + +* Settings are saved automatically and reloaded along with the clock. + +## About Clock Info's + +* The clock info modules enable all clocks to add the display of information to the clock face. + +* The default clock_info module provides a display of battery %, Steps, Heart Rate and Altitude. + +* Installing the [Sunrise ClockInfo](https://banglejs.com/apps/?id=clkinfosunrise) adds Sunrise and Sunset times into the list of info's. + + +## References + +* [What is Fast Load and how does it work](http://www.espruino.com/Bangle.js+Fast+Load) + +* [Clock Info Tutorial](http://www.espruino.com/Bangle.js+Clock+Info) + +* [How to load modules through the IDE](https://github.com/espruino/BangleApps/blob/master/modules/README.md) + + +## With Thanks + +* Gordon for support +* David Peer for his work on BW Clock + + +Written by: [Hugh Barney](https://github.com/hughbarney) For support +and discussion please post in the [Bangle JS +Forum](http://forum.espruino.com/microcosms/1424/) diff --git a/apps/simplestpp/app.js b/apps/simplestpp/app.js new file mode 100644 index 000000000..c07fdbcbb --- /dev/null +++ b/apps/simplestpp/app.js @@ -0,0 +1,108 @@ +/** + * + * Simplestpp Clock + * + * The entire clock code is contained within the block below this + * supports 'fast load' + * + * To add support for clock_info_supprt we add the code marked at [1] and [2] + * + */ + +{ + // must be inside our own scope here so that when we are unloaded everything disappears + // we also define functions using 'let fn = function() {..}' for the same reason. function decls are global + + let draw = function() { + var date = new Date(); + var timeStr = require("locale").time(date,1); + var h = g.getHeight(); + var w = g.getWidth(); + + g.reset(); + g.setColor(g.theme.bg); + g.fillRect(Bangle.appRect); + + g.setFont('Vector', w/3); + g.setFontAlign(0, 0); + g.setColor(g.theme.fg); + g.drawString(timeStr, w/2, h/2); + clockInfoMenu.redraw(); // clock_info_support + + // schedule a draw for the next minute + if (drawTimeout) clearTimeout(drawTimeout); + drawTimeout = setTimeout(function() { + drawTimeout = undefined; + draw(); + }, 60000 - (Date.now() % 60000)); + }; + + /** + * clock_info_support + * this is the callback function that get invoked by clockInfoMenu.redraw(); + * + * We will display the image and text on the same line and centre the combined + * length of the image+text + * + * + */ + let clockInfoDraw = (itm, info, options) => { + + g.reset().setFont('Vector',24).setBgColor(options.bg).setColor(options.fg); + + //use info.text.toString(), steps does not have length defined + var text_w = g.stringWidth(info.text.toString()); + // gap between image and text + var gap = 10; + // width of the image and text combined + var w = gap + (info.img ? 24 :0) + text_w; + // different fg color if we tapped on the menu + if (options.focus) g.setColor(options.hl); + + // clear the whole info line + g.clearRect(0, options.y -1, g.getWidth(), options.y+24); + + // draw the image if we have one + if (info.img) { + // image start + var x = (g.getWidth() / 2) - (w/2); + g.drawImage(info.img, x, options.y); + // draw the text to the side of the image (left/centre alignment) + g.setFontAlign(-1,0).drawString(info.text, x + 23 + gap, options.y+12); + } else { + // text only option, not tested yet + g.setFontAlign(0,0).drawString(info.text, g.getWidth() / 2, options.y+12); + } + + }; + + // clock_info_support + // retrieve all the clock_info modules that are installed + let clockInfoItems = require("clock_info").load(); + + // clock_info_support + // setup the way we wish to interact with the menu + // the hl property defines the color the of the info when the menu is selected after tapping on it + let clockInfoMenu = require("clock_info").addInteractive(clockInfoItems, { x:64, y:132, w:50, h:40, draw : clockInfoDraw, bg : g.theme.bg, fg : g.theme.fg, hl : "#0ff"} ); + + // timeout used to update every minute + var drawTimeout; + g.clear(); + + // Show launcher when middle button pressed, add updown button handlers + Bangle.setUI({ + mode : "clock", + remove : function() { + if (drawTimeout) clearTimeout(drawTimeout); + drawTimeout = undefined; + // remove info menu + clockInfoMenu.remove(); + delete clockInfoMenu; + } + }); + + // Load widgets + Bangle.loadWidgets(); + draw(); + setTimeout(Bangle.drawWidgets,0); +} // end of clock diff --git a/apps/simplestpp/app.png b/apps/simplestpp/app.png new file mode 100644 index 0000000000000000000000000000000000000000..814306471485b135eb105e2d63304b06565e4d7e GIT binary patch literal 994 zcmV<810DQ{P)D(Dg!Z*3O znLFp6^F8m~bKkk=at|HxP-=a{P$oUwaS#Wv2an<5RWjFc2^a7U&S4>w{Y_yM)A$N2 zXjj@TwD3!6tu$7ZS-~8RC0zqU6UXs;h0FrZ;0PXHhtO#H?`V=;tjzxnub|Oq?k4e5 z#qbw6v`NEFynxw?zIjY!VY&)KcnizP(06z$qy8!UkaREM4f*0z6Yp1)pTKY~h)N-0h3jV;ZY}D#w zhj{C4yx#5PNwF4}3})G^hp7sW+PhOzxmBL%k-)pD^@6t(mmk%PhvUkvve(__@6>uh zLy&Ld<&A_#m0#E#`+N=uV87sW1tXmVr8O@1X_*`&&z8I`Ja3J+x50F&1m`nY$ z#X!}8J*l4`7@h8MKJ~lT`twimnsT0wa>f8`6U+PR>OY3@j|h^S$n5|@ennb6#cuO} z$oOv5Q1Fg8+|#cCi?!I`D1kpBosR?op%=Yi0{YGPh{!CUY$j17qt6 zowIe*=@$jJ*-k>o>Iij#oDLKZ_edw9QBi1ZV{Zndxg2;}aJp=RBPCHKZi`ywRyow4 zPn=$=J7GRenCa1Yj;D(sx5Wvsxahu? z##YPBiri*1ZxH#eGRH(|@)=Pe+a)RoRa_M(sf!|?pOgO#o*fUSb`R^}U&vwyOs<=L Q@Bjb+07*qoM6N<$f{4=I_5c6? literal 0 HcmV?d00001 diff --git a/apps/simplestpp/icon.js b/apps/simplestpp/icon.js new file mode 100644 index 000000000..bec6c9752 --- /dev/null +++ b/apps/simplestpp/icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEw4UA///E8MBqtVoALHBQIABBQ0FqgDBitQCwwEIFoISEgoxEiodFFAQEGCQoiFEgsBLQwHDgplHD4UUCYwIDBZY6DBYgsCBZQGEAgwLXLwhvFqALmirvDXIQLPI9ibja677MBZZgELwhnHA4sBHgY6DCYatCAAcVAhASGEgoiEAANVAhASCDwUVIIwTBAARlHgIKBMgwAV")) diff --git a/apps/simplestpp/metadata.json b/apps/simplestpp/metadata.json new file mode 100644 index 000000000..10f756e32 --- /dev/null +++ b/apps/simplestpp/metadata.json @@ -0,0 +1,16 @@ +{ + "id": "simplestpp", + "name": "Simplest++ Clock", + "version": "0.01", + "description": "The simplest working clock, with fast load and clock_info, acts as a tutorial piece", + "readme": "README.md", + "icon": "app.png", + "screenshots": [{"url":"screenshot3.png"}], + "type": "clock", + "tags": "clock", + "supports": ["BANGLEJS2"], + "storage": [ + {"name":"simplestpp.app.js","url":"app.js"}, + {"name":"simplestpp.img","url":"icon.js","evaluate":true} + ] +} diff --git a/apps/simplestpp/screenshot1.png b/apps/simplestpp/screenshot1.png new file mode 100644 index 0000000000000000000000000000000000000000..94cb35cd604fd3648c679f135feb4df9101ee5d2 GIT binary patch literal 2411 zcmdT`dpOe#8=ha2ZK*~~4q?r_yzHx&P`3Ichmd30u#u9F$k1wtZI$wx-}AeEl`*IRM2;Ldy@9p~v>VEW0g>Z}S~lFJ z^Ye?DE6cIlMH?cmlUjFp&7GLw*wVFB@36kpdcb9*PWw;a!7O;+(9*rW{dvr>P?rEeeu7F}(#J9cGSB$9LBuXJJ%Jh`Wi<>v5 zUfV2Fp_D#sKDHSGJr3(B}}?q(eMgr0%U*%GXKv!DBwpA$n|@J=xJ z4d@jGpM#T`f1l!utOfa=O&V)CpPlPor=iCU9)x2T)`63at!oEtX)=falzI8H z@AYEL4ug|wVVc7mE;-i2c5SwN9}A#GPv#>vke zdC82%Me98s*PyjvN;+e>Ec=7bx}I6hDc(e$P2JhL^1rS6-^^~;+ycH9oY`)T7)#pC z@KKRgs`=I@?ezr^_wf#m>I(3NFr`y9aP)qc)L0V$ac*E+%NeA8RQAqgG8{ehWY^Vp zRU4`4Z!;AL{VH!F;toC$@;%*8Rj~;yW1wEE@)dustK~VPM6` z;d`bE@E+Box5+So`u|1v%2nFcoJoAIH_Yt36VX-rHewf@m8;le`f=>J%5L#g4t6f` zgC8L(#R!)up7ND%lerjSsga|!UR+JpRf@j6gQ5*iyb3qa#YaWxT7lt`>Marugwyce zG(yNIdg?wMhL6I04FzjiG{qi%&@cQNsH2dBv)Pwn)+WaGk;2{-vieE5DQ~mC{2cdX zXiMmT$*qByybhX5XmENy%K=G>+a-?9g3pPJ>~kNVrL%M<*D7duFkD+L&4j(vNvGR? zNkq-hwXka|D~-07CgBmZxK2)6+GH|>AhnJ-(Nr#}eteg`v+{i=ap9&?HO9$rG4-4W z)0Ob~Wq=D$j~mjyjTGyN8VYg^*VO>2lFTX0K<`U)e`%=aOv)l6{|76Bv<>*?bED%J zFE1+Ifu#pnC4BG*AXZ>jc(klTZaaKH662dJC!_>AC@Dbf80hLTx0ep58C6gY7Eh35olfZ$l+$2A{e zD=iPcIZ9dh2;f`Shk;=Ek)9JR7Dvh!5AMCixHS+ad{VsLUlJo#p48m#KxZuyR${J> zT8}M`Mej0PP-dB@J;(~FgK7s0P$Uy~4R9PY^&b)a87?v?d9V5WQ30twB8qy0ny*Un z4HVdmrVhXL10vp|g=r_3LIv7=1b4WP>QICyowfUA%mZ=7GeSm7eIC^D!px$iwhpjn z5K0;>-DUgn$6dSKSe#{Sm96p0gUGw|$K0#YqdPf+`c<|_(BAob&7gpcFg2?jcM5M~ zSHBJ>PI+Q(Kqx#jFw?6kb=Ush@-RDDk2jJ3Yw_ODQc}zLy5_7|rf|Zz*R4euEiG zY5=0#qp($O@X?0rfhYwy*~l|UZvF`Bk-gVofC=YuwLBOaDzNu#VW7Hm|B$Lp;OHRw z7&cL^F66=s;+95cJYNIWT7ydM3su)x8C#@8f5PFkzER&%Sg!aqXfB&^6?A4UA}<+?^AV2tj8>@_`@5BnFACd&qoxrR=)>;`yt4-;i$qqUvz= z(%JUD<=&to5*{3=?#mqlyA66!n1jl^&d!dwi<`T36vKMkO7e_u`v+GG>AmI)DkJ0H zqo02%Ak#|Pac=|V=luPYs{tpLOumagc#gM38^A`XH#Wvda{$3hZSFxAh9EUqiT{W3 zhizVY6S3>wdc|}6qV)OiDK;|})Zs4K%1O#-oYJ9Yt=NqNst>=uEAifZF`m=>^__cW zd3KuFw}-iFisZL;e}$(08hF+!oK;n>If`4-{}Su^lLi(oMen)NRm*_^dtUUupdwdw z!8je9-&yk}q5^y_or4Tfy~KywtkhUa(6VHim9n9dzX=to&`j@4a( z0hJGXEW|1{Qo2!2sGjROlx{CXX52bU0e5?QH1x--uU~ Ytg!jVig__2`S%2KvUjuN+Xi0w7v-!_{Qv*} literal 0 HcmV?d00001 diff --git a/apps/simplestpp/screenshot2.png b/apps/simplestpp/screenshot2.png new file mode 100644 index 0000000000000000000000000000000000000000..d24d55b029b7bbb2ba5f918188ab2df741526690 GIT binary patch literal 2444 zcmeHJ{X5eOAD&qm4vkt)Wtf-K(>2ReEDIY7qe5P1V&o-^@-j@`I^R>|UD75?JVJ#H z#WuCku5{{>jl7H^YbW89jb-JfH;;3j>-iU+>-pjN;d9?V+@Jft?(6f@r|_f~K}T!1 z76=5=@o;zX-Q&=LVchh(O4j%P5<=A* z^9h%q$cG1ARkoo=f(C^%?zl$bB=6^urIWG7TAV~=qrj3@n7kv?c69HSTsekmer!RR zBVfl%{cC10?W#rr3`IQp*0&7akG z!|xZ{N}=?(TK(I>_({8=WXXp=#W5s+%}=t5Elt`bzUxnL*}qF9N<`Y^#pzeg4U6h? zOvgoVdih+065kaqLEc-dm{UE-F{|&N7+9FtQ>9Q8oH^KxJwBpGb=_Q^pfr2-jVvqA zkoZ-F(ceN@7BMKRDk0->m*!{CT}CkHYB(j>*6VZlPB^X`Ds z1;$b;n0PS+ZR{~3)fi;WL&c$J)f#*mM)YJ*)a?j#-5RY{inuh?E}^?%lpi0pbC<=n<7A6t|1bVwmhcKJKHnU<2} z3MRf-&}W3Sc^tI}lPsV2m7Qo~+T~9Ht^K}eW6#l32O7o!p|orRVN01AiY^a+cJl9L zOB`$pVpLOp_N@fFR7G)_uU|)~Ct72`gb8bXqNk$eO&;jecSiytyp*E2F1_pr3B13$ z7$Qx6-X%J1HrudI7rEQ=J1Pd&j~(Wi?*s*ebcSro!}O;OVLLnkXJlFfOTAFAXW{cOL%^% z8Un*s9*WP~?j%cUJaPShS#+U%H%(HkUi+M@Mh-8Wy?sO`WVk@(-`oBW9?WNI0qRo{ zR7bjl{qhCRqcSG|on-9y@ICB`F1oEgk9T<=P1f^D0$GvwGDCA_ zufK=13H(Tq-eR0~RvCT2tcA9BC=c5uoOi3)vlla>F0yyi_f>&tX@rWWi!;H=l11OZ z-aakXbegGoSq2A=R7zj-FFUq^h}6vaek0pFAt9Ey%?W2O-UBvP(aT(kbz!qTVzjs# zeT&wE+`=`2XVU&415MMk_}U%Ry)`QdJ?zK_{}lK}m+kQiZ!eK1>xr+t8-r#WG{A#0 zaTC<4BH6p@$bSG?7IMUr8mqzpz(s8!tZRfle3uoJIb>y^dDr0*p$|W1%wc!;!%EVO1!-bvkGDBW+tTEio9YuAyyk_$IemipeTBr!AOv@K9fpXUky? zS_yPwr*?d<{+;hSyzxwLvMAHyY{l#rF8$~y3IvwHDf14r0(+0YkUV#mN$l{X9;gH9 zC=sOr5Es^>KAS3|bVAvN5HfqFQc^6e#H4ak{(Gh$YE~wS69F$xIGgVk$ivmkrR_-g GZ~q31IDNPP literal 0 HcmV?d00001 diff --git a/apps/simplestpp/screenshot3.png b/apps/simplestpp/screenshot3.png new file mode 100644 index 0000000000000000000000000000000000000000..af7ae7249bcc816643c766973237ca6472143124 GIT binary patch literal 2622 zcmdUx=|9wu7RUK!)R%OR2P930RsQ^Sjw!rgv89LXUg4;zNWwkQIZbN+Q3h)-mpkI=9pRktL^r;IsDys7{kC|GPo(-@T#ur*A zgP*Qb8B;Gn^mfCH8ueCXVYhZ*rhYi14sg#4m6n%Zb88@J;!B-z3LeABaOM6m)wnR+ z#*l}R%}@(f3ldYN_cmyIcg}?ejvZ1U+Q*k7E`~AQRg_=Hc1@rmP%0!98$D5 z#`&_m7!N4HKi~_k-xTTh{lfkMT1*@271sU&MKRsGTKeRlAPS(^Jxqxvoz6MxIumDS zpiQtUENboR5!E!B^@|YNRtS7}vNRpsLGROqwy)m|44@f#>8nVK4aBx9qqS0-uL!3gyK^98w~pWdTIfC2exL832&aO!dxmut&Gp$h?hOZ+*9KrO0*+q%lK+QIn_*MBM`{ z-f}L58nc0~=I|Qu|26iQbPY3Z-uLg>Pc)|ONlHew1G+xC1>(Si)CjuWLu2+H3-ft7 z2(XgR0pa!0x)O|37ayXO(Zqop(;1Zu_7|t}nn>_1-gcuoTcB~#-g1_X^!*|S)u}B< zyr(gr%dCEACh=hsQCOUMQ3X&*80gAF6v(D(0mYgY>0t&oA`Mq$juZ}?MBEoCUDgY# z2;x0nKpcqu0L_q{rMf4+)PHx$r5BDv^Npw`9u%6U>9s5V ziHL4XuGbKGcyi=fnOVl_mp(d?uGbd%CxpBMC&J@b1e!iaf9ytUSfO^#*_9xVJ)@9~ zS?64F+;6^>vWlgc7c;~amDahwpJ-~lV~espp{Y-D%Nk)yMi{FrwceFsjOdJV`Of=< zrpRPvZ+owRS34Y|1%o2TaZzvQ^{J8j7*6dbf(T5ywx-pkZ2h^CN`KzM=yIn<=3tT& z{@alkK#IbPg)>XTCmBC74(`{21-A0e{1F9UWltIh+SM_lVI{OrxGL`Sbk4ZwTM0n^ z)VZN{8uLmvw#wr*_l~#MIBrh$Re@&m<#NzsR1s$jcO0)=_<*HGJ;Iv9@V>l8NPg=S z!aF4kT<%J_+It@6CeMKGg3VFq+b7}cMTKf}@?2)4%*~bdDVMPW#vQiGWo2`FQw1nM z$`6r$PuZV;`Cv|Xu3y<)C^Q}C^jSu+UK3UOd!W7l=A|iLqGGl5<;`yn9@wRlKgRE_ z@nNzBP_;H+1~&Y+RkSk2KFC@8(77~R-edq7%5sd*9_~A+uJ$#uQl)C$#qfZ$)Aonn zCn#*MD4x4Y+b~IiAAfp*?c$=SB6)r*@^(nJb(#P6slT~kxy)+Eq4ixtm%vZ5U&o|4 zzp{3bcBBWus$W}Op;NFSV$N;!XdBAJG^J5VI`bOu>A)LG%e+3s1Id~E;dNc9Z9;sF z^T9OzRq*i?qJYcjFa?}>yDvObq>+vYA5)r=>Q62+wARJ5?u6kyse1T^9&2k`Npvco z#7%GA9g@>*0>C00pi@R8y)p)t@LnFVVw!VDPNTL(>3@10#yzNwi^oUw?!&Z86z*cSZHZu$IIV-d-#`<5!dZ)B_P$9{~x!hiJ1^ZCuYPwt|B#4Wc#q@(+)Dx6H=iu1t;Od9{YK9awY342hsnqn7~>fKl7JTty?^Bk{`D{Dxjx z5ZdBp3FQz(pu8oX>oZ9=HJz^2dUp|nD;b$EXk0XU-L-Lkm+=9yGXZ-Tn^nmcXo*0N|&%mcNW z$rX5JFG+;);AuAnjJskbwdQ6LN=??qmcJw++0a+~$uR zT;xV?OCT=4w5~re6LaFDyO(g!`Qk9D*HUHC2$st?c)}B{>aEF2zwdw>%Sz@hR=+#D zYSUhM4=n`|&zmuyE zCgM{47L^_kiNzQ=%2R=A`mZEf08yO&p4RsYtR(#P*uc&vsfX0xR9N#Djl;Afwmf)U mt3+UJSgN=~_5XTppA$@wb>`Tlh_fF;4pSp5! Date: Tue, 6 Dec 2022 23:19:28 +0000 Subject: [PATCH 077/110] Added simplestpp, updated icon --- apps/simplestpp/icon.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/simplestpp/icon.js b/apps/simplestpp/icon.js index bec6c9752..92e0fa271 100644 --- a/apps/simplestpp/icon.js +++ b/apps/simplestpp/icon.js @@ -1 +1 @@ -require("heatshrink").decompress(atob("mEw4UA///E8MBqtVoALHBQIABBQ0FqgDBitQCwwEIFoISEgoxEiodFFAQEGCQoiFEgsBLQwHDgplHD4UUCYwIDBZY6DBYgsCBZQGEAgwLXLwhvFqALmirvDXIQLPI9ibja677MBZZgELwhnHA4sBHgY6DCYatCAAcVAhASGEgoiEAANVAhASCDwUVIIwTBAARlHgIKBMgwAV")) +require("heatshrink").decompress(atob("mEwwIROj/4Aof//4ECgfgg/AAoMPAQPwAQMcAQM4AQNwAQMOAQPgAQMHgEBDQUDwEBwAFBAYMDGQfAgwJCgFgAosMAocwAosYAocYApcwAocMAqUHO4PgAo4jWJqJrLQZaVFUIqtFXIrFGaIrdFdIr1FgEf/AFDABIA=")) From c5086ad9351d7f30ecc0302a6c6a3e917221d4bd Mon Sep 17 00:00:00 2001 From: Hugh Barney Date: Tue, 6 Dec 2022 23:28:06 +0000 Subject: [PATCH 078/110] Added simplestpp, updated icon --- apps/simplestpp/icon.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/simplestpp/icon.js b/apps/simplestpp/icon.js index 92e0fa271..f8186ffce 100644 --- a/apps/simplestpp/icon.js +++ b/apps/simplestpp/icon.js @@ -1 +1 @@ -require("heatshrink").decompress(atob("mEwwIROj/4Aof//4ECgfgg/AAoMPAQPwAQMcAQM4AQNwAQMOAQPgAQMHgEBDQUDwEBwAFBAYMDGQfAgwJCgFgAosMAocwAosYAocYApcwAocMAqUHO4PgAo4jWJqJrLQZaVFUIqtFXIrFGaIrdFdIr1FgEf/AFDABIA=")) +require("heatshrink").decompress(atob("mEwwMB/4AW/ggDn/4Aocf+IQDx/zAofPArP+v4F+NgUfAo5N/U7QFDaIrdFdIr/PAA4=")) From 8f535ff067a3515dd410233868a8ef7095275092 Mon Sep 17 00:00:00 2001 From: Hugh Barney Date: Tue, 6 Dec 2022 23:43:07 +0000 Subject: [PATCH 079/110] Added simplestpp, updated icon --- apps/simplestpp/icon.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/simplestpp/icon.js b/apps/simplestpp/icon.js index f8186ffce..e4e40c82c 100644 --- a/apps/simplestpp/icon.js +++ b/apps/simplestpp/icon.js @@ -1 +1 @@ -require("heatshrink").decompress(atob("mEwwMB/4AW/ggDn/4Aocf+IQDx/zAofPArP+v4F+NgUfAo5N/U7QFDaIrdFdIr/PAA4=")) +require("heatshrink").decompress(atob("mEw4X/AAIHBqOM997IGkq1AKIltVqt4BQ0DBQIAB4ALFktVv/9qtYBYvVA4Ulq4KEgNVwAEBgVVoALDgtcAoc1qAFDitgAocJqguEGoowDgVWBYuVGoUBFwgwCHgUNGgUNuBCCAYY6CBYcJCYUlDYYLCgJxCmozCBYcCG4UVG4QLDgBgCBZeXBY/WBYcC1WtvWqGoILEVAIACJoILQgf/+tf/7jBBYg7JL66DLTZazLZZbjLfZcA6oLFq4EDio8CHQReCGgQwEmpCCHgVVFIUCVAQAD6plCkouEA4VVv/9qoPCAAcDZYa/BAAstBQN4BQwABlWoBRAAr")) From 9cd7106f38ebfe36dc6ff5b8446a81f1c784e5b7 Mon Sep 17 00:00:00 2001 From: Hank Date: Wed, 7 Dec 2022 10:27:29 +0100 Subject: [PATCH 080/110] Add Rotation on swipe Down --- apps/hworldclock/ChangeLog | 1 + apps/hworldclock/README.md | 1 + apps/hworldclock/app.js | 52 ++++++++++++++++++++++++++++++++++ apps/hworldclock/metadata.json | 2 +- 4 files changed, 55 insertions(+), 1 deletion(-) diff --git a/apps/hworldclock/ChangeLog b/apps/hworldclock/ChangeLog index 8c1517842..158ea1c91 100644 --- a/apps/hworldclock/ChangeLog +++ b/apps/hworldclock/ChangeLog @@ -9,3 +9,4 @@ 0.23: Added note to configure position in "my location" if not done yet. Small fixes. 0.24: Added fast load 0.25: Minor code optimization +0.26: Swipe down to rotate 180° diff --git a/apps/hworldclock/README.md b/apps/hworldclock/README.md index 25cc368ca..073a7c8a9 100644 --- a/apps/hworldclock/README.md +++ b/apps/hworldclock/README.md @@ -14,6 +14,7 @@ Provide names and the UTC offsets for up to three other timezones in the app sto The clock does not handle summer time / daylight saving time changes automatically. If one of your three locations changes its UTC offset, you can simply change the setting in the app store and update. Currently the clock only supports 24 hour time format for the additional time zones. +Swipe down to rotate screen. So you can show the time to a friend real quick. ## Requests diff --git a/apps/hworldclock/app.js b/apps/hworldclock/app.js index c80b712da..c5e1942a5 100644 --- a/apps/hworldclock/app.js +++ b/apps/hworldclock/app.js @@ -7,6 +7,7 @@ var showSunInfo; var colorWhenDark; // ------- Settings file +const BANGLEJS2 = process.env.HWVERSION == 2; const big = g.getWidth()>200; // Font for primary time and date const primaryTimeFontSize = big?6:5; @@ -24,6 +25,7 @@ const xcol1 = 10; const xcol2 = g.getWidth() - xcol1; const font = "6x8"; +let drag; /* TODO: we could totally use 'Layout' here and avoid a whole bunch of hard-coded offsets */ @@ -317,6 +319,56 @@ Bangle.drawWidgets(); draw(); + +function initDragEvents() { + +if (BANGLEJS2) { + Bangle.on("drag", e => { + if (!drag) { // start dragging + drag = {x: e.x, y: e.y}; + } else if (!e.b) { // released + const dx = e.x-drag.x, dy = e.y-drag.y; + drag = null; + if (Math.abs(dx)>Math.abs(dy)+10) { + // horizontal + if (dx < dy) { + + } else { + + } + } else if (Math.abs(dy)>Math.abs(dx)+10) { + // vertical + if (dx < dy) { + g.clear().setRotation(2); + //console.log(" + draw(); + Bangle.loadWidgets(); + Bangle.drawWidgets(); + + } else { + g.clear().setRotation(0); + draw(); + Bangle.loadWidgets(); + Bangle.drawWidgets(); + } + } else { + //console.log("tap " + e.x + " " + e.y); + if (e.x > 145 && e.y > 145) { + + } + } + } + }); + } else { + //setWatch(addDrink, BTN1, { repeat: true, debounce:50 }); + //setWatch(removeDrink, BTN3, { repeat: true, debounce:50 }); + //setWatch(previousDrink, BTN4, { repeat: true, debounce:50 }); + //setWatch(nextDrink, BTN5, { repeat: true, debounce:50 }); + } +} + +initDragEvents(); + if (!Bangle.isLocked()) { // Initial state if (showSunInfo) { if (PosInterval != 0 && typeof PosInterval != 'undefined') clearInterval(PosInterval); diff --git a/apps/hworldclock/metadata.json b/apps/hworldclock/metadata.json index e26599373..7dba8f752 100644 --- a/apps/hworldclock/metadata.json +++ b/apps/hworldclock/metadata.json @@ -2,7 +2,7 @@ "id": "hworldclock", "name": "Hanks World Clock", "shortName": "Hanks World Clock", - "version": "0.25", + "version": "0.26", "description": "Current time zone plus up to three others", "allow_emulator":true, "icon": "app.png", From 973b8e1565bc1183546fc6e5f6f22fe1eb03d38e Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Wed, 7 Dec 2022 09:58:45 +0000 Subject: [PATCH 081/110] circlesclock 0.19: Remove old code and fixing clkinfo handling (fix HRM and other items that change) --- apps/circlesclock/ChangeLog | 1 + apps/circlesclock/app.js | 693 +++----------------------------- apps/circlesclock/metadata.json | 2 +- apps/circlesclock/settings.js | 8 +- 4 files changed, 66 insertions(+), 638 deletions(-) diff --git a/apps/circlesclock/ChangeLog b/apps/circlesclock/ChangeLog index 8ec578fb6..b1b5637ad 100644 --- a/apps/circlesclock/ChangeLog +++ b/apps/circlesclock/ChangeLog @@ -32,3 +32,4 @@ Use widget_utils if available 0.17: Load circles from clkinfo 0.18: Improved clkinfo handling and using it for the weather circle +0.19: Remove old code and fixing clkinfo handling (fix HRM and other items that change) diff --git a/apps/circlesclock/app.js b/apps/circlesclock/app.js index ee6741398..11036dcfc 100644 --- a/apps/circlesclock/app.js +++ b/apps/circlesclock/app.js @@ -18,7 +18,6 @@ let settings = Object.assign( storage.readJSON("circlesclock.default.json", true) || {}, storage.readJSON(SETTINGS_FILE, true) || {} ); - //TODO deprecate this (and perhaps use in the clkinfo module) // Load step goal from health app and pedometer widget as fallback if (settings.stepGoal == undefined) { @@ -31,17 +30,7 @@ if (settings.stepGoal == undefined) { } } -let timerHrm; //TODO deprecate this let drawTimeout; - -/* - * Read location from myLocation app - */ -function getLocation() { - return storage.readJSON("mylocation.json", 1) || undefined; -} -let location = getLocation(); - let showWidgets = settings.showWidgets || false; let circleCount = settings.circleCount || 3; let showBigWeather = settings.showBigWeather || false; @@ -106,39 +95,9 @@ let circleItemNum = [ 2, // circle3 3, // circle4 ]; -let weatherCircleNum = 0; -let weatherCircleDataNum = 0; -let weatherCircleCondNum = 0; -let weatherCircleTempNum = 0; - -function hideWidgets() { - /* - * we are not drawing the widgets as we are taking over the whole screen - * so we will blank out the draw() functions of each widget and change the - * area to the top bar doesn't get cleared. - */ - if (WIDGETS && typeof WIDGETS === "object") { - for (let wd of WIDGETS) { - wd.draw = () => {}; - wd.area = ""; - } - } -} function draw() { - g.clear(true); - let widgetUtils; - - try { - widgetUtils = require("widget_utils"); - } catch (e) { - } - if (!showWidgets) { - if (widgetUtils) widgetUtils.hide(); else hideWidgets(); - } else { - if (widgetUtils) widgetUtils.show(); - Bangle.drawWidgets(); - } + g.reset().clearRect(Bangle.appRect); g.setColor(colorBg); g.fillRect(0, widgetOffset, w, h2 + 22); @@ -180,117 +139,18 @@ function draw() { if (icon) g.drawImage(icon, w - 48, h1, {scale:0.75}); } - drawCircle(1); - drawCircle(2); - drawCircle(3); - if (circleCount >= 4) drawCircle(4); + // FIXME do we really need to redraw circles every time? + for (var i=1;i<=circleCount;i++) + drawCircle(i); queueDraw(); } -function drawCircle(index) { - let type = settings['circle' + index]; - if (!type) type = defaultCircleTypes[index - 1]; - let w = getCircleXPosition(type); - - switch (type) { - case "weather": - drawWeather(w); - break; - case "sunprogress": - case "sunProgress": - drawSunProgress(w); - break; - //TODO those are going to be deprecated, keep for backwards compatibility for now - //ideally all data should come from some clkinfo - case "steps": - drawSteps(w); - break; - case "stepsDist": - drawStepsDistance(w); - break; - case "hr": - drawHeartRate(w); - break; - case "battery": - drawBattery(w); - break; - case "temperature": - drawTemperature(w); - break; - case "pressure": - drawPressure(w); - break; - case "altitude": - drawAltitude(w); - break; - //end deprecated - case "empty": - // we draw nothing here - return; - default: - drawClkInfo(index, w); - } -} - -// serves as cache for quicker lookup of circle positions -let circlePositionsCache = []; -/* - * Looks in the following order if a circle with the given type is somewhere visible/configured - * 1. circlePositionsCache - * 2. settings - * 3. defaultCircleTypes - * - * In case 2 and 3 the circlePositionsCache will be updated - */ -function getCirclePosition(type) { - if (circlePositionsCache[type] >= 0) { - return circlePositionsCache[type]; - } - for (let i = 1; i <= circleCount; i++) { - let setting = settings['circle' + i]; - if (setting == type) { - circlePositionsCache[type] = i - 1; - return i - 1; - } - } - for (let i = 0; i < defaultCircleTypes.length; i++) { - if (type == defaultCircleTypes[i] && (!settings || settings['circle' + (i + 1)] == undefined)) { - circlePositionsCache[type] = i; - return i; - } - } - return undefined; -} - -function getCircleXPosition(type) { - let circlePos = getCirclePosition(type); - if (circlePos != undefined) { - return circlePosX[circlePos]; - } - return undefined; -} - -function isCircleEnabled(type) { - return getCirclePosition(type) != undefined; -} - -function getCircleColor(type) { - let pos = getCirclePosition(type); - let color = settings["circle" + (pos + 1) + "color"]; +function getCircleColor(index) { + let color = settings["circle" + index + "color"]; if (color && color != "") return color; } -function getCircleIconColor(type, color, percent) { - let pos = getCirclePosition(type); - let colorizeIcon = settings["circle" + (pos + 1) + "colorizeIcon"] == true; - if (colorizeIcon) { - return getGradientColor(color, percent); - } else { - return ""; - } -} - function getGradientColor(color, percent) { if (isNaN(percent)) percent = 0; if (percent > 1) percent = 1; @@ -311,422 +171,15 @@ function getGradientColor(color, percent) { return color; } -function getImage(graphic, color) { - if (!color || color == "") { - return graphic; +function getCircleIconColor(index, color, percent) { + let colorizeIcon = settings["circle" + index + "colorizeIcon"] == true; + if (colorizeIcon) { + return getGradientColor(color, percent); } else { - return { - width: 16, - height: 16, - bpp: 1, - transparent: 0, - buffer: E.toArrayBuffer(graphic), - palette: new Uint16Array([colorBg, g.toColor(color)]) - }; + return ""; } } -function drawWeather(w) { - if (!w) w = getCircleXPosition("weather"); - let weatherInfo = menu[weatherCircleNum]; - let weatherCond = weatherCircleCondNum >= 0? weatherInfo.items[weatherCircleCondNum]: undefined; - let weatherData = weatherCircleDataNum >= 0? weatherInfo.items[weatherCircleDataNum]: undefined; - let weatherTemp = weatherCircleTempNum >= 0? weatherInfo.items[weatherCircleTempNum]: undefined; - let color = getCircleColor("weather"); - let percent = 0; - let data = settings.weatherCircleData; - let tempString = "?", icon = undefined; - let scale = 16/24; //our icons are 16x16 while clkinfo's are 24x24 - - if(weatherCond) { - weatherCond.show() - weatherCond.hide() - let data = weatherCond.get() - if(settings.legacyWeatherIcons) { //may disappear in future - icon = getWeatherIconByCode(data.v); - scale = 1; - } else - icon = data.img; - } - if(weatherTemp) { - weatherTemp.show() - weatherTemp.hide() - tempString = weatherTemp.get().text; - } - - drawCircleBackground(w); - - if(weatherData) { - weatherData.show(); - weatherData.hide(); - let data = weatherData.get(); - if(weatherData.hasRange) percent = (data.v-data.min) / (data.max-data.min); - drawGauge(w, h3, percent, color); - } - - drawInnerCircleAndTriangle(w); - - writeCircleText(w, tempString); - - if(icon) { - g.setColor(getCircleIconColor("weather", color, percent)) - .drawImage(icon, w - iconOffset, h3 + radiusOuter - iconOffset, {scale: scale}); - } else { - g.drawString("?", w, h3 + radiusOuter); - } -} -function drawWeatherOld(w) { - if (!w) w = getCircleXPosition("weather"); - let weather = getWeather(); - let tempString = weather ? locale.temp(weather.temp - 273.15) : undefined; - let code = weather ? weather.code : -1; - - drawCircleBackground(w); - - let color = getCircleColor("weather"); - let percent; - let data = settings.weatherCircleData; - switch (data) { - case "humidity": - let humidity = weather ? weather.hum : undefined; - if (humidity >= 0) { - percent = humidity / 100; - drawGauge(w, h3, percent, color); - } - break; - case "wind": - if (weather) { - let wind = locale.speed(weather.wind).match(/^(\D*\d*)(.*)$/); - if (wind[1] >= 0) { - if (wind[2] == "kmh") { - wind[1] = windAsBeaufort(wind[1]); - } - // wind goes from 0 to 12 (see https://en.wikipedia.org/wiki/Beaufort_scale) - percent = wind[1] / 12; - drawGauge(w, h3, percent, color); - } - } - break; - case "empty": - break; - } - - drawInnerCircleAndTriangle(w); - - writeCircleText(w, tempString ? tempString : "?"); - - if (code > 0) { - let icon = getWeatherIconByCode(code); - if (icon) g.drawImage(getImage(icon, getCircleIconColor("weather", color, percent)), w - iconOffset, h3 + radiusOuter - iconOffset); - } else { - g.drawString("?", w, h3 + radiusOuter); - } -} - -function drawSunProgress(w) { - if (!w) w = getCircleXPosition("sunprogress"); - let percent = getSunProgress(); - - // sunset icons: - let sunSetDown = atob("EBCBAAAAAAABgAAAAAATyAZoBCB//gAAAAAGYAPAAYAAAAAA"); - let sunSetUp = atob("EBCBAAAAAAABgAAAAAATyAZoBCB//gAAAAABgAPABmAAAAAA"); - - drawCircleBackground(w); - - let color = getCircleColor("sunprogress"); - - drawGauge(w, h3, percent, color); - - drawInnerCircleAndTriangle(w); - - let icon = sunSetDown; - let text = "?"; - let times = getSunData(); - if (times != undefined) { - let sunRise = Math.round(times.sunrise.getTime() / 1000); - let sunSet = Math.round(times.sunset.getTime() / 1000); - if (!isDay()) { - // night - if (now > sunRise) { - // after sunRise - let upcomingSunRise = sunRise + 60 * 60 * 24; - text = formatSeconds(upcomingSunRise - now); - } else { - text = formatSeconds(sunRise - now); - } - icon = sunSetUp; - } else { - // day, approx sunrise tomorrow: - text = formatSeconds(sunSet - now); - icon = sunSetDown; - } - } - - writeCircleText(w, text); - - g.drawImage(getImage(icon, getCircleIconColor("sunprogress", color, percent)), w - iconOffset, h3 + radiusOuter - iconOffset); -} - -/* - * Deprecated but nice as references for clkinfo - */ - -function drawSteps(w) { - if (!w) w = getCircleXPosition("steps"); - let steps = getSteps(); - - drawCircleBackground(w); - - let color = getCircleColor("steps"); - - let percent; - let stepGoal = settings.stepGoal; - if (stepGoal > 0) { - percent = steps / stepGoal; - if (stepGoal < steps) percent = 1; - drawGauge(w, h3, percent, color); - } - - drawInnerCircleAndTriangle(w); - - writeCircleText(w, shortValue(steps)); - - g.drawImage(getImage(atob("EBCBAAAACAAcAB4AHgAeABwwADgGeAZ4AHgAMAAAAHAAIAAA"), getCircleIconColor("steps", color, percent)), w - iconOffset, h3 + radiusOuter - iconOffset); -} - -function drawStepsDistance(w) { - if (!w) w = getCircleXPosition("stepsDistance"); - let steps = getSteps(); - let stepDistance = settings.stepLength; - let stepsDistance = Math.round(steps * stepDistance); - - drawCircleBackground(w); - - let color = getCircleColor("stepsDistance"); - - let percent; - let stepDistanceGoal = settings.stepDistanceGoal; - if (stepDistanceGoal > 0) { - percent = stepsDistance / stepDistanceGoal; - if (stepDistanceGoal < stepsDistance) percent = 1; - drawGauge(w, h3, percent, color); - } - - drawInnerCircleAndTriangle(w); - - writeCircleText(w, shortValue(stepsDistance)); - - g.drawImage(getImage(atob("EBCBAAAACAAcAB4AHgAeABwwADgGeAZ4AHgAMAAAAHAAIAAA"), getCircleIconColor("stepsDistance", color, percent)), w - iconOffset, h3 + radiusOuter - iconOffset); -} - -function drawHeartRate(w) { - if (!w) w = getCircleXPosition("hr"); - - let heartIcon = atob("EBCBAAAAAAAeeD/8P/x//n/+P/w//B/4D/AH4APAAYAAAAAA"); - - drawCircleBackground(w); - - let color = getCircleColor("hr"); - - let percent; - if (hrtValue != undefined) { - let minHR = settings.minHR; - let maxHR = settings.maxHR; - percent = (hrtValue - minHR) / (maxHR - minHR); - if (isNaN(percent)) percent = 0; - drawGauge(w, h3, percent, color); - } - - drawInnerCircleAndTriangle(w); - - writeCircleText(w, hrtValue != undefined ? hrtValue : "-"); - - g.drawImage(getImage(heartIcon, getCircleIconColor("hr", color, percent)), w - iconOffset, h3 + radiusOuter - iconOffset); -} - -function drawBattery(w) { - if (!w) w = getCircleXPosition("battery"); - let battery = E.getBattery(); - - let powerIcon = atob("EBCBAAAAA8ADwA/wD/AP8A/wD/AP8A/wD/AP8A/wD/AH4AAA"); - - drawCircleBackground(w); - - let color = getCircleColor("battery"); - - let percent; - if (battery > 0) { - percent = battery / 100; - drawGauge(w, h3, percent, color); - } - - drawInnerCircleAndTriangle(w); - - if (Bangle.isCharging()) { - color = colorGreen; - } else { - if (settings.batteryWarn != undefined && battery <= settings.batteryWarn) { - color = colorRed; - } - } - writeCircleText(w, battery + '%'); - - g.drawImage(getImage(powerIcon, getCircleIconColor("battery", color, percent)), w - iconOffset, h3 + radiusOuter - iconOffset); -} -function drawTemperature(w) { - if (!w) w = getCircleXPosition("temperature"); - - getPressureValue("temperature").then((temperature) => { - drawCircleBackground(w); - - let color = getCircleColor("temperature"); - - let percent; - if (temperature) { - let min = -40; - let max = 85; - percent = (temperature - min) / (max - min); - drawGauge(w, h3, percent, color); - } - - drawInnerCircleAndTriangle(w); - - if (temperature) - writeCircleText(w, locale.temp(temperature)); - - g.drawImage(getImage(atob("EBCBAAAAAYADwAJAAkADwAPAA8ADwAfgB+AH4AfgA8ABgAAA"), getCircleIconColor("temperature", color, percent)), w - iconOffset, h3 + radiusOuter - iconOffset); - - }); -} - -function drawPressure(w) { - if (!w) w = getCircleXPosition("pressure"); - - getPressureValue("pressure").then((pressure) => { - drawCircleBackground(w); - - let color = getCircleColor("pressure"); - - let percent; - if (pressure && pressure > 0) { - let minPressure = 950; - let maxPressure = 1050; - percent = (pressure - minPressure) / (maxPressure - minPressure); - drawGauge(w, h3, percent, color); - } - - drawInnerCircleAndTriangle(w); - - if (pressure) - writeCircleText(w, Math.round(pressure)); - - g.drawImage(getImage(atob("EBCBAAAAAYADwAJAAkADwAPAA8ADwAfgB+AH4AfgA8ABgAAA"), getCircleIconColor("pressure", color, percent)), w - iconOffset, h3 + radiusOuter - iconOffset); - - }); -} - -function drawAltitude(w) { - if (!w) w = getCircleXPosition("altitude"); - - getPressureValue("altitude").then((altitude) => { - drawCircleBackground(w); - - let color = getCircleColor("altitude"); - - let percent; - if (altitude) { - let min = 0; - let max = 10000; - percent = (altitude - min) / (max - min); - drawGauge(w, h3, percent, color); - } - - drawInnerCircleAndTriangle(w); - - if (altitude) - writeCircleText(w, locale.distance(Math.round(altitude))); - - g.drawImage(getImage(atob("EBCBAAAAAYADwAJAAkADwAPAA8ADwAfgB+AH4AfgA8ABgAAA"), getCircleIconColor("altitude", color, percent)), w - iconOffset, h3 + radiusOuter - iconOffset); - - }); -} - -function shortValue(v) { - if (isNaN(v)) return '-'; - if (v <= 999) return v; - if (v >= 1000 && v < 10000) { - v = Math.floor(v / 100) * 100; - return (v / 1000).toFixed(1).replace(/\.0$/, '') + 'k'; - } - if (v >= 10000) { - v = Math.floor(v / 1000) * 1000; - return (v / 1000).toFixed(1).replace(/\.0$/, '') + 'k'; - } -} - -function getSteps() { - if (Bangle.getHealthStatus) { - return Bangle.getHealthStatus("day").steps; - } - if (WIDGETS && WIDGETS.wpedom !== undefined) { - return WIDGETS.wpedom.getSteps(); - } - return 0; -} - -function getPressureValue(type) { - return new Promise((resolve) => { - if (Bangle.getPressure) { - if (!pressureLocked) { - pressureLocked = true; - if (pressureCache && pressureCache[type]) { - resolve(pressureCache[type]); - } - Bangle.getPressure().then(function(d) { - pressureLocked = false; - if (d) { - pressureCache = d; - if (d[type]) { - resolve(d[type]); - } - } - }).catch(() => {}); - } else { - if (pressureCache && pressureCache[type]) { - resolve(pressureCache[type]); - } - } - } - }); -} - -/* - * end deprecated - */ - -var menu = null; -function reloadMenu() { - menu = clock_info.load(); - for(var i=1; i<5; i++) - if(settings['circle'+i].includes("/")) { - let parts = settings['circle'+i].split("/"); - let infoName = parts[0], itemName = parts[1]; - let infoNum = menu.findIndex(e=>e.name==infoName); - let itemNum = 0; //get first if dynamic - if(!menu[infoNum].dynamic) - itemNum = menu[infoNum].items.findIndex(it=>it.name==itemName); - circleInfoNum[i-1] = infoNum; - circleItemNum[i-1] = itemNum; - } else if(settings['circle'+i] == "weather") { - weatherCircleNum = menu.findIndex(e=>e.name.toLowerCase() == "weather"); - weatherCircleDataNum = menu[weatherCircleNum].items.findIndex(it=>it.name==settings.weatherCircleData); - weatherCircleCondNum = menu[weatherCircleNum].items.findIndex(it=>it.name=="condition"); - weatherCircleTempNum = menu[weatherCircleNum].items.findIndex(it=>it.name=="temperature"); - } -} -//reload periodically for changes? -reloadMenu(); - function drawEmpty(img, w, color) { drawGauge(w, h3, 0, color); drawInnerCircleAndTriangle(w); @@ -736,45 +189,32 @@ function drawEmpty(img, w, color) { .drawImage(img, w - iconOffset, h3 + radiusOuter - iconOffset, {scale: 16/24}); } -function drawClkInfo(index, w) { +function drawCircle(index) { var info = menu[circleInfoNum[index-1]]; var type = settings['circle'+index]; - if (!w) w = getCircleXPosition(type); + var w = circlePosX[index-1]; drawCircleBackground(w); - const color = getCircleColor(type); - var item = info.items[circleItemNum[index-1]]; + const color = getCircleColor(index); + var item = info && info.items[circleItemNum[index-1]]; if(!info || !item) { drawEmpty(info? info.img : null, w, color); return; } - item.show(); - item.hide(); var data=item.get(); var img = data.img; var percent = 1; //fill up if no range - var txt = data.text; + var txt = ""+data.text; + if (txt.endsWith(" bpm")) txt=txt.slice(0,-4); // hack for heart rate - remove the 'bpm' text if(!img) img = info.img; if(item.hasRange) percent = (data.v-data.min) / (data.max-data.min); if(data.short) txt = data.short; drawGauge(w, h3, percent, color); drawInnerCircleAndTriangle(w); writeCircleText(w, txt); - g.setColor(getCircleIconColor(type, color, percent)) + g.setColor(getCircleIconColor(index, color, percent)) .drawImage(img, w - iconOffset, h3 + radiusOuter - iconOffset, {scale: 16/24}); } -/* - * wind goes from 0 to 12 (see https://en.wikipedia.org/wiki/Beaufort_scale) - */ -function windAsBeaufort(windInKmh) { - let beaufort = [2, 6, 12, 20, 29, 39, 50, 62, 75, 89, 103, 118]; - let l = 0; - while (l < beaufort.length && beaufort[l] < windInKmh) { - l++; - } - return l; -} - /* * Choose weather icon to display based on weather conditition code @@ -795,7 +235,7 @@ function getWeatherIconByCode(code, big) { let weatherFoggy = big ? atob("QEDBAP//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8AAAAAAAAADwAAAAAAAAAPAAAAAAAAAA8AAAAAAAAADwAAAAAAAAAPAAAAAAAAAA8AAAAAAAwADwADAAAAHgAPAAeAAAAfAA8AD4AAAA+ADwAfAAAAB8APAD4AAAAD4B+AfAAAAAHw//D4AAAAAPv//fAAAAAAf///4AAAAAA/4H/AAAAAAB+AH4AAAAAAPgAHwAAAAAA8AAPAAAAAAHwAA+AAAAAAeAAB4AAAAAB4AAHgAAAAAPAAAPAAAAAAAAAA//8AAAAAAAD//wAAAAAAAP//AAAAAAAA//8AD///AADwAAAP//8AAeAAAA///wAB4AAAD///AAPgAAAAAAAAA8AAAAAAAAAHwAAAAAAAAB+AAAAAAAAAf8AAAAD///D/4AAAAP//8P3wAAAA///w8PgAAAD///CAfAAAAAAAAAA+AAAAAAAAAB8AAAAAAAAAD4AAAAAAAAAHgAAP//8PAAMAAA///w8AAAAAD///DwAAAAAP//8PAAAAAAAAAA8AAAAAAAAADwAAAAAAAAAPAAAAAAAAAA8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==") : atob("EBCBAAAAAAADwAZgDDA4EGAcQAZAAgAAf74AAAAAd/4AAAAA"); let weatherStormy = big ? atob("QEDBAP//wxgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AAAAAAAAB//gAAAAAAAP//gAAAAAAD///AAAAAAAf4H+AAAAAAD8AD8AAAAAAfgAH4AAAAAB8AAPwAAAAAPgAAf/AAAAB8AAA//AAAAHgAAB/+AAAAeAAAH/8AAAH4AAAIH4AAB/AAAAAHwAAf8AAAAAPgAD/wAAAAAeAAPwAAAAAB4AB8AAAAAADwAHgAAAAAAPAA+AAAAAAA8ADwAAAAAADwA/AAAAAAAPAH8AAAAAAA8A/wAAAAAAHwH4AAAAAAAfg+AAAAAAAAfHwAAAAAAAA+eAAAAAAAAB54AAAAD/AAHvAAAAAf4AAP8AAAAB/gAA/wAAAAP8AAD/AAAAA/gAAP8AAAAH+AAA/wAAAAfwAAD3gAAAD/AAAeeAAAAP4AAB58AAAB/AAAPj4AAAH8AAB8H4AAA/gAAfgP//+D//D/8Af//4f/4P/gA///B//B/8AAf/8P/8P+AAAAAAAPgAAAAAAAAB8AAAAAAAAAHwAAAAAAAAA+AAAAAAAAADwAAAAAAAAAfAAAAAAAAAB4AAAAAAAAAPAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==") : atob("EBCBAAAAAYAH4AwwOBBgGEAOQMJAgjmOGcgAgACAAAAAAAAA"); let unknown = big ? atob("QEDBAP//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/wAAAAAAAAf/4AAAAAAAH//4AAAAAAA///wAAAAAAH+B/gAAAAAA/AA/AAAAAAH4AB+AAAAAA/AAD4AAAAAD4H4HwAAAAAfB/4PgAAAAB8P/weAAAAAHg//h4AAAAA+Hw+HwAAAAD4eB8PAAAAAP/wDw8AAAAA//APDwAAAAD/8A8PAAAAAH/gDw8AAAAAAAAfDwAAAAAAAH4fAAAAAAAB/B4AAAAAAAf4HgAAAAAAD/A+AAAAAAAfwHwAAAAAAD8A+AAAAAAAPgH4AAAAAAB8B/AAAAAAAHgf4AAAAAAA+H+AAAAAAADwfwAAAAAAAPD8AAAAAAAA8PAAAAAAAAD/8AAAAAAAAP/wAAAAAAAA//AAAAAAAAB/4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAf+AAAAAAAAD/8AAAAAAAAP/wAAAAAAAA//AAAAAAAADw8AAAAAAAAPDwAAAAAAAA8PAAAAAAAADw8AAAAAAAAP/wAAAAAAAA//AAAAAAAAD/8AAAAAAAAH/gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==") : undefined; - + switch (codeGroup) { case 2: return weatherStormy; @@ -823,7 +263,9 @@ function getWeatherIconByCode(code, big) { case 8: switch (code) { case 800: - return isDay() ? weatherSunny : weatherMoon; + var hr = (new Date()).getHours(); + var isDay = (hr>6) && (hr<=18); // fixme we don't want to include ALL of suncalc just to choose one icon + return isDay ? weatherSunny : weatherMoon; case 801: return weatherPartlyCloudy; case 802: @@ -836,16 +278,6 @@ function getWeatherIconByCode(code, big) { } } - -function isDay() { - let times = getSunData(); - if (times == undefined) return true; - let sunRise = Math.round(times.sunrise.getTime() / 1000); - let sunSet = Math.round(times.sunset.getTime() / 1000); - - return (now > sunRise && now < sunSet); -} - function formatSeconds(s) { if (s > 60 * 60) { // hours return Math.round(s / (60 * 60)) + "h"; @@ -856,45 +288,6 @@ function formatSeconds(s) { return "<1m"; } -function getSunData() { - if (location != undefined && location.lat != undefined) { - let SunCalc = require("https://raw.githubusercontent.com/mourner/suncalc/master/suncalc.js"); - // get today's sunlight times for lat/lon - return SunCalc ? SunCalc.getTimes(new Date(), location.lat, location.lon) : undefined; - } - return undefined; -} - -/* - * Calculated progress of the sun between sunrise and sunset in percent - * - * Taken from rebble app and modified - */ -function getSunProgress() { - let times = getSunData(); - if (times == undefined) return 0; - let sunRise = Math.round(times.sunrise.getTime() / 1000); - let sunSet = Math.round(times.sunset.getTime() / 1000); - - if (isDay()) { - // during day - let dayLength = sunSet - sunRise; - if (now > sunRise) { - return (now - sunRise) / dayLength; - } else { - return (sunRise - now) / dayLength; - } - } else { - // during night - if (now < sunRise) { - let prevSunSet = sunSet - 60 * 60 * 24; - return 1 - (sunRise - now) / (sunRise - prevSunSet); - } else { - let upcomingSunRise = sunRise + 60 * 60 * 24; - return (upcomingSunRise - now) / (upcomingSunRise - sunSet); - } - } -} /* * Draws the background and the grey circle @@ -961,18 +354,54 @@ function getWeather() { return jsonWeather && jsonWeather.weather ? jsonWeather.weather : undefined; } + +var menu = clock_info.load(); +for(var i=1; i<5; i++) { + var circleType = settings['circle'+i]; + if(circleType.includes("/")) { + let parts = circleType.split("/"); + let infoName = parts[0], itemName = parts[1]; + let infoNum = menu.findIndex(e=>e.name==infoName); + if (infoNum<0) infoNum=0; // not found! + let itemNum = 0; //get first if dynamic + if(!menu[infoNum].dynamic) + itemNum = menu[infoNum].items.findIndex(it=>it.name==itemName); + if (itemNum<0) itemNum=0; + circleInfoNum[i-1] = infoNum; + circleItemNum[i-1] = itemNum; + let menuItem = menu[infoNum].items[itemNum]; + if (menuItem) { + (function(i){ + menuItem.on('redraw', function() { + drawCircle(i); + }); + })(i); + menuItem.show(); + } + } else { // empty? + circleInfoNum[i-1] = -1; + circleItemNum[i-1] = -1; + } +} + Bangle.setUI({ mode : "clock", - remove : function() { + /*remove : function() { + THIS CLOCK IS NOT YET ABLE TO UNLOAD ALL OF ITSELF. + DO NOT UNCOMMENT THIS WITOUT FIXING IT + OR THERE WILL BE HUGE MEMORY LEAKS // Called to unload all of the clock app if (drawTimeout) clearTimeout(drawTimeout); drawTimeout = undefined; - + // must call clkinfo.hide here for any showing clkinfo delete Graphics.prototype.setFontRobotoRegular50NumericOnly; delete Graphics.prototype.setFontRobotoRegular21; - }}); + }*/ +}); Bangle.loadWidgets(); +if (!showWidgets) require("widget_utils").hide(); +else Bangle.drawWidgets(); // schedule a draw for the next second or minute function queueDraw() { diff --git a/apps/circlesclock/metadata.json b/apps/circlesclock/metadata.json index fb743ae4c..3b436a032 100644 --- a/apps/circlesclock/metadata.json +++ b/apps/circlesclock/metadata.json @@ -1,7 +1,7 @@ { "id": "circlesclock", "name": "Circles clock", "shortName":"Circles clock", - "version":"0.18", + "version":"0.19", "description": "A clock with three or four circles for different data at the bottom in a probably familiar style", "icon": "app.png", "screenshots": [{"url":"screenshot-dark.png"}, {"url":"screenshot-light.png"}, {"url":"screenshot-dark-4.png"}, {"url":"screenshot-light-4.png"}], diff --git a/apps/circlesclock/settings.js b/apps/circlesclock/settings.js index 2ab655f01..2e9506a98 100644 --- a/apps/circlesclock/settings.js +++ b/apps/circlesclock/settings.js @@ -12,17 +12,15 @@ storage.write(SETTINGS_FILE, settings); } - //const valuesCircleTypes = ["empty", "steps", "stepsDist", "hr", "battery", "weather", "sunprogress", "temperature", "pressure", "altitude", "timer"]; - //const namesCircleTypes = ["empty", "steps", "distance", "heart", "battery", "weather", "sun", "temperature", "pressure", "altitude", "timer"]; - var valuesCircleTypes = ["empty","weather", "sunprogress"]; - var namesCircleTypes = ["empty","weather", "sun"]; + var valuesCircleTypes = ["empty"]; + var namesCircleTypes = ["empty"]; clock_info.load().forEach(e=>{ if(e.dynamic) { valuesCircleTypes = valuesCircleTypes.concat([e.name+"/"]); namesCircleTypes = namesCircleTypes.concat([e.name]); } else { let values = e.items.map(i=>e.name+"/"+i.name); - let names =e.name=="Bangle" ? e.items.map(i=>i.name) : values; + let names = e.name=="Bangle" ? e.items.map(i=>i.name) : values; valuesCircleTypes = valuesCircleTypes.concat(values); namesCircleTypes = namesCircleTypes.concat(names); } From 416d5d0fff6e02d6f4c80e54df7555f3381237e0 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Wed, 7 Dec 2022 10:54:34 +0000 Subject: [PATCH 082/110] Remove settings for what is displayed and instead allow circles to be changed by swiping --- apps/circlesclock/ChangeLog | 1 + apps/circlesclock/README.md | 20 ++++-- apps/circlesclock/app.js | 109 ++++++++++----------------------- apps/circlesclock/default.json | 4 -- apps/circlesclock/settings.js | 21 ------- 5 files changed, 50 insertions(+), 105 deletions(-) diff --git a/apps/circlesclock/ChangeLog b/apps/circlesclock/ChangeLog index b1b5637ad..9e36f67ba 100644 --- a/apps/circlesclock/ChangeLog +++ b/apps/circlesclock/ChangeLog @@ -33,3 +33,4 @@ 0.17: Load circles from clkinfo 0.18: Improved clkinfo handling and using it for the weather circle 0.19: Remove old code and fixing clkinfo handling (fix HRM and other items that change) + Remove settings for what is displayed and instead allow circles to be changed by swiping diff --git a/apps/circlesclock/README.md b/apps/circlesclock/README.md index 8c8fbe4ae..7f6a2585c 100644 --- a/apps/circlesclock/README.md +++ b/apps/circlesclock/README.md @@ -5,6 +5,7 @@ A clock with three or four circles for different data at the bottom in a probabl By default the time, date and day of week is shown. It can show the following information (this can be configured): + * Steps * Steps distance * Heart rate (automatically updates when screen is on and unlocked) @@ -14,15 +15,24 @@ It can show the following information (this can be configured): * Temperature inside circle * Condition as icon below circle * Big weather icon next to clock - * Time and progress until next sunrise or sunset (requires [my location app](https://banglejs.com/apps/#mylocation)) - * Temperature, air pressure or altitude from internal pressure sensor + * Altitude from internal pressure sensor + * Active alarms (if `Alarm` app installed) + * Sunrise or sunset (if `Sunrise Clockinfo` app installed) +To change what is shown: -The color of each circle can be configured. The following colors are available: +* Unlock the watch +* Tap on the circle to change (a border is drawn around it) +* Swipe up/down to change the guage within the given group +* Swipe left/right to change the group (eg. between standard Bangle.js and Alarms/etc) + +Data is provided by ['Clock Info'](http://www.espruino.com/Bangle.js+Clock+Info) +so any apps that implement this feature can add extra information to be displayed. + +The color of each circle can be configured from `Settings -> Apps -> Circles Clock`. The following colors are available: * Basic colors (red, green, blue, yellow, magenta, cyan, black, white) * Color depending on value (green -> red, red -> green) - ## Screenshots ![Screenshot dark theme](screenshot-dark.png) ![Screenshot light theme](screenshot-light.png) @@ -38,5 +48,5 @@ The color of each circle can be configured. The following colors are available: Marco ([myxor](https://github.com/myxor)) ## Icons -Most of the icons are taken from [materialdesignicons](https://materialdesignicons.com) under Apache License 2.0 except the big weather icons which are from +Most of the icons are taken from [materialdesignicons](https://materialdesignicons.com) under Apache License 2.0 except the big weather icons which are from [icons8](https://icons8.com/icon/set/weather/small--static--black) diff --git a/apps/circlesclock/app.js b/apps/circlesclock/app.js index 11036dcfc..efd0b0aa6 100644 --- a/apps/circlesclock/app.js +++ b/apps/circlesclock/app.js @@ -41,11 +41,6 @@ let now = Math.round(new Date().getTime() / 1000); // layout values: let colorFg = g.theme.dark ? '#fff' : '#000'; let colorBg = g.theme.dark ? '#000' : '#fff'; -let colorGrey = '#808080'; -let colorRed = '#ff0000'; -let colorGreen = '#008000'; -let colorBlue = '#0000ff'; -let colorYellow = '#ffff00'; let widgetOffset = showWidgets ? 24 : 0; let dowOffset = circleCount == 3 ? 20 : 22; // dow offset relative to date let h = g.getHeight() - widgetOffset; @@ -53,7 +48,7 @@ let w = g.getWidth(); let hOffset = (circleCount == 3 ? 34 : 30) - widgetOffset; let h1 = Math.round(1 * h / 5 - hOffset); let h2 = Math.round(3 * h / 5 - hOffset); -let h3 = Math.round(8 * h / 8 - hOffset - 3); // circle y position +let h3 = Math.round(8 * h / 8 - hOffset - 3); // circle middle y position /* * circle x positions @@ -76,28 +71,17 @@ let circlePosX = [ ]; let radiusOuter = circleCount == 3 ? 25 : 20; +let radiusBorder = radiusOuter+3; // absolute border of circles let radiusInner = circleCount == 3 ? 20 : 15; let circleFontSmall = circleCount == 3 ? "Vector:14" : "Vector:10"; let circleFont = circleCount == 3 ? "Vector:15" : "Vector:11"; let circleFontBig = circleCount == 3 ? "Vector:16" : "Vector:12"; let iconOffset = circleCount == 3 ? 6 : 8; -let defaultCircleTypes = ["Bangle/Steps", "Bangle/HRM", "Bangle/Battery", "weather"]; -let circleInfoNum = [ - 0, // circle1 - 0, // circle2 - 0, // circle3 - 0, // circle4 -]; -let circleItemNum = [ - 0, // circle1 - 1, // circle2 - 2, // circle3 - 3, // circle4 -]; function draw() { - g.reset().clearRect(Bangle.appRect); + let R = Bangle.appRect; + g.reset().clearRect(R.x,R.y, R.x2, h3-(radiusBorder+1)); g.setColor(colorBg); g.fillRect(0, widgetOffset, w, h2 + 22); @@ -139,16 +123,13 @@ function draw() { if (icon) g.drawImage(icon, w - 48, h1, {scale:0.75}); } - // FIXME do we really need to redraw circles every time? - for (var i=1;i<=circleCount;i++) - drawCircle(i); - queueDraw(); } function getCircleColor(index) { let color = settings["circle" + index + "color"]; if (color && color != "") return color; + return g.theme.fg; } function getGradientColor(color, percent) { @@ -176,7 +157,7 @@ function getCircleIconColor(index, color, percent) { if (colorizeIcon) { return getGradientColor(color, percent); } else { - return ""; + return g.theme.fg; } } @@ -189,23 +170,15 @@ function drawEmpty(img, w, color) { .drawImage(img, w - iconOffset, h3 + radiusOuter - iconOffset, {scale: 16/24}); } -function drawCircle(index) { - var info = menu[circleInfoNum[index-1]]; - var type = settings['circle'+index]; +function drawCircle(index, item, data) { var w = circlePosX[index-1]; drawCircleBackground(w); const color = getCircleColor(index); - var item = info && info.items[circleItemNum[index-1]]; - if(!info || !item) { - drawEmpty(info? info.img : null, w, color); - return; - } - var data=item.get(); + //drawEmpty(info? info.img : null, w, color); var img = data.img; var percent = 1; //fill up if no range var txt = ""+data.text; if (txt.endsWith(" bpm")) txt=txt.slice(0,-4); // hack for heart rate - remove the 'bpm' text - if(!img) img = info.img; if(item.hasRange) percent = (data.v-data.min) / (data.max-data.min); if(data.short) txt = data.short; drawGauge(w, h3, percent, color); @@ -293,12 +266,11 @@ function formatSeconds(s) { * Draws the background and the grey circle */ function drawCircleBackground(w) { - g.clearRect(w - radiusOuter - 3, h3 - radiusOuter - 3, w + radiusOuter + 3, h3 + radiusOuter + 3); // Draw rectangle background: g.setColor(colorBg); - g.fillRect(w - radiusOuter - 3, h3 - radiusOuter - 3, w + radiusOuter + 3, h3 + radiusOuter + 3); + g.fillRect(w - radiusBorder, h3 - radiusBorder, w + radiusBorder, g.getHeight()-1); // Draw grey background circle: - g.setColor(colorGrey); + g.setColor('#808080'); // grey g.fillCircle(w, h3, radiusOuter); } @@ -310,10 +282,6 @@ function drawInnerCircleAndTriangle(w) { g.fillPoly([w, h3, w - 15, h3 + radiusOuter + 5, w + 15, h3 + radiusOuter + 5]); } -function radians(a) { - return a * Math.PI / 180; -} - /* * This draws the actual gauge consisting out of lots of little filled circles */ @@ -332,10 +300,12 @@ function drawGauge(cx, cy, percent, color) { color = getGradientColor(color, percent); g.setColor(color); + // FIXME: this one loop takes 0.25 sec EACH TIME the function is called for (let i = startRotation; i > endRotation - size; i -= size) { - x = cx + radius * Math.sin(radians(i)); - y = cy + radius * Math.cos(radians(i)); - g.fillCircle(x, y, size); + let r = i * Math.PI / 180; // radians + g.fillCircle( + cx + radius * Math.sin(r), + cy + radius * Math.cos(r), size); } } @@ -354,35 +324,7 @@ function getWeather() { return jsonWeather && jsonWeather.weather ? jsonWeather.weather : undefined; } - -var menu = clock_info.load(); -for(var i=1; i<5; i++) { - var circleType = settings['circle'+i]; - if(circleType.includes("/")) { - let parts = circleType.split("/"); - let infoName = parts[0], itemName = parts[1]; - let infoNum = menu.findIndex(e=>e.name==infoName); - if (infoNum<0) infoNum=0; // not found! - let itemNum = 0; //get first if dynamic - if(!menu[infoNum].dynamic) - itemNum = menu[infoNum].items.findIndex(it=>it.name==itemName); - if (itemNum<0) itemNum=0; - circleInfoNum[i-1] = infoNum; - circleItemNum[i-1] = itemNum; - let menuItem = menu[infoNum].items[itemNum]; - if (menuItem) { - (function(i){ - menuItem.on('redraw', function() { - drawCircle(i); - }); - })(i); - menuItem.show(); - } - } else { // empty? - circleInfoNum[i-1] = -1; - circleItemNum[i-1] = -1; - } -} +g.clear(1); // clear the whole screen Bangle.setUI({ mode : "clock", @@ -393,12 +335,29 @@ Bangle.setUI({ // Called to unload all of the clock app if (drawTimeout) clearTimeout(drawTimeout); drawTimeout = undefined; - // must call clkinfo.hide here for any showing clkinfo + for(var i=1;i<=circleCount; i++) + clockInfoMenu[i].remove(); delete Graphics.prototype.setFontRobotoRegular50NumericOnly; delete Graphics.prototype.setFontRobotoRegular21; }*/ }); +let clockInfoDraw = (itm, info, options) => { + //print("Draw",itm.name,options); + drawCircle(options.circlePosition, itm, info); + if (options.focus) g.reset().drawRect(options.x, options.y, options.x+options.w-2, options.y+options.h-1) +}; +let clockInfoItems = require("clock_info").load(); +let clockInfoMenu = []; +for(var i=0;i{ - if(e.dynamic) { - valuesCircleTypes = valuesCircleTypes.concat([e.name+"/"]); - namesCircleTypes = namesCircleTypes.concat([e.name]); - } else { - let values = e.items.map(i=>e.name+"/"+i.name); - let names = e.name=="Bangle" ? e.items.map(i=>i.name) : values; - valuesCircleTypes = valuesCircleTypes.concat(values); - namesCircleTypes = namesCircleTypes.concat(names); - } - }) - - const valuesColors = ["", "#ff0000", "#00ff00", "#0000ff", "#ffff00", "#ff00ff", "#00ffff", "#fff", "#000", "green-red", "red-green", "fg"]; const namesColors = ["default", "red", "green", "blue", "yellow", "magenta", @@ -103,12 +88,6 @@ const menu = { '': { 'title': /*LANG*/'Circle ' + circleId }, /*LANG*/'< Back': ()=>showMainMenu(), - /*LANG*/'data': { - value: valuesCircleTypes.indexOf(settings[circleName]), - min: 0, max: valuesCircleTypes.length - 1, - format: v => namesCircleTypes[v], - onchange: x => save(circleName, valuesCircleTypes[x]), - }, /*LANG*/'color': { value: valuesColors.indexOf(settings[colorKey]) || 0, min: 0, max: valuesColors.length - 1, From 383f18f92facbf8a4ea44bad2f8ea9ce0f763f6a Mon Sep 17 00:00:00 2001 From: Hank Date: Wed, 7 Dec 2022 12:18:14 +0100 Subject: [PATCH 083/110] Tidy up --- apps/hworldclock/ChangeLog | 2 +- apps/hworldclock/README.md | 2 +- apps/hworldclock/app.js | 17 +++++++---------- 3 files changed, 9 insertions(+), 12 deletions(-) diff --git a/apps/hworldclock/ChangeLog b/apps/hworldclock/ChangeLog index 158ea1c91..7b97ce527 100644 --- a/apps/hworldclock/ChangeLog +++ b/apps/hworldclock/ChangeLog @@ -9,4 +9,4 @@ 0.23: Added note to configure position in "my location" if not done yet. Small fixes. 0.24: Added fast load 0.25: Minor code optimization -0.26: Swipe down to rotate 180° +0.26: BJS2: Swipe down to rotate 180 degree diff --git a/apps/hworldclock/README.md b/apps/hworldclock/README.md index 073a7c8a9..5a1bcc7f0 100644 --- a/apps/hworldclock/README.md +++ b/apps/hworldclock/README.md @@ -14,7 +14,7 @@ Provide names and the UTC offsets for up to three other timezones in the app sto The clock does not handle summer time / daylight saving time changes automatically. If one of your three locations changes its UTC offset, you can simply change the setting in the app store and update. Currently the clock only supports 24 hour time format for the additional time zones. -Swipe down to rotate screen. So you can show the time to a friend real quick. +BangleJS2: Swipe down to rotate screen. So you can show the time to a friend real quick. ## Requests diff --git a/apps/hworldclock/app.js b/apps/hworldclock/app.js index c5e1942a5..fd9b9270f 100644 --- a/apps/hworldclock/app.js +++ b/apps/hworldclock/app.js @@ -332,19 +332,17 @@ if (BANGLEJS2) { if (Math.abs(dx)>Math.abs(dy)+10) { // horizontal if (dx < dy) { - + // for later purpose } else { - + // for later purpose } } else if (Math.abs(dy)>Math.abs(dx)+10) { // vertical if (dx < dy) { g.clear().setRotation(2); - //console.log(" draw(); Bangle.loadWidgets(); Bangle.drawWidgets(); - } else { g.clear().setRotation(0); draw(); @@ -354,16 +352,16 @@ if (BANGLEJS2) { } else { //console.log("tap " + e.x + " " + e.y); if (e.x > 145 && e.y > 145) { - + // for later purpose } } } }); } else { - //setWatch(addDrink, BTN1, { repeat: true, debounce:50 }); - //setWatch(removeDrink, BTN3, { repeat: true, debounce:50 }); - //setWatch(previousDrink, BTN4, { repeat: true, debounce:50 }); - //setWatch(nextDrink, BTN5, { repeat: true, debounce:50 }); + //setWatch(xxx, BTN1, { repeat: true, debounce:50 }); // maybe adding this later + //setWatch(xxx, BTN3, { repeat: true, debounce:50 }); + //setWatch(xxx, BTN4, { repeat: true, debounce:50 }); + //setWatch(xxx, BTN5, { repeat: true, debounce:50 }); } } @@ -402,7 +400,6 @@ if (!Bangle.isLocked()) { // Initial state updatePos(); } draw(); // draw immediately, queue redraw - } From 3cf55b6649dd09d08278e1fb86e1fc747b7d2d2f Mon Sep 17 00:00:00 2001 From: Hank Date: Wed, 7 Dec 2022 14:12:53 +0100 Subject: [PATCH 084/110] Changed direction --- apps/hworldclock/ChangeLog | 1 + apps/hworldclock/README.md | 2 +- apps/hworldclock/app.js | 6 +++--- apps/hworldclock/metadata.json | 2 +- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/apps/hworldclock/ChangeLog b/apps/hworldclock/ChangeLog index 7b97ce527..22be10e2d 100644 --- a/apps/hworldclock/ChangeLog +++ b/apps/hworldclock/ChangeLog @@ -10,3 +10,4 @@ 0.24: Added fast load 0.25: Minor code optimization 0.26: BJS2: Swipe down to rotate 180 degree +0.27: BJS2: Changed swipe down to swipe up diff --git a/apps/hworldclock/README.md b/apps/hworldclock/README.md index 5a1bcc7f0..905e9987b 100644 --- a/apps/hworldclock/README.md +++ b/apps/hworldclock/README.md @@ -14,7 +14,7 @@ Provide names and the UTC offsets for up to three other timezones in the app sto The clock does not handle summer time / daylight saving time changes automatically. If one of your three locations changes its UTC offset, you can simply change the setting in the app store and update. Currently the clock only supports 24 hour time format for the additional time zones. -BangleJS2: Swipe down to rotate screen. So you can show the time to a friend real quick. +BangleJS2: Swipe up to rotate screen. So you can show the time to a friend real quick. ## Requests diff --git a/apps/hworldclock/app.js b/apps/hworldclock/app.js index fd9b9270f..e5f782244 100644 --- a/apps/hworldclock/app.js +++ b/apps/hworldclock/app.js @@ -338,13 +338,13 @@ if (BANGLEJS2) { } } else if (Math.abs(dy)>Math.abs(dx)+10) { // vertical - if (dx < dy) { - g.clear().setRotation(2); + if (dx < dy) { //down + g.clear().setRotation(0); draw(); Bangle.loadWidgets(); Bangle.drawWidgets(); } else { - g.clear().setRotation(0); + g.clear().setRotation(2); draw(); Bangle.loadWidgets(); Bangle.drawWidgets(); diff --git a/apps/hworldclock/metadata.json b/apps/hworldclock/metadata.json index 7dba8f752..97a7963a5 100644 --- a/apps/hworldclock/metadata.json +++ b/apps/hworldclock/metadata.json @@ -2,7 +2,7 @@ "id": "hworldclock", "name": "Hanks World Clock", "shortName": "Hanks World Clock", - "version": "0.26", + "version": "0.27", "description": "Current time zone plus up to three others", "allow_emulator":true, "icon": "app.png", From bdaa9661cd900b7bc0ba8bdc6db9db056a1a0285 Mon Sep 17 00:00:00 2001 From: Richard de Boer Date: Wed, 7 Dec 2022 21:18:35 +0100 Subject: [PATCH 085/110] messages: erase messages file instead of writing empty [] for #2370 --- apps/messages/ChangeLog | 1 + apps/messages/lib.js | 3 ++- apps/messages/metadata.json | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/messages/ChangeLog b/apps/messages/ChangeLog index 3df056d62..c9ff39bc4 100644 --- a/apps/messages/ChangeLog +++ b/apps/messages/ChangeLog @@ -1,2 +1,3 @@ 0.55: Moved messages library into standalone library 0.56: Fix handling of music messages +0.57: Optimize saving empty message list diff --git a/apps/messages/lib.js b/apps/messages/lib.js index e5c81f3fd..1679d8296 100644 --- a/apps/messages/lib.js +++ b/apps/messages/lib.js @@ -135,7 +135,8 @@ exports.toggleWidget = function(show) { * @param {array} messages Messages to save */ exports.write = function(messages) { - require("Storage").writeJSON("messages.json", messages.map(m => { + if (!messages.length) require("Storage").erase("messages.json"); + else require("Storage").writeJSON("messages.json", messages.map(m => { // we never want to save saved/handled status to file; delete m.saved; delete m.handled; diff --git a/apps/messages/metadata.json b/apps/messages/metadata.json index 27e771975..e424c3eed 100644 --- a/apps/messages/metadata.json +++ b/apps/messages/metadata.json @@ -1,7 +1,7 @@ { "id": "messages", "name": "Messages", - "version": "0.56", + "version": "0.57", "description": "Library to handle, load and store message events received from Android/iOS", "icon": "app.png", "type": "module", From 8e5489486ed902077f5802768045442e85a3b8c9 Mon Sep 17 00:00:00 2001 From: Richard de Boer Date: Wed, 7 Dec 2022 21:56:07 +0100 Subject: [PATCH 086/110] messagegui: don't write to flash so often fixes #2370 --- apps/messagegui/ChangeLog | 2 ++ apps/messagegui/app.js | 17 ++++++++--------- apps/messagegui/lib.js | 27 +++++++++++++++++++++++---- apps/messagegui/metadata.json | 2 +- 4 files changed, 34 insertions(+), 14 deletions(-) diff --git a/apps/messagegui/ChangeLog b/apps/messagegui/ChangeLog index 854979d18..3e18b9885 100644 --- a/apps/messagegui/ChangeLog +++ b/apps/messagegui/ChangeLog @@ -79,3 +79,5 @@ Move widget to widmessage 0.56: Fix handling of music messages 0.57: Fix "unread Timeout" = off (previously defaulted to 60s) +0.58: Fast load messages without writing to flash + Don't write messages to flash until the app closes diff --git a/apps/messagegui/app.js b/apps/messagegui/app.js index f6f7779eb..0f3d90a9d 100644 --- a/apps/messagegui/app.js +++ b/apps/messagegui/app.js @@ -48,6 +48,11 @@ to the clock. */ var unreadTimeout; /// List of all our messages var MESSAGES = require("messages").getMessages(); +if (Bangle.MESSAGES) { + // fast loading messages + Bangle.MESSAGES.forEach(m => require("messages").apply(m, MESSAGES)); + delete Bangle.MESSAGES; +} var onMessagesModified = function(type,msg) { if (msg.handled) return; @@ -105,7 +110,6 @@ function showMapMessage(msg) { layout.render(); function back() { // mark as not new and return to menu msg.new = false; - saveMessages(); layout = undefined; checkMessages({clockIfNoMsg:1,clockIfAllRead:1,showMsgIfUnread:1,openMusic:0}); } @@ -140,7 +144,6 @@ function showMusicMessage(msg) { openMusic = false; var wasNew = msg.new; msg.new = false; - saveMessages(); layout = undefined; if (wasNew) checkMessages({clockIfNoMsg:1,clockIfAllRead:1,showMsgIfUnread:0,openMusic:0}); else checkMessages({clockIfNoMsg:0,clockIfAllRead:0,showMsgIfUnread:0,openMusic:0}); @@ -223,24 +226,20 @@ function showMessageSettings(msg) { }, /*LANG*/"Delete" : () => { MESSAGES = MESSAGES.filter(m=>m.id!=msg.id); - saveMessages(); checkMessages({clockIfNoMsg:0,clockIfAllRead:0,showMsgIfUnread:0,openMusic:0}); }, /*LANG*/"Mark Unread" : () => { msg.new = true; - saveMessages(); checkMessages({clockIfNoMsg:0,clockIfAllRead:0,showMsgIfUnread:0,openMusic:0}); }, /*LANG*/"Mark all read" : () => { MESSAGES.forEach(msg => msg.new = false); - saveMessages(); checkMessages({clockIfNoMsg:0,clockIfAllRead:0,showMsgIfUnread:0,openMusic:0}); }, /*LANG*/"Delete all messages" : () => { E.showPrompt(/*LANG*/"Are you sure?", {title:/*LANG*/"Delete All Messages"}).then(isYes => { if (isYes) { MESSAGES = []; - saveMessages(); } checkMessages({clockIfNoMsg:0,clockIfAllRead:0,showMsgIfUnread:0,openMusic:0}); }); @@ -295,7 +294,7 @@ function showMessage(msgid) { } function goBack() { layout = undefined; - msg.new = false; saveMessages(); // read mail + msg.new = false; // read mail cancelReloadTimeout(); // don't auto-reload to clock now checkMessages({clockIfNoMsg:1,clockIfAllRead:0,showMsgIfUnread:0,openMusic:openMusic}); } @@ -303,7 +302,7 @@ function showMessage(msgid) { ]; if (msg.positive) { buttons.push({type:"btn", src:atob("GRSBAAAAAYAAAcAAAeAAAfAAAfAAAfAAAfAAAfAAAfBgAfA4AfAeAfAPgfAD4fAA+fAAP/AAD/AAA/AAAPAAADAAAA=="), cb:()=>{ - msg.new = false; saveMessages(); + msg.new = false; cancelReloadTimeout(); // don't auto-reload to clock now Bangle.messageResponse(msg,true); checkMessages({clockIfNoMsg:1,clockIfAllRead:1,showMsgIfUnread:1,openMusic:openMusic}); @@ -312,7 +311,7 @@ function showMessage(msgid) { if (msg.negative) { if (buttons.length) buttons.push({width:32}); // nasty hack... buttons.push({type:"btn", src:atob("FhaBADAAMeAB78AP/4B/fwP4/h/B/P4D//AH/4AP/AAf4AB/gAP/AB/+AP/8B/P4P4fx/A/v4B//AD94AHjAAMA="), cb:()=>{ - msg.new = false; saveMessages(); + msg.new = false; cancelReloadTimeout(); // don't auto-reload to clock now Bangle.messageResponse(msg,false); checkMessages({clockIfNoMsg:1,clockIfAllRead:1,showMsgIfUnread:1,openMusic:openMusic}); diff --git a/apps/messagegui/lib.js b/apps/messagegui/lib.js index e45e6e5a0..4e1e7e11d 100644 --- a/apps/messagegui/lib.js +++ b/apps/messagegui/lib.js @@ -18,9 +18,22 @@ exports.listener = function(type, msg) { if (Bangle.CLOCK && msg.state && msg.title && appSettings.openMusic) loadMessages = true; else return; } - require("messages").save(msg); + if (Bangle.load === load) { + // no fast loading: store message to flash + require("messages").save(msg); + } else { + if (!Bangle.MESSAGES) Bangle.MESSAGES = []; + Bangle.MESSAGES.push(msg); + } + const saveToFlash = () => { + // save messages from RAM to flash after all, if we decide not to launch app + if (!Bangle.MESSAGES) return; + Bangle.MESSAGES.forEach(m => require("messages").save(m)); + delete Bangle.MESSAGES; + } msg.handled = true; if ((msg.t!=="add" || !msg.new) && (type!=="music")) { // music always has t:"modify" + saveToFlash(); return; } @@ -35,7 +48,11 @@ exports.listener = function(type, msg) { exports.messageTimeout = setTimeout(function() { delete exports.messageTimeout; if (type!=="music") { - if (!loadMessages) return require("messages").buzz(msg.src); // no opening the app, just buzz + if (!loadMessages) { + // not opening the app, just buzz + saveToFlash(); + return require("messages").buzz(msg.src); + } if (!quiet && unlockWatch) { Bangle.setLocked(false); Bangle.setLCDPower(1); // turn screen on @@ -51,9 +68,11 @@ exports.listener = function(type, msg) { */ exports.open = function(msg) { if (msg && msg.id && !msg.show) { - // store which message to load msg.show = 1; - require("messages").save(msg, {force: 1}); + if (Bangle.load === load) { + // no fast loading: store message to load in flash + require("messages").save(msg, {force: 1}); + } } Bangle.load((msg && msg.new && msg.id!=="music") ? "messagegui.new.js" : "messagegui.app.js"); diff --git a/apps/messagegui/metadata.json b/apps/messagegui/metadata.json index f3798f645..ad7a87675 100644 --- a/apps/messagegui/metadata.json +++ b/apps/messagegui/metadata.json @@ -1,7 +1,7 @@ { "id": "messagegui", "name": "Message UI", - "version": "0.57", + "version": "0.58", "description": "Default app to display notifications from iOS and Gadgetbridge/Android", "icon": "app.png", "type": "app", From e2b34fdd0f58f22abd531278fa38241a2cdf2a5f Mon Sep 17 00:00:00 2001 From: Hank Date: Thu, 8 Dec 2022 16:23:53 +0100 Subject: [PATCH 087/110] Reverted changes to implementation of 0.25 --- apps/hworldclock/ChangeLog | 1 + apps/hworldclock/README.md | 2 -- apps/hworldclock/app.js | 51 +--------------------------------- apps/hworldclock/metadata.json | 2 +- 4 files changed, 3 insertions(+), 53 deletions(-) diff --git a/apps/hworldclock/ChangeLog b/apps/hworldclock/ChangeLog index 22be10e2d..c029b432f 100644 --- a/apps/hworldclock/ChangeLog +++ b/apps/hworldclock/ChangeLog @@ -11,3 +11,4 @@ 0.25: Minor code optimization 0.26: BJS2: Swipe down to rotate 180 degree 0.27: BJS2: Changed swipe down to swipe up +0.28: Reverted changes to implementation of 0.25 diff --git a/apps/hworldclock/README.md b/apps/hworldclock/README.md index 905e9987b..93780bc2d 100644 --- a/apps/hworldclock/README.md +++ b/apps/hworldclock/README.md @@ -14,8 +14,6 @@ Provide names and the UTC offsets for up to three other timezones in the app sto The clock does not handle summer time / daylight saving time changes automatically. If one of your three locations changes its UTC offset, you can simply change the setting in the app store and update. Currently the clock only supports 24 hour time format for the additional time zones. -BangleJS2: Swipe up to rotate screen. So you can show the time to a friend real quick. - ## Requests Please use [the Espruino Forum](http://forum.espruino.com/microcosms/1424/) if you have feature requests or notice bugs. diff --git a/apps/hworldclock/app.js b/apps/hworldclock/app.js index e5f782244..c80b712da 100644 --- a/apps/hworldclock/app.js +++ b/apps/hworldclock/app.js @@ -7,7 +7,6 @@ var showSunInfo; var colorWhenDark; // ------- Settings file -const BANGLEJS2 = process.env.HWVERSION == 2; const big = g.getWidth()>200; // Font for primary time and date const primaryTimeFontSize = big?6:5; @@ -25,7 +24,6 @@ const xcol1 = 10; const xcol2 = g.getWidth() - xcol1; const font = "6x8"; -let drag; /* TODO: we could totally use 'Layout' here and avoid a whole bunch of hard-coded offsets */ @@ -319,54 +317,6 @@ Bangle.drawWidgets(); draw(); - -function initDragEvents() { - -if (BANGLEJS2) { - Bangle.on("drag", e => { - if (!drag) { // start dragging - drag = {x: e.x, y: e.y}; - } else if (!e.b) { // released - const dx = e.x-drag.x, dy = e.y-drag.y; - drag = null; - if (Math.abs(dx)>Math.abs(dy)+10) { - // horizontal - if (dx < dy) { - // for later purpose - } else { - // for later purpose - } - } else if (Math.abs(dy)>Math.abs(dx)+10) { - // vertical - if (dx < dy) { //down - g.clear().setRotation(0); - draw(); - Bangle.loadWidgets(); - Bangle.drawWidgets(); - } else { - g.clear().setRotation(2); - draw(); - Bangle.loadWidgets(); - Bangle.drawWidgets(); - } - } else { - //console.log("tap " + e.x + " " + e.y); - if (e.x > 145 && e.y > 145) { - // for later purpose - } - } - } - }); - } else { - //setWatch(xxx, BTN1, { repeat: true, debounce:50 }); // maybe adding this later - //setWatch(xxx, BTN3, { repeat: true, debounce:50 }); - //setWatch(xxx, BTN4, { repeat: true, debounce:50 }); - //setWatch(xxx, BTN5, { repeat: true, debounce:50 }); - } -} - -initDragEvents(); - if (!Bangle.isLocked()) { // Initial state if (showSunInfo) { if (PosInterval != 0 && typeof PosInterval != 'undefined') clearInterval(PosInterval); @@ -400,6 +350,7 @@ if (!Bangle.isLocked()) { // Initial state updatePos(); } draw(); // draw immediately, queue redraw + } diff --git a/apps/hworldclock/metadata.json b/apps/hworldclock/metadata.json index 97a7963a5..587c05067 100644 --- a/apps/hworldclock/metadata.json +++ b/apps/hworldclock/metadata.json @@ -2,7 +2,7 @@ "id": "hworldclock", "name": "Hanks World Clock", "shortName": "Hanks World Clock", - "version": "0.27", + "version": "0.28", "description": "Current time zone plus up to three others", "allow_emulator":true, "icon": "app.png", From 55ca187d5dc91ee52d57aa42f5d6a07c5bb20b0a Mon Sep 17 00:00:00 2001 From: Hugh Barney Date: Thu, 8 Dec 2022 20:12:47 +0000 Subject: [PATCH 088/110] Lato version of Simplepp Clock --- apps/lato/README.md | 54 +++++++++++++++ apps/lato/app.js | 138 +++++++++++++++++++++++++++++++++++++ apps/lato/app.png | Bin 0 -> 1139 bytes apps/lato/icon.js | 1 + apps/lato/metadata.json | 16 +++++ apps/lato/screenshot1..png | Bin 0 -> 2666 bytes apps/lato/screenshot2.png | Bin 0 -> 2741 bytes apps/lato/screenshot3.png | Bin 0 -> 2723 bytes 8 files changed, 209 insertions(+) create mode 100644 apps/lato/README.md create mode 100644 apps/lato/app.js create mode 100644 apps/lato/app.png create mode 100644 apps/lato/icon.js create mode 100644 apps/lato/metadata.json create mode 100644 apps/lato/screenshot1..png create mode 100644 apps/lato/screenshot2.png create mode 100644 apps/lato/screenshot3.png diff --git a/apps/lato/README.md b/apps/lato/README.md new file mode 100644 index 000000000..556ee6fbc --- /dev/null +++ b/apps/lato/README.md @@ -0,0 +1,54 @@ +# Lato + +A simple clock with the Lato font, with fast load and clock_info + +![](screenshot1.png) +![](screenshot2.png) +![](screenshot3.png) + +This clock is a Lato version of Simplest++. Simplest++ provided the +smallest example of a clock that supports 'fast load' and 'clock +info'. Lato takes this one step further and adds the lovely Lato +font. The clock is derived from Simplest++ and inspired by the +Pastel Clock. + +## Usage + +* When the screen is unlocked, tap at the bottom of the csreen on the information text. + It should change color showing it is selected. + +* Swipe up or down to cycle through the info screens that can be displayed + when you have finished tap again towards the centre of the screen to unselect. + +* Swipe left or right to change the type of info screens displayed (by default + there is only one type of data so this will have no effect) + +* Settings are saved automatically and reloaded along with the clock. + +## About Clock Info's + +* The clock info modules enable all clocks to add the display of information to the clock face. + +* The default clock_info module provides a display of battery %, Steps, Heart Rate and Altitude. + +* Installing the [Sunrise ClockInfo](https://banglejs.com/apps/?id=clkinfosunrise) adds Sunrise and Sunset times into the list of info's. + + +## References + +* [What is Fast Load and how does it work](http://www.espruino.com/Bangle.js+Fast+Load) + +* [Clock Info Tutorial](http://www.espruino.com/Bangle.js+Clock+Info) + +* [How to load modules through the IDE](https://github.com/espruino/BangleApps/blob/master/modules/README.md) + + +## With Thanks + +* Gordon for support +* David Peer for his work on BW Clock + + +Written by: [Hugh Barney](https://github.com/hughbarney) For support +and discussion please post in the [Bangle JS +Forum](http://forum.espruino.com/microcosms/1424/) diff --git a/apps/lato/app.js b/apps/lato/app.js new file mode 100644 index 000000000..6045d7f17 --- /dev/null +++ b/apps/lato/app.js @@ -0,0 +1,138 @@ +/** + * + * Lato Clock + * + * The entire clock code is contained within the block below this + * supports 'fast load' + * + * To add support for clock_info_supprt we add the code marked at [1] and [2] + * + */ + +Graphics.prototype.setFontLato = function(scale) { + // Actual height 50 (54 - 5) + this.setFontCustom( + E.toString(require('heatshrink').decompress(atob('ADkD8AHFg/wA4sP/AHVD44HHgPALD0OA40+F43+H4wHGn/8A4v/L4sH/5PFj//CxkD/6eFCw9/GooWHh//wAWLgP/TgoWHn5rFCw41BMYqCHaRDKGgzLYKAJgFv//LIhQBAAI7DWgIABU4adBAAJTDn4HCVAaOCQQhvDAYQuBDYaxBgJEDh4HBgYzDPgUDIYYECA5DUDgIHBg4HEEgIHfF44/EA45HDL4xvHP46PHT5CvHX47PDGYcDb4zvHf5AA/AA9wA4yoDZYq/DXAgHDXYQHEXYQHEj4HHXYQHDn6UCA4d/e4sAXYYHCd4gHCXwbADA86DFA/4HGAGA3Db40HA4UDe40Hc4YHCh7nDA4UfA4X/A4U/A4b/Cv7vGX4UB/A+CZ4YaCgf9A4sH+IHCHwfjA4JWDj/DA4s/wYHFv4kCA4f+A4pKBA4sD/AHCG4R9BA4YCBj/gA4s/4AECN4R5BA4f/gf/Mgn///+A4wZBA4d//6JBA4c/VATHEVASUEEwIHEAAbnDAGbyCAAg+DgKwDA4S4DLQSlCSYQHCn4HDFAV/bAX/4ADFCYgbCh4zHZ4SlBR4iSEA46XCe4QHCDgJWCngHOnwHGvwHRG4iFBI4ppBA4f4OIRnCN4MD9+AO4f///v8CHCDoP/54CBS4f/44CBU4f/wYHBX4f/EQLHDh6gB/6jDZQaTDAEUcA40/A4xODYoYHGgYHGh4HGNIIuG74uGz4uGj4uF/gHFh/4A4sf+AHFn/AA4q0BA4kBVgIHEFwIHFFwIHFj7jBA4guBA4rjCA4YuCA4guCA4r0BAATgBA75SEa4wHvAEEBA40DUYIAEg4HDgZ0Bh67BXAQHCZYJMBA4UHA4KPCA4SXEAgQHL4IEBgIHC/AMCgP4CQUDFgIHoIQY3DA4wCEDggHFO4YHB/iHDCQX+gE/S4IHCOIP/U4IHCv6CBA4k/A4K1CEQKpBEIIHDh//HILSDTQK+CAAd/f64Amn4GFgLxCAAZfBSIIADN4heDP4YeDR4Z5CEwN/U4IABg4NBj6ADEwLHDIoQtBVgQuCHoIHDFwIHBe4QLB/14A4kH/i1BeQQuB/AHFn/wA4pLBA4guBwAHELoMAA4o9BA4Q3BgYFBJ4gCCA4pqBvxvDf4T2Bh4HCIIc/R4MCKISfBS4aQCU4gHDX4ioBY4paBNwQAD/6uDAAUOf4wAjO4QHNdQYHYmAHGW4gUEA4kPA4z7BA4v/A4qYBY4QHCh63CA4c/V4QHDV4Y6DV4YHCDwYHDDwYHDv7ODA4MBZwgHBcwL1DA4MfdogHBDwgHB+LtFgf3DwhMCDwgHCDwhcFA4geEA4IeFA4IeFd5AArj77EsCgB/gGCg5QBOQkf/6oB/77D//DA4JrCv//44HB4DkC//n/E/MgIcCRIMPA4X8RIUHegQCBFoL8DA4cBA4QaBv4HGvwHBTgMHHQM+HgIHhF44HFJ5RfGN45/Bz6NBP4SPHT4XnT4ivHX47PHgCQCb4bvIAHxdBMgRfD/58CKgf/WgIADP4JlFR4J1ET4QHCiACBQwQEBuC/CDIIHBX4QtBn+Aa4sfZ4bvCh+Ah4HGUAUHA4d/AgIHEa4QHDwJyCA4eDKIQHDx5pCA4bPDG4c/RIRPCjwuCA4aJBUwZnCRAcBP4SgE/+D/7+ET4ImDA4jIEX4KvFh7HGgbXGgF+f6oAggZeBSgShEb4RYCagQHGh5iDA5QXEE443HADoA=='))), + 46, + atob("DhglJSUlJSUlJSUlEA=="), + 64+(scale<<8)+(1<<16) + ); + return this; +} + + +Graphics.prototype.setFontLatoSmall = function(scale) { + // Actual height 25 (24 - 0) + this.setFontCustom( + E.toString(require('heatshrink').decompress(atob('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'))), + 32, + atob("BQkKDw8UEgYICAoPBQkFCQ8PDw8PDw8PDw8GBg8PDwoVERAREw8OEhMICxENFxMUDxQQDQ8SERkQEBAICQgPCggNDgwODQgNDgYGDQYVDg4ODgoLCQ4NEw0NDAgICA8AAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAADAAFCQ8PDw8IDQgUCQwPABQICg8ICAgOEQcICAoMEhISChERERERERcRDw8PDwgICAgUExQUFBQUDxQSEhISEA8PDQ0NDQ0NFAwNDQ0NBgYGBg4ODg4ODg4PDg4ODg4NDg0="), + 25+(scale<<8)+(1<<16) + ); + return this; +} + + + +{ + // must be inside our own scope here so that when we are unloaded everything disappears + // we also define functions using 'let fn = function() {..}' for the same reason. function decls are global + + let draw = function() { + var date = new Date(); + var timeStr = require("locale").time(date,1); + var h = g.getHeight(); + var w = g.getWidth(); + + g.reset(); + g.setColor(g.theme.bg); + g.fillRect(Bangle.appRect); + + //g.setFont('Vector', w/3); + g.setFontLato(); + g.setFontAlign(0, 0); + g.setColor(g.theme.fg); + g.drawString(timeStr, w/2, h/2); + clockInfoMenu.redraw(); // clock_info_support + + // schedule a draw for the next minute + if (drawTimeout) clearTimeout(drawTimeout); + drawTimeout = setTimeout(function() { + drawTimeout = undefined; + draw(); + }, 60000 - (Date.now() % 60000)); + }; + + /** + * clock_info_support + * this is the callback function that get invoked by clockInfoMenu.redraw(); + * + * We will display the image and text on the same line and centre the combined + * length of the image+text + * + * + */ + let clockInfoDraw = (itm, info, options) => { + //g.reset().setFont('Vector',24).setBgColor(options.bg).setColor(options.fg); + g.reset().setFontLatoSmall(); + g.setBgColor(options.bg).setColor(options.fg); + + //use info.text.toString(), steps does not have length defined + var text_w = g.stringWidth(info.text.toString()); + // gap between image and text + var gap = 10; + // width of the image and text combined + var w = gap + (info.img ? 24 :0) + text_w; + // different fg color if we tapped on the menu + if (options.focus) g.setColor(options.hl); + + // clear the whole info line, allow additional 2 pixels in case LatoFont overflows area + g.clearRect(0, options.y -2, g.getWidth(), options.y+ 23 + 2); + + // draw the image if we have one + if (info.img) { + // image start + var x = (g.getWidth() / 2) - (w/2); + g.drawImage(info.img, x, options.y); + // draw the text to the side of the image (left/centre alignment) + g.setFontAlign(-1,0).drawString(info.text, x + 23 + gap, options.y+12); + } else { + // text only option, not tested yet + g.setFontAlign(0,0).drawString(info.text, g.getWidth() / 2, options.y+12); + } + + }; + + // clock_info_support + // retrieve all the clock_info modules that are installed + let clockInfoItems = require("clock_info").load(); + + // clock_info_support + // setup the way we wish to interact with the menu + // the hl property defines the color the of the info when the menu is selected after tapping on it + let clockInfoMenu = require("clock_info").addInteractive(clockInfoItems, { x:64, y:132, w:50, h:40, draw : clockInfoDraw, bg : g.theme.bg, fg : g.theme.fg, hl : "#0ff"} ); + + // timeout used to update every minute + var drawTimeout; + g.clear(); + + // Show launcher when middle button pressed, add updown button handlers + Bangle.setUI({ + mode : "clock", + remove : function() { + if (drawTimeout) clearTimeout(drawTimeout); + drawTimeout = undefined; + // remove info menu + clockInfoMenu.remove(); + delete clockInfoMenu; + // delete the custom fonts + delete Graphics.prototype.setFontLato; + delete Graphics.prototype.setFontLatoSmall; + } + }); + + // Load widgets + Bangle.loadWidgets(); + draw(); + setTimeout(Bangle.drawWidgets,0); +} // end of clock diff --git a/apps/lato/app.png b/apps/lato/app.png new file mode 100644 index 0000000000000000000000000000000000000000..02a4031a3555201deaa5c5cc5a37aba65189d090 GIT binary patch literal 1139 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 A&j0`b literal 0 HcmV?d00001 diff --git a/apps/lato/screenshot2.png b/apps/lato/screenshot2.png new file mode 100644 index 0000000000000000000000000000000000000000..f40495c79a26a8cfb53c699f536072adaf38e8eb GIT binary patch literal 2741 zcmdUx`BxHX7sr)B1#QN}T~SNG4FwY|cdcAdTb*1Ga!gH|+ymTA@XfK*G&c&@3TrI) z&_PX;92XLo%t^BpcP+&baVxD}-ap{|^*!gk=REhG=id9A`^$Yk=X>ki8P}g>HDo0u zBz|_oI(dp?!+#D)TI}mt3;yCDN%V9*AyGF3{UjkF8|CJ7{6f6{TG>c!rR4#q(H}oX z=%ZF1G`)bL%6x@$2@!Z&J*w+9{ne`2_B-qdZgYpWAuM&b= z2RdZ7f&cg_Sn39(INUiL8as0;dQe$%!Jzm7oQl~rXCWlN6+EO}KJRHD3C_-c(?SEn zqq)xv3=1hh7q{OD9so$oWn7_>yCZ;6X5DOdr5%HXdK60&n8dr8LP%OS&ixC z$f`&_&+#hLG4hMmVUW#|f)|Q#orHj}e@!e@cdzL+_9%25-0pP_V-FY>pM1jRNMmjd z-(h8OK-`<%=f5j|aUvR8ow%==t!IblRUp4@xsZqC`$tPI2A{>El42O58oTpSF8MVp zSI6FC8`X{&&+vw8OWTEJs*ED8diL)Cd`VDw=XT%`9Tj?`Zd&bf={M;=ja0{87yw)s z21#kPO3Gc05VfA(nVW2dQH`D_`X@o&X!m^#xf$J*;MKS%3c%m}`0T2yRSAkT5RFApX*G@(G%sImPIaWiYuCIPD-e0tW7BDKS=dj}lV^ltwU zJA<8NI_K0_g`IJ^H!%4Tr?J)z*>&iOqm3upHv~U{#FOk<*Zj8ORGA+kXc5V_nwdCu zi%?m#VWw@WgN`OsZPUDRi`d7z6rx`~njE!WUgBjRIs9y#1C8R*Ewrbo75}6#mIt#5 zRUGjZ*|6~Kw|b7?7(*U+vm2uJph-hyp1_zoh8g}90_NYpoYMG`Z=BQApW%YIH6#i* zVD`@E99(%(aTTW;Zc!h;?+PwWU;JcL)*E6?uwaJo_kl{KlohVwMpv#SHDZY4Lbbh+ zZnd=-0j6*Q1}sncJV^;t3sV^M=AzUB)0-%|`}efxeP`uIP(lamL4`h~ubhH=2KW)Zqnn6p)WfY$2Az_z(b5W|gFr@xM+sB6WOw*MMhq_=(; zdd^#=z0%HLH0QMz1ZNu)(bN%q{EdIiLJck7Tw(>O5p%ciwOZE5q5rOq|GWj%E|Y}y zYym>BzK0#&JaCPx%5qOmrA|Z{!y9(;(ORidRAhNeb>v%bnI;sJJo82_T@$LTsI@#e zlvqIFJ>40*4Mn?b_*ERPNcwULnp*!$^5*LW1u1IkU+fRe7h8IlHd`%JXJh8>g~=vw z9y*rT+>{PYS^T3vprc>I?Ivk9&z$q#Rm32i$=_`Q;MqnzRs8aW1!&^t<8C5ym~Vm^ z54_&BJg&N11@l&tRfsp48_|-qf+blW-k`+6eL_BiyS}&P`G2if!qs!$$;W6(xe(tM zm|$4cc86maFuw}ux86}lqlb})M;a>w>wdy*y$+LW-!Tof<0M25;=kU!;TmK{oS0I4 z_2|8==YEo0yJMhAxDq!JQAB@^YH1$A<_r+>NduI(o~J|0J*v!FGtw2yhPb2RS47f8HWv`HUg9ZKz(%H-lkGC|lG-3D2k40ei? ze`nyYJ7qzm;Oa^Ij3VXgt5zU=!S`j4-K7A_x%lclu_iD(mtNxG2pC?heajJR0`;n{LGcbRZ;V|H20-o|xG=jU zmI%azFbgwD@G0r1(M0iYXl-xSpi_W)KY6wMx3TN;_pL(lHqu7PVjU{s=6uGf?nFS^ FzX7Jd162S3 literal 0 HcmV?d00001 diff --git a/apps/lato/screenshot3.png b/apps/lato/screenshot3.png new file mode 100644 index 0000000000000000000000000000000000000000..1cf135a60bdeb64bea4957f56bbd923fd9ebe87c GIT binary patch literal 2723 zcmdT``#%#38=sxk*`kw8ZYOuWyj@ENG{1H z%VI8*r9(ALDnn&w$FL9^ayz*k@1OAg^nTtSp6B~{et16LU!L#x`DXd~p!V+haSs3h z*z4u#=D&mN{}g!lPH*5&gzbP5*&pQ!cr4VJ1_1Wpz1&U&CWXzFe!N;`ud?gi_V%C+ zlj9>(-Tg+i_dqSL`CxCgt5&ipB{em5bA9}Kpe9`5D!GlxecA~zIBXPJ0sw}$T{GGC zmN?&NroU(yP8sQR7B9%bA>@^DR8PQLB6JO!16w`-?ts#cFik@a(W1#WKoU zp<*&M1y+G3ZL+K4yAEcp{Lz>ZqL1Q9$*+p>UIh7tVw}`$DvD%?_{({0m2*bEreZK9 zf(8lBCrB%~zP;Hd)Q;Pfm+}r+h-pdcyEE9`M(z+5Xv<^$>QXEBXVu@g_!Dro$(AP=!c

cQOwCI~PFrxa zEfk{q(c}a7uPr>;oxv{<^r=Vx$|pWEbP=~^FoiV%k}=YFv$#XALtLlT!29m2APlcE zz7DC~rzm^%Hih8p(&I{?r!8-~+`KnRwRv8wtTbs>Qjx*ePVOsZ0Jf_y2paF?p8`

>P) zP5S>JRUD(PZZWDBACl0uzWUtmmfLc3Aic2Xo6NVJfa+eElH(pmG~{hqh*ISoyri-p zeJP@W0A=?Ejjca=5V;!n)aN{1of0V`X^wm#99>7o5q}#QuMGo-NFN-j?K3Yq$>a-m z+hmm+$`MAE2xAy(J#j**(V3@aYEIIxA-jU((e)NAuR0?i?X!CD4M+ zIETe@L>L+x`T{t=`AP8lz#+0#aBDUp)Rf)SDp(rEumrcd1wqi~g=CM;=hK4fi{Wq} zYN9_ry=lL07g}jvHE241G@)G^JA^pMhRY9J<*Mi|FabpO4}!C%RGZeo_Xpu@BYAt8 zdRDUjCu@Rpbi!0UEr+q}d;uqP2&566idvM$7R;?>QXkv1$1iuglM=2EL<>$ksW&M@ct}=L z7R{|a_5{YNvb8~m%MOe(ieouil%wq8ZOhqwLCtY}fbdt{IX=3(Y!VEeB-r^shfw#K zq4dId`&#mj-){2g9*r->X1G^IEEg0#YEJT6PPUFI;izLx#j2YolcG;Vwk_{mZJt1iF*1DiOnCc5(Z9s1m;`riNTME z9ntY)0?vB9y#jU`^i_L%%_(`|oUC-25QSI8;92WjIe&IbCJUBBfsTop&LUN*Bs7KIM*vis##-y$-tN zLpaA-H{@F%ilyFR{X>@%sSfE0ba#otU*Hyr|9q5!l^|i)Vthey&w2Y$TTaZzOYps2>d-|_&Cq0X1aS%} zMSp2G>KWAIIt3Ivx=J_$9mToaRY{e`)8Me#kBzIcp;k(SQpbOI5io>bnW-~M z!Z8RTzT}lO?>MRDGY@V$y)ZLwojmiv}45eNf7b>Wbxk_MV(ZS^_*ja;kMNqe< zMutymYwPF2T4uQ?p55l{h>a92EJR@L2_5lxapD#iI+B81)*u~Zz{@NYgU2FsI#Ll! zj`k}_bhohBG3g<5#oxcPf5OTxVe`D_%2J-#>u-r;gj@J$y4K-7l8%t|U<|ssjVAF??h7CHYK}KBBVEehMEff#2zHo_jx(IiQ+E;f?$j<2zodyk?dd8Ln&OaW?D} zL4Kx!qimUp8OBCX+P;*nm1}`@IznMff!ZQ(HyQ4c#oI^GmQRGR5yqe6S5{<2pZRrQ zff_}f;BJ3}1lItPu=CbH;y~l9ttKu{eLCN&H#hOC-%Y-zdeB@%;T?2bKKb0T)~v7* ze*LRqu5m^rL%M{VZXEmc?npf{CRHzQnDHi^$SUb%09K6|NWTtD@ zC#rko+qM3w&kZj^ZrF*BV_i~aR6!bXOwD|FpXiF92$~WVOs>DC8nj0_yj#*_?W|D=MicYU6orSoDzTyE^D6x<`|^$jcYmQwUt1~lV10sJHHx~AVL_Y z@gvP3|4Ih{>Gy>tkvsRO0;hVYx=5h!ahz-bu&Bc14R|LYq}xXqLR}=*`Jf+90H`QG zV!t&I9D0-CVhlD=fM-}Z4*<2-4|V~h1kyWEdZhQiBHaRV-;9MsKM^0;Nu2;McOSRM Iu7vb|09r^G=>Px# literal 0 HcmV?d00001 From 605f87bb8f07b543c19132bd29e0fd2a8542a691 Mon Sep 17 00:00:00 2001 From: Richard de Boer Date: Thu, 8 Dec 2022 21:57:54 +0100 Subject: [PATCH 089/110] widmsggrid: provides a "message" widget --- apps/widmsggrid/metadata.json | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/widmsggrid/metadata.json b/apps/widmsggrid/metadata.json index 68c2c3771..ad0f33e82 100644 --- a/apps/widmsggrid/metadata.json +++ b/apps/widmsggrid/metadata.json @@ -9,6 +9,7 @@ "supports": ["BANGLEJS","BANGLEJS2"], "dependencies" : { "messages":"module" }, "provides_modules" : ["messagewidget"], + "provides_widgets" : ["message"], "readme": "README.md", "storage": [ {"name":"messagewidget","url":"lib.js"}, From ec410fdac7186baede89f0f9b36b7462472fb275 Mon Sep 17 00:00:00 2001 From: Richard de Boer Date: Thu, 8 Dec 2022 22:33:04 +0100 Subject: [PATCH 090/110] Message widgets: we don't need a library --- apps/messages/ChangeLog | 1 + apps/messages/lib.js | 7 ++++--- apps/messages/metadata.json | 2 +- apps/widmessages/ChangeLog | 3 ++- apps/widmessages/lib.js | 8 -------- apps/widmessages/metadata.json | 4 +--- apps/widmessages/widget.js | 7 ++++++- apps/widmsggrid/ChangeLog | 3 ++- apps/widmsggrid/lib.js | 8 -------- apps/widmsggrid/metadata.json | 4 +--- apps/widmsggrid/widget.js | 9 ++++++--- bin/sanitycheck.js | 1 - 12 files changed, 24 insertions(+), 33 deletions(-) delete mode 100644 apps/widmessages/lib.js delete mode 100644 apps/widmsggrid/lib.js diff --git a/apps/messages/ChangeLog b/apps/messages/ChangeLog index c9ff39bc4..7d3414c1a 100644 --- a/apps/messages/ChangeLog +++ b/apps/messages/ChangeLog @@ -1,3 +1,4 @@ 0.55: Moved messages library into standalone library 0.56: Fix handling of music messages 0.57: Optimize saving empty message list +0.58: show/hide "messages" widget directly, instead of through library stub diff --git a/apps/messages/lib.js b/apps/messages/lib.js index 1679d8296..a710c81c4 100644 --- a/apps/messages/lib.js +++ b/apps/messages/lib.js @@ -125,9 +125,10 @@ exports.openGUI = function(msg) { * @param {boolean} show */ exports.toggleWidget = function(show) { - if (!require("Storage").read("messagewidget")) return; // "messagewidget" module is missing! - if (show) require("messagewidget").show(); - else require("messagewidget").hide(); + if (!global.WIDGETS || !WIDGETS["messages"]) return; // widget is missing! + const method = WIDGETS["messages"][show ? "show" : "hide"]; + /* if (typeof(method)!=="function") return; // widget must always have show()+hide(), fail hard rather than hide problems */ + method.apply(WIDGETS["messages"]); }; /** diff --git a/apps/messages/metadata.json b/apps/messages/metadata.json index e424c3eed..9c7c8b49e 100644 --- a/apps/messages/metadata.json +++ b/apps/messages/metadata.json @@ -1,7 +1,7 @@ { "id": "messages", "name": "Messages", - "version": "0.57", + "version": "0.58", "description": "Library to handle, load and store message events received from Android/iOS", "icon": "app.png", "type": "module", diff --git a/apps/widmessages/ChangeLog b/apps/widmessages/ChangeLog index 3a41005e9..bd329aa5a 100644 --- a/apps/widmessages/ChangeLog +++ b/apps/widmessages/ChangeLog @@ -1 +1,2 @@ -0.01: Moved messages widget into standalone widget app \ No newline at end of file +0.01: Moved messages widget into standalone widget app +0.02: Remove library stub diff --git a/apps/widmessages/lib.js b/apps/widmessages/lib.js deleted file mode 100644 index 897611ad1..000000000 --- a/apps/widmessages/lib.js +++ /dev/null @@ -1,8 +0,0 @@ -exports.hide = function() { - if (!global.WIDGETS||!WIDGETS["messages"]) return; - WIDGETS["messages"].hide(); -} -exports.show = function() { - if (!global.WIDGETS||!WIDGETS["messages"]) return; - WIDGETS["messages"].show(); -} \ No newline at end of file diff --git a/apps/widmessages/metadata.json b/apps/widmessages/metadata.json index 080e19273..a8a23df19 100644 --- a/apps/widmessages/metadata.json +++ b/apps/widmessages/metadata.json @@ -1,7 +1,7 @@ { "id": "widmessages", "name": "Message Widget", - "version": "0.01", + "version": "0.02", "description": "Widget showing new messages", "icon": "app.png", "type": "widget", @@ -9,12 +9,10 @@ "supports": ["BANGLEJS","BANGLEJS2"], "screenshots": [{"url": "screenshot.gif"}], "dependencies" : { "messageicons":"module" }, - "provides_modules" : ["messagewidget"], "provides_widgets" : ["message"], "default" : true, "readme": "README.md", "storage": [ - {"name":"messagewidget","url":"lib.js"}, {"name":"widmessages.wid.js","url":"widget.js"} ] } diff --git a/apps/widmessages/widget.js b/apps/widmessages/widget.js index 2ee11b690..764494638 100644 --- a/apps/widmessages/widget.js +++ b/apps/widmessages/widget.js @@ -7,6 +7,9 @@ .filter((msg, i, arr) => arr.findIndex(nmsg => msg.src == nmsg.src) == i); } + // NOTE when adding a custom "essages" widget: + // the name still needs to be "messages": the library calls WIDGETS["messages'].hide()/show() + // see e.g. widmsggrid WIDGETS["messages"] = { area: "tl", width: 0, srcs: [], draw: function(recall) { // If we had a setTimeout queued from the last time we were called, remove it @@ -54,7 +57,9 @@ var w = WIDGETS["messages"]; if (!w || !w.width || c.xw.x+w.width || c.yw.y+24) return; require("messages").openGUI(); - }, hide() { + }, + // hide() and show() are required by the "message" library! + hide() { this.hidden=true; if (this.width) { // hide widget diff --git a/apps/widmsggrid/ChangeLog b/apps/widmsggrid/ChangeLog index 9612da729..9be40817a 100644 --- a/apps/widmsggrid/ChangeLog +++ b/apps/widmsggrid/ChangeLog @@ -1,3 +1,4 @@ 0.01: New widget! 0.02: Adjust to message icons moving to messageicons lib -0.03: Use new message library \ No newline at end of file +0.03: Use new message library +0.04: Remove library stub \ No newline at end of file diff --git a/apps/widmsggrid/lib.js b/apps/widmsggrid/lib.js deleted file mode 100644 index 430577209..000000000 --- a/apps/widmsggrid/lib.js +++ /dev/null @@ -1,8 +0,0 @@ -exports.hide = function() { - if (!global.WIDGETS||!WIDGETS["msggrid"]) return; - WIDGETS["msggrid"].hide(); -} -exports.show = function() { - if (!global.WIDGETS||!WIDGETS["msggrid"]) return; - WIDGETS["msggrid"].show(); -} \ No newline at end of file diff --git a/apps/widmsggrid/metadata.json b/apps/widmsggrid/metadata.json index ad0f33e82..17d3573ad 100644 --- a/apps/widmsggrid/metadata.json +++ b/apps/widmsggrid/metadata.json @@ -1,18 +1,16 @@ { "id": "widmsggrid", "name": "Messages Grid Widget", - "version": "0.03", + "version": "0.04", "description": "Widget that displays notification icons in a grid", "icon": "widget.png", "type": "widget", "tags": "tool,system", "supports": ["BANGLEJS","BANGLEJS2"], "dependencies" : { "messages":"module" }, - "provides_modules" : ["messagewidget"], "provides_widgets" : ["message"], "readme": "README.md", "storage": [ - {"name":"messagewidget","url":"lib.js"}, {"name":"widmsggrid.wid.js","url":"widget.js"} ], "screenshots": [{"url":"screenshot.png"}] diff --git a/apps/widmsggrid/widget.js b/apps/widmsggrid/widget.js index 786f590b5..6a5b175ac 100644 --- a/apps/widmsggrid/widget.js +++ b/apps/widmsggrid/widget.js @@ -6,7 +6,8 @@ showRead: !!settings.showRead, }; delete settings; - WIDGETS["msggrid"] = { + // widget name needs to be "messages": the library calls WIDGETS["messages'].hide()/show() + WIDGETS["messages"] = { area: "tl", width: 0, flash: s.flash, showRead: s.showRead, @@ -57,7 +58,9 @@ .drawString(w.total, w.x + w.width - 1, w.y + 24, w.total > 9); } if (w.flash && w.status === "new") w.t = setTimeout(w.draw, 1000); // schedule redraw while blinking - }, show: function (m) { + }, + // show() and hide() are required by the "message" library! + show: function (m) { delete w.hidden; w.width = 24; w.srcs = require("messages").getMessages(m) @@ -94,6 +97,6 @@ } }; delete s; - const w = WIDGETS["msggrid"]; + const w = WIDGETS["messages"]; Bangle.on("message", w.listener); })(); diff --git a/bin/sanitycheck.js b/bin/sanitycheck.js index 5af6f1aa1..22c792e6f 100755 --- a/bin/sanitycheck.js +++ b/bin/sanitycheck.js @@ -93,7 +93,6 @@ const INTERNAL_FILES_IN_APP_TYPE = { // list of app types and files they SHOULD /* These are warnings we know about but don't want in our output */ var KNOWN_WARNINGS = [ "App gpsrec data file wildcard .gpsrc? does not include app ID", -"App widmessages storage file messagewidget is also listed as storage file for app widmsggrid", ]; function globToRegex(pattern) { From 2becb161bbf29c8edf437f96e5f175d07969c624 Mon Sep 17 00:00:00 2001 From: Richard de Boer Date: Thu, 8 Dec 2022 22:43:13 +0100 Subject: [PATCH 091/110] widmsggrid: update README --- apps/widmsggrid/README.md | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/apps/widmsggrid/README.md b/apps/widmsggrid/README.md index 274858d66..36aad20e2 100644 --- a/apps/widmsggrid/README.md +++ b/apps/widmsggrid/README.md @@ -12,12 +12,7 @@ Example: one SMS, one Signal, and two WhatsApp messages: ![screenshot](screenshot.png) ## Installation -This widget needs the [`messages`](/?id=messages) app to handle notifications. - -You probably want to disable the default widget, to do so: -1. Open `Settings` -2. Navigate to `Apps`>`Messages` -3. Scroll down to the `Widget messages` entry, and change it to `Hide` +There can only be one messages widget, so you should uninstall the default "Message Widget". ## Settings You can change settings by going to the global `Settings` app, then `App Settings` From 5a519e372da882aeb1858af651d6602df02e8b2f Mon Sep 17 00:00:00 2001 From: thyttan <6uuxstm66@mozmail.com⁩> Date: Thu, 8 Dec 2022 23:12:30 +0100 Subject: [PATCH 092/110] remove remnant of merge conflict --- apps/weather/ChangeLog | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/weather/ChangeLog b/apps/weather/ChangeLog index 359cb8635..f1d001c81 100644 --- a/apps/weather/ChangeLog +++ b/apps/weather/ChangeLog @@ -19,4 +19,3 @@ 0.20: Added weather condition with temperature to clkinfo. 0.21: Updated clkinfo icon. 0.22: Automatic translation of strings, some left untranslated. ->>>>>>> b37fcacd1 (weather - autotranslate strings) From c483cbc06746f7c11731347a5bf0946b015ba917 Mon Sep 17 00:00:00 2001 From: lauzonhomeschool <85599144+lauzonhomeschool@users.noreply.github.com> Date: Thu, 8 Dec 2022 17:48:56 -0500 Subject: [PATCH 093/110] lib.js support timezone - toLocalISOString Test scenario: E.setTimeZone(-8); date = new Date("2022-12-05T23:00"); date.toLocalISOString(); // -> "2022-12-05T23:00:00.000-0800" getActiveAlarms([{on: true, t: 0, dow: 0b1111111, date: "2022-12-05"}], date); //should be marked as active, but isn't getActiveAlarms([{on: true, t: 0, dow: 0b1111111, date: "2022-12-06"}], date); //should not be marked as active, but it is because it is already "tomorrow" in UTC --- apps/sched/lib.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/sched/lib.js b/apps/sched/lib.js index 74018dcde..c8961b9e3 100644 --- a/apps/sched/lib.js +++ b/apps/sched/lib.js @@ -21,7 +21,7 @@ exports.getActiveAlarms = function (alarms, time) { && (a.last != time.getDate()) // not already fired today && (a.t < currentTime) && (a.dow >> time.getDay() & 1) // is allowed on this day of the week - && (!a.date || a.date == time.toISOString().substr(0, 10)) // is allowed on this date + && (!a.date || a.date == time.toLocalISOString().substr(0, 10)) // is allowed on this date ) .sort((a, b) => a.t - b.t); } @@ -46,7 +46,7 @@ exports.getTimeToAlarm = function(alarm, time) { if (!alarm) return undefined; if (!time) time = new Date(); var currentTime = (time.getHours()*3600000)+(time.getMinutes()*60000)+(time.getSeconds()*1000); - var active = alarm.on && (alarm.dow>>((time.getDay()+(alarm.t>((time.getDay()+(alarm.t Date: Thu, 8 Dec 2022 17:50:46 -0500 Subject: [PATCH 094/110] boot.js toLocalISOString --- apps/sched/boot.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/sched/boot.js b/apps/sched/boot.js index 98bb0ff7d..c1bb1fc66 100644 --- a/apps/sched/boot.js +++ b/apps/sched/boot.js @@ -13,7 +13,7 @@ && (a.last != d) // not already fired today && (a.t + 60000 > currentTime) // is not in the past by >1 minute && (a.dow >> time.getDay() & 1) // is allowed on this day of the week - && (!a.date || a.date == time.toISOString().substr(0, 10)) // is allowed on this date + && (!a.date || a.date == time.toLocalISOString().substr(0, 10)) // is allowed on this date ); if (active.length) { active = active.sort((a,b)=>a.t-b.t); // sort by time From aa1e485db8dbd1483db4928a9934189a5dca9dcb Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Fri, 9 Dec 2022 08:34:50 +0000 Subject: [PATCH 095/110] 0.59: Ensure we do write messages if messages app can't be fast loaded (see #2373) --- apps/messagegui/ChangeLog | 1 + apps/messagegui/lib.js | 5 ++++- apps/messagegui/metadata.json | 3 ++- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/apps/messagegui/ChangeLog b/apps/messagegui/ChangeLog index 3e18b9885..3f5ff70fd 100644 --- a/apps/messagegui/ChangeLog +++ b/apps/messagegui/ChangeLog @@ -81,3 +81,4 @@ 0.57: Fix "unread Timeout" = off (previously defaulted to 60s) 0.58: Fast load messages without writing to flash Don't write messages to flash until the app closes +0.59: Ensure we do write messages if messages app can't be fast loaded (see #2373) diff --git a/apps/messagegui/lib.js b/apps/messagegui/lib.js index 4e1e7e11d..f9919c01c 100644 --- a/apps/messagegui/lib.js +++ b/apps/messagegui/lib.js @@ -18,8 +18,11 @@ exports.listener = function(type, msg) { if (Bangle.CLOCK && msg.state && msg.title && appSettings.openMusic) loadMessages = true; else return; } - if (Bangle.load === load) { + if (Bangle.load === load || !Bangle.uiRemove) { // no fast loading: store message to flash + /* FIXME: Maybe we need a better way of deciding if an app will + be fast loaded than just hard-coding a Bangle.uiRemove check. + Bangle.load could return a bool (as the load doesn't happen immediately). */ require("messages").save(msg); } else { if (!Bangle.MESSAGES) Bangle.MESSAGES = []; diff --git a/apps/messagegui/metadata.json b/apps/messagegui/metadata.json index ad7a87675..3ed22d356 100644 --- a/apps/messagegui/metadata.json +++ b/apps/messagegui/metadata.json @@ -1,7 +1,8 @@ { "id": "messagegui", "name": "Message UI", - "version": "0.58", + "sortName": "Messages", + "version": "0.59", "description": "Default app to display notifications from iOS and Gadgetbridge/Android", "icon": "app.png", "type": "app", From 7b18f54a76e9265c648ef7aab826a2fa83db73ac Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Fri, 9 Dec 2022 08:44:11 +0000 Subject: [PATCH 096/110] oops --- apps/messagegui/metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/messagegui/metadata.json b/apps/messagegui/metadata.json index 3ed22d356..80b362551 100644 --- a/apps/messagegui/metadata.json +++ b/apps/messagegui/metadata.json @@ -1,7 +1,7 @@ { "id": "messagegui", "name": "Message UI", - "sortName": "Messages", + "shortName": "Messages", "version": "0.59", "description": "Default app to display notifications from iOS and Gadgetbridge/Android", "icon": "app.png", From 00a022c7c1102ab6bb22b0a78f28a71a01e7f3da Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Fri, 9 Dec 2022 09:49:33 +0000 Subject: [PATCH 097/110] Use 'modules/suncalc.js' to avoid it being copied 8 times for different apps --- apps/astrocalc/ChangeLog | 1 + apps/astrocalc/astrocalc-app.js | 4 +- apps/astrocalc/metadata.json | 3 +- apps/astrocalc/suncalc.js | 328 -------------------------- apps/daisy/ChangeLog | 1 + apps/daisy/app.js | 20 +- apps/daisy/metadata.json | 2 +- apps/hworldclock/ChangeLog | 1 + apps/hworldclock/app.js | 60 +++-- apps/hworldclock/hsuncalc.js | 298 ----------------------- apps/hworldclock/metadata.json | 9 +- apps/pastel/ChangeLog | 1 + apps/pastel/metadata.json | 2 +- apps/pastel/pastel.app.js | 22 +- apps/rebble/ChangeLog | 7 +- apps/rebble/metadata.json | 5 +- apps/rebble/rebble.app.js | 30 +-- apps/rebble/suncalc.js | 143 ----------- apps/sunclock/ChangeLog | 2 + apps/sunclock/app.js | 20 +- apps/sunclock/metadata.json | 5 +- apps/timerclk/ChangeLog | 1 + apps/timerclk/app.js | 6 +- apps/timerclk/metadata.json | 4 +- {apps/sunclock => modules}/suncalc.js | 83 +++++-- 25 files changed, 171 insertions(+), 887 deletions(-) delete mode 100644 apps/astrocalc/suncalc.js delete mode 100644 apps/hworldclock/hsuncalc.js delete mode 100644 apps/rebble/suncalc.js create mode 100644 apps/sunclock/ChangeLog rename {apps/sunclock => modules}/suncalc.js (76%) diff --git a/apps/astrocalc/ChangeLog b/apps/astrocalc/ChangeLog index 60ef5da0a..746ab2162 100644 --- a/apps/astrocalc/ChangeLog +++ b/apps/astrocalc/ChangeLog @@ -1,2 +1,3 @@ 0.01: Create astrocalc app 0.02: Store last GPS lock, can be used instead of waiting for new GPS on start +0.03: Use 'modules/suncalc.js' to avoid it being copied 8 times for different apps diff --git a/apps/astrocalc/astrocalc-app.js b/apps/astrocalc/astrocalc-app.js index 4e7aa0b40..46fb855ec 100644 --- a/apps/astrocalc/astrocalc-app.js +++ b/apps/astrocalc/astrocalc-app.js @@ -9,7 +9,7 @@ * Calculate the Sun and Moon positions based on watch GPS and display graphically */ -const SunCalc = require("suncalc.js"); +const SunCalc = require("suncalc"); // from modules folder const storage = require("Storage"); const LAST_GPS_FILE = "astrocalc.gps.json"; let lastGPS = (storage.readJSON(LAST_GPS_FILE, 1) || null); @@ -385,4 +385,4 @@ function init() { } let m; -init(); \ No newline at end of file +init(); diff --git a/apps/astrocalc/metadata.json b/apps/astrocalc/metadata.json index 384c7fa1e..d77474700 100644 --- a/apps/astrocalc/metadata.json +++ b/apps/astrocalc/metadata.json @@ -1,7 +1,7 @@ { "id": "astrocalc", "name": "Astrocalc", - "version": "0.02", + "version": "0.03", "description": "Calculates interesting information on the sun and moon cycles for the current day based on your location.", "icon": "astrocalc.png", "tags": "app,sun,moon,cycles,tool,outdoors", @@ -9,7 +9,6 @@ "allow_emulator": true, "storage": [ {"name":"astrocalc.app.js","url":"astrocalc-app.js"}, - {"name":"suncalc.js","url":"suncalc.js"}, {"name":"astrocalc.img","url":"astrocalc-icon.js","evaluate":true}, {"name":"first-quarter.img","url":"first-quarter-icon.js","evaluate":true}, {"name":"last-quarter.img","url":"last-quarter-icon.js","evaluate":true}, diff --git a/apps/astrocalc/suncalc.js b/apps/astrocalc/suncalc.js deleted file mode 100644 index e2beaedca..000000000 --- a/apps/astrocalc/suncalc.js +++ /dev/null @@ -1,328 +0,0 @@ -/* - (c) 2011-2015, Vladimir Agafonkin - SunCalc is a JavaScript library for calculating sun/moon position and light phases. - https://github.com/mourner/suncalc -*/ - -(function () { 'use strict'; - - // shortcuts for easier to read formulas - - var PI = Math.PI, - sin = Math.sin, - cos = Math.cos, - tan = Math.tan, - asin = Math.asin, - atan = Math.atan2, - acos = Math.acos, - rad = PI / 180; - - // sun calculations are based on http://aa.quae.nl/en/reken/zonpositie.html formulas - - - // date/time constants and conversions - - var dayMs = 1000 * 60 * 60 * 24, - J1970 = 2440588, - J2000 = 2451545; - - function toJulian(date) { return date.valueOf() / dayMs - 0.5 + J1970; } - function fromJulian(j) { return (j + 0.5 - J1970) * dayMs; } - function toDays(date) { return toJulian(date) - J2000; } - - - // general calculations for position - - var e = rad * 23.4397; // obliquity of the Earth - - function rightAscension(l, b) { return atan(sin(l) * cos(e) - tan(b) * sin(e), cos(l)); } - function declination(l, b) { return asin(sin(b) * cos(e) + cos(b) * sin(e) * sin(l)); } - - function azimuth(H, phi, dec) { return atan(sin(H), cos(H) * sin(phi) - tan(dec) * cos(phi)); } - function altitude(H, phi, dec) { return asin(sin(phi) * sin(dec) + cos(phi) * cos(dec) * cos(H)); } - - function siderealTime(d, lw) { return rad * (280.16 + 360.9856235 * d) - lw; } - - function astroRefraction(h) { - if (h < 0) // the following formula works for positive altitudes only. - h = 0; // if h = -0.08901179 a div/0 would occur. - - // formula 16.4 of "Astronomical Algorithms" 2nd edition by Jean Meeus (Willmann-Bell, Richmond) 1998. - // 1.02 / tan(h + 10.26 / (h + 5.10)) h in degrees, result in arc minutes -> converted to rad: - return 0.0002967 / Math.tan(h + 0.00312536 / (h + 0.08901179)); - } - - // general sun calculations - - function solarMeanAnomaly(d) { return rad * (357.5291 + 0.98560028 * d); } - - function eclipticLongitude(M) { - - var C = rad * (1.9148 * sin(M) + 0.02 * sin(2 * M) + 0.0003 * sin(3 * M)), // equation of center - P = rad * 102.9372; // perihelion of the Earth - - return M + C + P + PI; - } - - function sunCoords(d) { - - var M = solarMeanAnomaly(d), - L = eclipticLongitude(M); - - return { - dec: declination(L, 0), - ra: rightAscension(L, 0) - }; - } - - - var SunCalc = {}; - - - // calculates sun position for a given date and latitude/longitude - - SunCalc.getPosition = function (date, lat, lng) { - - var lw = rad * -lng, - phi = rad * lat, - d = toDays(date), - - c = sunCoords(d), - H = siderealTime(d, lw) - c.ra; - - return { - azimuth: azimuth(H, phi, c.dec), - altitude: altitude(H, phi, c.dec) - }; - }; - - - // sun times configuration (angle, morning name, evening name) - - var times = SunCalc.times = [ - [-0.833, 'sunrise', 'sunset' ], - [ -0.3, 'sunriseEnd', 'sunsetStart' ], - [ -6, 'dawn', 'dusk' ], - [ -12, 'nauticalDawn', 'nauticalDusk'], - [ -18, 'nightEnd', 'night' ], - [ 6, 'goldenHourEnd', 'goldenHour' ] - ]; - - // adds a custom time to the times config - - SunCalc.addTime = function (angle, riseName, setName) { - times.push([angle, riseName, setName]); - }; - - - // calculations for sun times - - var J0 = 0.0009; - - function julianCycle(d, lw) { return Math.round(d - J0 - lw / (2 * PI)); } - - function approxTransit(Ht, lw, n) { return J0 + (Ht + lw) / (2 * PI) + n; } - function solarTransitJ(ds, M, L) { return J2000 + ds + 0.0053 * sin(M) - 0.0069 * sin(2 * L); } - - function hourAngle(h, phi, d) { return acos((sin(h) - sin(phi) * sin(d)) / (cos(phi) * cos(d))); } - function observerAngle(height) { return -2.076 * Math.sqrt(height) / 60; } - - // returns set time for the given sun altitude - function getSetJ(h, lw, phi, dec, n, M, L) { - - var w = hourAngle(h, phi, dec), - a = approxTransit(w, lw, n); - return solarTransitJ(a, M, L); - } - - - // calculates sun times for a given date, latitude/longitude, and, optionally, - // the observer height (in meters) relative to the horizon - - SunCalc.getTimes = function (date, lat, lng, height) { - - height = height || 0; - - var lw = rad * -lng, - phi = rad * lat, - - dh = observerAngle(height), - - d = toDays(date), - n = julianCycle(d, lw), - ds = approxTransit(0, lw, n), - - M = solarMeanAnomaly(ds), - L = eclipticLongitude(M), - dec = declination(L, 0), - - Jnoon = solarTransitJ(ds, M, L), - - i, len, time, h0, Jset, Jrise; - - - var result = { - solarNoon: new Date(fromJulian(Jnoon)), - nadir: new Date(fromJulian(Jnoon - 0.5)) - }; - - for (i = 0, len = times.length; i < len; i += 1) { - time = times[i]; - h0 = (time[0] + dh) * rad; - - Jset = getSetJ(h0, lw, phi, dec, n, M, L); - Jrise = Jnoon - (Jset - Jnoon); - - result[time[1]] = new Date(fromJulian(Jrise) - (dayMs / 2)); - result[time[2]] = new Date(fromJulian(Jset) + (dayMs / 2)); - } - - return result; - }; - - - // moon calculations, based on http://aa.quae.nl/en/reken/hemelpositie.html formulas - - function moonCoords(d) { // geocentric ecliptic coordinates of the moon - - var L = rad * (218.316 + 13.176396 * d), // ecliptic longitude - M = rad * (134.963 + 13.064993 * d), // mean anomaly - F = rad * (93.272 + 13.229350 * d), // mean distance - - l = L + rad * 6.289 * sin(M), // longitude - b = rad * 5.128 * sin(F), // latitude - dt = 385001 - 20905 * cos(M); // distance to the moon in km - - return { - ra: rightAscension(l, b), - dec: declination(l, b), - dist: dt - }; - } - - SunCalc.getMoonPosition = function (date, lat, lng) { - - var lw = rad * -lng, - phi = rad * lat, - d = toDays(date), - - c = moonCoords(d), - H = siderealTime(d, lw) - c.ra, - h = altitude(H, phi, c.dec), - // formula 14.1 of "Astronomical Algorithms" 2nd edition by Jean Meeus (Willmann-Bell, Richmond) 1998. - pa = atan(sin(H), tan(phi) * cos(c.dec) - sin(c.dec) * cos(H)); - - h = h + astroRefraction(h); // altitude correction for refraction - - return { - azimuth: azimuth(H, phi, c.dec), - altitude: h, - distance: c.dist, - parallacticAngle: pa - }; - }; - - - // calculations for illumination parameters of the moon, - // based on http://idlastro.gsfc.nasa.gov/ftp/pro/astro/mphase.pro formulas and - // Chapter 48 of "Astronomical Algorithms" 2nd edition by Jean Meeus (Willmann-Bell, Richmond) 1998. - - // Function updated from gist: https://gist.github.com/endel/dfe6bb2fbe679781948c - - SunCalc.getMoonIllumination = function (date) { - let month = date.getMonth(); - let year = date.getFullYear(); - let day = date.getDate(); - - let c = 0; - let e = 0; - let jd = 0; - let b = 0; - - if (month < 3) { - year--; - month += 12; - } - - ++month; - c = 365.25 * year; - e = 30.6 * month; - jd = c + e + day - 694039.09; // jd is total days elapsed - jd /= 29.5305882; // divide by the moon cycle - b = parseInt(jd); // int(jd) -> b, take integer part of jd - jd -= b; // subtract integer part to leave fractional part of original jd - b = Math.round(jd * 8); // scale fraction from 0-8 and round - - if (b >= 8) b = 0; // 0 and 8 are the same so turn 8 into 0 - - return {phase: b}; - }; - - - function hoursLater(date, h) { - return new Date(date.valueOf() + h * dayMs / 24); - } - - // calculations for moon rise/set times are based on http://www.stargazing.net/kepler/moonrise.html article - - SunCalc.getMoonTimes = function (date, lat, lng, inUTC) { - var t = date; - if (inUTC) t.setUTCHours(0, 0, 0, 0); - else t.setHours(0, 0, 0, 0); - - var hc = 0.133 * rad, - h0 = SunCalc.getMoonPosition(t, lat, lng).altitude - hc, - h1, h2, rise, set, a, b, xe, ye, d, roots, x1, x2, dx; - - // go in 2-hour chunks, each time seeing if a 3-point quadratic curve crosses zero (which means rise or set) - for (var i = 1; i <= 24; i += 2) { - h1 = SunCalc.getMoonPosition(hoursLater(t, i), lat, lng).altitude - hc; - h2 = SunCalc.getMoonPosition(hoursLater(t, i + 1), lat, lng).altitude - hc; - - a = (h0 + h2) / 2 - h1; - b = (h2 - h0) / 2; - xe = -b / (2 * a); - ye = (a * xe + b) * xe + h1; - d = b * b - 4 * a * h1; - roots = 0; - - if (d >= 0) { - dx = Math.sqrt(d) / (Math.abs(a) * 2); - x1 = xe - dx; - x2 = xe + dx; - if (Math.abs(x1) <= 1) roots++; - if (Math.abs(x2) <= 1) roots++; - if (x1 < -1) x1 = x2; - } - - if (roots === 1) { - if (h0 < 0) rise = i + x1; - else set = i + x1; - - } else if (roots === 2) { - rise = i + (ye < 0 ? x2 : x1); - set = i + (ye < 0 ? x1 : x2); - } - - if (rise && set) break; - - h0 = h2; - } - - var result = {}; - - if (rise) result.rise = hoursLater(t, rise); - if (set) result.set = hoursLater(t, set); - - if (!rise && !set) result[ye > 0 ? 'alwaysUp' : 'alwaysDown'] = true; - - return result; - }; - - - // export as Node module / AMD module / browser variable - if (typeof exports === 'object' && typeof module !== 'undefined') module.exports = SunCalc; - else if (typeof define === 'function' && define.amd) define(SunCalc); - else global.SunCalc = SunCalc; - -}()); diff --git a/apps/daisy/ChangeLog b/apps/daisy/ChangeLog index b13ce261b..61a09a18d 100644 --- a/apps/daisy/ChangeLog +++ b/apps/daisy/ChangeLog @@ -6,3 +6,4 @@ 0.06: better contrast for light theme, use fg color instead of dithered for ring 0.07: Use default Bangle formatter for booleans 0.08: fix idle timer always getting set to true +0.09: Use 'modules/suncalc.js' to avoid it being copied 8 times for different apps diff --git a/apps/daisy/app.js b/apps/daisy/app.js index 848cd1801..c99b19228 100644 --- a/apps/daisy/app.js +++ b/apps/daisy/app.js @@ -1,4 +1,4 @@ -var SunCalc = require("https://raw.githubusercontent.com/mourner/suncalc/master/suncalc.js"); +var SunCalc = require("suncalc"); // from modules folder const storage = require('Storage'); const locale = require("locale"); const SETTINGS_FILE = "daisy.json"; @@ -70,7 +70,7 @@ function getSteps() { try { return Bangle.getHealthStatus("day").steps; } catch (e) { - if (WIDGETS.wpedom !== undefined) + if (WIDGETS.wpedom !== undefined) return WIDGETS.wpedom.getSteps(); else return 0; @@ -151,7 +151,7 @@ function prevInfo() { function clearInfo() { g.setColor(g.theme.bg); //g.setColor(g.theme.fg); - g.fillRect((w/2) - infoWidth, infoLine - infoHeight, (w/2) + infoWidth, infoLine + infoHeight); + g.fillRect((w/2) - infoWidth, infoLine - infoHeight, (w/2) + infoWidth, infoLine + infoHeight); } function drawInfo() { @@ -202,7 +202,7 @@ function drawClock() { var mm = da[4].substr(3,2); var steps = getSteps(); var p_steps = Math.round(100*(steps/10000)); - + g.reset(); g.setColor(g.theme.bg); g.fillRect(0, 0, w, h); @@ -218,7 +218,7 @@ function drawClock() { g.drawString(mm, (w/2) + 1, h/2); drawInfo(); - + // recalc sunrise / sunset every hour if (drawCount % 60 == 0) updateSunRiseSunSet(new Date(), location.lat, location.lon); @@ -254,7 +254,7 @@ function resetHrm() { Bangle.on('HRM', function(hrm) { hrmCurrent = hrm.bpm; hrmConfidence = hrm.confidence; - log_debug("HRM=" + hrm.bpm + " (" + hrm.confidence + ")"); + log_debug("HRM=" + hrm.bpm + " (" + hrm.confidence + ")"); if (infoMode == "ID_HRM" ) drawHrm(); }); @@ -360,7 +360,7 @@ function getGaugeImage(p) { palette : pal2, buffer : require("heatshrink").decompress(atob("AH4A/AH4AChWq1WpqtUFUgpBFYYABoApggQqDFYlVqBVjFYxZfFQorGLLrWCFZbgbVguoBQcFLD8qFQYMHiosDKzoOJFgZYYKwYPLFgZWawARMLDJWCawgAJcAZWYCZ6FCLCkKFQOgCZ8BFYNUFaZWSLAlAQShWQLAiESQQRtTLAKESFQOoFacFQiSCCwArTgCESQSyEUlTZTboyCnQiSCYQiSCYQiSCZQgdAVxwqYQgSwMVwOoFbMFWBquaWCArBVzKwDbRoqaWATcKbQKuaWAbcKbQKuaWAbcKVzqwNFYIqcWATaKVziwDbhDaebhjaebhgrBbTrcCFZDafbheqFcTcHbT7cDFY0CbT7cDqArxhWqwArfgFVqgrHFUDcBFY0qFcdVFY2oFcMFFY2qFclAFYugFcMBFYsCFctQFYuAFcMAFYsKFctUFYoqigEVFeEqFctVFYmoFccFFYmqFc1AcIdQFccBFf4rbGAoAhKQYr/Fa8FFc9UFYYqkgEVFf4r/FYwDDAEZTDFf4r/Ff4rbqorooArBqArlgIr/Ff4r/Ff4r/Ff4r/Ff4r/Ff4r/Ff4rbqgrlgorCioroAYIr/Ff4r/FbYDDAEZTDFf4r/FYtAFclVFYUBFc9QFf4rZAgoAgKQor/FbFUFccFFYkVFcwFDioFEAD4lFGIorgPogrtWoYAfqorEgIrlqArFAwgAdEg4rlPgqKFADrUHcQorfA4sVA4wAbEY4zHFbh7GRY4AbaY7jBqAqfERArrMBAAZUxNVbkEVFZAJBFcJhRAC6lJFYLcebQIrIBRTaXJhIrhUhLcfD5YLBbjtVFZTceZ5jceJRpkLVyaiLWDpJNFYKwaUIIrMSIKwaDhw6OVx50NFYKwZDZ6waOaCTBQjBGBZZw8CQi4ZBOR6EYeySEYQSCEaQSITDH6BvGIaKEWQSSEEbqQVVQgRYSKwLGUQgRCQKwTFUC4RYQKwSCTDAhEONQTwULAqcNCARWVLAhGMB55YPDhQqDKy4dFFhAMMLCzgFawZWbEI4AIGogAYFZtAFbgsMFTyyGVkBZOKr7gJazoA/AHIA=")) }; - + // p90 if (p >= 90 && p < 100) return { width : 176, height : 176, bpp : 2, @@ -410,7 +410,7 @@ function BUTTON(name,x,y,w,h,c,f,tx) { // if pressed the callback BUTTON.prototype.check = function(x,y) { //console.log(this.name + ":check() x=" + x + " y=" + y +"\n"); - + if (x>= this.x && x<= (this.x + this.w) && y>= this.y && y<= (this.y + this.h)) { log_debug(this.name + ":callback\n"); this.callback(); @@ -472,7 +472,7 @@ function checkIdle() { warned = false; return; } - + let hour = (new Date()).getHours(); let active = (hour >= 9 && hour < 21); //let active = true; @@ -501,7 +501,7 @@ function buzzer(n) { if (n-- < 1) return; Bangle.buzz(250); - + if (buzzTimeout) clearTimeout(buzzTimeout); buzzTimeout = setTimeout(function() { buzzTimeout = undefined; diff --git a/apps/daisy/metadata.json b/apps/daisy/metadata.json index c6cc93620..0bad50151 100644 --- a/apps/daisy/metadata.json +++ b/apps/daisy/metadata.json @@ -1,6 +1,6 @@ { "id": "daisy", "name": "Daisy", - "version":"0.08", + "version":"0.09", "dependencies": {"mylocation":"app"}, "description": "A beautiful digital clock with large ring guage, idle timer and a cyclic information line that includes, day, date, steps, battery, sunrise and sunset times", "icon": "app.png", diff --git a/apps/hworldclock/ChangeLog b/apps/hworldclock/ChangeLog index c029b432f..13e3fa809 100644 --- a/apps/hworldclock/ChangeLog +++ b/apps/hworldclock/ChangeLog @@ -12,3 +12,4 @@ 0.26: BJS2: Swipe down to rotate 180 degree 0.27: BJS2: Changed swipe down to swipe up 0.28: Reverted changes to implementation of 0.25 +0.29: Use 'modules/suncalc.js' to avoid it being copied 8 times for different apps diff --git a/apps/hworldclock/app.js b/apps/hworldclock/app.js index c80b712da..6bd30be8e 100644 --- a/apps/hworldclock/app.js +++ b/apps/hworldclock/app.js @@ -15,7 +15,7 @@ require("Font5x9Numeric7Seg").add(Graphics); require("FontTeletext10x18Ascii").add(Graphics); // Font for single secondary time -const secondaryTimeFontSize = 4; +const secondaryTimeFontSize = 4; const secondaryTimeZoneFontSize = 2; // Font / columns for multiple secondary times @@ -39,14 +39,14 @@ const yposWorld = big ? 170 : 120; const OFFSET_TIME_ZONE = 0; const OFFSET_HOURS = 1; -var PosInterval = 0; +var PosInterval = 0; var offsets = require("Storage").readJSON("hworldclock.settings.json") || []; //=======Sun setting = require("Storage").readJSON("setting.json",1); E.setTimeZone(setting.timezone); // timezone = 1 for MEZ, = 2 for MESZ -SunCalc = require("hsuncalc.js"); +SunCalc = require("suncalc"); // from modules folder const LOCATION_FILE = "mylocation.json"; var rise = "read"; var set = "..."; @@ -87,7 +87,7 @@ const mockOffsets = { //offsets = mockOffsets.fourOffsets; // should render in columns // END TESTING CODE - + // Load settings function loadMySettings() { @@ -141,11 +141,9 @@ function getCurrentTimeFromOffset(dt, offset) { function updatePos() { coord = require("Storage").readJSON(LOCATION_FILE,1)|| {"lat":0,"lon":0,"location":"-"}; //{"lat":53.3,"lon":10.1,"location":"Pattensen"}; if (coord.lat != 0 && coord.lon != 0) { - //pos = SunCalc.getPosition(Date.now(), coord.lat, coord.lon); times = SunCalc.getTimes(Date.now(), coord.lat, coord.lon); rise = "^" + times.sunrise.toString().split(" ")[4].substr(0,5); set = "v" + times.sunset.toString().split(" ")[4].substr(0,5); - //noonpos = SunCalc.getPosition(times.solarNoon, coord.lat, coord.lon); } else { rise = null; set = null; @@ -179,7 +177,7 @@ function drawSeconds() { //console.log(seconds); if (Bangle.isLocked() && secondsMode != "always") seconds = seconds.slice(0, -1) + ':::'; // we use :: as the font does not have an x //console.log(seconds); - g.drawString(`${seconds}`, xyCenterSeconds, yposTime+14, true); + g.drawString(`${seconds}`, xyCenterSeconds, yposTime+14, true); queueDrawSeconds(); } @@ -196,18 +194,18 @@ function draw() { let time = da[4].split(":"); let hours = time[0], minutes = time[1]; - - + + if (_12hour){ //do 12 hour stuff if (hours > 12) { ampm = "PM"; - hours = hours - 12; - if (hours < 10) hours = doublenum(hours); + hours = hours - 12; + if (hours < 10) hours = doublenum(hours); } else { - ampm = "AM"; - } - } + ampm = "AM"; + } + } //g.setFont(font, primaryTimeFontSize); g.setFont("5x9Numeric7Seg",primaryTimeFontSize); @@ -221,18 +219,18 @@ function draw() { g.setColor(g.theme.fg); } g.drawString(`${hours}:${minutes}`, xyCenter-10, yposTime, true); - + // am / PM ? if (_12hour){ //do 12 hour stuff //let ampm = require("locale").medidian(new Date()); Not working g.setFont("Vector", 17); g.drawString(ampm, xyCenterSeconds, yAmPm, true); - } + } if (secondsMode != "none") drawSeconds(); // To make sure... - - // draw Day, name of month, Date + + // draw Day, name of month, Date //DATE let localDate = require("locale").date(new Date(), 1); localDate = localDate.substring(0, localDate.length - 5); @@ -251,7 +249,7 @@ function draw() { if (offsets.length === 1) { - let date = [require("locale").dow(new Date(), 1), require("locale").date(new Date(), 1)]; + let date = [require("locale").dow(new Date(), 1), require("locale").date(new Date(), 1)]; // For a single secondary timezone, draw it bigger and drop time zone to second line const xOffset = 30; g.setFont(font, secondaryTimeFontSize).drawString(`${hours}:${minutes}`, xyCenter, yposTime2, true); @@ -277,7 +275,7 @@ function draw() { g.setFontAlign(-1, 0).setFont("Vector",12).drawString(`${rise}`, 10, 3 + yposWorld + 3 * 15, true); // draw rise g.setFontAlign(1, 0).drawString(`${set}`, xcol2, 3 + yposWorld + 3 * 15, true); // draw set } else { - g.setFontAlign(-1, 0).setFont("Vector",11).drawString("set city in \'my location\' app!", 10, 3 + yposWorld + 3 * 15, true); + g.setFontAlign(-1, 0).setFont("Vector",11).drawString("set city in \'my location\' app!", 10, 3 + yposWorld + 3 * 15, true); } } //debug settings @@ -287,7 +285,7 @@ function draw() { //g.drawString(colorWhenDark, xcol2, 3 + yposWorld + 3 * 15, true); queueDraw(); - + if (secondsMode != "none") queueDrawSeconds(); } @@ -307,7 +305,7 @@ Bangle.setUI({ if (drawTimeoutSeconds) clearTimeout(drawTimeoutSeconds); drawTimeoutSeconds = undefined; if (drawTimeout) clearTimeout(drawTimeout); - drawTimeout = undefined; + drawTimeout = undefined; }}); Bangle.loadWidgets(); Bangle.drawWidgets(); @@ -328,15 +326,15 @@ if (!Bangle.isLocked()) { // Initial state if (secondsMode != "none") { if (drawTimeoutSeconds) clearTimeout(drawTimeoutSeconds); drawTimeoutSeconds = undefined; - } + } if (drawTimeout) clearTimeout(drawTimeout); drawTimeout = undefined; draw(); // draw immediately, queue redraw - + }else{ if (secondsMode == "always") secondsTimeout = 1000; if (secondsMode == "when unlocked") secondsTimeout = 10 * 1000; - + if (secondsMode != "none") { if (drawTimeoutSeconds) clearTimeout(drawTimeoutSeconds); drawTimeoutSeconds = undefined; @@ -350,9 +348,9 @@ if (!Bangle.isLocked()) { // Initial state updatePos(); } draw(); // draw immediately, queue redraw - + } - + Bangle.on('lock',on=>{ if (!on) { // UNlocked @@ -366,7 +364,7 @@ Bangle.on('lock',on=>{ if (secondsMode != "none") { if (drawTimeoutSeconds) clearTimeout(drawTimeoutSeconds); drawTimeoutSeconds = undefined; - } + } if (drawTimeout) clearTimeout(drawTimeout); drawTimeout = undefined; @@ -375,7 +373,7 @@ Bangle.on('lock',on=>{ if (secondsMode == "always") secondsTimeout = 1000; if (secondsMode == "when unlocked") secondsTimeout = 10 * 1000; - + if (secondsMode != "none") { if (drawTimeoutSeconds) clearTimeout(drawTimeoutSeconds); drawTimeoutSeconds = undefined; @@ -388,7 +386,7 @@ Bangle.on('lock',on=>{ PosInterval = setInterval(updatePos, 60*60E3); // refesh every 60 mins updatePos(); } - draw(); // draw immediately, queue redraw + draw(); // draw immediately, queue redraw } }); -} \ No newline at end of file +} diff --git a/apps/hworldclock/hsuncalc.js b/apps/hworldclock/hsuncalc.js deleted file mode 100644 index b1af0a0d9..000000000 --- a/apps/hworldclock/hsuncalc.js +++ /dev/null @@ -1,298 +0,0 @@ -/* Module suncalc.js - (c) 2011-2015, Vladimir Agafonkin - SunCalc is a JavaScript library for calculating sun/moon position and light phases. - https://github.com/mourner/suncalc - -PB: Usage: -E.setTimeZone(2); // 1 = MEZ, 2 = MESZ -SunCalc = require("suncalc.js"); -pos = SunCalc.getPosition(Date.now(), 53.3, 10.1); -times = SunCalc.getTimes(Date.now(), 53.3, 10.1); -rise = times.sunrise; // Date object -rise_str = rise.getHours() + ':' + rise.getMinutes(); //hh:mm -*/ -var exports={}; - -// shortcuts for easier to read formulas - -var PI = Math.PI, - sin = Math.sin, - cos = Math.cos, - tan = Math.tan, - asin = Math.asin, - atan = Math.atan2, - acos = Math.acos, - rad = PI / 180; - -// sun calculations are based on http://aa.quae.nl/en/reken/zonpositie.html formulas - -// date/time constants and conversions - -var dayMs = 1000 * 60 * 60 * 24, - J1970 = 2440588, - J2000 = 2451545; - -function toJulian(date) { return date.valueOf() / dayMs - 0.5 + J1970; } -function fromJulian(j) { return new Date((j + 0.5 - J1970) * dayMs); } // PB: onece removed + 0.5; included it again 4 Jan 2021 -function toDays(date) { return toJulian(date) - J2000; } - - -// general calculations for position - -var e = rad * 23.4397; // obliquity of the Earth - -function rightAscension(l, b) { return atan(sin(l) * cos(e) - tan(b) * sin(e), cos(l)); } -function declination(l, b) { return asin(sin(b) * cos(e) + cos(b) * sin(e) * sin(l)); } - -function azimuth(H, phi, dec) { return atan(sin(H), cos(H) * sin(phi) - tan(dec) * cos(phi)); } -function altitude(H, phi, dec) { return asin(sin(phi) * sin(dec) + cos(phi) * cos(dec) * cos(H)); } - -function siderealTime(d, lw) { return rad * (280.16 + 360.9856235 * d) - lw; } - -function astroRefraction(h) { - if (h < 0) // the following formula works for positive altitudes only. - h = 0; // if h = -0.08901179 a div/0 would occur. - - // formula 16.4 of "Astronomical Algorithms" 2nd edition by Jean Meeus (Willmann-Bell, Richmond) 1998. - // 1.02 / tan(h + 10.26 / (h + 5.10)) h in degrees, result in arc minutes -> converted to rad: - return 0.0002967 / Math.tan(h + 0.00312536 / (h + 0.08901179)); -} - -// general sun calculations - -function solarMeanAnomaly(d) { return rad * (357.5291 + 0.98560028 * d); } - -function eclipticLongitude(M) { - - var C = rad * (1.9148 * sin(M) + 0.02 * sin(2 * M) + 0.0003 * sin(3 * M)), // equation of center - P = rad * 102.9372; // perihelion of the Earth - - return M + C + P + PI; -} - -function sunCoords(d) { - - var M = solarMeanAnomaly(d), - L = eclipticLongitude(M); - - return { - dec: declination(L, 0), - ra: rightAscension(L, 0) - }; -} - -// calculates sun position for a given date and latitude/longitude - -exports.getPosition = function (date, lat, lng) { - - var lw = rad * -lng, - phi = rad * lat, - d = toDays(date), - - c = sunCoords(d), - H = siderealTime(d, lw) - c.ra; - - return { - azimuth: Math.round((azimuth(H, phi, c.dec) / rad + 180) % 360), // PB: converted to deg - altitude: Math.round( altitude(H, phi, c.dec) / rad) // PB: converted to deg - }; -}; - - -// sun times configuration (angle, morning name, evening name) - -var times = [ - [-0.833, 'sunrise', 'sunset' ] -]; - -// calculations for sun times -var J0 = 0.0009; - -function julianCycle(d, lw) { return Math.round(d - J0 - lw / (2 * PI)); } - -function approxTransit(Ht, lw, n) { return J0 + (Ht + lw) / (2 * PI) + n; } -function solarTransitJ(ds, M, L) { return J2000 + ds + 0.0053 * sin(M) - 0.0069 * sin(2 * L); } - -function hourAngle(h, phi, d) { return acos((sin(h) - sin(phi) * sin(d)) / (cos(phi) * cos(d))); } -function observerAngle(height) { return -2.076 * Math.sqrt(height) / 60; } - -// returns set time for the given sun altitude -function getSetJ(h, lw, phi, dec, n, M, L) { - - var w = hourAngle(h, phi, dec), - a = approxTransit(w, lw, n); - return solarTransitJ(a, M, L); -} - - -// calculates sun times for a given date, latitude/longitude, and, optionally, -// the observer height (in meters) relative to the horizon - -exports.getTimes = function (date, lat, lng, height) { - - height = height || 0; - - var lw = rad * -lng, - phi = rad * lat, - - dh = observerAngle(height), - - d = toDays(date), - n = julianCycle(d, lw), - ds = approxTransit(0, lw, n), - - M = solarMeanAnomaly(ds), - L = eclipticLongitude(M), - dec = declination(L, 0), - - Jnoon = solarTransitJ(ds, M, L), - - i, len, time, h0, Jset, Jrise; - - - var result = { - solarNoon: fromJulian(Jnoon), - nadir: fromJulian(Jnoon - 0.5) - }; - - for (i = 0, len = times.length; i < len; i += 1) { - time = times[i]; - h0 = (time[0] + dh) * rad; - - Jset = getSetJ(h0, lw, phi, dec, n, M, L); - Jrise = Jnoon - (Jset - Jnoon); - - result[time[1]] = fromJulian(Jrise); - result[time[2]] = fromJulian(Jset); - } - - return result; -}; - - -// moon calculations, based on http://aa.quae.nl/en/reken/hemelpositie.html formulas - -function moonCoords(d) { // geocentric ecliptic coordinates of the moon - - var L = rad * (218.316 + 13.176396 * d), // ecliptic longitude - M = rad * (134.963 + 13.064993 * d), // mean anomaly - F = rad * (93.272 + 13.229350 * d), // mean distance - - l = L + rad * 6.289 * sin(M), // longitude - b = rad * 5.128 * sin(F), // latitude - dt = 385001 - 20905 * cos(M); // distance to the moon in km - - return { - ra: rightAscension(l, b), - dec: declination(l, b), - dist: dt - }; -} - -getMoonPosition = function (date, lat, lng) { - - var lw = rad * -lng, - phi = rad * lat, - d = toDays(date), - - c = moonCoords(d), - H = siderealTime(d, lw) - c.ra, - h = altitude(H, phi, c.dec), - // formula 14.1 of "Astronomical Algorithms" 2nd edition by Jean Meeus (Willmann-Bell, Richmond) 1998. - pa = atan(sin(H), tan(phi) * cos(c.dec) - sin(c.dec) * cos(H)); - - h = h + astroRefraction(h); // altitude correction for refraction - - return { - azimuth: azimuth(H, phi, c.dec), - altitude: h, - distance: c.dist, - parallacticAngle: pa - }; -}; - - -// calculations for illumination parameters of the moon, -// based on http://idlastro.gsfc.nasa.gov/ftp/pro/astro/mphase.pro formulas and -// Chapter 48 of "Astronomical Algorithms" 2nd edition by Jean Meeus (Willmann-Bell, Richmond) 1998. - -getMoonIllumination = function (date) { - - var d = toDays(date || new Date()), - s = sunCoords(d), - m = moonCoords(d), - - sdist = 149598000, // distance from Earth to Sun in km - - phi = acos(sin(s.dec) * sin(m.dec) + cos(s.dec) * cos(m.dec) * cos(s.ra - m.ra)), - inc = atan(sdist * sin(phi), m.dist - sdist * cos(phi)), - angle = atan(cos(s.dec) * sin(s.ra - m.ra), sin(s.dec) * cos(m.dec) - - cos(s.dec) * sin(m.dec) * cos(s.ra - m.ra)); - - return { - fraction: (1 + cos(inc)) / 2, - phase: 0.5 + 0.5 * inc * (angle < 0 ? -1 : 1) / Math.PI, - angle: angle - }; -}; - - -function hoursLater(date, h) { - return new Date(date.valueOf() + h * dayMs / 24); -} - -// calculations for moon rise/set times are based on http://www.stargazing.net/kepler/moonrise.html article - -getMoonTimes = function (date, lat, lng, inUTC) { - var t = new Date(date); - if (inUTC) t.setUTCHours(0, 0, 0, 0); - else t.setHours(0, 0, 0, 0); - - var hc = 0.133 * rad, - h0 = SunCalc.getMoonPosition(t, lat, lng).altitude - hc, - h1, h2, rise, set, a, b, xe, ye, d, roots, x1, x2, dx; - - // go in 2-hour chunks, each time seeing if a 3-point quadratic curve crosses zero (which means rise or set) - for (var i = 1; i <= 24; i += 2) { - h1 = SunCalc.getMoonPosition(hoursLater(t, i), lat, lng).altitude - hc; - h2 = SunCalc.getMoonPosition(hoursLater(t, i + 1), lat, lng).altitude - hc; - - a = (h0 + h2) / 2 - h1; - b = (h2 - h0) / 2; - xe = -b / (2 * a); - ye = (a * xe + b) * xe + h1; - d = b * b - 4 * a * h1; - roots = 0; - - if (d >= 0) { - dx = Math.sqrt(d) / (Math.abs(a) * 2); - x1 = xe - dx; - x2 = xe + dx; - if (Math.abs(x1) <= 1) roots++; - if (Math.abs(x2) <= 1) roots++; - if (x1 < -1) x1 = x2; - } - - if (roots === 1) { - if (h0 < 0) rise = i + x1; - else set = i + x1; - - } else if (roots === 2) { - rise = i + (ye < 0 ? x2 : x1); - set = i + (ye < 0 ? x1 : x2); - } - - if (rise && set) break; - - h0 = h2; - } - - var result = {}; - - if (rise) result.rise = hoursLater(t, rise); - if (set) result.set = hoursLater(t, set); - - if (!rise && !set) result[ye > 0 ? 'alwaysUp' : 'alwaysDown'] = true; - - return result; -}; \ No newline at end of file diff --git a/apps/hworldclock/metadata.json b/apps/hworldclock/metadata.json index 587c05067..3b633ead7 100644 --- a/apps/hworldclock/metadata.json +++ b/apps/hworldclock/metadata.json @@ -2,7 +2,7 @@ "id": "hworldclock", "name": "Hanks World Clock", "shortName": "Hanks World Clock", - "version": "0.28", + "version": "0.29", "description": "Current time zone plus up to three others", "allow_emulator":true, "icon": "app.png", @@ -15,11 +15,10 @@ "storage": [ {"name":"hworldclock.app.js","url":"app.js"}, {"name":"hworldclock.img","url":"hworldclock-icon.js","evaluate":true}, - {"name":"hworldclock.settings.js","url":"settings.js"}, - {"name":"hsuncalc.js","url":"hsuncalc.js"} + {"name":"hworldclock.settings.js","url":"settings.js"} ], "data": [ {"name":"hworldclock.settings.json"}, - {"name":"hworldclock.json"} + {"name":"hworldclock.json"} ] -} \ No newline at end of file +} diff --git a/apps/pastel/ChangeLog b/apps/pastel/ChangeLog index 28dcc0c28..02cef7774 100644 --- a/apps/pastel/ChangeLog +++ b/apps/pastel/ChangeLog @@ -19,3 +19,4 @@ 0.16: make check_idle boolean setting work properly with new B2 menu 0.17: Use default Bangle formatter for booleans 0.18: fix idle option always getting defaulted to true +0.19: Use 'modules/suncalc.js' to avoid it being copied 8 times for different apps diff --git a/apps/pastel/metadata.json b/apps/pastel/metadata.json index 860ed833b..cf4bbbe9b 100644 --- a/apps/pastel/metadata.json +++ b/apps/pastel/metadata.json @@ -2,7 +2,7 @@ "id": "pastel", "name": "Pastel Clock", "shortName": "Pastel", - "version": "0.18", + "version": "0.19", "description": "A Configurable clock with custom fonts, background and weather display. Has a cyclic information line that includes, day, date, battery, sunrise and sunset times", "icon": "pastel.png", "dependencies": {"mylocation":"app","weather":"app"}, diff --git a/apps/pastel/pastel.app.js b/apps/pastel/pastel.app.js index 05c0e2367..bc41588d8 100644 --- a/apps/pastel/pastel.app.js +++ b/apps/pastel/pastel.app.js @@ -1,4 +1,4 @@ -var SunCalc = require("https://raw.githubusercontent.com/mourner/suncalc/master/suncalc.js"); +var SunCalc = require("suncalc"); // from modules folder require("f_latosmall").add(Graphics); const storage = require('Storage'); const locale = require("locale"); @@ -85,7 +85,7 @@ function getSteps() { try { return Bangle.getHealthStatus("day").steps; } catch (e) { - if (WIDGETS.wpedom !== undefined) + if (WIDGETS.wpedom !== undefined) return WIDGETS.wpedom.getSteps(); else return '???'; @@ -181,12 +181,12 @@ function drawClock() { var d = new Date(); var da = d.toString().split(" "); var time = da[4].substr(0,5); - + var hh = da[4].substr(0,2); var mm = da[4].substr(3,2); var day = da[0]; var month_day = da[1] + " " + da[2]; - + // fix hh for 12hr clock var h2 = "0" + parseInt(hh) % 12 || 12; if (parseInt(hh) > 12) @@ -215,12 +215,12 @@ function drawClock() { g.reset(); g.setColor(g.theme.bg); g.fillRect(Bangle.appRect); - + // draw a grid like graph paper if (settings.grid && process.env.HWVERSION !=1) { g.setColor("#0f0"); for (var gx=20; gx <= w; gx += 20) - g.drawLine(gx, 30, gx, h - 24); + g.drawLine(gx, 30, gx, h - 24); for (var gy=30; gy <= h - 24; gy += 20) g.drawLine(0, gy, w, gy); } @@ -238,7 +238,7 @@ function drawClock() { g.drawString( (w_wind.split(' ').slice(0, 2).join(' ')), (w/2) + 6, 24 + ((y - 24)/2)); // display first 2 words of the wind string eg '4 mph' } - + if (settings.font == "Architect") g.setFontArchitect(); else if (settings.font == "GochiHand") @@ -253,7 +253,7 @@ function drawClock() { g.setFontSpecialElite(); else g.setFontLato(); - + g.setFontAlign(1,-1); // right aligned g.drawString(hh, x - 6, y); g.setFontAlign(-1,-1); // left aligned @@ -310,7 +310,7 @@ function BUTTON(name,x,y,w,h,c,f,tx) { // if pressed the callback BUTTON.prototype.check = function(x,y) { //console.log(this.name + ":check() x=" + x + " y=" + y +"\n"); - + if (x>= this.x && x<= (this.x + this.w) && y>= this.y && y<= (this.y + this.h)) { log_debug(this.name + ":callback\n"); this.callback(); @@ -366,7 +366,7 @@ function checkIdle() { warned = false; return; } - + let hour = (new Date()).getHours(); let active = (hour >= 9 && hour < 21); //let active = true; @@ -397,7 +397,7 @@ function buzzer(n) { if (n-- < 1) return; Bangle.buzz(250); - + if (buzzTimeout) clearTimeout(buzzTimeout); buzzTimeout = setTimeout(function() { buzzTimeout = undefined; diff --git a/apps/rebble/ChangeLog b/apps/rebble/ChangeLog index c009a4ec1..78ba0c5da 100644 --- a/apps/rebble/ChangeLog +++ b/apps/rebble/ChangeLog @@ -9,7 +9,8 @@ 0.09: fix battery icon size 0.10: Tell clock widgets to hide. 0.11: fix issue https://github.com/espruino/BangleApps/issues/2128 (#2128) ( settings undefined ) -0.12: implemented widget_utils +0.12: implemented widget_utils 0.13: convert var/function into let -0.14: cleanup code and fix fastload issue -0.15: fix draw before widget hide \ No newline at end of file +0.14: cleanup code and fix fastload issue +0.15: fix draw before widget hide +0.16: Use 'modules/suncalc.js' to avoid it being copied 8 times for different apps diff --git a/apps/rebble/metadata.json b/apps/rebble/metadata.json index 7042fcb95..c380204a4 100644 --- a/apps/rebble/metadata.json +++ b/apps/rebble/metadata.json @@ -2,7 +2,7 @@ "id": "rebble", "name": "Rebble Clock", "shortName": "Rebble", - "version": "0.15", + "version": "0.16", "description": "A Pebble style clock, with configurable background, three sidebars including steps, day, date, sunrise, sunset, long live the rebellion", "readme": "README.md", "icon": "rebble.png", @@ -14,7 +14,6 @@ "storage": [ {"name":"rebble.app.js","url":"rebble.app.js"}, {"name":"rebble.settings.js","url":"rebble.settings.js"}, - {"name":"rebble.img","url":"rebble.icon.js","evaluate":true}, - {"name":"suncalc","url":"suncalc.js"} + {"name":"rebble.img","url":"rebble.icon.js","evaluate":true} ] } diff --git a/apps/rebble/rebble.app.js b/apps/rebble/rebble.app.js index fd0c8f7f9..445c30125 100644 --- a/apps/rebble/rebble.app.js +++ b/apps/rebble/rebble.app.js @@ -11,7 +11,7 @@ Graphics.prototype.setFontKdamThmor = function(scale) { { - let SunCalc = require("suncalc"); + let SunCalc = require("suncalc"); // from modules folder const SETTINGS_FILE = "rebble.json"; const LOCATION_FILE = "mylocation.json"; const GLOBAL_SETTINGS = "setting.json"; @@ -49,7 +49,7 @@ Graphics.prototype.setFontKdamThmor = function(scale) { } if(settings.sideTap!=0) - sideBar=parseInt(settings.sideTap)-1; //tab to + sideBar=parseInt(settings.sideTap)-1; //tab to is12Hour = (require("Storage").readJSON(GLOBAL_SETTINGS, 1) || {})["12hour"] || false; } @@ -110,15 +110,15 @@ Graphics.prototype.setFontKdamThmor = function(scale) { let date = new Date(); let hh = date.getHours(); let mm = date.getMinutes(); - + hh = formatHours(hh); mm = zeroPad(mm,2); - + //const t = 6; if (drawCount % 60 == 0) updateSunRiseSunSet(location.lat, location.lon); - + g.reset(); g.setColor(g.theme.bg); g.fillRect(0, 0, w2, h); @@ -143,7 +143,7 @@ Graphics.prototype.setFontKdamThmor = function(scale) { drawSideBar3(); break; } - + drawCount++; queueDraw(); } @@ -154,14 +154,14 @@ Graphics.prototype.setFontKdamThmor = function(scale) { let dd=date.getDate(); let mm=require("date_utils").month(date.getMonth()+1,1).toUpperCase(); - + drawBattery(w2 + (w-w2-wb)/2, h/10, wb, 17); setTextColor(); g.setFont('Vector', 20); g.setFontAlign(0, -1); g.drawString(E.getBattery() + '%', w3, (h/10) + 17 + 7); - + drawDateAndCalendar(w3, h/2, dy, dd, mm); } @@ -250,7 +250,7 @@ Graphics.prototype.setFontKdamThmor = function(scale) { } } - + // format steps so they fit in the place let formatSteps=function() { let s = Bangle.getHealthStatus("day").steps; @@ -292,8 +292,8 @@ Graphics.prototype.setFontKdamThmor = function(scale) { - let chargingListener= function(charging) { - + let chargingListener= function(charging) { + //redraw the sidebar ( with the battery ) switch(sideBar) { case 0: @@ -304,7 +304,7 @@ Graphics.prototype.setFontKdamThmor = function(scale) { break; } } - + let deleteAll=function() { // Called to unload all of the clock app @@ -320,7 +320,7 @@ Graphics.prototype.setFontKdamThmor = function(scale) { log_debug("starting.."); loadSettings(); loadLocation(); - + if(settings.autoCycle || settings.sideTap==0) { Bangle.setUI({ @@ -332,7 +332,7 @@ Graphics.prototype.setFontKdamThmor = function(scale) { if (btn>0) nextSidebar(); draw(); }); - + } else{ Bangle.setUI({ @@ -354,4 +354,4 @@ Graphics.prototype.setFontKdamThmor = function(scale) { main(); -} \ No newline at end of file +} diff --git a/apps/rebble/suncalc.js b/apps/rebble/suncalc.js deleted file mode 100644 index d86f039c5..000000000 --- a/apps/rebble/suncalc.js +++ /dev/null @@ -1,143 +0,0 @@ -/* - (c) 2011-2015, Vladimir Agafonkin - SunCalc is a JavaScript library for calculating sun/moon position and light phases. - https://github.com/mourner/suncalc - - edit for banglejs -*/ - -(function () { 'use strict'; - -// shortcuts for easier to read formulas - -var PI = Math.PI, - sin = Math.sin, - cos = Math.cos, - tan = Math.tan, - asin = Math.asin, - atan = Math.atan2, - acos = Math.acos, - rad = PI / 180; - -// sun calculations are based on http://aa.quae.nl/en/reken/zonpositie.html formulas - - -// date/time constants and conversions - -var dayMs = 1000 * 60 * 60 * 24, - J1970 = 2440588, - J2000 = 2451545; - -function toJulian(date) { return date.valueOf() / dayMs - 0.5 + J1970; } -function fromJulian(j) { return new Date((j + 0.5 - J1970) * dayMs); } -function toDays(date) { return toJulian(date) - J2000; } - - -// general calculations for position - -var e = rad * 23.4397; // obliquity of the Earth - -function declination(l, b) { return asin(sin(b) * cos(e) + cos(b) * sin(e) * sin(l)); } - - -// general sun calculations - -function solarMeanAnomaly(d) { return rad * (357.5291 + 0.98560028 * d); } - -function eclipticLongitude(M) { - - var C = rad * (1.9148 * sin(M) + 0.02 * sin(2 * M) + 0.0003 * sin(3 * M)), // equation of center - P = rad * 102.9372; // perihelion of the Earth - - return M + C + P + PI; -} - -var SunCalc = {}; - - -// sun times configuration (angle, morning name, evening name) - -var times = SunCalc.times = [ - [-0.833, 'sunrise', 'sunset' ], - [ -0.3, 'sunriseEnd', 'sunsetStart' ], - [ -6, 'dawn', 'dusk' ], - [ -12, 'nauticalDawn', 'nauticalDusk'], - [ -18, 'nightEnd', 'night' ], - [ 6, 'goldenHourEnd', 'goldenHour' ] -]; - - - -// calculations for sun times - -var J0 = 0.0009; - -function julianCycle(d, lw) { return Math.round(d - J0 - lw / (2 * PI)); } - -function approxTransit(Ht, lw, n) { return J0 + (Ht + lw) / (2 * PI) + n; } -function solarTransitJ(ds, M, L) { return J2000 + ds + 0.0053 * sin(M) - 0.0069 * sin(2 * L); } - -function hourAngle(h, phi, d) { return acos((sin(h) - sin(phi) * sin(d)) / (cos(phi) * cos(d))); } -function observerAngle(height) { return -2.076 * Math.sqrt(height) / 60; } - -// returns set time for the given sun altitude -function getSetJ(h, lw, phi, dec, n, M, L) { - - var w = hourAngle(h, phi, dec), - a = approxTransit(w, lw, n); - return solarTransitJ(a, M, L); -} - - -// calculates sun times for a given date, latitude/longitude, and, optionally, -// the observer height (in meters) relative to the horizon - -SunCalc.getTimes = function (date, lat, lng, height) { - - height = height || 0; - - var lw = rad * -lng, - phi = rad * lat, - - dh = observerAngle(height), - - d = toDays(date), - n = julianCycle(d, lw), - ds = approxTransit(0, lw, n), - - M = solarMeanAnomaly(ds), - L = eclipticLongitude(M), - dec = declination(L, 0), - - Jnoon = solarTransitJ(ds, M, L), - - i, len, time, h0, Jset, Jrise; - - - var result = { - solarNoon: fromJulian(Jnoon), - nadir: fromJulian(Jnoon - 0.5) - }; - - for (i = 0, len = times.length; i < len; i += 1) { - time = times[i]; - h0 = (time[0] + dh) * rad; - - Jset = getSetJ(h0, lw, phi, dec, n, M, L); - Jrise = Jnoon - (Jset - Jnoon); - - result[time[1]] = fromJulian(Jrise); - result[time[2]] = fromJulian(Jset); - } - - return result; -}; - - -// export as Node module / AMD module / browser variable -if (typeof exports === 'object' && typeof module !== 'undefined') module.exports = SunCalc; -else if (typeof define === 'function' && define.amd) define(SunCalc); -else window.SunCalc = SunCalc; - - -}()); \ No newline at end of file diff --git a/apps/sunclock/ChangeLog b/apps/sunclock/ChangeLog new file mode 100644 index 000000000..d63f1567e --- /dev/null +++ b/apps/sunclock/ChangeLog @@ -0,0 +1,2 @@ +0.01: First commit +0.02: Use 'modules/suncalc.js' to avoid it being copied 8 times for different apps diff --git a/apps/sunclock/app.js b/apps/sunclock/app.js index 4609565a2..1685bc218 100644 --- a/apps/sunclock/app.js +++ b/apps/sunclock/app.js @@ -9,8 +9,8 @@ SunCalc = require("suncalc.js"); loc = require('locale'); const LOCATION_FILE = "mylocation.json"; const xyCenter = g.getWidth() / 2 + 3; -const yposTime = 60; -const yposDate = 100; +const yposTime = 60; +const yposDate = 100; const yposRS = 135; const yposPos = 160; var rise = "07:00"; @@ -19,13 +19,21 @@ var pos = {altitude: 20, azimuth: 135}; var noonpos = {altitude: 37, azimuth: 180}; let idTimeout = null; + + function updatePos() { + function radToDeg(pos) { + return { // instead of mofidying suncalc + azimuth: Math.round((pos.azimuth / rad + 180) % 360), + altitude: Math.round( pos.altitude / rad) + }; + } coord = require("Storage").readJSON(LOCATION_FILE,1)|| {"lat":53.3,"lon":10.1,"location":"Pattensen"}; - pos = SunCalc.getPosition(Date.now(), coord.lat, coord.lon); + pos = radToDeg(SunCalc.getPosition(Date.now(), coord.lat, coord.lon)); times = SunCalc.getTimes(Date.now(), coord.lat, coord.lon); rise = times.sunrise.toString().split(" ")[4].substr(0,5); set = times.sunset.toString().split(" ")[4].substr(0,5); - noonpos = SunCalc.getPosition(times.solarNoon, coord.lat, coord.lon); + noonpos = radToDeg(SunCalc.getPosition(times.solarNoon, coord.lat, coord.lon)); } function drawSimpleClock() { @@ -38,7 +46,7 @@ function drawSimpleClock() { var time = da[4].substr(0, 5); // draw time - g.setFont("Vector",60); + g.setFont("Vector",60); g.drawString(time, xyCenter, yposTime, true); var date = [loc.dow(new Date(),1), loc.date(d,1)].join(" "); // draw day of week, date @@ -51,7 +59,7 @@ function drawSimpleClock() { g.setFont("Vector",21); g.drawString(`H${pos.altitude}/${noonpos.altitude} Az${pos.azimuth}`, xyCenter, yposPos, true); // draw sun pos - + let t = d.getSeconds()*1000 + d.getMilliseconds(); idTimeout = setTimeout(drawSimpleClock, 60000 - t); // time till next minute } diff --git a/apps/sunclock/metadata.json b/apps/sunclock/metadata.json index 617d76821..a9155f6f6 100644 --- a/apps/sunclock/metadata.json +++ b/apps/sunclock/metadata.json @@ -1,7 +1,7 @@ { "id": "sunclock", "name": "Sun Clock", - "version": "0.01", + "version": "0.02", "description": "A clock with sunset/sunrise, sun height/azimuth", "icon": "app.png", "type": "clock", @@ -11,7 +11,6 @@ "allow_emulator": true, "storage": [ {"name":"sunclock.app.js","url":"app.js"}, - {"name":"sunclock.img","url":"app-icon.js","evaluate":true}, - {"name":"suncalc.js","url":"suncalc.js"} + {"name":"sunclock.img","url":"app-icon.js","evaluate":true} ] } diff --git a/apps/timerclk/ChangeLog b/apps/timerclk/ChangeLog index 7a357b1aa..5a954d58c 100644 --- a/apps/timerclk/ChangeLog +++ b/apps/timerclk/ChangeLog @@ -1,3 +1,4 @@ 0.01: New App! 0.02: Add sunrise/sunset. Fix timer bugs. 0.03: Use default Bangle formatter for booleans +0.04: Use 'modules/suncalc.js' to avoid it being copied 8 times for different apps diff --git a/apps/timerclk/app.js b/apps/timerclk/app.js index c750fcfde..ee30b059a 100644 --- a/apps/timerclk/app.js +++ b/apps/timerclk/app.js @@ -3,7 +3,7 @@ Graphics.prototype.setFontAnton = function(scale) { g.setFontCustom(atob("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADgAAAAAAAAAAA/gAAAAAAAAAAP/gAAAAAAAAAH//gAAAAAAAAB///gAAAAAAAAf///gAAAAAAAP////gAAAAAAD/////gAAAAAA//////gAAAAAP//////gAAAAH///////gAAAB////////gAAAf////////gAAP/////////gAD//////////AA//////////gAA/////////4AAA////////+AAAA////////gAAAA///////wAAAAA//////8AAAAAA//////AAAAAAA/////gAAAAAAA////4AAAAAAAA///+AAAAAAAAA///gAAAAAAAAA//wAAAAAAAAAA/8AAAAAAAAAAA/AAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD//////AAAAAB///////8AAAAH////////AAAAf////////wAAA/////////4AAB/////////8AAD/////////+AAH//////////AAP//////////gAP//////////gAP//////////gAf//////////wAf//////////wAf//////////wAf//////////wA//8AAAAAB//4A//wAAAAAAf/4A//gAAAAAAP/4A//gAAAAAAP/4A//gAAAAAAP/4A//wAAAAAAf/4A///////////4Af//////////wAf//////////wAf//////////wAf//////////wAP//////////gAP//////////gAH//////////AAH//////////AAD/////////+AAB/////////8AAA/////////4AAAP////////gAAAD///////+AAAAAf//////4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP/gAAAAAAAAAAP/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/AAAAAAAAAAA//AAAAAAAAAAA/+AAAAAAAAAAB/8AAAAAAAAAAD//////////gAH//////////gAP//////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH/4AAAAB/gAAD//4AAAAf/gAAP//4AAAB//gAA///4AAAH//gAB///4AAAf//gAD///4AAA///gAH///4AAD///gAP///4AAH///gAP///4AAP///gAf///4AAf///gAf///4AB////gAf///4AD////gA////4AH////gA////4Af////gA////4A/////gA//wAAB/////gA//gAAH/////gA//gAAP/////gA//gAA///8//gA//gAD///w//gA//wA////g//gA////////A//gA///////8A//gA///////4A//gAf//////wA//gAf//////gA//gAf/////+AA//gAP/////8AA//gAP/////4AA//gAH/////gAA//gAD/////AAA//gAB////8AAA//gAA////wAAA//gAAP///AAAA//gAAD//8AAAA//gAAAP+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB/+AAAAAD/wAAB//8AAAAP/wAAB///AAAA//wAAB///wAAB//wAAB///4AAD//wAAB///8AAH//wAAB///+AAP//wAAB///+AAP//wAAB////AAf//wAAB////AAf//wAAB////gAf//wAAB////gA///wAAB////gA///wAAB////gA///w//AAf//wA//4A//AAA//wA//gA//AAAf/wA//gB//gAAf/wA//gB//gAAf/wA//gD//wAA//wA//wH//8AB//wA///////////gA///////////gA///////////gA///////////gAf//////////AAf//////////AAP//////////AAP/////////+AAH/////////8AAH///+/////4AAD///+f////wAAA///8P////gAAAf//4H///+AAAAH//gB///wAAAAAP4AAH/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/wAAAAAAAAAA//wAAAAAAAAAP//wAAAAAAAAB///wAAAAAAAAf///wAAAAAAAH////wAAAAAAA/////wAAAAAAP/////wAAAAAB//////wAAAAAf//////wAAAAH///////wAAAA////////wAAAP////////wAAA///////H/wAAA//////wH/wAAA/////8AH/wAAA/////AAH/wAAA////gAAH/wAAA///4AAAH/wAAA//+AAAAH/wAAA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gAAAAAAAAH/4AAAAAAAAAAH/wAAAAAAAAAAH/wAAAAAAAAAAH/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB//8AAA/////+B///AAA/////+B///wAA/////+B///4AA/////+B///8AA/////+B///8AA/////+B///+AA/////+B////AA/////+B////AA/////+B////AA/////+B////gA/////+B////gA/////+B////gA/////+A////gA//gP/gAAB//wA//gf/AAAA//wA//gf/AAAAf/wA//g//AAAAf/wA//g//AAAA//wA//g//gAAA//wA//g//+AAP//wA//g////////gA//g////////gA//g////////gA//g////////gA//g////////AA//gf///////AA//gf//////+AA//gP//////+AA//gH//////8AA//gD//////4AA//gB//////wAA//gA//////AAAAAAAH////8AAAAAAAA////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD//////gAAAAB///////+AAAAH////////gAAAf////////4AAB/////////8AAD/////////+AAH//////////AAH//////////gAP//////////gAP//////////gAf//////////wAf//////////wAf//////////wAf//////////wAf//////////4A//wAD/4AAf/4A//gAH/wAAP/4A//gAH/wAAP/4A//gAP/wAAP/4A//gAP/4AAf/4A//wAP/+AD//4A///wP//////4Af//4P//////wAf//4P//////wAf//4P//////wAf//4P//////wAP//4P//////gAP//4H//////gAH//4H//////AAH//4D/////+AAD//4D/////8AAB//4B/////4AAA//4A/////wAAAP/4AP////AAAAB/4AD///4AAAAAAAAAH/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//AAAAAAAAAAA//gAAAAAAAAAA//gAAAAAAAAAA//gAAAAAAADgA//gAAAAAAP/gA//gAAAAAH//gA//gAAAAB///gA//gAAAAP///gA//gAAAD////gA//gAAAf////gA//gAAB/////gA//gAAP/////gA//gAB//////gA//gAH//////gA//gA///////gA//gD///////gA//gf///////gA//h////////gA//n////////gA//////////gAA/////////AAAA////////wAAAA///////4AAAAA///////AAAAAA//////4AAAAAA//////AAAAAAA/////4AAAAAAA/////AAAAAAAA////8AAAAAAAA////gAAAAAAAA///+AAAAAAAAA///4AAAAAAAAA///AAAAAAAAAA//4AAAAAAAAAA/+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD//gB///wAAAAP//4H///+AAAA///8P////gAAB///+f////4AAD///+/////8AAH/////////+AAH//////////AAP//////////gAP//////////gAf//////////gAf//////////wAf//////////wAf//////////wA///////////wA//4D//wAB//4A//wB//gAA//4A//gA//gAAf/4A//gA//AAAf/4A//gA//gAAf/4A//wB//gAA//4A///P//8AH//4Af//////////wAf//////////wAf//////////wAf//////////wAf//////////gAP//////////gAP//////////AAH//////////AAD/////////+AAD///+/////8AAB///8f////wAAAf//4P////AAAAH//wD///8AAAAA/+AAf//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH//gAAAAAAAAB///+AA/+AAAAP////gA//wAAAf////wA//4AAB/////4A//8AAD/////8A//+AAD/////+A///AAH/////+A///AAP//////A///gAP//////A///gAf//////A///wAf//////A///wAf//////A///wAf//////A///wA///////AB//4A//4AD//AAP/4A//gAB//AAP/4A//gAA//AAP/4A//gAA/+AAP/4A//gAB/8AAP/4A//wAB/8AAf/4Af//////////wAf//////////wAf//////////wAf//////////wAf//////////wAP//////////gAP//////////gAH//////////AAH/////////+AAD/////////8AAB/////////4AAAf////////wAAAP////////AAAAB///////4AAAAAD/////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAf/AAB/8AAAAAA//AAD/8AAAAAA//AAD/8AAAAAA//AAD/8AAAAAA//AAD/8AAAAAA//AAD/8AAAAAA//AAD/8AAAAAA//AAD/8AAAAAA//AAD/8AAAAAA//AAD/8AAAAAA//AAD/8AAAAAA//AAD/8AAAAAA//AAD/8AAAAAA//AAD/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=="), 46, atob("EiAnGicnJycnJycnEw=="), 78+(scale<<8)+(1<<16)); }; -var SunCalc = require("https://raw.githubusercontent.com/mourner/suncalc/master/suncalc.js"); +var SunCalc = require("suncalc"); // from modules folder const LOCATION_FILE = "mylocation.json"; let location; var sunRise = "--:--"; @@ -72,7 +72,7 @@ function drawSpecial() { g.setFontAlign(0,0).setFont(settings.specialFont, settings.specialFontSize); var y = Bangle.appRect.y + g.stringMetrics("00:00").height/2; g.clearRect(Bangle.appRect.x, Bangle.appRect.y, Bangle.appRect.x2, Bangle.appRect.y+g.stringMetrics("00:00").height); - + if (stopwatches.length) { time = timerclk.getTime(stopwatches[stopwatch]); g.drawString(timerclk.formatTime(time, true), x, y); @@ -111,7 +111,7 @@ function draw() { var dateStr = require("locale").date(date,settings.shortDate).toUpperCase(); var dowStr = require("locale").dow(date).toUpperCase(); var srssStr = sunRise + sunIcons + sunSet; - + // draw time if (settings.timeFont == "Anton") { g.setFontAlign(0,0).setFont("Anton"); diff --git a/apps/timerclk/metadata.json b/apps/timerclk/metadata.json index 899eda59d..5bd6bee24 100644 --- a/apps/timerclk/metadata.json +++ b/apps/timerclk/metadata.json @@ -1,8 +1,8 @@ -{ +{ "id": "timerclk", "name": "Timer Clock", "shortName":"Timer Clock", - "version":"0.03", + "version":"0.04", "description": "A clock with stopwatches, timers and alarms build in.", "icon": "app-icon.png", "type": "clock", diff --git a/apps/sunclock/suncalc.js b/modules/suncalc.js similarity index 76% rename from apps/sunclock/suncalc.js rename to modules/suncalc.js index b1af0a0d9..0c22c6cb2 100644 --- a/apps/sunclock/suncalc.js +++ b/modules/suncalc.js @@ -1,17 +1,34 @@ -/* Module suncalc.js +/* (c) 2011-2015, Vladimir Agafonkin SunCalc is a JavaScript library for calculating sun/moon position and light phases. https://github.com/mourner/suncalc -PB: Usage: -E.setTimeZone(2); // 1 = MEZ, 2 = MESZ -SunCalc = require("suncalc.js"); -pos = SunCalc.getPosition(Date.now(), 53.3, 10.1); -times = SunCalc.getTimes(Date.now(), 53.3, 10.1); -rise = times.sunrise; // Date object -rise_str = rise.getHours() + ':' + rise.getMinutes(); //hh:mm +Copyright (c) 2014, Vladimir Agafonkin +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are +permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this list of + conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, this list + of conditions and the following disclaimer in the documentation and/or other materials + provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR +TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ -var exports={}; + +(function () { 'use strict'; // shortcuts for easier to read formulas @@ -26,6 +43,7 @@ var PI = Math.PI, // sun calculations are based on http://aa.quae.nl/en/reken/zonpositie.html formulas + // date/time constants and conversions var dayMs = 1000 * 60 * 60 * 24, @@ -33,7 +51,7 @@ var dayMs = 1000 * 60 * 60 * 24, J2000 = 2451545; function toJulian(date) { return date.valueOf() / dayMs - 0.5 + J1970; } -function fromJulian(j) { return new Date((j + 0.5 - J1970) * dayMs); } // PB: onece removed + 0.5; included it again 4 Jan 2021 +function fromJulian(j) { return new Date((j + 0.5 - J1970) * dayMs); } function toDays(date) { return toJulian(date) - J2000; } @@ -81,9 +99,13 @@ function sunCoords(d) { }; } + +var SunCalc = {}; + + // calculates sun position for a given date and latitude/longitude -exports.getPosition = function (date, lat, lng) { +SunCalc.getPosition = function (date, lat, lng) { var lw = rad * -lng, phi = rad * lat, @@ -93,19 +115,32 @@ exports.getPosition = function (date, lat, lng) { H = siderealTime(d, lw) - c.ra; return { - azimuth: Math.round((azimuth(H, phi, c.dec) / rad + 180) % 360), // PB: converted to deg - altitude: Math.round( altitude(H, phi, c.dec) / rad) // PB: converted to deg + azimuth: azimuth(H, phi, c.dec), + altitude: altitude(H, phi, c.dec) }; }; // sun times configuration (angle, morning name, evening name) -var times = [ - [-0.833, 'sunrise', 'sunset' ] +var times = SunCalc.times = [ + [-0.833, 'sunrise', 'sunset' ], + [ -0.3, 'sunriseEnd', 'sunsetStart' ], + [ -6, 'dawn', 'dusk' ], + [ -12, 'nauticalDawn', 'nauticalDusk'], + [ -18, 'nightEnd', 'night' ], + [ 6, 'goldenHourEnd', 'goldenHour' ] ]; +// adds a custom time to the times config + +SunCalc.addTime = function (angle, riseName, setName) { + times.push([angle, riseName, setName]); +}; + + // calculations for sun times + var J0 = 0.0009; function julianCycle(d, lw) { return Math.round(d - J0 - lw / (2 * PI)); } @@ -128,7 +163,7 @@ function getSetJ(h, lw, phi, dec, n, M, L) { // calculates sun times for a given date, latitude/longitude, and, optionally, // the observer height (in meters) relative to the horizon -exports.getTimes = function (date, lat, lng, height) { +SunCalc.getTimes = function (date, lat, lng, height) { height = height || 0; @@ -189,7 +224,7 @@ function moonCoords(d) { // geocentric ecliptic coordinates of the moon }; } -getMoonPosition = function (date, lat, lng) { +SunCalc.getMoonPosition = function (date, lat, lng) { var lw = rad * -lng, phi = rad * lat, @@ -216,7 +251,7 @@ getMoonPosition = function (date, lat, lng) { // based on http://idlastro.gsfc.nasa.gov/ftp/pro/astro/mphase.pro formulas and // Chapter 48 of "Astronomical Algorithms" 2nd edition by Jean Meeus (Willmann-Bell, Richmond) 1998. -getMoonIllumination = function (date) { +SunCalc.getMoonIllumination = function (date) { var d = toDays(date || new Date()), s = sunCoords(d), @@ -243,7 +278,7 @@ function hoursLater(date, h) { // calculations for moon rise/set times are based on http://www.stargazing.net/kepler/moonrise.html article -getMoonTimes = function (date, lat, lng, inUTC) { +SunCalc.getMoonTimes = function (date, lat, lng, inUTC) { var t = new Date(date); if (inUTC) t.setUTCHours(0, 0, 0, 0); else t.setHours(0, 0, 0, 0); @@ -295,4 +330,12 @@ getMoonTimes = function (date, lat, lng, inUTC) { if (!rise && !set) result[ye > 0 ? 'alwaysUp' : 'alwaysDown'] = true; return result; -}; \ No newline at end of file +}; + + +// export as Node module / AMD module / browser variable +if (typeof exports === 'object' && typeof module !== 'undefined') module.exports = SunCalc; +else if (typeof define === 'function' && define.amd) define(SunCalc); +else window.SunCalc = SunCalc; + +}()); From 7a2af0e61d9cd4260d3f30d382a0946ce2fb7e93 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Fri, 9 Dec 2022 09:52:34 +0000 Subject: [PATCH 098/110] Fixing warnings --- apps/espruinoprog/metadata.json | 3 ++- apps/hourstrike/metadata.json | 3 ++- apps/imageclock/app.js | 2 +- apps/presentor/metadata.json | 3 ++- bin/sanitycheck.js | 1 + 5 files changed, 8 insertions(+), 4 deletions(-) diff --git a/apps/espruinoprog/metadata.json b/apps/espruinoprog/metadata.json index ebb55b23d..7371e005d 100644 --- a/apps/espruinoprog/metadata.json +++ b/apps/espruinoprog/metadata.json @@ -11,7 +11,8 @@ "custom": "custom.html", "storage": [ {"name":"espruinoprog.app.js","url":"app.js"}, - {"name":"espruinoprog.img","url":"app-icon.js","evaluate":true}, + {"name":"espruinoprog.img","url":"app-icon.js","evaluate":true} + ], "data": [ {"name":"espruinoprog.json"} ] } diff --git a/apps/hourstrike/metadata.json b/apps/hourstrike/metadata.json index 614db54e4..d0ddb511a 100644 --- a/apps/hourstrike/metadata.json +++ b/apps/hourstrike/metadata.json @@ -11,7 +11,8 @@ "storage": [ {"name":"hourstrike.app.js","url":"app.js"}, {"name":"hourstrike.boot.js","url":"boot.js"}, - {"name":"hourstrike.img","url":"app-icon.js","evaluate":true}, + {"name":"hourstrike.img","url":"app-icon.js","evaluate":true} + ], "data" : [ {"name":"hourstrike.json","url":"hourstrike.json"} ] } diff --git a/apps/imageclock/app.js b/apps/imageclock/app.js index 374e73070..dc21d7162 100644 --- a/apps/imageclock/app.js +++ b/apps/imageclock/app.js @@ -622,7 +622,7 @@ s.pl = {}; endPerfLog("fullDraw", true); if (!Bangle.uiRemove){ - setUi(); + setUi(); // Calls Bangle.setUI() (this comment also fixes lint warning) let orig = Bangle.drawWidgets; Bangle.drawWidgets = ()=>{}; Bangle.loadWidgets(); diff --git a/apps/presentor/metadata.json b/apps/presentor/metadata.json index e5b5e289f..2d0a22102 100644 --- a/apps/presentor/metadata.json +++ b/apps/presentor/metadata.json @@ -12,7 +12,8 @@ "allow_emulator": true, "storage": [ {"name":"presentor.app.js","url":"app.js"}, - {"name":"presentor.img","url":"app-icon.js","evaluate":true}, + {"name":"presentor.img","url":"app-icon.js","evaluate":true} + ], "data": [ {"name":"presentor.json","url":"settings.json"} ] } diff --git a/bin/sanitycheck.js b/bin/sanitycheck.js index 5af6f1aa1..8bec3a9a1 100755 --- a/bin/sanitycheck.js +++ b/bin/sanitycheck.js @@ -94,6 +94,7 @@ const INTERNAL_FILES_IN_APP_TYPE = { // list of app types and files they SHOULD var KNOWN_WARNINGS = [ "App gpsrec data file wildcard .gpsrc? does not include app ID", "App widmessages storage file messagewidget is also listed as storage file for app widmsggrid", +"App owmweather data file weather.json is also listed as data file for app weather", ]; function globToRegex(pattern) { From a0d3d15dbf5997e9b5741f3b26281fb4a98bb203 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Fri, 9 Dec 2022 09:52:44 +0000 Subject: [PATCH 099/110] Use 'modules/suncalc.js' to avoid it being copied 8 times for different apps + Add a 'time' clockinfo that also displays a percentage of day left --- apps/clkinfosunrise/ChangeLog | 2 + apps/clkinfosunrise/clkinfo.js | 64 ++++++++++++++++++++++++------- apps/clkinfosunrise/metadata.json | 2 +- 3 files changed, 53 insertions(+), 15 deletions(-) diff --git a/apps/clkinfosunrise/ChangeLog b/apps/clkinfosunrise/ChangeLog index 5560f00bc..9854c6b53 100644 --- a/apps/clkinfosunrise/ChangeLog +++ b/apps/clkinfosunrise/ChangeLog @@ -1 +1,3 @@ 0.01: New App! +0.02: Use 'modules/suncalc.js' to avoid it being copied 8 times for different apps + Add a 'time' clockinfo that also displays a percentage of day left diff --git a/apps/clkinfosunrise/clkinfo.js b/apps/clkinfosunrise/clkinfo.js index 1454a83f3..93bdfad41 100644 --- a/apps/clkinfosunrise/clkinfo.js +++ b/apps/clkinfosunrise/clkinfo.js @@ -1,32 +1,68 @@ (function() { // get today's sunlight times for lat/lon - var sunrise, sunset; + var sunrise, sunset, date; + var SunCalc = require("suncalc"); // from modules folder + const locale = require("locale"); function calculate() { - var SunCalc = require("https://raw.githubusercontent.com/mourner/suncalc/master/suncalc.js"); - const locale = require("locale"); var location = require("Storage").readJSON("mylocation.json",1)||{}; location.lat = location.lat||51.5072; - location.lon = location.lon||0.1276; - location.location = location.location||"London"; - var times = SunCalc.getTimes(new Date(), location.lat, location.lon); - sunrise = locale.time(times.sunrise,1); - sunset = locale.time(times.sunset,1); + location.lon = location.lon||0.1276; // London + date = new Date(Date.now()); + var times = SunCalc.getTimes(date, location.lat, location.lon); + sunrise = times.sunrise; + sunset = times.sunset; /* do we want to re-calculate this every day? Or we just assume that 'show' will get called once a day? */ } + function show() { + this.interval = setTimeout(()=>{ + this.emit("redraw"); + this.interval = setInterval(()=>{ + this.emit("redraw"); + }, 60000); + }, 60000 - (Date.now() % 60000)); + } + function hide() { + clearInterval(this.interval); + this.interval = undefined; + } + return { name: "Bangle", items: [ { name : "Sunrise", - get : () => ({ text : sunrise, - img : atob("GBiBAAAAAAAAAAAAAAAYAAA8AAB+AAD/AAAAAAAAAAAAAAAYAAAYAAQYIA4AcAYAYAA8AAB+AAD/AAH/gD///D///AAAAAAAAAAAAA==") }), - show : calculate, hide : () => {} + get : () => { calculate(); + return { text : locale.time(sunrise,1), + img : atob("GBiBAAAAAAAAAAAAAAAYAAA8AAB+AAD/AAAAAAAAAAAAAAAYAAAYAAQYIA4AcAYAYAA8AAB+AAD/AAH/gD///D///AAAAAAAAAAAAA==") }}, + show : show, hide : hide }, { name : "Sunset", - get : () => ({ text : sunset, - img : atob("GBiBAAAAAAAAAAAAAAB+AAA8AAAYAAAYAAAAAAAAAAAAAAAYAAAYAAQYIA4AcAYAYAA8AAB+AAD/AAH/gD///D///AAAAAAAAAAAAA==") }), - show : calculate, hide : () => {} + get : () => { calculate(); + return { text : locale.time(sunset,1), + img : atob("GBiBAAAAAAAAAAAAAAB+AAA8AAAYAAAYAAAAAAAAAAAAAAAYAAAYAAQYIA4AcAYAYAA8AAB+AAD/AAH/gD///D///AAAAAAAAAAAAA==") }}, + show : show, hide : hide + }, { name : "Time", // Time in day (uses v/min/max to show percentage through day) + get : () => { + calculate(); + let day = true; + let v = 0; + let d = date.getTime(); + let dayLength = sunset.getTime()-sunrise.getTime(); + if (d < sunrise.getTime()) { + day = false; // early morning + v = 100 - Math.round(100 * (sunrise.getTime()-d) / (86400000-dayLength)); + } else if (d > sunset.getTime()) { + day = false; // evening + v = Math.round(100 * (d-sunset.getTime()) / (86400000-dayLength)); + } else { // day! + v = Math.round(100 * (d-sunrise.getTime()) / dayLength); + } + return { text : locale.time(date,1), v : v, min : 0, max : 100, + img : day ? atob("GBiBAAAYAAAYAAAYAAgAEBwAOAx+MAD/AAH/gAP/wAf/4Af/4Of/5+f/5wf/4Af/4AP/wAH/gAD/AAx+MBwAOAgAEAAYAAAYAAAYAA==") : atob("GBiBAAfwAA/8AAP/AAH/gAD/wAB/wAB/4AA/8AA/8AA/8AAf8AAf8AAf8AAf8AA/8AA/8AA/4AB/4AB/wAD/wAH/gAf/AA/8AAfwAA==") + } + }, + show : show, hide : hide } ] }; diff --git a/apps/clkinfosunrise/metadata.json b/apps/clkinfosunrise/metadata.json index f8b68e11f..74877c523 100644 --- a/apps/clkinfosunrise/metadata.json +++ b/apps/clkinfosunrise/metadata.json @@ -1,6 +1,6 @@ { "id": "clkinfosunrise", "name": "Sunrise Clockinfo", - "version":"0.01", + "version":"0.02", "description": "For clocks that display 'clockinfo' (messages that can be cycled through using the clock_info module) this displays sunrise and sunset based on the location from the 'My Location' app", "icon": "app.png", "type": "clkinfo", From e303c15ac27fb513bf98fe7c18f94bdce16b8f82 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Fri, 9 Dec 2022 10:32:16 +0000 Subject: [PATCH 100/110] faster circles rendering --- apps/circlesclock/ChangeLog | 1 + apps/circlesclock/app.js | 21 ++++++++++++--------- apps/circlesclock/metadata.json | 2 +- 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/apps/circlesclock/ChangeLog b/apps/circlesclock/ChangeLog index 9e36f67ba..262228ff0 100644 --- a/apps/circlesclock/ChangeLog +++ b/apps/circlesclock/ChangeLog @@ -34,3 +34,4 @@ 0.18: Improved clkinfo handling and using it for the weather circle 0.19: Remove old code and fixing clkinfo handling (fix HRM and other items that change) Remove settings for what is displayed and instead allow circles to be changed by swiping +0.20: Add much faster circle rendering (250ms -> 40ms) diff --git a/apps/circlesclock/app.js b/apps/circlesclock/app.js index efd0b0aa6..5585d7145 100644 --- a/apps/circlesclock/app.js +++ b/apps/circlesclock/app.js @@ -288,8 +288,7 @@ function drawInnerCircleAndTriangle(w) { function drawGauge(cx, cy, percent, color) { let offset = 15; let end = 360 - offset; - let radius = radiusInner + (circleCount == 3 ? 3 : 2); - let size = radiusOuter - radiusInner - 2; + let radius = radiusOuter+1; if (percent <= 0) return; // no gauge needed if (percent > 1) percent = 1; @@ -299,14 +298,18 @@ function drawGauge(cx, cy, percent, color) { color = getGradientColor(color, percent); g.setColor(color); - - // FIXME: this one loop takes 0.25 sec EACH TIME the function is called - for (let i = startRotation; i > endRotation - size; i -= size) { - let r = i * Math.PI / 180; // radians - g.fillCircle( + // convert to radians + startRotation *= Math.PI / 180; + let amt = Math.PI / 10; + endRotation = (endRotation * Math.PI / 180) - amt; + // all we need to draw is an arc, because we'll fill the center + let poly = [cx,cy]; + for (let r = startRotation; r > endRotation; r -= amt) + poly.push( cx + radius * Math.sin(r), - cy + radius * Math.cos(r), size); - } + cy + radius * Math.cos(r) + ); + g.fillPoly(poly); } function writeCircleText(w, content) { diff --git a/apps/circlesclock/metadata.json b/apps/circlesclock/metadata.json index 3b436a032..fb66c064e 100644 --- a/apps/circlesclock/metadata.json +++ b/apps/circlesclock/metadata.json @@ -1,7 +1,7 @@ { "id": "circlesclock", "name": "Circles clock", "shortName":"Circles clock", - "version":"0.19", + "version":"0.20", "description": "A clock with three or four circles for different data at the bottom in a probably familiar style", "icon": "app.png", "screenshots": [{"url":"screenshot-dark.png"}, {"url":"screenshot-light.png"}, {"url":"screenshot-dark-4.png"}, {"url":"screenshot-light-4.png"}], From d33106bc8fea127e91074c39112599a9f3ee9167 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Fri, 9 Dec 2022 10:32:35 +0000 Subject: [PATCH 101/110] Allow sunrise to show a 'range' --- apps/clkinfosunrise/clkinfo.js | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/clkinfosunrise/clkinfo.js b/apps/clkinfosunrise/clkinfo.js index 93bdfad41..b31cc22ba 100644 --- a/apps/clkinfosunrise/clkinfo.js +++ b/apps/clkinfosunrise/clkinfo.js @@ -43,6 +43,7 @@ img : atob("GBiBAAAAAAAAAAAAAAB+AAA8AAAYAAAYAAAAAAAAAAAAAAAYAAAYAAQYIA4AcAYAYAA8AAB+AAD/AAH/gD///D///AAAAAAAAAAAAA==") }}, show : show, hide : hide }, { name : "Time", // Time in day (uses v/min/max to show percentage through day) + hasRange : true, get : () => { calculate(); let day = true; From 117560ffedc26f14968202a89a0caa6116f0daf0 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Fri, 9 Dec 2022 10:32:45 +0000 Subject: [PATCH 102/110] Fix 'srcs' being defined in global scope --- apps/widmessages/ChangeLog | 3 ++- apps/widmessages/metadata.json | 2 +- apps/widmessages/widget.js | 3 +-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/widmessages/ChangeLog b/apps/widmessages/ChangeLog index 3a41005e9..f82b8a310 100644 --- a/apps/widmessages/ChangeLog +++ b/apps/widmessages/ChangeLog @@ -1 +1,2 @@ -0.01: Moved messages widget into standalone widget app \ No newline at end of file +0.01: Moved messages widget into standalone widget app +0.02: Fix 'srcs' being defined in global scope diff --git a/apps/widmessages/metadata.json b/apps/widmessages/metadata.json index 080e19273..bf88ca401 100644 --- a/apps/widmessages/metadata.json +++ b/apps/widmessages/metadata.json @@ -1,7 +1,7 @@ { "id": "widmessages", "name": "Message Widget", - "version": "0.01", + "version": "0.02", "description": "Widget showing new messages", "icon": "app.png", "type": "widget", diff --git a/apps/widmessages/widget.js b/apps/widmessages/widget.js index 2ee11b690..743833c77 100644 --- a/apps/widmessages/widget.js +++ b/apps/widmessages/widget.js @@ -18,7 +18,7 @@ if (!this.width) return; let settings = Object.assign({flash: true, maxMessages: 3}, require("Storage").readJSON("messages.settings.json", true) || {}); if (recall!==true || settings.flash) { - const msgsShown = E.clip(this.srcs.length, 0, settings.maxMessages), + const msgsShown = E.clip(this.srcs.length, 0, settings.maxMessages); srcs = Object.keys(this.srcs); g.reset().clearRect(this.x, this.y, this.x+this.width, this.y+23); for(let i = 0; i Date: Fri, 9 Dec 2022 10:33:38 +0000 Subject: [PATCH 103/110] Add fast load capability --- apps/circlesclock/ChangeLog | 1 + apps/circlesclock/app.js | 58 +++++++++++++++---------------------- 2 files changed, 24 insertions(+), 35 deletions(-) diff --git a/apps/circlesclock/ChangeLog b/apps/circlesclock/ChangeLog index 262228ff0..da6066e32 100644 --- a/apps/circlesclock/ChangeLog +++ b/apps/circlesclock/ChangeLog @@ -35,3 +35,4 @@ 0.19: Remove old code and fixing clkinfo handling (fix HRM and other items that change) Remove settings for what is displayed and instead allow circles to be changed by swiping 0.20: Add much faster circle rendering (250ms -> 40ms) + Add fast load capability diff --git a/apps/circlesclock/app.js b/apps/circlesclock/app.js index 5585d7145..7f7e49032 100644 --- a/apps/circlesclock/app.js +++ b/apps/circlesclock/app.js @@ -1,6 +1,3 @@ -let clock_info = require("clock_info"); -let locale = require("locale"); -let storage = require("Storage"); Graphics.prototype.setFontRobotoRegular50NumericOnly = function(scale) { // Actual height 39 (40 - 2) this.setFontCustom(atob("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAAAAB8AAAAAAAfAAAAAAAPwAAAAAAB8AAAAAAAeAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAA4AAAAAAB+AAAAAAD/gAAAAAD/4AAAAAH/4AAAAAP/wAAAAAP/gAAAAAf/gAAAAAf/AAAAAA/+AAAAAB/+AAAAAB/8AAAAAD/4AAAAAH/4AAAAAD/wAAAAAA/wAAAAAAPgAAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA///wAAAB////gAAA////8AAA/////gAAP////8AAH8AAA/gAB8AAAD4AA+AAAAfAAPAAAADwADwAAAA8AA8AAAAPAAPAAAADwADwAAAA8AA8AAAAPAAPgAAAHwAB8AAAD4AAfwAAD+AAD/////AAA/////wAAH////4AAAf///4AAAB///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeAAAAAAAPgAAAAAADwAAAAAAB8AAAAAAAfAAAAAAAHgAAAAAAD4AAAAAAA+AAAAAAAPAAAAAAAH/////wAB/////8AA//////AAP/////wAD/////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOAAAAAAAfgAADwAAP4AAB8AAH+AAA/AAD/gAAfwAB/AAAf8AAfAAAP/AAPgAAH7wAD4AAD88AA8AAB+PAAPAAA/DwADwAAfg8AA8AAPwPAAPAAH4DwADwAH8A8AA+AD+APAAPwB/ADwAB/D/gA8AAf//gAPAAD//wADwAAf/wAA8AAD/4AAPAAAHwAADwAAAAAAA8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAADgAAAHwAA+AAAD8AAP4AAB/AAD/AAA/wAA/wAAf4AAD+AAHwAAAPgAD4APAB8AA+ADwAPAAPAA8ADwADwAPAA8AA8ADwAPAAPAA8ADwADwAfAA8AA8AH4APAAPgD+AHwAB8B/wD4AAf7/+B+AAD//v//AAA//x//wAAD/4P/4AAAf8B/4AAAAYAH4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPAAAAAAAHwAAAAAAH8AAAAAAD/AAAAAAD/wAAAAAD/8AAAAAB/vAAAAAB/jwAAAAA/g8AAAAA/wPAAAAAfwDwAAAAf4A8AAAAf4APAAAAP8ADwAAAP8AA8AAAH8AAPAAAD/////8AA//////AAP/////wAD/////8AA//////AAAAAAPAAAAAAADwAAAAAAA8AAAAAAAPAAAAAAADwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8AAAAB/APwAAH//wD+AAD//8A/wAA///AH+AAP//wAPgAD/B4AB8AA8A+AAfAAPAPAADwADwDwAA8AA8A8AAPAAPAPAADwADwD4AA8AA8A+AAPAAPAPwAHwADwD8AD4AA8AfwD+AAPAH///AADwA///wAA8AH//4AAPAAf/4AAAAAB/4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//AAAAAD//+AAAAD///4AAAD////AAAB////4AAA/78D/AAAfw8AH4AAPweAA+AAD4PgAHwAB8DwAA8AAfA8AAPAAHgPAADwAD4DwAA8AA+A8AAPAAPAPgAHwADwD4AB8AA8AfgA+AAPAH+B/gAAAA///wAAAAH//4AAAAA//8AAAAAH/8AAAAAAP4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwAAAAAAA8AAAAAAAPAAAAAAADwAAAAAAA8AAAABAAPAAAABwADwAAAB8AA8AAAB/AAPAAAB/wADwAAD/8AA8AAD/8AAPAAD/4AADwAD/4AAA8AD/4AAAPAH/wAAADwH/wAAAA8H/wAAAAPH/wAAAAD3/gAAAAA//gAAAAAP/gAAAAAD/gAAAAAA/AAAAAAAPAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwA/4AAAH/Af/AAAH/8P/4AAD//n//AAA//7//4AAfx/+A+AAHwD+AHwAD4AfgB8AA8AHwAPAAPAA8ADwADwAPAA8AA8ADwAPAAPAA8ADwADwAfAA8AA+AH4AfAAHwD+AHwAB/D/4D4AAP/+/n+AAD//n//AAAf/w//gAAB/wH/wAAAHwA/4AAAAAABgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB+AAAAAAD/8AAAAAD//wAAAAB//+AAAAA///wAAAAf4H+APAAH4AfgDwAD8AB8A8AA+AAfAPAAPAADwDwADwAA8B8AA8AAPAfAAPAADwHgADwAA8D4AA+AAeB+AAHwAHg/AAB+ADwfgAAP8D4/4AAD////8AAAf///8AAAB///+AAAAP//+AAAAAP/4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADgAAOAAAB8AAHwAAAfgAD8AAAH4AA/AAAB8AAHwAAAOAAA4AAAAAAAAAAAAAAAAAAAAAAAAAA"), 46, atob("DRUcHBwcHBwcHBwcDA=="), 50+(scale<<8)+(1<<16)); @@ -13,6 +10,11 @@ Graphics.prototype.setFontRobotoRegular21 = function(scale) { return this; }; +{ +let clock_info = require("clock_info"); +let locale = require("locale"); +let storage = require("Storage"); + let SETTINGS_FILE = "circlesclock.json"; let settings = Object.assign( storage.readJSON("circlesclock.default.json", true) || {}, @@ -79,7 +81,7 @@ let circleFontBig = circleCount == 3 ? "Vector:16" : "Vector:12"; let iconOffset = circleCount == 3 ? 6 : 8; -function draw() { +let draw = function() { let R = Bangle.appRect; g.reset().clearRect(R.x,R.y, R.x2, h3-(radiusBorder+1)); @@ -126,13 +128,13 @@ function draw() { queueDraw(); } -function getCircleColor(index) { +let getCircleColor = function(index) { let color = settings["circle" + index + "color"]; if (color && color != "") return color; return g.theme.fg; } -function getGradientColor(color, percent) { +let getGradientColor = function(color, percent) { if (isNaN(percent)) percent = 0; if (percent > 1) percent = 1; let colorList = [ @@ -152,7 +154,7 @@ function getGradientColor(color, percent) { return color; } -function getCircleIconColor(index, color, percent) { +let getCircleIconColor = function(index, color, percent) { let colorizeIcon = settings["circle" + index + "colorizeIcon"] == true; if (colorizeIcon) { return getGradientColor(color, percent); @@ -161,7 +163,7 @@ function getCircleIconColor(index, color, percent) { } } -function drawEmpty(img, w, color) { +let drawEmpty = function(img, w, color) { drawGauge(w, h3, 0, color); drawInnerCircleAndTriangle(w); writeCircleText(w, "?"); @@ -170,7 +172,7 @@ function drawEmpty(img, w, color) { .drawImage(img, w - iconOffset, h3 + radiusOuter - iconOffset, {scale: 16/24}); } -function drawCircle(index, item, data) { +let drawCircle = function(index, item, data) { var w = circlePosX[index-1]; drawCircleBackground(w); const color = getCircleColor(index); @@ -193,7 +195,7 @@ function drawCircle(index, item, data) { * Choose weather icon to display based on weather conditition code * https://openweathermap.org/weather-conditions#Weather-Condition-Codes-2 */ -function getWeatherIconByCode(code, big) { +let getWeatherIconByCode = function(code, big) { let codeGroup = Math.round(code / 100); if (big == undefined) big = false; @@ -251,21 +253,10 @@ function getWeatherIconByCode(code, big) { } } -function formatSeconds(s) { - if (s > 60 * 60) { // hours - return Math.round(s / (60 * 60)) + "h"; - } - if (s > 60) { // minutes - return Math.round(s / 60) + "m"; - } - return "<1m"; -} - - /* * Draws the background and the grey circle */ -function drawCircleBackground(w) { +let drawCircleBackground = function(w) { // Draw rectangle background: g.setColor(colorBg); g.fillRect(w - radiusBorder, h3 - radiusBorder, w + radiusBorder, g.getHeight()-1); @@ -274,7 +265,7 @@ function drawCircleBackground(w) { g.fillCircle(w, h3, radiusOuter); } -function drawInnerCircleAndTriangle(w) { +let drawInnerCircleAndTriangle = function(w) { // Draw inner circle g.setColor(colorBg); g.fillCircle(w, h3, radiusInner); @@ -285,7 +276,7 @@ function drawInnerCircleAndTriangle(w) { /* * This draws the actual gauge consisting out of lots of little filled circles */ -function drawGauge(cx, cy, percent, color) { +let drawGauge = function(cx, cy, percent, color) { let offset = 15; let end = 360 - offset; let radius = radiusOuter+1; @@ -312,7 +303,7 @@ function drawGauge(cx, cy, percent, color) { g.fillPoly(poly); } -function writeCircleText(w, content) { +let writeCircleText = function(w, content) { if (content == undefined) return; let font = String(content).length > 4 ? circleFontSmall : String(content).length > 3 ? circleFont : circleFontBig; g.setFont(font); @@ -322,7 +313,7 @@ function writeCircleText(w, content) { g.drawString(content, w, h3); } -function getWeather() { +let getWeather=function() { let jsonWeather = storage.readJSON('weather.json'); return jsonWeather && jsonWeather.weather ? jsonWeather.weather : undefined; } @@ -331,18 +322,14 @@ g.clear(1); // clear the whole screen Bangle.setUI({ mode : "clock", - /*remove : function() { - THIS CLOCK IS NOT YET ABLE TO UNLOAD ALL OF ITSELF. - DO NOT UNCOMMENT THIS WITOUT FIXING IT - OR THERE WILL BE HUGE MEMORY LEAKS - // Called to unload all of the clock app + remove : function() { + // Called to unload all of the clock app (allowing for 'fast load') if (drawTimeout) clearTimeout(drawTimeout); drawTimeout = undefined; - for(var i=1;i<=circleCount; i++) - clockInfoMenu[i].remove(); + clockInfoMenu.forEach(c => c.remove()); delete Graphics.prototype.setFontRobotoRegular50NumericOnly; delete Graphics.prototype.setFontRobotoRegular21; - }*/ + } }); let clockInfoDraw = (itm, info, options) => { @@ -366,7 +353,7 @@ if (!showWidgets) require("widget_utils").hide(); else Bangle.drawWidgets(); // schedule a draw for the next second or minute -function queueDraw() { +let queueDraw=function() { let queueMillis = settings.updateInterval * 1000; if (drawTimeout) clearTimeout(drawTimeout); drawTimeout = setTimeout(function() { @@ -376,3 +363,4 @@ function queueDraw() { } draw(); +} From 79acfbb5a8ac28dd204e2c594e575550609ea085 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Fri, 9 Dec 2022 13:14:02 +0000 Subject: [PATCH 104/110] Calendar clockinfo --- apps/clkinfocal/ChangeLog | 1 + apps/clkinfocal/app.png | Bin 0 -> 901 bytes apps/clkinfocal/clkinfo.js | 32 ++++++++++++++++++++++++++++++++ apps/clkinfocal/metadata.json | 12 ++++++++++++ 4 files changed, 45 insertions(+) create mode 100644 apps/clkinfocal/ChangeLog create mode 100644 apps/clkinfocal/app.png create mode 100644 apps/clkinfocal/clkinfo.js create mode 100644 apps/clkinfocal/metadata.json diff --git a/apps/clkinfocal/ChangeLog b/apps/clkinfocal/ChangeLog new file mode 100644 index 000000000..5560f00bc --- /dev/null +++ b/apps/clkinfocal/ChangeLog @@ -0,0 +1 @@ +0.01: New App! diff --git a/apps/clkinfocal/app.png b/apps/clkinfocal/app.png new file mode 100644 index 0000000000000000000000000000000000000000..ed79cd884b54dc076665137caedbdcc1e21962c1 GIT binary patch literal 901 zcmV;01A6?4P)L)Chr)I}5{4KBxs*>drsWb|(+{ z`eX*c3AG?od-GwSG@uo!W#G_b8fZ7vCVtp4)v7#dGKtr!$EgN4;2#VXL(hv2dd3TGN!8sa)BjmJbkP|)vUz6BO_(u zuyPpl4)1BtyXRm4q^{jW-sguU5`^>393t;uBF-_2^}Bj5^AX`f0)Ezw8{8#@)`Ow9 z(TtP@0Hmc%g(j&403h#^|NrEB`{k1-;;QR+b+{n!3l-w3x_$$sayYCU0J)aSb;&8$ ztR)hZ=de5%d5`M)UF~Px0D%5ZUR75NN{X69Qu=y82z*0q_L1Va_wEDOPM^_pikkE~ z)q8+yAe!2!Ft8F`lb<414&%O&3O%%$LumdPnB)eEE-(BOx3GS!TXX%mZv=Dc1%!5L ze#&uKq08|(J@q$nx~hiDwQckq;2dH;I5OU4Q#vp { + let d = new Date(); + let g = Graphics.createArrayBuffer(24,24,1,{msb:true}); + g.drawImage(atob("FhgBDADAMAMP/////////////////////8AADwAAPAAA8AADwAAPAAA8AADwAAPAAA8AADwAAPAAA8AADwAAP///////"),1,0); + g.setFont("6x15").setFontAlign(0,0).drawString(d.getDate(),11,17); + return { + text : require("locale").dow(d,1).toUpperCase(), + img : g.asImage("string") + }; + }, + show : function() { + this.interval = setTimeout(()=>{ + this.emit("redraw"); + this.interval = setInterval(()=>{ + this.emit("redraw"); + }, 86400000); + }, 86400000 - (Date.now() % 86400000)); + }, + hide : function() { + clearInterval(this.interval); + this.interval = undefined; + } + } + ] + }; +}) diff --git a/apps/clkinfocal/metadata.json b/apps/clkinfocal/metadata.json new file mode 100644 index 000000000..6d6dd63fc --- /dev/null +++ b/apps/clkinfocal/metadata.json @@ -0,0 +1,12 @@ +{ "id": "clkinfocal", + "name": "Calendar Clockinfo", + "version":"0.01", + "description": "For clocks that display 'clockinfo' (messages that can be cycled through using the clock_info module) this displays the day of the month in the icon, and the weekday", + "icon": "app.png", + "type": "clkinfo", + "tags": "clkinfo,calendar", + "supports" : ["BANGLEJS2"], + "storage": [ + {"name":"clkinfocal.clkinfo.js","url":"clkinfo.js"} + ] +} From a115c3f86254fe098d2b2dddf0f1a46003d8bc30 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Fri, 9 Dec 2022 13:19:07 +0000 Subject: [PATCH 105/110] Change 3rd mode to show the next sunrise/sunset time (not actual time) --- apps/clkinfosunrise/ChangeLog | 1 + apps/clkinfosunrise/clkinfo.js | 4 ++-- apps/clkinfosunrise/metadata.json | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/apps/clkinfosunrise/ChangeLog b/apps/clkinfosunrise/ChangeLog index 9854c6b53..d50fb06f4 100644 --- a/apps/clkinfosunrise/ChangeLog +++ b/apps/clkinfosunrise/ChangeLog @@ -1,3 +1,4 @@ 0.01: New App! 0.02: Use 'modules/suncalc.js' to avoid it being copied 8 times for different apps Add a 'time' clockinfo that also displays a percentage of day left +0.03: Change 3rd mode to show the next sunrise/sunset time (not actual time) diff --git a/apps/clkinfosunrise/clkinfo.js b/apps/clkinfosunrise/clkinfo.js index b31cc22ba..71031e1d5 100644 --- a/apps/clkinfosunrise/clkinfo.js +++ b/apps/clkinfosunrise/clkinfo.js @@ -42,7 +42,7 @@ return { text : locale.time(sunset,1), img : atob("GBiBAAAAAAAAAAAAAAB+AAA8AAAYAAAYAAAAAAAAAAAAAAAYAAAYAAQYIA4AcAYAYAA8AAB+AAD/AAH/gD///D///AAAAAAAAAAAAA==") }}, show : show, hide : hide - }, { name : "Time", // Time in day (uses v/min/max to show percentage through day) + }, { name : "Sunrise/set", // Time in day (uses v/min/max to show percentage through day) hasRange : true, get : () => { calculate(); @@ -59,7 +59,7 @@ } else { // day! v = Math.round(100 * (d-sunrise.getTime()) / dayLength); } - return { text : locale.time(date,1), v : v, min : 0, max : 100, + return { text : locale.time(day ? sunset.getTime() : sunrise.getTime(),1), v : v, min : 0, max : 100, img : day ? atob("GBiBAAAYAAAYAAAYAAgAEBwAOAx+MAD/AAH/gAP/wAf/4Af/4Of/5+f/5wf/4Af/4AP/wAH/gAD/AAx+MBwAOAgAEAAYAAAYAAAYAA==") : atob("GBiBAAfwAA/8AAP/AAH/gAD/wAB/wAB/4AA/8AA/8AA/8AAf8AAf8AAf8AAf8AA/8AA/8AA/4AB/4AB/wAD/wAH/gAf/AA/8AAfwAA==") } }, diff --git a/apps/clkinfosunrise/metadata.json b/apps/clkinfosunrise/metadata.json index 74877c523..d130c6453 100644 --- a/apps/clkinfosunrise/metadata.json +++ b/apps/clkinfosunrise/metadata.json @@ -1,6 +1,6 @@ { "id": "clkinfosunrise", "name": "Sunrise Clockinfo", - "version":"0.02", + "version":"0.03", "description": "For clocks that display 'clockinfo' (messages that can be cycled through using the clock_info module) this displays sunrise and sunset based on the location from the 'My Location' app", "icon": "app.png", "type": "clkinfo", From 870ecae41c30e9238ffd09b963159afce1fab816 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Fri, 9 Dec 2022 13:31:55 +0000 Subject: [PATCH 106/110] Change 3rd mode to show the time to next sunrise/sunset time (not actual time) --- apps/clkinfosunrise/ChangeLog | 2 +- apps/clkinfosunrise/clkinfo.js | 16 +++++++++++----- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/apps/clkinfosunrise/ChangeLog b/apps/clkinfosunrise/ChangeLog index d50fb06f4..86e7a7fa8 100644 --- a/apps/clkinfosunrise/ChangeLog +++ b/apps/clkinfosunrise/ChangeLog @@ -1,4 +1,4 @@ 0.01: New App! 0.02: Use 'modules/suncalc.js' to avoid it being copied 8 times for different apps Add a 'time' clockinfo that also displays a percentage of day left -0.03: Change 3rd mode to show the next sunrise/sunset time (not actual time) +0.03: Change 3rd mode to show the time to next sunrise/sunset time (not actual time) diff --git a/apps/clkinfosunrise/clkinfo.js b/apps/clkinfosunrise/clkinfo.js index 71031e1d5..22c507f34 100644 --- a/apps/clkinfosunrise/clkinfo.js +++ b/apps/clkinfosunrise/clkinfo.js @@ -47,19 +47,25 @@ get : () => { calculate(); let day = true; - let v = 0; let d = date.getTime(); let dayLength = sunset.getTime()-sunrise.getTime(); + let timeUntil, timeTotal; if (d < sunrise.getTime()) { day = false; // early morning - v = 100 - Math.round(100 * (sunrise.getTime()-d) / (86400000-dayLength)); + timePast = sunrise.getTime()-d; + timeTotal = 86400000-dayLength; } else if (d > sunset.getTime()) { day = false; // evening - v = Math.round(100 * (d-sunset.getTime()) / (86400000-dayLength)); + timePast = d-sunset.getTime(); + timeTotal = 86400000-dayLength; } else { // day! - v = Math.round(100 * (d-sunrise.getTime()) / dayLength); + timePast = d-sunrise.getTime(); + timeTotal = dayLength; } - return { text : locale.time(day ? sunset.getTime() : sunrise.getTime(),1), v : v, min : 0, max : 100, + let v = Math.round(100 * timePast / timeTotal); + let minutesTo = (timeTotal-timePast)/60000; + return { text : (minutesTo>90) ? (Math.round(minutesTo/60)+"h") : (Math.round(minutesTo)+"m"), + v : v, min : 0, max : 100, img : day ? atob("GBiBAAAYAAAYAAAYAAgAEBwAOAx+MAD/AAH/gAP/wAf/4Af/4Of/5+f/5wf/4Af/4AP/wAH/gAD/AAx+MBwAOAgAEAAYAAAYAAAYAA==") : atob("GBiBAAfwAA/8AAP/AAH/gAD/wAB/wAB/4AA/8AA/8AA/8AAf8AAf8AAf8AAf8AA/8AA/8AA/4AB/4AB/wAD/wAH/gAf/AA/8AAfwAA==") } }, From 25c50d2d97d9b1a4bb986f7f04a5a8aa8d803c38 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Fri, 9 Dec 2022 14:42:33 +0000 Subject: [PATCH 107/110] 0.21: Remade all icons without a palette for dark theme --- apps/circlesclock/ChangeLog | 1 + apps/circlesclock/app.js | 20 ++++++++++---------- apps/circlesclock/metadata.json | 2 +- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/apps/circlesclock/ChangeLog b/apps/circlesclock/ChangeLog index da6066e32..9c3b673aa 100644 --- a/apps/circlesclock/ChangeLog +++ b/apps/circlesclock/ChangeLog @@ -36,3 +36,4 @@ Remove settings for what is displayed and instead allow circles to be changed by swiping 0.20: Add much faster circle rendering (250ms -> 40ms) Add fast load capability +0.21: Remade all icons without a palette for dark theme diff --git a/apps/circlesclock/app.js b/apps/circlesclock/app.js index 7f7e49032..5039488a7 100644 --- a/apps/circlesclock/app.js +++ b/apps/circlesclock/app.js @@ -200,16 +200,16 @@ let getWeatherIconByCode = function(code, big) { if (big == undefined) big = false; // weather icons: - let weatherCloudy = big ? atob("QEDBAP//wxgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AAAAAAAAB//gAAAAAAAP//gAAAAAAD///AAAAAAAf4H+AAAAAAD8AD8AAAAAAfgAH4AAAAAB8AAPwAAAAAPgAAf/AAAAB8AAA//AAAAHgAAB/+AAAAeAAAH/8AAAH4AAAIH4AAB/AAAAAHwAAf8AAAAAPgAD/wAAAAAeAAPwAAAAAB4AB8AAAAAADwAHgAAAAAAPAA+AAAAAAA8ADwAAAAAADwA/AAAAAAAPAH8AAAAAAA8A/wAAAAAAHwH4AAAAAAAfg+AAAAAAAAfHwAAAAAAAA+eAAAAAAAAB54AAAAAAAAHvAAAAAAAAAP8AAAAAAAAA/wAAAAAAAAD/AAAAAAAAAP8AAAAAAAAA/wAAAAAAAAD3gAAAAAAAAeeAAAAAAAAB58AAAAAAAAPj4AAAAAAAB8H4AAAAAAAfgP////////8Af////////gA////////8AAf//////+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==") : atob("EBCBAAAAAAAAAAfgD/Af8H/4//7///////9//z/+AAAAAAAA"); - let weatherSunny = big ? atob("QEDBAP//wxgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8AAAAAAAAADwAAAAAAAAAPAAAAAAAAAA8AAAAAAAAADwAAAAAAAAAPAAAAAAAAAA8AAAAAAAwADwADAAAAHgAPAAeAAAAfAA8AD4AAAA+ADwAfAAAAB8APAD4AAAAD4B+AfAAAAAHw//D4AAAAAPv//fAAAAAAf///4AAAAAA/4H/AAAAAAB+AH4AAAAAAPgAHwAAAAAA8AAPAAAAAAHwAA+AAAAAAeAAB4AAAAAB4AAHgAAAAAPAAAPAAAA//8AAA//8AD//wAAD//wAP//AAAP//AA//8AAA//8AAADwAADwAAAAAHgAAeAAAAAAeAAB4AAAAAB8AAPgAAAAADwAA8AAAAAAPgAHwAAAAAAfgB+AAAAAAD/gf8AAAAAAf///4AAAAAD7//3wAAAAAfD/8PgAAAAD4B+AfAAAAAfADwA+AAAAD4APAB8AAAAfAA8AD4AAAB4ADwAHgAAADAAPAAMAAAAAAA8AAAAAAAAADwAAAAAAAAAPAAAAAAAAAA8AAAAAAAAADwAAAAAAAAAPAAAAAAAAAA8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==") : atob("EBCBAAAAAYAQCBAIA8AH4A/wb/YP8A/gB+ARiBAIAYABgAAA"); - let weatherMoon = big ? atob("QEDBAP//wxgAAAYAAAAPAAAAD4AAAA8AAAAPwAAADwAAAA/gAAAPAAAAB/APAP/wAAAH+A8A//AAAAf4DwD/8AAAB/wPAP/wAAAH/gAADwAAAAe+AAAPAAAAB54AAA8AAAAHngAADwAAAAePAAAAAAAAD48OAAAAAAAPDw+AAAAAAB8PD8AAAAAAHg8P4AAAAAA+DwPwAAAAAHwfAfgAAAAB+D4A/AAA8AfwfgB/8AD//+D+AD/8AP//wfgAH/4Af/8B8AAf/wB//APgAAgfgD+AA8AAAAfAH8AHwAAAA+AP8B+AAAAB4Af//4AAAAHgA///gAAAAPAA//8AAAAA8AAf/wAAAADwAAAAAAAAAPAAAAAAAAAA8AcAAAAAAADwD+AAAAAAAfAfgAAAAAAB+D4AAAAAAAB8fAAAAAAAAD54AAAAAAAAHngAAAAAAAAe8AAAAAAAAA/wAAAAAAAAD/AAAAAAAAAP8AAAAAAAAA/wAAAAAAAAD/AAAAAAAAAPeAAAAAAAAB54AAAAAAAAHnwAAAAAAAA+PgAAAAAAAHwfgAAAAAAB+A/////////wB////////+AD////////wAB///////4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==") : atob("EBCBAAAAAYAP8B/4P/w//D/8f/5//j/8P/w//B/4D/ABgAAA"); - let weatherPartlyCloudy = big ? atob("QEDBAP//wxgAAA8AAAAAAAAADwAAAAAAAAAPAAAAAAAAAA8AAAAAAAAADwAAAAAABwAPAA4AAAAHgA8AHgAAAAfADwA+AAAAA+AfgHwAAAAB8P/w+AAAAAD7//3wAAAAAH///+BAAAAAP+B/wOAAAAAfgB+B8AAAAD4AD8H4AAAAPAA/wPwAAAB8AH+Af/AAAHgA/AA//AAAeAH4AB/+AADwAfAAH/8A//AD4AAIH4D/8AfAAAAHwP/wB4AAAAPg//AHgAAAAeAA8B+AAAAB4AB4fwAAAADwAHn/AAAAAPAAff8AAAAA8AA/8AAAAADwAD/AAAAAAPAEH4AAAAAA8A4PgAAAAAHwHgcAAAAAAfg+AwAAAAAAfHwAAAAAAAA+eAAAAAAAAB54AAAAAAAAHvAAAAAAAAAP8AAAAAAAAA/wAAAAAAAAD/AAAAAAAAAP8AAAAAAAAA/wAAAAAAAAD3gAAAAAAAAeeAAAAAAAAB58AAAAAAAAPj4AAAAAAAB8H4AAAAAAAfgP////////8Af////////gA////////8AAf//////+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==") : atob("EBCBAAAAAAAYQAMAD8AIQBhoW+AOYBwwOBBgHGAGP/wf+AAA"); - let weatherRainy = big ? atob("QEDBAP//wxgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AAAAAAAAB//gAAAAAAAP//gAAAAAAD///AAAAAAAf4H+AAAAAAD8AD8AAAAAAfgAH4AAAAAB8AAPwAAAAAPgAAf/AAAAB8AAA//AAAAHgAAB/+AAAAeAAAH/8AAAH4AAAIH4AAB/AAAAAHwAAf8AAAAAPgAD/wAAAAAeAAPwAAAAAB4AB8AAAAAADwAHgAAAAAAPAA+AAAAAAA8ADwAAAAAADwA/AAAAAAAPAH8AAAAAAA8A/wAAAAAAHwH4APAA8AAfg+AA8ADwAAfHwADwAPAAA+eAAPAA8AAB54AAAAAAAAHvAAAAAAAAAP8AAAAAAAAA/wAAAAAAAAD/AADw8PDwAP8AAPDw8PAA/wAA8PDw8AD3gADw8PDwAeeAAAAAAAAB58AAAAAAAAPj4AAAAAAAB8H4AAAAAAAfgP/w8PDw8P8Af/Dw8PDw/gA/8PDw8PD8AAfw8PDw8OAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwAPAAAAAAAPAA8AAAAAAA8ADwAAAAAADwAPAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==") : atob("EBCBAAAAAYAH4AwwOBBgGEAOQAJBgjPOEkgGYAZgA8ABgAAA"); - let weatherPartlyRainy = big ? atob("QEDBAP//wxgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AAAAAAAAB//gAAAAAAAP//gAAAAAAD///AAAAAAAf4H+AAAAAAD8AD8AAAAAAfgAH4AAAAAB8AAPwAAAAAPgAAf/AAAAB8AAA//AAAAHgAAB/+AAAAeAAAH/8AAAH4AAAIH4AAB/AAAAAHwAAf8AAAAAPgAD/wAAAAAeAAPwAAAAAB4AB8AAAAAADwAHgAAAAAAPAA+AAAAAAA8ADwAAAAAADwA/AAAAAAAPAH8AAAAAAA8A/wAAAAAAHwH4AAAA8AAfg+AAAADwAAfHwAAAAPAAA+eAAAAA8AAB54AAAADwAAHvAAAAAPAAAP8AAAAA8AAA/wAAAADwAAD/AAAA8PAAAP8AAADw8AAA/wAAAPDwAAD3gAAA8PAAAeeAAADw8AAB58AAAPDwAAPj4AAA8PAAB8H4AADw8AAfgP//8PDw//8Af//w8PD//gA///Dw8P/8AAf/8PDw/+AAAAAA8AAAAAAAAADwAAAAAAAAAPAAAAAAAAAA8AAAAAAAAADwAAAAAAAAAPAAAAAAAAAA8AAAAAAAAADwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==") : atob("EBCBAAAAEEAQAAeADMAYaFvoTmAMMDgQIBxhhiGGG9wDwAGA"); - let weatherSnowy = big ? atob("QEDBAP//wxgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AAAAAAAAB//gAAAAAAAP//gAAAAAAD///AAAAAAAf4H+AAAAAAD8AD8AAAAAAfgAH4AAAAAB8AAPwAAAAAPgAAf/AAAAB8AAA//AAAAHgAAB/+AAAAeAAAH/8AAAH4AAAIH4AAB/AAAAAHwAAf8AAAAAPgAD/wAAAAAeAAPwAAAAAB4AB8AAAAAADwAHgAAAAAAPAA+AAAAAAA8ADwAAAAAADwA/AAAAAAAPAH8AAAAAAA8A/wAAAAAAHwH4AAAADwAfg+AAAAAPAAfHwAAAAA8AA+eAAAAADwAB54AA8AD/8AHvAADwAP/wAP8AAPAA//AA/wAA8AD/8AD/AA//AA8AAP8AD/8ADwAA/wAP/wAPAAD3gA//AA8AAeeAAPAAAAAB58AA8AAAAAPj4ADwAAAAB8H4APAAAAAfgP/wAA8A//8Af/AADwD//gA/8AAPAP/8AAfwAA8A/+AAAAAA//AAAAAAAAD/8AAAAAAAAP/wAAAAAAAA//AAAAAAAAAPAAAAAAAAAA8AAAAAAAAADwAAAAAAAAAPAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==") : atob("EBCBAAAAAAADwAGAEYg73C50BCAEIC50O9wRiAGAA8AAAAAA"); - let weatherFoggy = big ? atob("QEDBAP//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8AAAAAAAAADwAAAAAAAAAPAAAAAAAAAA8AAAAAAAAADwAAAAAAAAAPAAAAAAAAAA8AAAAAAAwADwADAAAAHgAPAAeAAAAfAA8AD4AAAA+ADwAfAAAAB8APAD4AAAAD4B+AfAAAAAHw//D4AAAAAPv//fAAAAAAf///4AAAAAA/4H/AAAAAAB+AH4AAAAAAPgAHwAAAAAA8AAPAAAAAAHwAA+AAAAAAeAAB4AAAAAB4AAHgAAAAAPAAAPAAAAAAAAAA//8AAAAAAAD//wAAAAAAAP//AAAAAAAA//8AD///AADwAAAP//8AAeAAAA///wAB4AAAD///AAPgAAAAAAAAA8AAAAAAAAAHwAAAAAAAAB+AAAAAAAAAf8AAAAD///D/4AAAAP//8P3wAAAA///w8PgAAAD///CAfAAAAAAAAAA+AAAAAAAAAB8AAAAAAAAAD4AAAAAAAAAHgAAP//8PAAMAAA///w8AAAAAD///DwAAAAAP//8PAAAAAAAAAA8AAAAAAAAADwAAAAAAAAAPAAAAAAAAAA8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==") : atob("EBCBAAAAAAADwAZgDDA4EGAcQAZAAgAAf74AAAAAd/4AAAAA"); - let weatherStormy = big ? atob("QEDBAP//wxgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AAAAAAAAB//gAAAAAAAP//gAAAAAAD///AAAAAAAf4H+AAAAAAD8AD8AAAAAAfgAH4AAAAAB8AAPwAAAAAPgAAf/AAAAB8AAA//AAAAHgAAB/+AAAAeAAAH/8AAAH4AAAIH4AAB/AAAAAHwAAf8AAAAAPgAD/wAAAAAeAAPwAAAAAB4AB8AAAAAADwAHgAAAAAAPAA+AAAAAAA8ADwAAAAAADwA/AAAAAAAPAH8AAAAAAA8A/wAAAAAAHwH4AAAAAAAfg+AAAAAAAAfHwAAAAAAAA+eAAAAAAAAB54AAAAD/AAHvAAAAAf4AAP8AAAAB/gAA/wAAAAP8AAD/AAAAA/gAAP8AAAAH+AAA/wAAAAfwAAD3gAAAD/AAAeeAAAAP4AAB58AAAB/AAAPj4AAAH8AAB8H4AAA/gAAfgP//+D//D/8Af//4f/4P/gA///B//B/8AAf/8P/8P+AAAAAAAPgAAAAAAAAB8AAAAAAAAAHwAAAAAAAAA+AAAAAAAAADwAAAAAAAAAfAAAAAAAAAB4AAAAAAAAAPAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==") : atob("EBCBAAAAAYAH4AwwOBBgGEAOQMJAgjmOGcgAgACAAAAAAAAA"); - let unknown = big ? atob("QEDBAP//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/wAAAAAAAAf/4AAAAAAAH//4AAAAAAA///wAAAAAAH+B/gAAAAAA/AA/AAAAAAH4AB+AAAAAA/AAD4AAAAAD4H4HwAAAAAfB/4PgAAAAB8P/weAAAAAHg//h4AAAAA+Hw+HwAAAAD4eB8PAAAAAP/wDw8AAAAA//APDwAAAAD/8A8PAAAAAH/gDw8AAAAAAAAfDwAAAAAAAH4fAAAAAAAB/B4AAAAAAAf4HgAAAAAAD/A+AAAAAAAfwHwAAAAAAD8A+AAAAAAAPgH4AAAAAAB8B/AAAAAAAHgf4AAAAAAA+H+AAAAAAADwfwAAAAAAAPD8AAAAAAAA8PAAAAAAAAD/8AAAAAAAAP/wAAAAAAAA//AAAAAAAAB/4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAf+AAAAAAAAD/8AAAAAAAAP/wAAAAAAAA//AAAAAAAADw8AAAAAAAAPDwAAAAAAAA8PAAAAAAAADw8AAAAAAAAP/wAAAAAAAA//AAAAAAAAD/8AAAAAAAAH/gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==") : undefined; + let weatherCloudy = big ? atob("QECBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/wAAAAAAAAf/4AAAAAAAD//4AAAAAAA///wAAAAAAH+B/gAAAAAA/AA/AAAAAAH4AB+AAAAAAfAAD8AAAAAD4AAH/wAAAAfAAAP/wAAAB4AAAf/gAAAHgAAB//AAAB+AAACB+AAAfwAAAAB8AAH/AAAAAD4AA/8AAAAAHgAD8AAAAAAeAAfAAAAAAA8AB4AAAAAADwAPgAAAAAAPAA8AAAAAAA8APwAAAAAADwB/AAAAAAAPAP8AAAAAAB8B+AAAAAAAH4PgAAAAAAAHx8AAAAAAAAPngAAAAAAAAeeAAAAAAAAB7wAAAAAAAAD/AAAAAAAAAP8AAAAAAAAA/wAAAAAAAAD/AAAAAAAAAP8AAAAAAAAA94AAAAAAAAHngAAAAAAAAefAAAAAAAAD4+AAAAAAAAfB+AAAAAAAH4D/////////AH////////4AP////////AAH///////gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=") : atob("EBCBAAAAAAAAAAfgD/Af8H/4//7///////9//z/+AAAAAAAA"); + let weatherSunny = big ? atob("QECBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPAAAAAAAAAA8AAAAAAAAADwAAAAAAAAAPAAAAAAAAAA8AAAAAAAAADwAAAAAAAAAPAAAAAAAMAA8AAwAAAB4ADwAHgAAAHwAPAA+AAAAPgA8AHwAAAAfADwA+AAAAA+AfgHwAAAAB8P/w+AAAAAD7//3wAAAAAH///+AAAAAAP+B/wAAAAAAfgB+AAAAAAD4AB8AAAAAAPAADwAAAAAB8AAPgAAAAAHgAAeAAAAAAeAAB4AAAAADwAADwAAAP//AAAP//AA//8AAA//8AD//wAAD//wAP//AAAP//AAAA8AAA8AAAAAB4AAHgAAAAAHgAAeAAAAAAfAAD4AAAAAA8AAPAAAAAAD4AB8AAAAAAH4AfgAAAAAA/4H/AAAAAAH///+AAAAAA+//98AAAAAHw//D4AAAAA+AfgHwAAAAHwA8APgAAAA+ADwAfAAAAHwAPAA+AAAAeAA8AB4AAAAwADwADAAAAAAAPAAAAAAAAAA8AAAAAAAAADwAAAAAAAAAPAAAAAAAAAA8AAAAAAAAADwAAAAAAAAAPAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=") : atob("EBCBAAAAAYAQCBAIA8AH4A/wb/YP8A/gB+ARiBAIAYABgAAA"); + let weatherMoon = big ? atob("QECBAAAGAAAADwAAAA+AAAAPAAAAD8AAAA8AAAAP4AAADwAAAAfwDwD/8AAAB/gPAP/wAAAH+A8A//AAAAf8DwD/8AAAB/4AAA8AAAAHvgAADwAAAAeeAAAPAAAAB54AAA8AAAAHjwAAAAAAAA+PDgAAAAAADw8PgAAAAAAfDw/AAAAAAB4PD+AAAAAAPg8D8AAAAAB8HwH4AAAAAfg+APwAAPAH8H4Af/AA///g/gA//AD//8H4AB/+AH//AfAAH/8Af/wD4AAIH4A/gAPAAAAHwB/AB8AAAAPgD/AfgAAAAeAH//+AAAAB4AP//4AAAADwAP//AAAAAPAAH/8AAAAA8AAAAAAAAADwAAAAAAAAAPAHAAAAAAAA8A/gAAAAAAHwH4AAAAAAAfg+AAAAAAAAfHwAAAAAAAA+eAAAAAAAAB54AAAAAAAAHvAAAAAAAAAP8AAAAAAAAA/wAAAAAAAAD/AAAAAAAAAP8AAAAAAAAA/wAAAAAAAAD3gAAAAAAAAeeAAAAAAAAB58AAAAAAAAPj4AAAAAAAB8H4AAAAAAAfgP////////8Af////////gA////////8AAf//////+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=") : atob("EBCBAAAAAYAP8B/4P/w//D/8f/5//j/8P/w//B/4D/ABgAAA"); + let weatherPartlyCloudy = big ? atob("QECBAAAPAAAAAAAAAA8AAAAAAAAADwAAAAAAAAAPAAAAAAAAAA8AAAAAAAcADwAOAAAAB4APAB4AAAAHwA8APgAAAAPgH4B8AAAAAfD/8PgAAAAA+//98AAAAAB////gQAAAAD/gf8DgAAAAH4AfgfAAAAA+AA/B+AAAADwAP8D8AAAAfAB/gH/wAAB4APwAP/wAAHgB+AAf/gAA8AHwAB//AP/wA+AACB+A//AHwAAAB8D/8AeAAAAD4P/wB4AAAAHgAPAfgAAAAeAAeH8AAAAA8AB5/wAAAADwAH3/AAAAAPAAP/AAAAAA8AA/wAAAAADwBB+AAAAAAPAOD4AAAAAB8B4HAAAAAAH4PgMAAAAAAHx8AAAAAAAAPngAAAAAAAAeeAAAAAAAAB7wAAAAAAAAD/AAAAAAAAAP8AAAAAAAAA/wAAAAAAAAD/AAAAAAAAAP8AAAAAAAAA94AAAAAAAAHngAAAAAAAAefAAAAAAAAD4+AAAAAAAAfB+AAAAAAAH4D/////////AH////////4AP////////AAH///////gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=") : atob("EBCBAAAAAAAYQAMAD8AIQBhoW+AOYBwwOBBgHGAGP/wf+AAA"); + let weatherRainy = big ? atob("QECBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/wAAAAAAAAf/4AAAAAAAD//4AAAAAAA///wAAAAAAH+B/gAAAAAA/AA/AAAAAAH4AB+AAAAAAfAAD8AAAAAD4AAH/wAAAAfAAAP/wAAAB4AAAf/gAAAHgAAB//AAAB+AAACB+AAAfwAAAAB8AAH/AAAAAD4AA/8AAAAAHgAD8AAAAAAeAAfAAAAAAA8AB4AAAAAADwAPgAAAAAAPAA8AAAAAAA8APwAAAAAADwB/AAAAAAAPAP8AAAAAAB8B+ADwAPAAH4PgAPAA8AAHx8AA8ADwAAPngADwAPAAAeeAAAAAAAAB7wAAAAAAAAD/AAAAAAAAAP8AAAAAAAAA/wAA8PDw8AD/AADw8PDwAP8AAPDw8PAA94AA8PDw8AHngAAAAAAAAefAAAAAAAAD4+AAAAAAAAfB+AAAAAAAH4D/8PDw8PD/AH/w8PDw8P4AP/Dw8PDw/AAH8PDw8PDgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8ADwAAAAAADwAPAAAAAAAPAA8AAAAAAA8ADwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=") : atob("EBCBAAAAAYAH4AwwOBBgGEAOQAJBgjPOEkgGYAZgA8ABgAAA"); + let weatherPartlyRainy = big ? atob("QECBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/wAAAAAAAAf/4AAAAAAAD//4AAAAAAA///wAAAAAAH+B/gAAAAAA/AA/AAAAAAH4AB+AAAAAAfAAD8AAAAAD4AAH/wAAAAfAAAP/wAAAB4AAAf/gAAAHgAAB//AAAB+AAACB+AAAfwAAAAB8AAH/AAAAAD4AA/8AAAAAHgAD8AAAAAAeAAfAAAAAAA8AB4AAAAAADwAPgAAAAAAPAA8AAAAAAA8APwAAAAAADwB/AAAAAAAPAP8AAAAAAB8B+AAAAPAAH4PgAAAA8AAHx8AAAADwAAPngAAAAPAAAeeAAAAA8AAB7wAAAADwAAD/AAAAAPAAAP8AAAAA8AAA/wAAAPDwAAD/AAAA8PAAAP8AAADw8AAA94AAAPDwAAHngAAA8PAAAefAAADw8AAD4+AAAPDwAAfB+AAA8PAAH4D///Dw8P//AH//8PDw//4AP//w8PD//AAH//Dw8P/gAAAAAPAAAAAAAAAA8AAAAAAAAADwAAAAAAAAAPAAAAAAAAAA8AAAAAAAAADwAAAAAAAAAPAAAAAAAAAA8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=") : atob("EBCBAAAAEEAQAAeADMAYaFvoTmAMMDgQIBxhhiGGG9wDwAGA"); + let weatherSnowy = big ? atob("QECBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/wAAAAAAAAf/4AAAAAAAD//4AAAAAAA///wAAAAAAH+B/gAAAAAA/AA/AAAAAAH4AB+AAAAAAfAAD8AAAAAD4AAH/wAAAAfAAAP/wAAAB4AAAf/gAAAHgAAB//AAAB+AAACB+AAAfwAAAAB8AAH/AAAAAD4AA/8AAAAAHgAD8AAAAAAeAAfAAAAAAA8AB4AAAAAADwAPgAAAAAAPAA8AAAAAAA8APwAAAAAADwB/AAAAAAAPAP8AAAAAAB8B+AAAAA8AH4PgAAAADwAHx8AAAAAPAAPngAAAAA8AAeeAAPAA//AB7wAA8AD/8AD/AADwAP/wAP8AAPAA//AA/wAP/wAPAAD/AA//AA8AAP8AD/8ADwAA94AP/wAPAAHngADwAAAAAefAAPAAAAAD4+AA8AAAAAfB+ADwAAAAH4D/8AAPAP//AH/wAA8A//4AP/AADwD//AAH8AAPAP/gAAAAAP/wAAAAAAAA//AAAAAAAAD/8AAAAAAAAP/wAAAAAAAADwAAAAAAAAAPAAAAAAAAAA8AAAAAAAAADwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=") : atob("EBCBAAAAAAADwAGAEYg73C50BCAEIC50O9wRiAGAA8AAAAAA"); + let weatherFoggy = big ? atob("QECBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPAAAAAAAAAA8AAAAAAAAADwAAAAAAAAAPAAAAAAAAAA8AAAAAAAAADwAAAAAAAAAPAAAAAAAMAA8AAwAAAB4ADwAHgAAAHwAPAA+AAAAPgA8AHwAAAAfADwA+AAAAA+AfgHwAAAAB8P/w+AAAAAD7//3wAAAAAH///+AAAAAAP+B/wAAAAAAfgB+AAAAAAD4AB8AAAAAAPAADwAAAAAB8AAPgAAAAAHgAAeAAAAAAeAAB4AAAAADwAADwAAAAAAAAAP//AAAAAAAA//8AAAAAAAD//wAAAAAAAP//AA///wAA8AAAD///AAHgAAAP//8AAeAAAA///wAD4AAAAAAAAAPAAAAAAAAAB8AAAAAAAAAfgAAAAAAAAH/AAAAA///w/+AAAAD///D98AAAAP//8PD4AAAA///wgHwAAAAAAAAAPgAAAAAAAAAfAAAAAAAAAA+AAAAAAAAAB4AAD///DwADAAAP//8PAAAAAA///w8AAAAAD///DwAAAAAAAAAPAAAAAAAAAA8AAAAAAAAADwAAAAAAAAAPAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=") : atob("EBCBAAAAAAADwAZgDDA4EGAcQAZAAgAAf74AAAAAd/4AAAAA"); + let weatherStormy = big ? atob("QECBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/wAAAAAAAAf/4AAAAAAAD//4AAAAAAA///wAAAAAAH+B/gAAAAAA/AA/AAAAAAH4AB+AAAAAAfAAD8AAAAAD4AAH/wAAAAfAAAP/wAAAB4AAAf/gAAAHgAAB//AAAB+AAACB+AAAfwAAAAB8AAH/AAAAAD4AA/8AAAAAHgAD8AAAAAAeAAfAAAAAAA8AB4AAAAAADwAPgAAAAAAPAA8AAAAAAA8APwAAAAAADwB/AAAAAAAPAP8AAAAAAB8B+AAAAAAAH4PgAAAAAAAHx8AAAAAAAAPngAAAAAAAAeeAAAAA/wAB7wAAAAH+AAD/AAAAAf4AAP8AAAAD/AAA/wAAAAP4AAD/AAAAB/gAAP8AAAAH8AAA94AAAA/wAAHngAAAD+AAAefAAAAfwAAD4+AAAB/AAAfB+AAAP4AAH4D///g//w//AH//+H/+D/4AP//wf/wf/AAH//D//D/gAAAAAAD4AAAAAAAAAfAAAAAAAAAB8AAAAAAAAAPgAAAAAAAAA8AAAAAAAAAHwAAAAAAAAAeAAAAAAAAADwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=") : atob("EBCBAAAAAYAH4AwwOBBgGEAOQMJAgjmOGcgAgACAAAAAAAAA"); + let unknown = big ? atob("QECBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP8AAAAAAAAH/+AAAAAAAB//+AAAAAAAP//8AAAAAAB/gf4AAAAAAPwAPwAAAAAB+AAfgAAAAAPwAA+AAAAAA+B+B8AAAAAHwf+D4AAAAAfD/8HgAAAAB4P/4eAAAAAPh8Ph8AAAAA+HgfDwAAAAD/8A8PAAAAAP/wDw8AAAAA//APDwAAAAB/4A8PAAAAAAAAHw8AAAAAAAB+HwAAAAAAAfweAAAAAAAH+B4AAAAAAA/wPgAAAAAAH8B8AAAAAAA/APgAAAAAAD4B+AAAAAAAfAfwAAAAAAB4H+AAAAAAAPh/gAAAAAAA8H8AAAAAAADw/AAAAAAAAPDwAAAAAAAA//AAAAAAAAD/8AAAAAAAAP/wAAAAAAAAf+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH/gAAAAAAAA//AAAAAAAAD/8AAAAAAAAP/wAAAAAAAA8PAAAAAAAADw8AAAAAAAAPDwAAAAAAAA8PAAAAAAAAD/8AAAAAAAAP/wAAAAAAAA//AAAAAAAAB/4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=") : undefined; switch (codeGroup) { case 2: diff --git a/apps/circlesclock/metadata.json b/apps/circlesclock/metadata.json index fb66c064e..7b4c25532 100644 --- a/apps/circlesclock/metadata.json +++ b/apps/circlesclock/metadata.json @@ -1,7 +1,7 @@ { "id": "circlesclock", "name": "Circles clock", "shortName":"Circles clock", - "version":"0.20", + "version":"0.21", "description": "A clock with three or four circles for different data at the bottom in a probably familiar style", "icon": "app.png", "screenshots": [{"url":"screenshot-dark.png"}, {"url":"screenshot-light.png"}, {"url":"screenshot-dark-4.png"}, {"url":"screenshot-light-4.png"}], From 31dadf83a01d21c34f5a6b6e6f8d38a7d55cfb36 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Fri, 9 Dec 2022 14:59:18 +0000 Subject: [PATCH 108/110] Now re-adds widgets if they were hidden when fast-loading --- apps/circlesclock/ChangeLog | 1 + apps/circlesclock/app.js | 7 ++++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/apps/circlesclock/ChangeLog b/apps/circlesclock/ChangeLog index 9c3b673aa..cb5248e32 100644 --- a/apps/circlesclock/ChangeLog +++ b/apps/circlesclock/ChangeLog @@ -37,3 +37,4 @@ 0.20: Add much faster circle rendering (250ms -> 40ms) Add fast load capability 0.21: Remade all icons without a palette for dark theme + Now re-adds widgets if they were hidden when fast-loading diff --git a/apps/circlesclock/app.js b/apps/circlesclock/app.js index 5039488a7..444040ef0 100644 --- a/apps/circlesclock/app.js +++ b/apps/circlesclock/app.js @@ -33,9 +33,9 @@ if (settings.stepGoal == undefined) { } let drawTimeout; -let showWidgets = settings.showWidgets || false; -let circleCount = settings.circleCount || 3; -let showBigWeather = settings.showBigWeather || false; +const showWidgets = settings.showWidgets || false; +const circleCount = settings.circleCount || 3; +const showBigWeather = settings.showBigWeather || false; let hrtValue; //TODO deprecate this let now = Math.round(new Date().getTime() / 1000); @@ -329,6 +329,7 @@ Bangle.setUI({ clockInfoMenu.forEach(c => c.remove()); delete Graphics.prototype.setFontRobotoRegular50NumericOnly; delete Graphics.prototype.setFontRobotoRegular21; + if (!showWidgets) require("widget_utils").show(); } }); From 0502e90489862f6f0059f35759672b1b865f1808 Mon Sep 17 00:00:00 2001 From: lauzonhomeschool <85599144+lauzonhomeschool@users.noreply.github.com> Date: Fri, 9 Dec 2022 12:02:15 -0500 Subject: [PATCH 109/110] Update ChangeLog --- apps/sched/ChangeLog | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/sched/ChangeLog b/apps/sched/ChangeLog index 711326200..6d9d5caee 100644 --- a/apps/sched/ChangeLog +++ b/apps/sched/ChangeLog @@ -16,3 +16,4 @@ 0.13: Ask to delete a timer after stopping it 0.14: Added clkinfo for alarms and timers 0.15: Automatic translation of some string in clkinfo +0.16: Improve support for date timezone From e0495a1b85ebfd03974fbf3a7819bee07f3a2882 Mon Sep 17 00:00:00 2001 From: lauzonhomeschool <85599144+lauzonhomeschool@users.noreply.github.com> Date: Fri, 9 Dec 2022 12:02:42 -0500 Subject: [PATCH 110/110] Update metadata.json --- apps/sched/metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/sched/metadata.json b/apps/sched/metadata.json index a266d11f8..9c1a1d6b0 100644 --- a/apps/sched/metadata.json +++ b/apps/sched/metadata.json @@ -1,7 +1,7 @@ { "id": "sched", "name": "Scheduler", - "version": "0.15", + "version": "0.16", "description": "Scheduling library for alarms and timers", "icon": "app.png", "type": "scheduler",