From 4bb96f314c74e59f68d2600ef597e8ca85fc820c Mon Sep 17 00:00:00 2001 From: Rob Pilling Date: Fri, 10 Mar 2023 23:20:28 +0000 Subject: [PATCH 01/39] low-power-mode: initial app --- apps/lowpower/ChangeLog | 1 + apps/lowpower/README.md | 25 ++++++++++++++++++ apps/lowpower/app.js | 40 ++++++++++++++++++++++++++++ apps/lowpower/app.ts | 52 +++++++++++++++++++++++++++++++++++++ apps/lowpower/boot.js | 8 ++++++ apps/lowpower/boot.ts | 8 ++++++ apps/lowpower/metadata.json | 15 +++++++++++ 7 files changed, 149 insertions(+) create mode 100644 apps/lowpower/ChangeLog create mode 100644 apps/lowpower/README.md create mode 100644 apps/lowpower/app.js create mode 100644 apps/lowpower/app.ts create mode 100644 apps/lowpower/boot.js create mode 100644 apps/lowpower/boot.ts create mode 100644 apps/lowpower/metadata.json diff --git a/apps/lowpower/ChangeLog b/apps/lowpower/ChangeLog new file mode 100644 index 000000000..1a3bc1757 --- /dev/null +++ b/apps/lowpower/ChangeLog @@ -0,0 +1 @@ +0.01: New app! diff --git a/apps/lowpower/README.md b/apps/lowpower/README.md new file mode 100644 index 000000000..e139d3d23 --- /dev/null +++ b/apps/lowpower/README.md @@ -0,0 +1,25 @@ +# Low Power Mode + +With this app installed, your Bangle will automatically switch into low power mode when the battery reaches a specified threshold, displaying a simple clock. + +# Features + +## Time +[x] Show simple date/time +[ ] Disable alarms - with a setting? + +## No backlight (#2502) +[x] LCD brightness +[ ] LCD timeout + +## Peripherals +[x] Disable auto heart rate measurement in health app (#2502) +[x] Overwrite setGPSPower() function (#2502) +[ ] Turn off already-running GPS / HRM + +## Features +[ ] Wake on twist -> off (#2502) + +# Creator + +[bobrippling](https://github.com/bobrippling/) diff --git a/apps/lowpower/app.js b/apps/lowpower/app.js new file mode 100644 index 000000000..63709cc2b --- /dev/null +++ b/apps/lowpower/app.js @@ -0,0 +1,40 @@ +"use strict"; +if (typeof lowpowerInterval !== "undefined") + lowpowerInterval = clearInterval(lowpowerInterval); +Bangle.setLCDBrightness(0); +Bangle.setGPSPower = Bangle.setHRMPower = function (_val, _name) { return false; }; +Bangle.removeAllListeners(); +var nextDraw; +var draw = function () { + var x = g.getWidth() / 2; + var y = g.getHeight() / 2 - 48; + var date = new Date(); + var timeStr = require("locale").time(date, 1); + var dateStr = require("locale").date(date, 0).toUpperCase() + + "\n" + + require("locale").dow(date, 0).toUpperCase(); + g.reset() + .clearRect(Bangle.appRect) + .setFont("Vector", 32) + .setFontAlign(0, 0) + .drawString(timeStr, x, y) + .setFont("Vector", 24) + .drawString(dateStr, x, y + 56) + .drawString("".concat(E.getBattery(), "%"), x, y + 104); + if (nextDraw) + clearTimeout(nextDraw); + nextDraw = setTimeout(function () { + nextDraw = undefined; + draw(); + }, 60000 - (date.getTime() % 60000)); +}; +Bangle.setUI({ + mode: "clock", + remove: function () { + if (nextDraw) + clearTimeout(nextDraw); + nextDraw = undefined; + }, +}); +g.clear(); +draw(); diff --git a/apps/lowpower/app.ts b/apps/lowpower/app.ts new file mode 100644 index 000000000..fadc6ef4a --- /dev/null +++ b/apps/lowpower/app.ts @@ -0,0 +1,52 @@ +// from boot.js +if(typeof lowpowerInterval !== "undefined") + lowpowerInterval = clearInterval(lowpowerInterval) as undefined; + +// backlight +Bangle.setLCDBrightness(0); + +// peripherals +Bangle.setGPSPower = Bangle.setHRMPower = (_val: boolean, _name: string) => false; + +// events +Bangle.removeAllListeners(); + +// clock +let nextDraw: number | undefined; +const draw = () => { + const x = g.getWidth() / 2; + const y = g.getHeight() / 2 - 48; + + const date = new Date(); + + const timeStr = require("locale").time(date, 1); + const dateStr = require("locale").date(date, 0).toUpperCase() + + "\n" + + require("locale").dow(date, 0).toUpperCase(); + + g.reset() + .clearRect(Bangle.appRect) + .setFont("Vector", 32) + .setFontAlign(0, 0) + .drawString(timeStr, x, y) + .setFont("Vector", 24) + .drawString(dateStr, x, y + 56) + .drawString(`${E.getBattery()}%`, x, y + 104); + + if(nextDraw) clearTimeout(nextDraw); + nextDraw = setTimeout(() => { + nextDraw = undefined; + draw(); + }, 60000 - (date.getTime() % 60000)); +}; + +Bangle.setUI({ + mode: "clock", + remove: () => { + if (nextDraw) clearTimeout(nextDraw); + nextDraw = undefined; + }, +}); + +g.clear(); +draw(); diff --git a/apps/lowpower/boot.js b/apps/lowpower/boot.js new file mode 100644 index 000000000..56a02c6ad --- /dev/null +++ b/apps/lowpower/boot.js @@ -0,0 +1,8 @@ +"use strict"; +var lowpowerInterval = setInterval(function () { + if (Bangle.isCharging()) + return; + if (E.getBattery() > 5) + return; + load("lowpower.app.js"); +}, 5 * 60 * 1000); diff --git a/apps/lowpower/boot.ts b/apps/lowpower/boot.ts new file mode 100644 index 000000000..bb4cfa0b4 --- /dev/null +++ b/apps/lowpower/boot.ts @@ -0,0 +1,8 @@ +let lowpowerInterval: number | undefined = setInterval(() => { + if(Bangle.isCharging()) + return; + if(E.getBattery() > 5) + return; + + load("lowpower.app.js"); +}, 5 * 60 * 1000); diff --git a/apps/lowpower/metadata.json b/apps/lowpower/metadata.json new file mode 100644 index 000000000..c231bd495 --- /dev/null +++ b/apps/lowpower/metadata.json @@ -0,0 +1,15 @@ +{ + "id": "lowpower", + "name": "Low Power Mode", + "version": "0.01", + "description": "Switches to displaying a simple clock when the battery percentage is low, nothing more", + "readme": "README.md", + "icon": "TODOOOOOOOOOOOOOOOO.png", + "type": "clock", + "tags": "clock", + "supports": ["BANGLEJS2"], + "storage": [ + {"name":"lowpower.boot.js","url":"boot.js"}, + {"name":"lowpower.app.js","url":"app.js"} + ] +} From 1fa36bd2b838f1bb84c12b26c0b754b86c5e108e Mon Sep 17 00:00:00 2001 From: Rob Pilling Date: Fri, 7 Apr 2023 17:52:54 +0100 Subject: [PATCH 02/39] drained: rename from low-power-mode --- apps/{lowpower => drained}/ChangeLog | 0 apps/{lowpower => drained}/README.md | 2 +- apps/{lowpower => drained}/app.js | 4 ++-- apps/{lowpower => drained}/app.ts | 4 ++-- apps/{lowpower => drained}/boot.js | 4 ++-- apps/{lowpower => drained}/boot.ts | 4 ++-- apps/{lowpower => drained}/metadata.json | 10 +++++----- 7 files changed, 14 insertions(+), 14 deletions(-) rename apps/{lowpower => drained}/ChangeLog (100%) rename apps/{lowpower => drained}/README.md (97%) rename apps/{lowpower => drained}/app.js (91%) rename apps/{lowpower => drained}/app.ts (90%) rename apps/{lowpower => drained}/boot.js (61%) rename apps/{lowpower => drained}/boot.ts (51%) rename apps/{lowpower => drained}/metadata.json (55%) diff --git a/apps/lowpower/ChangeLog b/apps/drained/ChangeLog similarity index 100% rename from apps/lowpower/ChangeLog rename to apps/drained/ChangeLog diff --git a/apps/lowpower/README.md b/apps/drained/README.md similarity index 97% rename from apps/lowpower/README.md rename to apps/drained/README.md index e139d3d23..74300da59 100644 --- a/apps/lowpower/README.md +++ b/apps/drained/README.md @@ -1,4 +1,4 @@ -# Low Power Mode +# Drained With this app installed, your Bangle will automatically switch into low power mode when the battery reaches a specified threshold, displaying a simple clock. diff --git a/apps/lowpower/app.js b/apps/drained/app.js similarity index 91% rename from apps/lowpower/app.js rename to apps/drained/app.js index 63709cc2b..2e9d3be54 100644 --- a/apps/lowpower/app.js +++ b/apps/drained/app.js @@ -1,6 +1,6 @@ "use strict"; -if (typeof lowpowerInterval !== "undefined") - lowpowerInterval = clearInterval(lowpowerInterval); +if (typeof drainedInterval !== "undefined") + drainedInterval = clearInterval(drainedInterval); Bangle.setLCDBrightness(0); Bangle.setGPSPower = Bangle.setHRMPower = function (_val, _name) { return false; }; Bangle.removeAllListeners(); diff --git a/apps/lowpower/app.ts b/apps/drained/app.ts similarity index 90% rename from apps/lowpower/app.ts rename to apps/drained/app.ts index fadc6ef4a..1cb1b9d44 100644 --- a/apps/lowpower/app.ts +++ b/apps/drained/app.ts @@ -1,6 +1,6 @@ // from boot.js -if(typeof lowpowerInterval !== "undefined") - lowpowerInterval = clearInterval(lowpowerInterval) as undefined; +if(typeof drainedInterval !== "undefined") + drainedInterval = clearInterval(drainedInterval) as undefined; // backlight Bangle.setLCDBrightness(0); diff --git a/apps/lowpower/boot.js b/apps/drained/boot.js similarity index 61% rename from apps/lowpower/boot.js rename to apps/drained/boot.js index 56a02c6ad..b6fd3bf35 100644 --- a/apps/lowpower/boot.js +++ b/apps/drained/boot.js @@ -1,8 +1,8 @@ "use strict"; -var lowpowerInterval = setInterval(function () { +var drainedInterval = setInterval(function () { if (Bangle.isCharging()) return; if (E.getBattery() > 5) return; - load("lowpower.app.js"); + load("drained.app.js"); }, 5 * 60 * 1000); diff --git a/apps/lowpower/boot.ts b/apps/drained/boot.ts similarity index 51% rename from apps/lowpower/boot.ts rename to apps/drained/boot.ts index bb4cfa0b4..6ee7c8e92 100644 --- a/apps/lowpower/boot.ts +++ b/apps/drained/boot.ts @@ -1,8 +1,8 @@ -let lowpowerInterval: number | undefined = setInterval(() => { +let drainedInterval: number | undefined = setInterval(() => { if(Bangle.isCharging()) return; if(E.getBattery() > 5) return; - load("lowpower.app.js"); + load("drained.app.js"); }, 5 * 60 * 1000); diff --git a/apps/lowpower/metadata.json b/apps/drained/metadata.json similarity index 55% rename from apps/lowpower/metadata.json rename to apps/drained/metadata.json index c231bd495..32b5e5ce5 100644 --- a/apps/lowpower/metadata.json +++ b/apps/drained/metadata.json @@ -1,15 +1,15 @@ { - "id": "lowpower", - "name": "Low Power Mode", + "id": "drained", + "name": "Drained", "version": "0.01", - "description": "Switches to displaying a simple clock when the battery percentage is low, nothing more", + "description": "Switches to displaying a simple clock when the battery percentage is low, and disables some peripherals", "readme": "README.md", "icon": "TODOOOOOOOOOOOOOOOO.png", "type": "clock", "tags": "clock", "supports": ["BANGLEJS2"], "storage": [ - {"name":"lowpower.boot.js","url":"boot.js"}, - {"name":"lowpower.app.js","url":"app.js"} + {"name":"drained.boot.js","url":"boot.js"}, + {"name":"drained.app.js","url":"app.js"} ] } From 2de5831827467336c8f5540a667b83bbe03d44c5 Mon Sep 17 00:00:00 2001 From: Rob Pilling Date: Fri, 7 Apr 2023 21:16:01 +0100 Subject: [PATCH 03/39] drained: add icon --- apps/drained/icon.png | Bin 0 -> 469 bytes apps/drained/metadata.json | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 apps/drained/icon.png diff --git a/apps/drained/icon.png b/apps/drained/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..33311cf2c74616e85e30b1e15cf6520f2d508d5c GIT binary patch literal 469 zcmV;`0V@89P)oJU)Gm0!9uctku-(Y00000 LNkvXXu0mjfc~Z_Y literal 0 HcmV?d00001 diff --git a/apps/drained/metadata.json b/apps/drained/metadata.json index 32b5e5ce5..c4f11f0df 100644 --- a/apps/drained/metadata.json +++ b/apps/drained/metadata.json @@ -4,7 +4,7 @@ "version": "0.01", "description": "Switches to displaying a simple clock when the battery percentage is low, and disables some peripherals", "readme": "README.md", - "icon": "TODOOOOOOOOOOOOOOOO.png", + "icon": "icon.png", "type": "clock", "tags": "clock", "supports": ["BANGLEJS2"], From 39aa8e7e7bdd8491f4c0912a172468857f569268 Mon Sep 17 00:00:00 2001 From: Rob Pilling Date: Fri, 7 Apr 2023 21:26:25 +0100 Subject: [PATCH 04/39] drained: enable emulator --- apps/drained/metadata.json | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/drained/metadata.json b/apps/drained/metadata.json index c4f11f0df..2af347f79 100644 --- a/apps/drained/metadata.json +++ b/apps/drained/metadata.json @@ -8,6 +8,7 @@ "type": "clock", "tags": "clock", "supports": ["BANGLEJS2"], + "allow_emulator": true, "storage": [ {"name":"drained.boot.js","url":"boot.js"}, {"name":"drained.app.js","url":"app.js"} From a36e705d79d41396271d1ab0060688de04d510bd Mon Sep 17 00:00:00 2001 From: Rob Pilling Date: Fri, 7 Apr 2023 21:27:15 +0100 Subject: [PATCH 05/39] drained: force off gps/hrm --- apps/drained/README.md | 4 ++-- apps/drained/app.ts | 15 ++++++++++++++- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/apps/drained/README.md b/apps/drained/README.md index 74300da59..e4217493b 100644 --- a/apps/drained/README.md +++ b/apps/drained/README.md @@ -10,12 +10,12 @@ With this app installed, your Bangle will automatically switch into low power mo ## No backlight (#2502) [x] LCD brightness -[ ] LCD timeout +[ ] LCD timeout? ## Peripherals [x] Disable auto heart rate measurement in health app (#2502) [x] Overwrite setGPSPower() function (#2502) -[ ] Turn off already-running GPS / HRM +[x] Turn off already-running GPS / HRM ## Features [ ] Wake on twist -> off (#2502) diff --git a/apps/drained/app.ts b/apps/drained/app.ts index 1cb1b9d44..029c64f47 100644 --- a/apps/drained/app.ts +++ b/apps/drained/app.ts @@ -1,3 +1,5 @@ +const app = "drained"; + // from boot.js if(typeof drainedInterval !== "undefined") drainedInterval = clearInterval(drainedInterval) as undefined; @@ -6,7 +8,18 @@ if(typeof drainedInterval !== "undefined") Bangle.setLCDBrightness(0); // peripherals -Bangle.setGPSPower = Bangle.setHRMPower = (_val: boolean, _name: string) => false; +const powerNoop = () => false; + +const forceOff = (name: "GPS" | "HRM" | "Compass" /*| "Barom"*/) => { + (Bangle as any)._PWR[name] = []; + + // if(name === "Barom"){ setBarometerPower(...) } + // ^^^^ + Bangle[`set${name}Power`](false, app); + Bangle[`set${name}Power`] = powerNoop; +}; +forceOff("GPS"); +forceOff("HRM"); // events Bangle.removeAllListeners(); From 92ff678ac057f0b216570ba8d80c11ac67347460 Mon Sep 17 00:00:00 2001 From: Rob Pilling Date: Fri, 7 Apr 2023 21:27:46 +0100 Subject: [PATCH 06/39] drained: turn off wake-on-twist etc --- apps/drained/README.md | 2 +- apps/drained/app.ts | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/apps/drained/README.md b/apps/drained/README.md index e4217493b..cb3be81a6 100644 --- a/apps/drained/README.md +++ b/apps/drained/README.md @@ -18,7 +18,7 @@ With this app installed, your Bangle will automatically switch into low power mo [x] Turn off already-running GPS / HRM ## Features -[ ] Wake on twist -> off (#2502) +[x] Wake on twist -> off (#2502) # Creator diff --git a/apps/drained/app.ts b/apps/drained/app.ts index 029c64f47..2f1a72755 100644 --- a/apps/drained/app.ts +++ b/apps/drained/app.ts @@ -24,6 +24,13 @@ forceOff("HRM"); // events Bangle.removeAllListeners(); +// UI +Bangle.setOptions({ + wakeOnFaceUp: false, + wakeOnTouch: false, + wakeOnTwist: false, +}); + // clock let nextDraw: number | undefined; const draw = () => { From 1f35c9825a340d244b1826dca0ffe1d26f5dc0d0 Mon Sep 17 00:00:00 2001 From: Rob Pilling Date: Fri, 7 Apr 2023 21:28:23 +0100 Subject: [PATCH 07/39] drained: regenerate js --- apps/drained/app.js | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/apps/drained/app.js b/apps/drained/app.js index 2e9d3be54..59c8ff690 100644 --- a/apps/drained/app.js +++ b/apps/drained/app.js @@ -1,9 +1,22 @@ "use strict"; +var app = "drained"; if (typeof drainedInterval !== "undefined") drainedInterval = clearInterval(drainedInterval); Bangle.setLCDBrightness(0); -Bangle.setGPSPower = Bangle.setHRMPower = function (_val, _name) { return false; }; +var powerNoop = function () { return false; }; +var forceOff = function (name) { + Bangle._PWR[name] = []; + Bangle["set".concat(name, "Power")](false, app); + Bangle["set".concat(name, "Power")] = powerNoop; +}; +forceOff("GPS"); +forceOff("HRM"); Bangle.removeAllListeners(); +Bangle.setOptions({ + wakeOnFaceUp: false, + wakeOnTouch: false, + wakeOnTwist: false, +}); var nextDraw; var draw = function () { var x = g.getWidth() / 2; From 10881c93362bce5d81a24a3afa38b9f8270d1f93 Mon Sep 17 00:00:00 2001 From: Rob Pilling Date: Fri, 7 Apr 2023 21:34:38 +0100 Subject: [PATCH 08/39] drained: tweak readme --- apps/drained/README.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/apps/drained/README.md b/apps/drained/README.md index cb3be81a6..92924393a 100644 --- a/apps/drained/README.md +++ b/apps/drained/README.md @@ -1,25 +1,25 @@ # Drained -With this app installed, your Bangle will automatically switch into low power mode when the battery reaches a specified threshold, displaying a simple clock. +With this app installed, your Bangle will automatically switch into low power mode when the battery reaches 5% battery, displaying a simple clock. # Features ## Time -[x] Show simple date/time -[ ] Disable alarms - with a setting? +- [x] Show simple date/time +- [ ] Disable alarms - with a setting? ## No backlight (#2502) -[x] LCD brightness -[ ] LCD timeout? +- [x] LCD brightness +- [ ] LCD timeout? ## Peripherals -[x] Disable auto heart rate measurement in health app (#2502) -[x] Overwrite setGPSPower() function (#2502) -[x] Turn off already-running GPS / HRM +- [x] Disable auto heart rate measurement in health app (#2502) +- [x] Overwrite setGPSPower() function (#2502) +- [x] Turn off already-running GPS / HRM ## Features -[x] Wake on twist -> off (#2502) +- [x] Wake on twist -> off (#2502) # Creator -[bobrippling](https://github.com/bobrippling/) +- [bobrippling](https://github.com/bobrippling/) From acbd5d3b53e41c1fe512adc364fea160827f779f Mon Sep 17 00:00:00 2001 From: Rob Pilling Date: Fri, 7 Apr 2023 21:44:34 +0100 Subject: [PATCH 09/39] Update main.d.ts - setUI & removeAllListeners() --- typescript/types/main.d.ts | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/typescript/types/main.d.ts b/typescript/types/main.d.ts index 944d55326..c66135d4d 100644 --- a/typescript/types/main.d.ts +++ b/typescript/types/main.d.ts @@ -174,6 +174,12 @@ type BangleOptions = { btnLoadTimeout: number; }; +type SetUIArg = Mode | { + mode: Mode, + back?: () => void, + remove?: () => void, +}; + type NRFFilters = { services?: string[]; name?: string; @@ -4294,7 +4300,11 @@ declare class Bangle { * @param {any} callback - A function with one argument which is the direction * @url http://www.espruino.com/Reference#l_Bangle_setUI */ - static setUI(type?: "updown" | "leftright" | "clock" | "clockupdown" | { mode: "custom"; back?: () => void; touch?: TouchCallback; swipe?: SwipeCallback; drag?: DragCallback; btn?: (n: number) => void, remove?: () => void, clock?: boolean }, callback?: (direction?: -1 | 1) => void): void; + static setUI(type?: undefined): void; + static setUI(type: SetUIArg<"updown" | "leftright">, callback: (direction?: -1 | 1) => void): void; + static setUI(type: SetUIArg<"clock">): void; + static setUI(type: SetUIArg<"clockupdown">, callback?: (direction: -1 | 1) => void): void; + static setUI(type: SetUIArg<"custom"> & { touch?: TouchCallback; swipe?: SwipeCallback; drag?: DragCallback; btn?: (n: 1 | 2 | 3) => void; clock?: boolean | 0 | 1 }): void; /** * @url http://www.espruino.com/Reference#l_Bangle_setUI @@ -8946,10 +8956,10 @@ interface Object { * ``` * For more information see `Object.on` * - * @param {any} event - The name of the event, for instance `'data'`. If not specified *all* listeners are removed. + * @param {any} [event] - [optional] The name of the event, for instance `'data'`. If not specified *all* listeners are removed. * @url http://www.espruino.com/Reference#l_Object_removeAllListeners */ - removeAllListeners(event: any): void; + removeAllListeners(event?: any): void; } /** From b5fec28e9f59ebd3d862e759622cd45e3a0ac0fb Mon Sep 17 00:00:00 2001 From: Rob Pilling Date: Fri, 7 Apr 2023 22:32:26 +0100 Subject: [PATCH 10/39] drained: handle empty `_PWR` --- apps/drained/app.js | 4 +++- apps/drained/app.ts | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/apps/drained/app.js b/apps/drained/app.js index 59c8ff690..0928f6440 100644 --- a/apps/drained/app.js +++ b/apps/drained/app.js @@ -5,7 +5,9 @@ if (typeof drainedInterval !== "undefined") Bangle.setLCDBrightness(0); var powerNoop = function () { return false; }; var forceOff = function (name) { - Bangle._PWR[name] = []; + var _a; + if ((_a = Bangle._PWR) === null || _a === void 0 ? void 0 : _a[name]) + Bangle._PWR[name] = []; Bangle["set".concat(name, "Power")](false, app); Bangle["set".concat(name, "Power")] = powerNoop; }; diff --git a/apps/drained/app.ts b/apps/drained/app.ts index 2f1a72755..04f16ef09 100644 --- a/apps/drained/app.ts +++ b/apps/drained/app.ts @@ -11,7 +11,8 @@ Bangle.setLCDBrightness(0); const powerNoop = () => false; const forceOff = (name: "GPS" | "HRM" | "Compass" /*| "Barom"*/) => { - (Bangle as any)._PWR[name] = []; + if ((Bangle as any)._PWR?.[name]) + (Bangle as any)._PWR[name] = []; // if(name === "Barom"){ setBarometerPower(...) } // ^^^^ From 512381a2defe31ea8801347698b9ab287085fad4 Mon Sep 17 00:00:00 2001 From: Rob Pilling Date: Fri, 7 Apr 2023 22:32:38 +0100 Subject: [PATCH 11/39] drained: increase clock font size --- apps/drained/app.js | 2 +- apps/drained/app.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/drained/app.js b/apps/drained/app.js index 0928f6440..b68a33e44 100644 --- a/apps/drained/app.js +++ b/apps/drained/app.js @@ -30,7 +30,7 @@ var draw = function () { require("locale").dow(date, 0).toUpperCase(); g.reset() .clearRect(Bangle.appRect) - .setFont("Vector", 32) + .setFont("Vector", 55) .setFontAlign(0, 0) .drawString(timeStr, x, y) .setFont("Vector", 24) diff --git a/apps/drained/app.ts b/apps/drained/app.ts index 04f16ef09..0d528113c 100644 --- a/apps/drained/app.ts +++ b/apps/drained/app.ts @@ -47,7 +47,7 @@ const draw = () => { g.reset() .clearRect(Bangle.appRect) - .setFont("Vector", 32) + .setFont("Vector", 55) .setFontAlign(0, 0) .drawString(timeStr, x, y) .setFont("Vector", 24) From 9c643f6b5dd584d84e0f75843eefb059e3d37407 Mon Sep 17 00:00:00 2001 From: Rob Pilling Date: Sat, 8 Apr 2023 08:25:27 +0100 Subject: [PATCH 12/39] drained: configure battery% and check interval --- apps/drained/README.md | 1 + apps/drained/boot.ts | 7 +++++-- apps/drained/metadata.json | 3 ++- apps/drained/settings.ts | 37 +++++++++++++++++++++++++++++++++++++ 4 files changed, 45 insertions(+), 3 deletions(-) create mode 100644 apps/drained/settings.ts diff --git a/apps/drained/README.md b/apps/drained/README.md index 92924393a..da3f16ef8 100644 --- a/apps/drained/README.md +++ b/apps/drained/README.md @@ -7,6 +7,7 @@ With this app installed, your Bangle will automatically switch into low power mo ## Time - [x] Show simple date/time - [ ] Disable alarms - with a setting? +- [ ] Smarter/backoff interval for checking battery percentage ## No backlight (#2502) - [x] LCD brightness diff --git a/apps/drained/boot.ts b/apps/drained/boot.ts index 6ee7c8e92..ceba64bad 100644 --- a/apps/drained/boot.ts +++ b/apps/drained/boot.ts @@ -1,8 +1,11 @@ +const { battery = 5, interval = 10 } = require("Storage") + .readJSON(`${app}.setting.json`, true) || {}; + let drainedInterval: number | undefined = setInterval(() => { if(Bangle.isCharging()) return; - if(E.getBattery() > 5) + if(E.getBattery() > battery) return; load("drained.app.js"); -}, 5 * 60 * 1000); +}, interval * 60 * 1000); diff --git a/apps/drained/metadata.json b/apps/drained/metadata.json index 2af347f79..b665311a4 100644 --- a/apps/drained/metadata.json +++ b/apps/drained/metadata.json @@ -11,6 +11,7 @@ "allow_emulator": true, "storage": [ {"name":"drained.boot.js","url":"boot.js"}, - {"name":"drained.app.js","url":"app.js"} + {"name":"drained.app.js","url":"app.js"}, + {"name":"drained.settings.js","url":"settings.js"} ] } diff --git a/apps/drained/settings.ts b/apps/drained/settings.ts new file mode 100644 index 000000000..f511a16c6 --- /dev/null +++ b/apps/drained/settings.ts @@ -0,0 +1,37 @@ +((back: () => void) => { + const SETTINGS_FILE = "drained.setting.json"; + + const storage = require("Storage") + const settings = storage.readJSON(SETTINGS_FILE, true) || {}; + settings.battery ??= 5; + settings.interval ??= 10; + + const save = () => { + storage.writeJSON(SETTINGS_FILE, settings) + }; + + E.showMenu({ + "": { "title": "Drained" }, + "< Back": back, + "Trigger when battery reaches": { + value: settings.battery, + min: 0, + max: 95, + step: 5, + onchange: (v: number) => { + settings.battery = v; + save(); + }, + }, + "Check every N minutes": { + value: settings.interval, + min: 1, + max: 60 * 2, + step: 5, + onchange: (v: number) => { + settings.interval = v; + save(); + }, + }, + }); +}) From 923b5dbb96dbc99f44e885df51156520493843c0 Mon Sep 17 00:00:00 2001 From: Rob Pilling Date: Sat, 8 Apr 2023 08:25:54 +0100 Subject: [PATCH 13/39] drained: clearWatch() and turn off bluetooth --- apps/drained/app.ts | 3 +++ typescript/types/main.d.ts | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/drained/app.ts b/apps/drained/app.ts index 0d528113c..160bed8a8 100644 --- a/apps/drained/app.ts +++ b/apps/drained/app.ts @@ -21,9 +21,12 @@ const forceOff = (name: "GPS" | "HRM" | "Compass" /*| "Barom"*/) => { }; forceOff("GPS"); forceOff("HRM"); +NRF.disconnect(); +NRF.sleep(); // events Bangle.removeAllListeners(); +clearWatch(); // UI Bangle.setOptions({ diff --git a/typescript/types/main.d.ts b/typescript/types/main.d.ts index c66135d4d..4541bef9b 100644 --- a/typescript/types/main.d.ts +++ b/typescript/types/main.d.ts @@ -11450,7 +11450,7 @@ declare function setWatch(func: ((arg: { state: boolean, time: number, lastTime: * @param {any} id - The id returned by a previous call to setWatch. **Only one argument is allowed.** * @url http://www.espruino.com/Reference#l__global_clearWatch */ -declare function clearWatch(id: number): void; +declare function clearWatch(id?: number): void; /** * A variable containing the arguments given to the function: From 105da767b72c6535ca2fa63e66a72c2eecc3b858 Mon Sep 17 00:00:00 2001 From: Rob Pilling Date: Sat, 8 Apr 2023 08:26:10 +0100 Subject: [PATCH 14/39] drained: generate js --- apps/drained/app.js | 3 +++ apps/drained/boot.js | 6 ++++-- apps/drained/settings.js | 36 ++++++++++++++++++++++++++++++++++++ 3 files changed, 43 insertions(+), 2 deletions(-) create mode 100644 apps/drained/settings.js diff --git a/apps/drained/app.js b/apps/drained/app.js index b68a33e44..e8b9bc95d 100644 --- a/apps/drained/app.js +++ b/apps/drained/app.js @@ -13,7 +13,10 @@ var forceOff = function (name) { }; forceOff("GPS"); forceOff("HRM"); +NRF.disconnect(); +NRF.sleep(); Bangle.removeAllListeners(); +clearWatch(); Bangle.setOptions({ wakeOnFaceUp: false, wakeOnTouch: false, diff --git a/apps/drained/boot.js b/apps/drained/boot.js index b6fd3bf35..8a09441db 100644 --- a/apps/drained/boot.js +++ b/apps/drained/boot.js @@ -1,8 +1,10 @@ "use strict"; +var _a = require("Storage") + .readJSON("".concat(app, ".setting.json"), true) || {}, _b = _a.battery, battery = _b === void 0 ? 5 : _b, _c = _a.interval, interval = _c === void 0 ? 10 : _c; var drainedInterval = setInterval(function () { if (Bangle.isCharging()) return; - if (E.getBattery() > 5) + if (E.getBattery() > battery) return; load("drained.app.js"); -}, 5 * 60 * 1000); +}, interval * 60 * 1000); diff --git a/apps/drained/settings.js b/apps/drained/settings.js new file mode 100644 index 000000000..a2ed58163 --- /dev/null +++ b/apps/drained/settings.js @@ -0,0 +1,36 @@ +"use strict"; +(function (back) { + var _a, _b; + var SETTINGS_FILE = "drained.setting.json"; + var storage = require("Storage"); + var settings = storage.readJSON(SETTINGS_FILE, true) || {}; + (_a = settings.battery) !== null && _a !== void 0 ? _a : (settings.battery = 5); + (_b = settings.interval) !== null && _b !== void 0 ? _b : (settings.interval = 10); + var save = function () { + storage.writeJSON(SETTINGS_FILE, settings); + }; + E.showMenu({ + "": { "title": "Drained" }, + "< Back": back, + "Trigger when battery reaches": { + value: settings.battery, + min: 0, + max: 95, + step: 5, + onchange: function (v) { + settings.battery = v; + save(); + }, + }, + "Check every N minutes": { + value: settings.interval, + min: 1, + max: 60 * 2, + step: 5, + onchange: function (v) { + settings.interval = v; + save(); + }, + }, + }); +}); From 7ee3279a02657299368d2ce318991cbaf2e80993 Mon Sep 17 00:00:00 2001 From: Rob Pilling Date: Sat, 8 Apr 2023 08:30:43 +0100 Subject: [PATCH 15/39] Update main.d.ts --- typescript/types/main.d.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/typescript/types/main.d.ts b/typescript/types/main.d.ts index 4541bef9b..f80260a2b 100644 --- a/typescript/types/main.d.ts +++ b/typescript/types/main.d.ts @@ -11447,10 +11447,11 @@ declare function setWatch(func: ((arg: { state: boolean, time: number, lastTime: * Clear the Watch that was created with setWatch. If no parameter is supplied, all watches will be removed. * To avoid accidentally deleting all Watches, if a parameter is supplied but is `undefined` then an Exception will be thrown. * - * @param {any} id - The id returned by a previous call to setWatch. **Only one argument is allowed.** + * @param {any} id - The id returned by a previous call to setWatch. **Only one argument is allowed.** (or pass nothing to clear all watches) * @url http://www.espruino.com/Reference#l__global_clearWatch */ -declare function clearWatch(id?: number): void; +declare function clearWatch(id: number): void; +declare function clearWatch(): void; /** * A variable containing the arguments given to the function: From 663ea983e4a1baf5d11c90e1b38bdd1db50300f9 Mon Sep 17 00:00:00 2001 From: thyttan <97237430+thyttan@users.noreply.github.com> Date: Sat, 8 Apr 2023 23:56:21 +0200 Subject: [PATCH 16/39] Change to 'custom' setUI to not set btn watch > ['clock' - called for clocks. Sets Bangle.CLOCK=1 and allows a button to start the launcher](https://www.espruino.com/Reference#l_Bangle_setUI) --- apps/drained/app.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/drained/app.ts b/apps/drained/app.ts index 160bed8a8..291ff4200 100644 --- a/apps/drained/app.ts +++ b/apps/drained/app.ts @@ -65,12 +65,13 @@ const draw = () => { }; Bangle.setUI({ - mode: "clock", + mode: "custom", remove: () => { if (nextDraw) clearTimeout(nextDraw); nextDraw = undefined; }, }); +Bangle.CLOCK=1; g.clear(); draw(); From f68abbd33d845700f57089e7a70c5d1eabc84ccc Mon Sep 17 00:00:00 2001 From: Rob Pilling Date: Tue, 11 Apr 2023 18:07:46 +0100 Subject: [PATCH 17/39] Regenerate types: ShortBoolean --- typescript/types/main.d.ts | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/typescript/types/main.d.ts b/typescript/types/main.d.ts index f80260a2b..806725535 100644 --- a/typescript/types/main.d.ts +++ b/typescript/types/main.d.ts @@ -90,6 +90,8 @@ type Widget = { }; declare const WIDGETS: { [key: string]: Widget }; +type ShortBoolean = boolean | 0 | 1; + type AccelData = { x: number; y: number; @@ -153,13 +155,13 @@ type LCDMode = | "120x120" | "80x80" -type BangleOptions = { - wakeOnBTN1: boolean; - wakeOnBTN2: boolean; - wakeOnBTN3: boolean; - wakeOnFaceUp: boolean; - wakeOnTouch: boolean; - wakeOnTwist: boolean; +type BangleOptions = { + wakeOnBTN1: Boolean; + wakeOnBTN2: Boolean; + wakeOnBTN3: Boolean; + wakeOnFaceUp: Boolean; + wakeOnTouch: Boolean; + wakeOnTwist: Boolean; twistThreshold: number; twistMaxY: number; twistTimeout: number; @@ -3789,7 +3791,7 @@ declare class Bangle { * @param {any} options * @url http://www.espruino.com/Reference#l_Bangle_setOptions */ - static setOptions(options: { [key in keyof BangleOptions]?: BangleOptions[key] }): void; + static setOptions(options: { [key in keyof BangleOptions]?: BangleOptions[key] }): void; /** * Return the current state of options as set by `Bangle.setOptions` @@ -3850,7 +3852,7 @@ declare class Bangle { * @returns {boolean} Is HRM on? * @url http://www.espruino.com/Reference#l_Bangle_setHRMPower */ - static setHRMPower(isOn: boolean, appID: string): boolean; + static setHRMPower(isOn: ShortBoolean, appID: string): boolean; /** * Is the Heart rate monitor powered? @@ -3874,7 +3876,7 @@ declare class Bangle { * @returns {boolean} Is the GPS on? * @url http://www.espruino.com/Reference#l_Bangle_setGPSPower */ - static setGPSPower(isOn: boolean, appID: string): boolean; + static setGPSPower(isOn: ShortBoolean, appID: string): boolean; /** * Is the GPS powered? @@ -3906,7 +3908,7 @@ declare class Bangle { * @returns {boolean} Is the Compass on? * @url http://www.espruino.com/Reference#l_Bangle_setCompassPower */ - static setCompassPower(isOn: boolean, appID: string): boolean; + static setCompassPower(isOn: ShortBoolean, appID: string): boolean; /** * Is the compass powered? @@ -3934,7 +3936,7 @@ declare class Bangle { * @returns {boolean} Is the Barometer on? * @url http://www.espruino.com/Reference#l_Bangle_setBarometerPower */ - static setBarometerPower(isOn: boolean, appID: string): boolean; + static setBarometerPower(isOn: ShortBoolean, appID: string): boolean; /** * Is the Barometer powered? @@ -4326,7 +4328,7 @@ declare class Bangle { */ static appRect: { x: number, y: number, w: number, h: number, x2: number, y2: number }; - static CLOCK: boolean; + static CLOCK: ShortBoolean; static strokes: undefined | { [key: string]: Unistroke }; } From 1aed25f05ff957a52f26c84ca4f4c811e0c6d41a Mon Sep 17 00:00:00 2001 From: Rob Pilling Date: Tue, 11 Apr 2023 18:15:25 +0100 Subject: [PATCH 18/39] drained: use short booleans --- apps/drained/app.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/drained/app.ts b/apps/drained/app.ts index 291ff4200..cfac5bacf 100644 --- a/apps/drained/app.ts +++ b/apps/drained/app.ts @@ -16,7 +16,7 @@ const forceOff = (name: "GPS" | "HRM" | "Compass" /*| "Barom"*/) => { // if(name === "Barom"){ setBarometerPower(...) } // ^^^^ - Bangle[`set${name}Power`](false, app); + Bangle[`set${name}Power`](0, app); Bangle[`set${name}Power`] = powerNoop; }; forceOff("GPS"); @@ -30,9 +30,9 @@ clearWatch(); // UI Bangle.setOptions({ - wakeOnFaceUp: false, - wakeOnTouch: false, - wakeOnTwist: false, + wakeOnFaceUp: 0, + wakeOnTouch: 0, + wakeOnTwist: 0, }); // clock From 4a8cd6e7a86183907b53ebe7726ef9227d6d00cb Mon Sep 17 00:00:00 2001 From: Rob Pilling Date: Tue, 11 Apr 2023 18:16:01 +0100 Subject: [PATCH 19/39] Regenerate typescript --- apps/drained/app.js | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/apps/drained/app.js b/apps/drained/app.js index e8b9bc95d..ef1a00db0 100644 --- a/apps/drained/app.js +++ b/apps/drained/app.js @@ -8,7 +8,7 @@ var forceOff = function (name) { var _a; if ((_a = Bangle._PWR) === null || _a === void 0 ? void 0 : _a[name]) Bangle._PWR[name] = []; - Bangle["set".concat(name, "Power")](false, app); + Bangle["set".concat(name, "Power")](0, app); Bangle["set".concat(name, "Power")] = powerNoop; }; forceOff("GPS"); @@ -18,9 +18,9 @@ NRF.sleep(); Bangle.removeAllListeners(); clearWatch(); Bangle.setOptions({ - wakeOnFaceUp: false, - wakeOnTouch: false, - wakeOnTwist: false, + wakeOnFaceUp: 0, + wakeOnTouch: 0, + wakeOnTwist: 0, }); var nextDraw; var draw = function () { @@ -47,12 +47,13 @@ var draw = function () { }, 60000 - (date.getTime() % 60000)); }; Bangle.setUI({ - mode: "clock", + mode: "custom", remove: function () { if (nextDraw) clearTimeout(nextDraw); nextDraw = undefined; }, }); +Bangle.CLOCK = 1; g.clear(); draw(); From 671ee4af7af8fcd4acff14abe0ffd3f19a4de074 Mon Sep 17 00:00:00 2001 From: Rob Pilling Date: Tue, 11 Apr 2023 18:25:11 +0100 Subject: [PATCH 20/39] drained: fit settings prompts into screen (and format) --- apps/drained/settings.js | 6 ++++-- apps/drained/settings.ts | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/apps/drained/settings.js b/apps/drained/settings.js index a2ed58163..e5a30163c 100644 --- a/apps/drained/settings.js +++ b/apps/drained/settings.js @@ -12,21 +12,23 @@ E.showMenu({ "": { "title": "Drained" }, "< Back": back, - "Trigger when battery reaches": { + "Trigger at batt%": { value: settings.battery, min: 0, max: 95, step: 5, + format: function (v) { return "".concat(v, "%"); }, onchange: function (v) { settings.battery = v; save(); }, }, - "Check every N minutes": { + "Poll interval": { value: settings.interval, min: 1, max: 60 * 2, step: 5, + format: function (v) { return "".concat(v, " mins"); }, onchange: function (v) { settings.interval = v; save(); diff --git a/apps/drained/settings.ts b/apps/drained/settings.ts index f511a16c6..77ee800f8 100644 --- a/apps/drained/settings.ts +++ b/apps/drained/settings.ts @@ -13,21 +13,23 @@ E.showMenu({ "": { "title": "Drained" }, "< Back": back, - "Trigger when battery reaches": { + "Trigger at batt%": { value: settings.battery, min: 0, max: 95, step: 5, + format: (v: number) => `${v}%`, onchange: (v: number) => { settings.battery = v; save(); }, }, - "Check every N minutes": { + "Poll interval": { value: settings.interval, min: 1, max: 60 * 2, step: 5, + format: (v: number) => `${v} mins`, onchange: (v: number) => { settings.interval = v; save(); From 14ad4b760a1912930a8048336a35deb300412b54 Mon Sep 17 00:00:00 2001 From: Rob Pilling Date: Thu, 13 Apr 2023 17:51:04 +0100 Subject: [PATCH 21/39] drained: add settings type --- apps/drained/app.ts | 1 + apps/drained/boot.ts | 2 +- apps/drained/settings.ts | 7 ++++++- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/apps/drained/app.ts b/apps/drained/app.ts index cfac5bacf..65966ed6e 100644 --- a/apps/drained/app.ts +++ b/apps/drained/app.ts @@ -1,6 +1,7 @@ const app = "drained"; // from boot.js +declare var drainedInterval: number | undefined; if(typeof drainedInterval !== "undefined") drainedInterval = clearInterval(drainedInterval) as undefined; diff --git a/apps/drained/boot.ts b/apps/drained/boot.ts index ceba64bad..6252edafb 100644 --- a/apps/drained/boot.ts +++ b/apps/drained/boot.ts @@ -1,4 +1,4 @@ -const { battery = 5, interval = 10 } = require("Storage") +const { battery = 5, interval = 10 }: DrainedSettings = require("Storage") .readJSON(`${app}.setting.json`, true) || {}; let drainedInterval: number | undefined = setInterval(() => { diff --git a/apps/drained/settings.ts b/apps/drained/settings.ts index 77ee800f8..f763a8fe7 100644 --- a/apps/drained/settings.ts +++ b/apps/drained/settings.ts @@ -1,8 +1,13 @@ +type DrainedSettings = { + battery?: number, + interval?: number, +}; + ((back: () => void) => { const SETTINGS_FILE = "drained.setting.json"; const storage = require("Storage") - const settings = storage.readJSON(SETTINGS_FILE, true) || {}; + const settings: DrainedSettings = storage.readJSON(SETTINGS_FILE, true) || {}; settings.battery ??= 5; settings.interval ??= 10; From 49527fbd22d174ac1d4dba5dc1b1794b5e30ce1f Mon Sep 17 00:00:00 2001 From: Rob Pilling Date: Thu, 13 Apr 2023 17:51:23 +0100 Subject: [PATCH 22/39] drained: add ability to disable other boot code --- apps/drained/boot.ts | 15 ++++++++++++--- apps/drained/settings.ts | 10 ++++++++++ 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/apps/drained/boot.ts b/apps/drained/boot.ts index 6252edafb..faedd3153 100644 --- a/apps/drained/boot.ts +++ b/apps/drained/boot.ts @@ -1,7 +1,16 @@ -const { battery = 5, interval = 10 }: DrainedSettings = require("Storage") - .readJSON(`${app}.setting.json`, true) || {}; +const { battery = 5, interval = 10, disableBoot = false }: DrainedSettings + = require("Storage").readJSON(`drained.setting.json`, true) || {}; -let drainedInterval: number | undefined = setInterval(() => { +if(disableBoot){ + require("Storage").erase(".boot0"); + + Bangle.on("charging", charging => { + if (charging) + eval(require('Storage').read('bootupdate.js')); + }); +} + +drainedInterval = setInterval(() => { if(Bangle.isCharging()) return; if(E.getBattery() > battery) diff --git a/apps/drained/settings.ts b/apps/drained/settings.ts index f763a8fe7..a3b377045 100644 --- a/apps/drained/settings.ts +++ b/apps/drained/settings.ts @@ -1,6 +1,7 @@ type DrainedSettings = { battery?: number, interval?: number, + disableBoot?: ShortBoolean, }; ((back: () => void) => { @@ -10,6 +11,7 @@ type DrainedSettings = { const settings: DrainedSettings = storage.readJSON(SETTINGS_FILE, true) || {}; settings.battery ??= 5; settings.interval ??= 10; + settings.disableBoot ??= false; const save = () => { storage.writeJSON(SETTINGS_FILE, settings) @@ -18,6 +20,14 @@ type DrainedSettings = { E.showMenu({ "": { "title": "Drained" }, "< Back": back, + "Keep startup code": { + value: settings.disableBoot, + format: () => settings.disableBoot ? "No" : "Yes", + onchange: () => { + settings.disableBoot = !settings.disableBoot; + save(); + }, + }, "Trigger at batt%": { value: settings.battery, min: 0, From ab75d5b3530d9622ab275f52b62c9033182f6b61 Mon Sep 17 00:00:00 2001 From: Rob Pilling Date: Thu, 13 Apr 2023 18:05:59 +0100 Subject: [PATCH 23/39] Regenerate JS --- apps/drained/boot.js | 12 +++++++++--- apps/drained/settings.js | 11 ++++++++++- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/apps/drained/boot.js b/apps/drained/boot.js index 8a09441db..a02b20e4f 100644 --- a/apps/drained/boot.js +++ b/apps/drained/boot.js @@ -1,7 +1,13 @@ "use strict"; -var _a = require("Storage") - .readJSON("".concat(app, ".setting.json"), true) || {}, _b = _a.battery, battery = _b === void 0 ? 5 : _b, _c = _a.interval, interval = _c === void 0 ? 10 : _c; -var drainedInterval = setInterval(function () { +var _a = require("Storage").readJSON("drained.setting.json", true) || {}, _b = _a.battery, battery = _b === void 0 ? 5 : _b, _c = _a.interval, interval = _c === void 0 ? 10 : _c, _d = _a.disableBoot, disableBoot = _d === void 0 ? false : _d; +if (disableBoot) { + require("Storage").erase(".boot0"); + Bangle.on("charging", function (charging) { + if (charging) + eval(require('Storage').read('bootupdate.js')); + }); +} +drainedInterval = setInterval(function () { if (Bangle.isCharging()) return; if (E.getBattery() > battery) diff --git a/apps/drained/settings.js b/apps/drained/settings.js index e5a30163c..4461f8965 100644 --- a/apps/drained/settings.js +++ b/apps/drained/settings.js @@ -1,17 +1,26 @@ "use strict"; (function (back) { - var _a, _b; + var _a, _b, _c; var SETTINGS_FILE = "drained.setting.json"; var storage = require("Storage"); var settings = storage.readJSON(SETTINGS_FILE, true) || {}; (_a = settings.battery) !== null && _a !== void 0 ? _a : (settings.battery = 5); (_b = settings.interval) !== null && _b !== void 0 ? _b : (settings.interval = 10); + (_c = settings.disableBoot) !== null && _c !== void 0 ? _c : (settings.disableBoot = false); var save = function () { storage.writeJSON(SETTINGS_FILE, settings); }; E.showMenu({ "": { "title": "Drained" }, "< Back": back, + "Keep startup code": { + value: settings.disableBoot, + format: function () { return settings.disableBoot ? "No" : "Yes"; }, + onchange: function () { + settings.disableBoot = !settings.disableBoot; + save(); + }, + }, "Trigger at batt%": { value: settings.battery, min: 0, From 80a77772e8ebc4e9db55b3a26c62c398d86fdc23 Mon Sep 17 00:00:00 2001 From: Rob Pilling Date: Thu, 13 Apr 2023 18:30:49 +0100 Subject: [PATCH 24/39] drained: emit "drained" event --- apps/drained/README.md | 1 + apps/drained/app.js | 1 + apps/drained/app.ts | 3 +++ apps/drained/boot.js | 18 +++++++++--------- apps/drained/boot.ts | 22 +++++++++++----------- 5 files changed, 25 insertions(+), 20 deletions(-) diff --git a/apps/drained/README.md b/apps/drained/README.md index da3f16ef8..3ddee5907 100644 --- a/apps/drained/README.md +++ b/apps/drained/README.md @@ -20,6 +20,7 @@ With this app installed, your Bangle will automatically switch into low power mo ## Features - [x] Wake on twist -> off (#2502) +- [x] Emit `"drained"` event # Creator diff --git a/apps/drained/app.js b/apps/drained/app.js index ef1a00db0..529d51639 100644 --- a/apps/drained/app.js +++ b/apps/drained/app.js @@ -57,3 +57,4 @@ Bangle.setUI({ Bangle.CLOCK = 1; g.clear(); draw(); +Bangle.emit("drained", E.getBattery()); diff --git a/apps/drained/app.ts b/apps/drained/app.ts index 65966ed6e..a7b53d2b8 100644 --- a/apps/drained/app.ts +++ b/apps/drained/app.ts @@ -76,3 +76,6 @@ Bangle.CLOCK=1; g.clear(); draw(); + +// permit other apps to put themselves into low-power mode +Bangle.emit("drained", E.getBattery()); diff --git a/apps/drained/boot.js b/apps/drained/boot.js index a02b20e4f..9ed524b7f 100644 --- a/apps/drained/boot.js +++ b/apps/drained/boot.js @@ -1,16 +1,16 @@ "use strict"; -var _a = require("Storage").readJSON("drained.setting.json", true) || {}, _b = _a.battery, battery = _b === void 0 ? 5 : _b, _c = _a.interval, interval = _c === void 0 ? 10 : _c, _d = _a.disableBoot, disableBoot = _d === void 0 ? false : _d; -if (disableBoot) { - require("Storage").erase(".boot0"); - Bangle.on("charging", function (charging) { - if (charging) - eval(require('Storage').read('bootupdate.js')); - }); -} +var _a = require("Storage").readJSON("drained.setting.json", true) || {}, _b = _a.battery, threshold = _b === void 0 ? 5 : _b, _c = _a.interval, interval = _c === void 0 ? 10 : _c, _d = _a.disableBoot, disableBoot = _d === void 0 ? false : _d; drainedInterval = setInterval(function () { if (Bangle.isCharging()) return; - if (E.getBattery() > battery) + if (E.getBattery() > threshold) return; + if (disableBoot) { + require("Storage").erase(".boot0"); + Bangle.on("charging", function (charging) { + if (charging) + eval(require('Storage').read('bootupdate.js')); + }); + } load("drained.app.js"); }, interval * 60 * 1000); diff --git a/apps/drained/boot.ts b/apps/drained/boot.ts index faedd3153..46c6811fd 100644 --- a/apps/drained/boot.ts +++ b/apps/drained/boot.ts @@ -1,20 +1,20 @@ -const { battery = 5, interval = 10, disableBoot = false }: DrainedSettings +const { battery: threshold = 5, interval = 10, disableBoot = false }: DrainedSettings = require("Storage").readJSON(`drained.setting.json`, true) || {}; -if(disableBoot){ - require("Storage").erase(".boot0"); - - Bangle.on("charging", charging => { - if (charging) - eval(require('Storage').read('bootupdate.js')); - }); -} - drainedInterval = setInterval(() => { if(Bangle.isCharging()) return; - if(E.getBattery() > battery) + if(E.getBattery() > threshold) return; + if(disableBoot){ + require("Storage").erase(".boot0"); + + Bangle.on("charging", charging => { + if (charging) + eval(require('Storage').read('bootupdate.js')); + }); + } + load("drained.app.js"); }, interval * 60 * 1000); From ea5acf0b12c978b0fadc4691a1347a02af5bd569 Mon Sep 17 00:00:00 2001 From: Rob Pilling Date: Thu, 13 Apr 2023 18:38:39 +0100 Subject: [PATCH 25/39] drained: rearrange disabling/enabling bootcode --- apps/drained/app.js | 7 +++++++ apps/drained/app.ts | 11 +++++++++++ apps/drained/boot.js | 27 ++++++++++++--------------- apps/drained/boot.ts | 10 +++------- 4 files changed, 33 insertions(+), 22 deletions(-) diff --git a/apps/drained/app.js b/apps/drained/app.js index 529d51639..133d5e192 100644 --- a/apps/drained/app.js +++ b/apps/drained/app.js @@ -58,3 +58,10 @@ Bangle.CLOCK = 1; g.clear(); draw(); Bangle.emit("drained", E.getBattery()); +var _a = (require("Storage").readJSON("".concat(app, ".setting.json"), true) || {}).disableBoot, disableBoot = _a === void 0 ? false : _a; +if (disableBoot) { + Bangle.on("charging", function (charging) { + if (charging) + eval(require('Storage').read('bootupdate.js')); + }); +} diff --git a/apps/drained/app.ts b/apps/drained/app.ts index a7b53d2b8..14fa3e378 100644 --- a/apps/drained/app.ts +++ b/apps/drained/app.ts @@ -79,3 +79,14 @@ draw(); // permit other apps to put themselves into low-power mode Bangle.emit("drained", E.getBattery()); + +// restore normal boot on charge +const { disableBoot = false }: DrainedSettings + = require("Storage").readJSON(`${app}.setting.json`, true) || {}; + +if(disableBoot){ + Bangle.on("charging", charging => { + if (charging) + eval(require('Storage').read('bootupdate.js')); + }); +} diff --git a/apps/drained/boot.js b/apps/drained/boot.js index 9ed524b7f..d1c64780b 100644 --- a/apps/drained/boot.js +++ b/apps/drained/boot.js @@ -1,16 +1,13 @@ "use strict"; -var _a = require("Storage").readJSON("drained.setting.json", true) || {}, _b = _a.battery, threshold = _b === void 0 ? 5 : _b, _c = _a.interval, interval = _c === void 0 ? 10 : _c, _d = _a.disableBoot, disableBoot = _d === void 0 ? false : _d; -drainedInterval = setInterval(function () { - if (Bangle.isCharging()) - return; - if (E.getBattery() > threshold) - return; - if (disableBoot) { - require("Storage").erase(".boot0"); - Bangle.on("charging", function (charging) { - if (charging) - eval(require('Storage').read('bootupdate.js')); - }); - } - load("drained.app.js"); -}, interval * 60 * 1000); +{ + var _a = require("Storage").readJSON("drained.setting.json", true) || {}, _b = _a.battery, threshold_1 = _b === void 0 ? 5 : _b, _c = _a.interval, interval = _c === void 0 ? 10 : _c, _d = _a.disableBoot, disableBoot_1 = _d === void 0 ? false : _d; + drainedInterval = setInterval(function () { + if (Bangle.isCharging()) + return; + if (E.getBattery() > threshold_1) + return; + if (disableBoot_1) + require("Storage").erase(".boot0"); + load("drained.app.js"); + }, interval * 60 * 1000); +} diff --git a/apps/drained/boot.ts b/apps/drained/boot.ts index 46c6811fd..c269bf08a 100644 --- a/apps/drained/boot.ts +++ b/apps/drained/boot.ts @@ -1,3 +1,4 @@ +{ const { battery: threshold = 5, interval = 10, disableBoot = false }: DrainedSettings = require("Storage").readJSON(`drained.setting.json`, true) || {}; @@ -7,14 +8,9 @@ drainedInterval = setInterval(() => { if(E.getBattery() > threshold) return; - if(disableBoot){ + if(disableBoot) require("Storage").erase(".boot0"); - Bangle.on("charging", charging => { - if (charging) - eval(require('Storage').read('bootupdate.js')); - }); - } - load("drained.app.js"); }, interval * 60 * 1000); +} From 3ac91b5feefac1cded021d7cdf0ae87d47114c15 Mon Sep 17 00:00:00 2001 From: thyttan <6uuxstm66@mozmail.com⁩> Date: Wed, 19 Apr 2023 18:51:02 +0200 Subject: [PATCH 26/39] make clock_info border one pixel wider --- apps/bwclklite/ChangeLog | 1 + apps/bwclklite/app.js | 2 +- apps/bwclklite/metadata.json | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/bwclklite/ChangeLog b/apps/bwclklite/ChangeLog index c728997da..eca453be0 100644 --- a/apps/bwclklite/ChangeLog +++ b/apps/bwclklite/ChangeLog @@ -34,3 +34,4 @@ clkinfo.addInteractive that would cause ReferenceError. 0.32: Diverge from BW Clock. Change out the custom font for a standard bitmap one to speed up loading times. Remove invertion of theme as this doesn'twork very well with fastloading. Do an quick inital fillRect on theclock info area. +0.33: Make the border of the clock_info box extend all the way to the right of the screen. diff --git a/apps/bwclklite/app.js b/apps/bwclklite/app.js index 1008eae9c..697776ea0 100644 --- a/apps/bwclklite/app.js +++ b/apps/bwclklite/app.js @@ -95,7 +95,7 @@ let clockInfoMenu = clock_info.addInteractive(clockInfoItems, { app: "bwclklite", x : 0, y: 135, - w: W, + w: W+1, h: H-135, draw : (itm, info, options) => { let hideClkInfo = info.text == null; diff --git a/apps/bwclklite/metadata.json b/apps/bwclklite/metadata.json index bab852623..8932274d4 100644 --- a/apps/bwclklite/metadata.json +++ b/apps/bwclklite/metadata.json @@ -1,7 +1,7 @@ { "id": "bwclklite", "name": "BW Clock Lite", - "version": "0.32", + "version": "0.33", "description": "A very minimalistic clock. This version of BW Clock is quicker at the cost of the custom font.", "readme": "README.md", "icon": "app.png", From d0ad4cd8df69746d77b01ea15d84f7496a077c2a Mon Sep 17 00:00:00 2001 From: Rob Pilling Date: Wed, 19 Apr 2023 18:13:23 +0100 Subject: [PATCH 27/39] drained: restore normal operation on sufficient charge --- apps/drained/app.ts | 16 +++++++++++++--- apps/drained/settings.ts | 13 +++++++++++++ 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/apps/drained/app.ts b/apps/drained/app.ts index 14fa3e378..7f019da81 100644 --- a/apps/drained/app.ts +++ b/apps/drained/app.ts @@ -81,12 +81,22 @@ draw(); Bangle.emit("drained", E.getBattery()); // restore normal boot on charge -const { disableBoot = false }: DrainedSettings +const { disableBoot = false, restore = 20 }: DrainedSettings = require("Storage").readJSON(`${app}.setting.json`, true) || {}; +// re-enable normal boot code when we're above a threshold: if(disableBoot){ + const checkCharge = () => { + if(E.getBattery() < restore) return; + + eval(require('Storage').read('bootupdate.js')); + load(); // necessary after updating boot.0 + }; + + if (Bangle.isCharging()) + checkCharge(); + Bangle.on("charging", charging => { - if (charging) - eval(require('Storage').read('bootupdate.js')); + if(charging) checkCharge(); }); } diff --git a/apps/drained/settings.ts b/apps/drained/settings.ts index a3b377045..5b7523fc9 100644 --- a/apps/drained/settings.ts +++ b/apps/drained/settings.ts @@ -1,5 +1,6 @@ type DrainedSettings = { battery?: number, + restore?: number, interval?: number, disableBoot?: ShortBoolean, }; @@ -10,6 +11,7 @@ type DrainedSettings = { const storage = require("Storage") const settings: DrainedSettings = storage.readJSON(SETTINGS_FILE, true) || {}; settings.battery ??= 5; + settings.restore ??= 20; settings.interval ??= 10; settings.disableBoot ??= false; @@ -50,5 +52,16 @@ type DrainedSettings = { save(); }, }, + "Restore watch at %": { + value: settings.restore, + min: 0, + max: 95, + step: 5, + format: (v: number) => `${v}%`, + onchange: (v: number) => { + settings.restore = v; + save(); + }, + }, }); }) From 6830e5ed16afcc6b576974063cc13fdebd241ed6 Mon Sep 17 00:00:00 2001 From: thyttan <6uuxstm66@mozmail.com⁩> Date: Wed, 19 Apr 2023 19:02:55 +0200 Subject: [PATCH 28/39] make clock_info border one pixel wider --- apps/bwclk/ChangeLog | 1 + apps/bwclk/app.js | 2 +- apps/bwclk/metadata.json | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/bwclk/ChangeLog b/apps/bwclk/ChangeLog index 06f94854e..a5458d2da 100644 --- a/apps/bwclk/ChangeLog +++ b/apps/bwclk/ChangeLog @@ -31,3 +31,4 @@ clkinfo.addInteractive that would cause ReferenceError. 0.29: use setItem of clockInfoMenu to change the active item 0.30: Use widget_utils 0.31: Use clock_info module as an app +0.32: Make the border of the clock_info box extend all the way to the right of the screen. diff --git a/apps/bwclk/app.js b/apps/bwclk/app.js index 770c053c2..359baebae 100644 --- a/apps/bwclk/app.js +++ b/apps/bwclk/app.js @@ -135,7 +135,7 @@ let clockInfoMenu = clock_info.addInteractive(clockInfoItems, { app: "bwclk", x : 0, y: 135, - w: W, + w: W+1, h: H-135, draw : (itm, info, options) => { var hideClkInfo = info.text == null; diff --git a/apps/bwclk/metadata.json b/apps/bwclk/metadata.json index 430f466b2..6b8230555 100644 --- a/apps/bwclk/metadata.json +++ b/apps/bwclk/metadata.json @@ -1,7 +1,7 @@ { "id": "bwclk", "name": "BW Clock", - "version": "0.31", + "version": "0.32", "description": "A very minimalistic clock.", "readme": "README.md", "icon": "app.png", From a28891e6dfb89d32cc32bf8148215701c1fe1221 Mon Sep 17 00:00:00 2001 From: Rob Pilling Date: Wed, 19 Apr 2023 18:13:48 +0100 Subject: [PATCH 29/39] drained: guard against BLE exceptions --- apps/drained/app.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/apps/drained/app.ts b/apps/drained/app.ts index 7f019da81..f8b2bee2a 100644 --- a/apps/drained/app.ts +++ b/apps/drained/app.ts @@ -22,8 +22,12 @@ const forceOff = (name: "GPS" | "HRM" | "Compass" /*| "Barom"*/) => { }; forceOff("GPS"); forceOff("HRM"); -NRF.disconnect(); -NRF.sleep(); +try{ + NRF.disconnect(); + NRF.sleep(); +}catch(e){ + console.log(`couldn't disable ble: ${e}`); +} // events Bangle.removeAllListeners(); From c7aa2b36553dd6f36fb203e74a8f51ddd7b9426d Mon Sep 17 00:00:00 2001 From: Rob Pilling Date: Wed, 19 Apr 2023 18:14:10 +0100 Subject: [PATCH 30/39] drained: load self on startup this allows us to then control restoring normal operation --- apps/drained/boot.ts | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/apps/drained/boot.ts b/apps/drained/boot.ts index c269bf08a..4dc885c20 100644 --- a/apps/drained/boot.ts +++ b/apps/drained/boot.ts @@ -8,9 +8,14 @@ drainedInterval = setInterval(() => { if(E.getBattery() > threshold) return; - if(disableBoot) - require("Storage").erase(".boot0"); + const app = "drained.app.js"; - load("drained.app.js"); + if(disableBoot) + require("Storage").write( + ".boot0", + `if(typeof __FILE__ === "undefined" || __FILE__ !== "${app}") setTimeout(load, 100, "${app}");` + ); + + load(app); }, interval * 60 * 1000); } From 99a211a93751dd0d5383848f8ed402397d081990 Mon Sep 17 00:00:00 2001 From: Rob Pilling Date: Wed, 19 Apr 2023 18:16:21 +0100 Subject: [PATCH 31/39] drained: publicise `drainedRestore()` --- apps/drained/app.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/apps/drained/app.ts b/apps/drained/app.ts index f8b2bee2a..8dc4a77c8 100644 --- a/apps/drained/app.ts +++ b/apps/drained/app.ts @@ -90,11 +90,14 @@ const { disableBoot = false, restore = 20 }: DrainedSettings // re-enable normal boot code when we're above a threshold: if(disableBoot){ - const checkCharge = () => { - if(E.getBattery() < restore) return; - + function drainedRestore() { // "public", to allow users to call eval(require('Storage').read('bootupdate.js')); load(); // necessary after updating boot.0 + } + + const checkCharge = () => { + if(E.getBattery() < restore) return; + drainedRestore(); }; if (Bangle.isCharging()) From 73d41a40ff26099f058146a2a2d32ad589da11dd Mon Sep 17 00:00:00 2001 From: Rob Pilling Date: Wed, 19 Apr 2023 18:33:30 +0100 Subject: [PATCH 32/39] drained: allow user to restore full-power mode --- apps/drained/app.ts | 40 +++++++++++++++++++++++++++------------- 1 file changed, 27 insertions(+), 13 deletions(-) diff --git a/apps/drained/app.ts b/apps/drained/app.ts index 8dc4a77c8..af97454a4 100644 --- a/apps/drained/app.ts +++ b/apps/drained/app.ts @@ -69,17 +69,29 @@ const draw = () => { }, 60000 - (date.getTime() % 60000)); }; -Bangle.setUI({ - mode: "custom", - remove: () => { - if (nextDraw) clearTimeout(nextDraw); - nextDraw = undefined; - }, -}); -Bangle.CLOCK=1; +const reload = () => { + Bangle.setUI({ + mode: "custom", + remove: () => { + if (nextDraw) clearTimeout(nextDraw); + nextDraw = undefined; + }, + btn: () => { + E.showPrompt("Restore watch to full power?").then(v => { + if(v){ + drainedRestore(); + }else{ + reload(); + } + }) + } + }); + Bangle.CLOCK=1; -g.clear(); -draw(); + g.clear(); + draw(); +}; +reload(); // permit other apps to put themselves into low-power mode Bangle.emit("drained", E.getBattery()); @@ -89,12 +101,14 @@ const { disableBoot = false, restore = 20 }: DrainedSettings = require("Storage").readJSON(`${app}.setting.json`, true) || {}; // re-enable normal boot code when we're above a threshold: -if(disableBoot){ - function drainedRestore() { // "public", to allow users to call +function drainedRestore() { // "public", to allow users to call + if(disableBoot){ eval(require('Storage').read('bootupdate.js')); - load(); // necessary after updating boot.0 } + load(); // necessary after updating boot.0 +} +if(disableBoot){ const checkCharge = () => { if(E.getBattery() < restore) return; drainedRestore(); From f8fc93301e78f614382757e3f8c2e5cbbe0f6950 Mon Sep 17 00:00:00 2001 From: Rob Pilling Date: Wed, 19 Apr 2023 18:36:03 +0100 Subject: [PATCH 33/39] drained: handle errors from bootupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Such as: ``` Uncaught ReferenceError: "bleServiceOptions" is not defined  at line 4 col 228 in .boot0 ...ECwA=="));bleServiceOptions.hid=Bangle.HID;                               ^ at line 68 col 50 in drained.app.js eval(require('Storage').read('bootupdate.js'));                                              ^ ``` --- apps/drained/app.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/apps/drained/app.ts b/apps/drained/app.ts index af97454a4..9fc2665ee 100644 --- a/apps/drained/app.ts +++ b/apps/drained/app.ts @@ -103,7 +103,11 @@ const { disableBoot = false, restore = 20 }: DrainedSettings // re-enable normal boot code when we're above a threshold: function drainedRestore() { // "public", to allow users to call if(disableBoot){ - eval(require('Storage').read('bootupdate.js')); + try{ + eval(require('Storage').read('bootupdate.js')); + }catch(e){ + console.log("error restoring bootupdate:" + e); + } } load(); // necessary after updating boot.0 } From 96c8b9e49dde8a9fdb10bb944b2ffe3b998a288f Mon Sep 17 00:00:00 2001 From: Rob Pilling Date: Wed, 19 Apr 2023 18:14:41 +0100 Subject: [PATCH 34/39] drained: regenerate JS --- apps/drained/app.js | 66 +++++++++++++++++++++++++++++++--------- apps/drained/boot.js | 5 +-- apps/drained/settings.js | 18 +++++++++-- 3 files changed, 69 insertions(+), 20 deletions(-) diff --git a/apps/drained/app.js b/apps/drained/app.js index 133d5e192..000727e19 100644 --- a/apps/drained/app.js +++ b/apps/drained/app.js @@ -13,8 +13,13 @@ var forceOff = function (name) { }; forceOff("GPS"); forceOff("HRM"); -NRF.disconnect(); -NRF.sleep(); +try { + NRF.disconnect(); + NRF.sleep(); +} +catch (e) { + console.log("couldn't disable ble: ".concat(e)); +} Bangle.removeAllListeners(); clearWatch(); Bangle.setOptions({ @@ -46,22 +51,53 @@ var draw = function () { draw(); }, 60000 - (date.getTime() % 60000)); }; -Bangle.setUI({ - mode: "custom", - remove: function () { - if (nextDraw) - clearTimeout(nextDraw); - nextDraw = undefined; - }, -}); -Bangle.CLOCK = 1; -g.clear(); -draw(); +var reload = function () { + Bangle.setUI({ + mode: "custom", + remove: function () { + if (nextDraw) + clearTimeout(nextDraw); + nextDraw = undefined; + }, + btn: function () { + E.showPrompt("Restore watch to full power?").then(function (v) { + if (v) { + drainedRestore(); + } + else { + reload(); + } + }); + } + }); + Bangle.CLOCK = 1; + g.clear(); + draw(); +}; +reload(); Bangle.emit("drained", E.getBattery()); -var _a = (require("Storage").readJSON("".concat(app, ".setting.json"), true) || {}).disableBoot, disableBoot = _a === void 0 ? false : _a; +var _a = require("Storage").readJSON("".concat(app, ".setting.json"), true) || {}, _b = _a.disableBoot, disableBoot = _b === void 0 ? false : _b, _c = _a.restore, restore = _c === void 0 ? 20 : _c; +function drainedRestore() { + if (disableBoot) { + try { + eval(require('Storage').read('bootupdate.js')); + } + catch (e) { + console.log("error restoring bootupdate:" + e); + } + } + load(); +} if (disableBoot) { + var checkCharge_1 = function () { + if (E.getBattery() < restore) + return; + drainedRestore(); + }; + if (Bangle.isCharging()) + checkCharge_1(); Bangle.on("charging", function (charging) { if (charging) - eval(require('Storage').read('bootupdate.js')); + checkCharge_1(); }); } diff --git a/apps/drained/boot.js b/apps/drained/boot.js index d1c64780b..639b39ef3 100644 --- a/apps/drained/boot.js +++ b/apps/drained/boot.js @@ -6,8 +6,9 @@ return; if (E.getBattery() > threshold_1) return; + var app = "drained.app.js"; if (disableBoot_1) - require("Storage").erase(".boot0"); - load("drained.app.js"); + require("Storage").write(".boot0", "if(typeof __FILE__ === \"undefined\" || __FILE__ !== \"".concat(app, "\") setTimeout(load, 100, \"").concat(app, "\");")); + load(app); }, interval * 60 * 1000); } diff --git a/apps/drained/settings.js b/apps/drained/settings.js index 4461f8965..310570455 100644 --- a/apps/drained/settings.js +++ b/apps/drained/settings.js @@ -1,12 +1,13 @@ "use strict"; (function (back) { - var _a, _b, _c; + var _a, _b, _c, _d; var SETTINGS_FILE = "drained.setting.json"; var storage = require("Storage"); var settings = storage.readJSON(SETTINGS_FILE, true) || {}; (_a = settings.battery) !== null && _a !== void 0 ? _a : (settings.battery = 5); - (_b = settings.interval) !== null && _b !== void 0 ? _b : (settings.interval = 10); - (_c = settings.disableBoot) !== null && _c !== void 0 ? _c : (settings.disableBoot = false); + (_b = settings.restore) !== null && _b !== void 0 ? _b : (settings.restore = 20); + (_c = settings.interval) !== null && _c !== void 0 ? _c : (settings.interval = 10); + (_d = settings.disableBoot) !== null && _d !== void 0 ? _d : (settings.disableBoot = false); var save = function () { storage.writeJSON(SETTINGS_FILE, settings); }; @@ -43,5 +44,16 @@ save(); }, }, + "Restore watch at %": { + value: settings.restore, + min: 0, + max: 95, + step: 5, + format: function (v) { return "".concat(v, "%"); }, + onchange: function (v) { + settings.restore = v; + save(); + }, + }, }); }); From 524b204a30b3f6bf564d0bc9a41b9098c0b209b6 Mon Sep 17 00:00:00 2001 From: Rob Pilling Date: Wed, 19 Apr 2023 22:40:54 +0100 Subject: [PATCH 35/39] drained: document features in README --- apps/drained/README.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/apps/drained/README.md b/apps/drained/README.md index 3ddee5907..7bef74d81 100644 --- a/apps/drained/README.md +++ b/apps/drained/README.md @@ -1,9 +1,15 @@ # Drained -With this app installed, your Bangle will automatically switch into low power mode when the battery reaches 5% battery, displaying a simple clock. +With this app installed, your Bangle will automatically switch into low power mode when the battery reaches 5% battery (or a preconfigured percentage), displaying a simple clock. When the battery is then charged above 20% (also configurable), normal operation is restored. + +Low power mode can also be exited manually, by tapping the primary watch button (an initial tap may be required to unlock the watch). # Features +## Persistence +- [x] Restore normal operation with sufficient charge +- [x] Reactivate on watch startup + ## Time - [x] Show simple date/time - [ ] Disable alarms - with a setting? From 45ec4dddd4c1634f307c1246ec286c5be96b6b3c Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Thu, 20 Apr 2023 08:58:51 +0100 Subject: [PATCH 36/39] remind about latest version --- loader.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/loader.js b/loader.js index 414aa99d1..1fcae8da6 100644 --- a/loader.js +++ b/loader.js @@ -16,7 +16,7 @@ if (window.location.host=="banglejs.com") { 'This is not the official Bangle.js App Loader - you can try the Official Version here.'; } -var RECOMMENDED_VERSION = "2v16"; +var RECOMMENDED_VERSION = "2v17"; // could check http://www.espruino.com/json/BANGLEJS.json for this // We're only interested in Bangles From fc82d3b13bc49c49de145802731f2b44d5293ef4 Mon Sep 17 00:00:00 2001 From: Rob Pilling Date: Thu, 20 Apr 2023 13:06:29 +0100 Subject: [PATCH 37/39] Update typescript & remove "use strict"s --- apps/clkinfostopw/clkinfo.ts | 4 +- apps/clkinfostopw/settings.ts | 4 +- apps/drained/app.js | 1 - apps/drained/boot.js | 1 - apps/drained/settings.js | 1 - apps/drained/settings.ts | 4 +- typescript/types/funcs.d.ts | 2 + typescript/types/main.d.ts | 120 +++++++++++++++++++++++++--------- 8 files changed, 97 insertions(+), 40 deletions(-) create mode 100644 typescript/types/funcs.d.ts diff --git a/apps/clkinfostopw/clkinfo.ts b/apps/clkinfostopw/clkinfo.ts index 6051e106e..e5361644d 100644 --- a/apps/clkinfostopw/clkinfo.ts +++ b/apps/clkinfostopw/clkinfo.ts @@ -1,4 +1,4 @@ -((): ClockInfo.Menu => { +(() => { let durationOnPause = "---"; let redrawInterval: number | undefined; let startTime: number | undefined; @@ -74,4 +74,4 @@ } ] }; -}) +}) satisfies ClockInfoFunc diff --git a/apps/clkinfostopw/settings.ts b/apps/clkinfostopw/settings.ts index 3d7ff5c05..a9a35f245 100644 --- a/apps/clkinfostopw/settings.ts +++ b/apps/clkinfostopw/settings.ts @@ -6,7 +6,7 @@ type StopWatchSettings = { format: StopWatchFormat, }; -((back: () => void) => { +(back => { const SETTINGS_FILE = "clkinfostopw.setting.json"; const storage = require("Storage"); @@ -31,4 +31,4 @@ type StopWatchSettings = { }, }, }); -}) +}) satisfies SettingsFunc diff --git a/apps/drained/app.js b/apps/drained/app.js index 000727e19..f9ae04605 100644 --- a/apps/drained/app.js +++ b/apps/drained/app.js @@ -1,4 +1,3 @@ -"use strict"; var app = "drained"; if (typeof drainedInterval !== "undefined") drainedInterval = clearInterval(drainedInterval); diff --git a/apps/drained/boot.js b/apps/drained/boot.js index 639b39ef3..97f405123 100644 --- a/apps/drained/boot.js +++ b/apps/drained/boot.js @@ -1,4 +1,3 @@ -"use strict"; { var _a = require("Storage").readJSON("drained.setting.json", true) || {}, _b = _a.battery, threshold_1 = _b === void 0 ? 5 : _b, _c = _a.interval, interval = _c === void 0 ? 10 : _c, _d = _a.disableBoot, disableBoot_1 = _d === void 0 ? false : _d; drainedInterval = setInterval(function () { diff --git a/apps/drained/settings.js b/apps/drained/settings.js index 310570455..fe4ab9c4b 100644 --- a/apps/drained/settings.js +++ b/apps/drained/settings.js @@ -1,4 +1,3 @@ -"use strict"; (function (back) { var _a, _b, _c, _d; var SETTINGS_FILE = "drained.setting.json"; diff --git a/apps/drained/settings.ts b/apps/drained/settings.ts index 5b7523fc9..c79e6605c 100644 --- a/apps/drained/settings.ts +++ b/apps/drained/settings.ts @@ -5,7 +5,7 @@ type DrainedSettings = { disableBoot?: ShortBoolean, }; -((back: () => void) => { +(back => { const SETTINGS_FILE = "drained.setting.json"; const storage = require("Storage") @@ -64,4 +64,4 @@ type DrainedSettings = { }, }, }); -}) +}) satisfies SettingsFunc diff --git a/typescript/types/funcs.d.ts b/typescript/types/funcs.d.ts new file mode 100644 index 000000000..81c4646ea --- /dev/null +++ b/typescript/types/funcs.d.ts @@ -0,0 +1,2 @@ +type SettingsFunc = (back: () => void) => void; +type ClockInfoFunc = () => ClockInfo.Menu; diff --git a/typescript/types/main.d.ts b/typescript/types/main.d.ts index 806725535..29118b7c6 100644 --- a/typescript/types/main.d.ts +++ b/typescript/types/main.d.ts @@ -304,6 +304,12 @@ type VariableSizeInformation = { more?: VariableSizeInformation; }; +type PipeOptions = { + chunkSize?: number, + end?: boolean, + complete?: () => void, +}; + // CLASSES @@ -802,6 +808,29 @@ declare class NRF { */ static on(event: "security", callback: (status: any) => void): void; + /** + * Called when Bluetooth advertising starts or stops on Espruino + * @param {string} event - The event to listen to. + * @param {(isAdvertising: boolean) => void} callback - A function that is executed when the event occurs. Its arguments are: + * * `isAdvertising` Whether we are advertising or not + * @url http://www.espruino.com/Reference#l_NRF_advertising + */ + static on(event: "advertising", callback: (isAdvertising: boolean) => void): void; + + /** + * Called during the bonding process to update on status + * `status` is one of: + * * `"request"` - Bonding has been requested in code via `NRF.startBonding` + * * `"start"` - The bonding procedure has started + * * `"success"` - The bonding procedure has succeeded (`NRF.startBonding`'s promise resolves) + * * `"fail"` - The bonding procedure has failed (`NRF.startBonding`'s promise rejects) + * @param {string} event - The event to listen to. + * @param {(status: any) => void} callback - A function that is executed when the event occurs. Its arguments are: + * * `status` One of `'request'/'start'/'success'/'fail'` + * @url http://www.espruino.com/Reference#l_NRF_bond + */ + static on(event: "bond", callback: (status: any) => void): void; + /** * Called with a single byte value when Espruino is set up as a HID device and the * computer it is connected to sends a HID report back to Espruino. This is usually @@ -993,15 +1022,17 @@ declare class NRF { * `options` is an object, which can contain: * ``` * { - * name: "Hello" // The name of the device - * showName: true/false // include full name, or nothing - * discoverable: true/false // general discoverable, or limited - default is limited - * connectable: true/false // whether device is connectable - default is true - * scannable : true/false // whether device can be scanned for scan response packets - default is true - * interval: 600 // Advertising interval in msec, between 20 and 10000 (default is 375ms) - * manufacturer: 0x0590 // IF sending manufacturer data, this is the manufacturer ID - * manufacturerData: [...] // IF sending manufacturer data, this is an array of data - * phy: "1mbps/2mbps/coded" // (NRF52840 only) use the long-range coded phy for transmission (1mbps default) + * name: "Hello" // The name of the device + * showName: true/false // include full name, or nothing + * discoverable: true/false // general discoverable, or limited - default is limited + * connectable: true/false // whether device is connectable - default is true + * scannable : true/false // whether device can be scanned for scan response packets - default is true + * whenConnected : true/false // keep advertising when connected (nRF52 only) + * // switches to advertising as non-connectable when it is connected + * interval: 600 // Advertising interval in msec, between 20 and 10000 (default is 375ms) + * manufacturer: 0x0590 // IF sending manufacturer data, this is the manufacturer ID + * manufacturerData: [...] // IF sending manufacturer data, this is an array of data + * phy: "1mbps/2mbps/coded" // (NRF52840 only) use the long-range coded phy for transmission (1mbps default) * } * ``` * Setting `connectable` and `scannable` to false gives the lowest power @@ -2282,7 +2313,7 @@ declare class Socket { * end : call the 'end' function on the destination when the source is finished * @url http://www.espruino.com/Reference#l_Socket_pipe */ - pipe(destination: any, options?: any): void; + pipe(destination: any, options?: PipeOptions): void /** * This function writes the `data` argument as a string. Data that is passed in @@ -2477,7 +2508,7 @@ declare class httpSRq { * end : call the 'end' function on the destination when the source is finished * @url http://www.espruino.com/Reference#l_httpSRq_pipe */ - pipe(destination: any, options?: any): void; + pipe(dest: any, options?: PipeOptions): void } /** @@ -2700,7 +2731,7 @@ declare class httpCRs { * end : call the 'end' function on the destination when the source is finished * @url http://www.espruino.com/Reference#l_httpCRs_pipe */ - pipe(destination: any, options?: any): void; + pipe(destination: any, options?: PipeOptions): void } /** @@ -2914,20 +2945,11 @@ declare class Microbit { } -/** - * This is the File object - it allows you to stream data to and from files (As - * opposed to the `require('fs').readFile(..)` style functions that read an entire - * file). - * To create a File object, you must type ```var fd = - * E.openFile('filepath','mode')``` - see [E.openFile](#l_E_openFile) for more - * information. - * **Note:** If you want to remove an SD card after you have started using it, you - * *must* call `E.unmountSD()` or you may cause damage to the card. - * @url http://www.espruino.com/Reference#File - */ -declare class File { +interface FileConstructor { +} +interface File { /** * Close an open file. * @url http://www.espruino.com/Reference#l_File_close @@ -2984,9 +3006,22 @@ declare class File { * end : call the 'end' function on the destination when the source is finished * @url http://www.espruino.com/Reference#l_File_pipe */ - pipe(destination: any, options?: any): void; + pipe(destination: any, options?: PipeOptions): void } +/** + * This is the File object - it allows you to stream data to and from files (As + * opposed to the `require('fs').readFile(..)` style functions that read an entire + * file). + * To create a File object, you must type ```var fd = + * E.openFile('filepath','mode')``` - see [E.openFile](#l_E_openFile) for more + * information. + * **Note:** If you want to remove an SD card after you have started using it, you + * *must* call `E.unmountSD()` or you may cause damage to the card. + * @url http://www.espruino.com/Reference#File + */ +declare const File: FileConstructor + /** * Class containing [Puck.js's](http://www.puck-js.com) utility functions. * @url http://www.espruino.com/Reference#Puck @@ -3527,7 +3562,7 @@ declare class Bangle { * @param {string} event - The event to listen to. * @param {(button: number, xy: any) => void} callback - A function that is executed when the event occurs. Its arguments are: * * `button` `1` for left, `2` for right - * * `xy` Object of form `{x,y}` containing touch coordinates (if the device supports full touch). Clipped to 0..175 (LCD pixel coordinates) on firmware 2v13 and later. + * * `xy` Object of form `{x,y,type}` containing touch coordinates (if the device supports full touch). Clipped to 0..175 (LCD pixel coordinates) on firmware 2v13 and later.`type` is only available on Bangle.js 2 and is an integer, either 0 for swift touches or 2 for longer ones. * @url http://www.espruino.com/Reference#l_Bangle_touch */ static on(event: "touch", callback: TouchCallback): void; @@ -7984,7 +8019,7 @@ declare class E { * end : call the 'end' function on the destination when the source is finished * @url http://www.espruino.com/Reference#l_E_pipe */ - static pipe(source: any, destination: any, options?: { chunkSize?: number, end?: boolean, complete?: () => void }): void + static pipe(source: any, destination: any, options?: PipeOptions): void /** * Create an ArrayBuffer from the given string. This is done via a reference, not a @@ -8621,6 +8656,12 @@ declare class E { /** * This class provides a software-defined OneWire master. It is designed to be * similar to Arduino's OneWire library. + * **Note:** OneWire commands are very timing-sensitive, and on nRF52 devices + * (Bluetooth LE Espruino boards) the bluetooth stack can get in the way. Before + * version 2v18 of Espruino OneWire could be unreliable, but as of firmware 2v18 + * Espruino now schedules OneWire accesses with the bluetooth stack to ensure it doesn't interfere. + * OneWire is now reliable but some functions such as `OneWire.search` can now take + * a while to execute (around 1 second). * @url http://www.espruino.com/Reference#OneWire */ declare class OneWire { @@ -9680,6 +9721,19 @@ declare class StorageFile { * @url http://www.espruino.com/Reference#l_StorageFile_erase */ erase(): void; + + /** + * Pipe this file to a stream (an object with a 'write' method) + * + * @param {any} destination - The destination file/stream that will receive content from the source. + * @param {any} [options] + * [optional] An object `{ chunkSize : int=32, end : bool=true, complete : function }` + * chunkSize : The amount of data to pipe from source to destination at a time + * complete : a function to call when the pipe activity is complete + * end : call the 'end' function on the destination when the source is finished + * @url http://www.espruino.com/Reference#l_StorageFile_pipe + */ + pipe(destination: any, options?: PipeOptions): void } interface processConstructor { @@ -10014,7 +10068,7 @@ declare class Serial { * end : call the 'end' function on the destination when the source is finished * @url http://www.espruino.com/Reference#l_Serial_pipe */ - pipe(destination: any, options?: any): void; + pipe(destination: any, options?: PipeOptions): void } interface StringConstructor { @@ -12004,6 +12058,10 @@ declare module "neopixel" { * white). These are still supported but the array of data supplied must still be a * multiple of 3 bytes long. Just round the size up - it won't cause any problems. * * On some platforms like STM32, pins capable of hardware SPI MOSI are required. + * * On STM32, `neopixel.write` chooses a hardware SPI device to output the signal on + * and uses that. However in order to avoid spikes in the output, if that hardware device is *already + * initialised* it will not be re-initialised. This means that if the SPI device was already in use, + * you may have to use `SPIx.setup({baud:3200000, mosi:the_pin})` to force it to be re-setup on the pin. * * Espruino devices tend to have 3.3v IO, while WS2812/etc run off of 5v. Many * WS2812 will only register a logic '1' at 70% of their input voltage - so if * powering them off 5v you will not be able to send them data reliably. You can @@ -12928,7 +12986,7 @@ declare module "fs" { * end : call the 'end' function on the destination when the source is finished * @url http://www.espruino.com/Reference#l_fs_pipe */ - function pipe(source: any, destination: any, options?: any): void; + function pipe(destination: any, options?: PipeOptions): void } /** @@ -13285,7 +13343,7 @@ declare module "Storage" { /** * The Flash Storage system is journaling. To make the most of the limited write - * cycles of Flash memory, Espruino marks deleted/replaced files as garbage and + * cycles of Flash memory, Espruino marks deleted/replaced files as garbage/trash files and * moves on to a fresh part of flash memory. Espruino only fully erases those files * when it is running low on flash, or when `compact` is called. * `compact` may fail if there isn't enough RAM free on the stack to use as swap @@ -13324,7 +13382,7 @@ declare module "Storage" { * fileBytes // How many bytes of allocated files do we have? * fileCount // How many allocated files do we have? * trashBytes // How many bytes of trash files do we have? - * trashCount // How many trash files do we have? + * trashCount // How many trash files do we have? (can be cleared with .compact) * } * ``` * @returns {any} An object containing info about the current Storage system From 079598bc4884b2b58436ff8288b0cc9baa40b3ae Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Fri, 21 Apr 2023 11:38:27 +0100 Subject: [PATCH 38/39] Merge in https://github.com/espruino/BangleApps/pull/2702 (PR included a bunch of other stuff not required) --- apps/xxlmessage/ChangeLog | 2 + apps/xxlmessage/README.md | 13 ++ apps/xxlmessage/app-icon.js | 1 + apps/xxlmessage/app.js | 42 +++++++ apps/xxlmessage/app.png | Bin 0 -> 315 bytes apps/xxlmessage/boot.js | 1 + apps/xxlmessage/lib-unbuffered.js | 133 ++++++++++++++++++++ apps/xxlmessage/lib.js | 194 ++++++++++++++++++++++++++++++ apps/xxlmessage/metadata.json | 20 +++ apps/xxlmessage/screenshot.png | Bin 0 -> 2032 bytes 10 files changed, 406 insertions(+) create mode 100644 apps/xxlmessage/ChangeLog create mode 100644 apps/xxlmessage/README.md create mode 100644 apps/xxlmessage/app-icon.js create mode 100644 apps/xxlmessage/app.js create mode 100644 apps/xxlmessage/app.png create mode 100644 apps/xxlmessage/boot.js create mode 100644 apps/xxlmessage/lib-unbuffered.js create mode 100644 apps/xxlmessage/lib.js create mode 100644 apps/xxlmessage/metadata.json create mode 100644 apps/xxlmessage/screenshot.png diff --git a/apps/xxlmessage/ChangeLog b/apps/xxlmessage/ChangeLog new file mode 100644 index 000000000..4c587db52 --- /dev/null +++ b/apps/xxlmessage/ChangeLog @@ -0,0 +1,2 @@ +0.01: New App! +0.02: Display icon of the message origin's app \ No newline at end of file diff --git a/apps/xxlmessage/README.md b/apps/xxlmessage/README.md new file mode 100644 index 000000000..40e62fdd2 --- /dev/null +++ b/apps/xxlmessage/README.md @@ -0,0 +1,13 @@ +# XXL Message app +This app displays an incomming message with a very large +font and scrolls the text. For people who can't read the +menu font without glasses, this might be an alternative +to the default messages UI app. + +When arrived, new messages are displayed instantly on the screen. +When the message fully scrolled two times or +if you touch the screen or press the button, +the default clock is loaded. + +Nothing more, nothing less. + diff --git a/apps/xxlmessage/app-icon.js b/apps/xxlmessage/app-icon.js new file mode 100644 index 000000000..ee6642f11 --- /dev/null +++ b/apps/xxlmessage/app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwwcA/4A/AH4A/AH2SpMkAQ1/CI3+CI+fB4v5AQQRFk4JB84REBAXkCIgLFEAYsCIgo+BCIwLEC4oRHF4w7CCJAIRGQaDECLQIRLKB9QUKDFRdKB3GQYwAFBwpKFAAhEFAQokHAH4A/AH4A/ABA")) \ No newline at end of file diff --git a/apps/xxlmessage/app.js b/apps/xxlmessage/app.js new file mode 100644 index 000000000..207221fc6 --- /dev/null +++ b/apps/xxlmessage/app.js @@ -0,0 +1,42 @@ + + +if (require("Storage").read("messagegui")){ // "messagegui" module is installed + require("messages").openGUI(); + console.log("Opened Messages UI"); + Bangle.load("messagegui"); +} + + +function stop() { + g.setBgColor(0, 1, 1); + g.clear(); + g.reset(); + load(); +} +var txt = 'No Messages'; +try{ + console.log("try delete messages"); + var MESSAGES = require("messages").getMessages(); + MESSAGES = []; + txt = 'Deleted all messages'; + console.log("worked"); +}catch(e){} +g.setBgColor('#ffff00'); +g.setColor('#000000'); +g.clear(); + +g.setFont('6x8:3'); +g.setFontAlign(0, 0); +g.setColor('#000000'); +g.drawString(g.wrapString(txt, g.getWidth()).join("\n"), g.getWidth()/2, g.getHeight()/2); + +Bangle.loadWidgets(); +Bangle.drawWidgets(); + +//E.showMessage(txt,{ +// title:"XXL Messages", +// img:atob("FBQBAfgAf+Af/4P//D+fx/n+f5/v+f//n//5//+f//n////3//5/n+P//D//wf/4B/4AH4A=") // (i) +//}) + +setTimeout(stop, 4000); + diff --git a/apps/xxlmessage/app.png b/apps/xxlmessage/app.png new file mode 100644 index 0000000000000000000000000000000000000000..88dae4c66789915451183a6f1d860be86908d95c GIT binary patch literal 315 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA1SD@H(7p!ia> zONTwMEm$OyW6_ei6DE~8rHHtIHFqeSGMwv?xhz%Ssl^tp);j&N#?N0*`(22B`J%RZ rSEbdLHKLpU|8Ru32<|l7-~X7dHq;*x?>3YG`i;TU)z4*}Q$iB}(i3^k literal 0 HcmV?d00001 diff --git a/apps/xxlmessage/boot.js b/apps/xxlmessage/boot.js new file mode 100644 index 000000000..62053a0b9 --- /dev/null +++ b/apps/xxlmessage/boot.js @@ -0,0 +1 @@ +Bangle.on("message", (type, msg) => require("xxlmessage.lib.js").listener(type, msg)); \ No newline at end of file diff --git a/apps/xxlmessage/lib-unbuffered.js b/apps/xxlmessage/lib-unbuffered.js new file mode 100644 index 000000000..68fb2a7a2 --- /dev/null +++ b/apps/xxlmessage/lib-unbuffered.js @@ -0,0 +1,133 @@ +// GB({"t":"notify","id":1575479849,"src":"Hangouts","title":"A Name","body":"message contents"}) +var xxl = { +// private: + msg: [], + drawTimeout: undefined, + xpos : 0, + loopCount : 0, + txt:'', + wtot:0, + img:undefined, + imgcol:'#ffffff', + + setFont: function(){ + g.setFont('6x8:5x9'); // TODO this is a bottleneck. How to prepare the font once? + }, + +//public: + show: function(theMessage){ + console.log("theMessage is:"); + console.log(theMessage); + xxl.msg = theMessage; + // prepare string and metrics + xxl.txt = xxl.msg.src + ": " + xxl.msg.body; + xxl.setFont(); + xxl.wtot = g.stringMetrics(xxl.txt).width; + xxl.xpos = 2 * g.getWidth(); + + // get icon + xxl.img = require("messageicons").getImage(xxl.msg); + xxl.imgcol = require("messageicons").getColor(xxl.msg, '#ffffff'); + + Bangle.loadWidgets(); + + Bangle.on('touch', function (b, xy) { + xxl.stop(); + }); + setWatch(xxl.stop, BTN1); + Bangle.buzz(500,1); + + xxl.draw(); + }, + +//private: + // schedule a draw for 30 FPS + queueDraw: function() { + if (xxl.drawTimeout) { return; } // clearTimeout(xxl.drawTimeout); } + xxl.drawTimeout = setTimeout(function () { + xxl.drawTimeout = undefined; + xxl.draw(); + }, 33 - (Date.now() % 33)); + }, + + + stop:function() { + console.log("stop"); + if (xxl.drawTimeout) { clearTimeout(xxl.drawTimeout); } + xxl.drawTimeout = undefined; + g.reset(); + g.setBgColor('#ffff00'); + g.clear(); + + // Bangle.setLCDPower(0); // light off + // Bangle.setLocked(true); // disable touch + + setTimeout(load, 100); + }, + + draw: function() { + wh = 24; // widgets height + var gw = g.getWidth(); + var h = (g.getHeight() - wh)/2; // height of drawing area per stripe + + Bangle.setLCDPower(1); // light on + Bangle.setLocked(false); // keep the touch input active + g.setBgColor('#000000'); + g.clear(); + + if (xxl.img) { // 24x24 + g.setColor(xxl.imgcol); + g.drawImage(xxl.img + , gw/2, wh+h // center point + ,{rotate:0,scale:2} + ); + } + + xxl.setFont(); + g.setFontAlign(-1, -1); + + // draw both lines + g.setBgColor('#000000'); + g.setColor('#ffffff'); + g.drawString(xxl.txt, xxl.xpos, wh); + g.drawString(xxl.txt, xxl.xpos - gw - 32, h + wh); + + g.reset(); + // widget redraw + Bangle.drawWidgets(); + + // scroll + xxl.xpos -= 25; + if (xxl.xpos < -xxl.wtot - gw * 2) { + ++xxl.loopCount; + if (xxl.loopCount > 2) { + xxl.stop(); + return; + } + xxl.xpos = 3 * gw; + } + // loop drawing + xxl.queueDraw(); + } +}; + + +// for IDE +// var exports={}; + +exports.listener = function (type, msg) { + // msg = {t:"add",id:int, src,title,subject,body,sender,tel, important:bool, new:bool} + if (!msg) return; + if (type === 'text' && msg.t !== 'remove') { + msg.handled = true; // don't do anything else with the message + xxl.show(msg); + } +}; + +// debug +// Bangle.on("message", (type, msg) => exports.listener(type, msg)); + + + + + diff --git a/apps/xxlmessage/lib.js b/apps/xxlmessage/lib.js new file mode 100644 index 000000000..9aa85462d --- /dev/null +++ b/apps/xxlmessage/lib.js @@ -0,0 +1,194 @@ +// GB({t:"notify",id:1680248072,src:"SMS Messenger",title:"Fabia",body:"Nein"}) +// msg = {"t":"add","id":1680248072,"src":"SMS Messenger","title":"Fabia","body":"Nein","new":true,"handled":true} +var xxl = { +// private: + msg: [], + drawTimeout: undefined, + xpos : 0, + loopCount : 0, + txt:'', + wtot:0, + img:undefined, + imgcol:'#ffffff', + + // gfx buffer + bufimg:undefined, + bufpal4color:undefined, + buffnt:'6x15', // font to use. Built-in: 4x6, 6x8,12x20,6x15,Vector + bufw:0, // width of buffer for all lines + bufh:0, // height of buffer + buflin:0, // number of lines to print + bufscale:0, // scale factor for buffer to screen + +// public: + show: function(theMessage){ + // console.log("theMessage is:"); + // console.log(theMessage); + xxl.msg = theMessage; + + // get icon + try{ + xxl.img = require("messageicons").getImage(xxl.msg); + xxl.imgcol = (require("messageicons").getColor(xxl.msg, '#ffffff')||'#00ffff'); + }catch(e){} + + Bangle.loadWidgets(); + + Bangle.on('touch', function (b, xy) { + xxl.stop(); + }); + setWatch(xxl.stop, BTN1); + Bangle.buzz(500,1); + + + // offscreen gfx buffer + // screen is 176x176 + // font should be scaled 5x9=30x72px + // built in fonts are 4x6, 6x8,12x20,6x15,Vector + xxl.bufpal4color = new Uint16Array([0x0000,0xFFFF,0x7BEF,0xAFE5],0,2); // b,w,grey,greenyellow + g.setFont(xxl.buffnt); + var hfont = g.getFontHeight(); + xxl.bufscale=parseInt((g.getHeight() - 24/*widgets*/)/2) / hfont; + xxl.buflin=2; // number of lines + xxl.bufw=(g.getWidth() * xxl.buflin) / xxl.bufscale; // 6x15 font scaled by 5 on 176 screen width + xxl.bufh=hfont; + + xxl.bufimg = Graphics.createArrayBuffer(xxl.bufw,xxl.bufh,2,{msb:true}); + + // prepare string and metrics + xxl.txt = (xxl.msg.title||(xxl.msg.src||"MSG")) + ": " + (xxl.msg.body||"-x-"); + g.setFont(xxl.buffnt); + xxl.wtot = g.stringMetrics(xxl.txt).width; + xxl.xpos = xxl.bufw; // g.getWidth(); + + xxl.draw(); + }, + +//private: + // schedule a draw for 60 FPS + queueDraw: function() { + if (xxl.drawTimeout) { return; } // clearTimeout(xxl.drawTimeout); } + xxl.drawTimeout = setTimeout(function () { + xxl.drawTimeout = undefined; + xxl.draw(); + }, 16 - (Date.now() % 16)); + }, + + + stop:function() { + // console.log("stop"); + if (xxl.drawTimeout) { clearTimeout(xxl.drawTimeout); } + xxl.drawTimeout = undefined; + g.reset(); + g.setBgColor('#ffff00'); + g.clear(); + + // Bangle.setLCDPower(0); // light off + // Bangle.setLocked(true); // disable touch + + setTimeout(function(){Bangle.showClock();}, 100); + }, + + // this is even slower than the scaled printing :( + // megaPrintBufferd: function(txt, x, y){ + // xxl.bufimg.setFont(xxl.buffnt); + // xxl.bufimg.setFontAlign(-1, -1); + // xxl.bufimg.setColor(1); // index in palette + // xxl.bufimg.clear(); + // xxl.bufimg.drawString(txt, x, 0); + // for(var i = 0; i 2) { + xxl.stop(); + return; + } + xxl.xpos = (3*xxl.bufw)/2; + } + // loop drawing + xxl.queueDraw(); + } +}; + + +// for IDE +// var exports={}; + +exports.listener = function (type, msg) { + // msg = {t:"add",id:int, src,title,subject,body,sender,tel, important:bool, new:bool} + if (!msg) return; + if (type === 'text' && msg.t !== 'remove') { + msg.handled = true; // don't do anything else with the message + xxl.show(msg); + } +}; + +// debug +// var msg = {t:"add",id:12341, src:"SMS",title:undefined,subject:undefined,body:"yes",sender:"phoo",tel:undefined, important:false, new:true}; +// exports.listener('text', msg); + + + + + + + diff --git a/apps/xxlmessage/metadata.json b/apps/xxlmessage/metadata.json new file mode 100644 index 000000000..f8150f0e7 --- /dev/null +++ b/apps/xxlmessage/metadata.json @@ -0,0 +1,20 @@ +{ + "id": "xxlmessage", + "name": "XXL Message", + "version": "0.02", + "shortName": "XXL Msg", + "description": "App to display large notifications from iOS and Gadgetbridge/Android", + "icon": "app.png", + "type": "app", + "tags": "tool,system", + "supports": ["BANGLEJS","BANGLEJS2"], + "dependencies" : {"messages":"module", "messageicons":"module" }, + "readme": "README.md", + "screenshots": [{"url":"screenshot.png"}], + "storage": [ + {"name":"xxlmessage.app.js","url":"app.js"}, + {"name":"xxlmessage.lib.js","url":"lib.js"}, + {"name":"xxlmessage.boot.js","url":"boot.js"}, + {"name":"xxlmessage.img","url":"app-icon.js","evaluate":true} + ] +} \ No newline at end of file diff --git a/apps/xxlmessage/screenshot.png b/apps/xxlmessage/screenshot.png new file mode 100644 index 0000000000000000000000000000000000000000..5d9fbcf55317dae1572772bd31abbf209720acdc GIT binary patch literal 2032 zcmd^=i8~tx1ID9TN0GIqTgA0%&1aNsG~y_8WRW`Bs-ud84~b}rtHSDN=Tl#crf92* zm^kYQ77`T|v|>`Et&xxer7R_jI|wrSFZMipp5Obv&+jjI?_c(UYa9g~1pojV2sc;n zgKhacDoO|4Oq)XbXa^R}5ZUG4Z0PxMf^o8RilT$A z<*0yECh1@mLvrzS;IXgrt8zA-P8$`DU%h-V7 z*XFK?U>0vn?^ZH~aJ6NJ@>FKm?~Ye~K4GYCrEjuAnn=BfJ#IYQT~V))eU%~KEHGCD zJ^8ZLvD^wZ-mVF6i}Xocb&oR9Z*}y1VC^${qA$n7_?q*y*&7Or)mWnqH3|9%v#YzI zs?g?~8j;`f;Xh|W+MaAZ=akpLJbEHc7`qIklNw9|M zew}(zM!0M9$8yA#!-DPt{pK~FOQ!GX#3ag)k!#Ry{SZ^!ta)gp6EUWJDiWise9!98 zKbYY=codiB2w!ral+Ha)D?znnZd|};YURgue`*M_j(uDn&j@1ylLT2X9jb)+0^%2u zOVO?cqh9V6ZRdT+IuC^)^=NjuG8;u)G;fAgpH}|LH#Jt;kj1YP1j{}_T(X;|c=%VFga#E zIt2ZDa2W5X({JrVEuNGOX1ab!K$$@5$BpN;L&u=AN!a&tac}PK9E?@?3kmFqIYJZA zlABi#AA5J#a{18)kPs+eHI;=W^zQJhvk5U{P@VJtos74f!7f*&;8#_zCR4++d$ChP zZFE$xDa`v9jfbOlQmzt{U)*FQ%iq8&zpcwWNxMJ|DO$M4*VZU|rD>hYA$OG~VWLX% zKu_qwJ88zKee1@{>JgJW5`vb+;0G?$Wn2zk#k0*HW4KUxxXLGeVLOu6M4~7HJ^2l3 z5Zfj}S^Qzh$|aEzbbpnxk1`<@PcOWFJt$uu1{qtmhG+H%*tbO~Bi!pYj_{-uiHA_h zm`{B)@&)u+p1JTvqiRN)?P7ZiDl>*B#iZlX*+62WQf(z9mNBkZ#T*zE5X>ux1L#mk zzdE994B7ehbcp8`=REDC{UZZ*I)*Hr4>u`2X&tyzMs7vWp}NS+`5XU>N-hmiz4fxo zg%%}y|2k}uEvEC1F9oLF+-qI&Nrd%4?7fNimtMz=a(dzA4o@M>A1~hcZARy*sd=DZ z(=oGvhr(AT;zYsA{Fls|&_JNY0sQOK;+~-_wh&L-uZ|#bjy~mI)mIHZ%=Q z_{(ehxjzS=;K$_{PJaX4dA3gGcGx`)ETHQN5TIWj418QEOdHWwXnR4(fcS+ll+y91 z3iPMs&pWYi^{q0@Xj@EIMa$r;Oq--@=N^4u*dTgvM-8_JbWc^X3v;rnrqOhQFc54h zOS7V14#d={9om!xWr0dmO)XY9OU@~qlN6Kze;$jLu3pJU=Zyy2I!ssYj&xnc4!mQW5AldtEpSL{AkOXyz_`?VD1v&8;x*WveIFkEkW%*$>B2 z-2FMXv%(Oeuw8^~J8#x94vY+SSapqLRn(rQ#|olj#8%56rW)fC2bFcx zJ$~JFRPB>6a1)$~>eYn^8T!km&kO#d+x!{hah3s{PwlI;k%4q@8P!_2xJK)h2|ODp zkVJV&%U|z0d=a8TO0ugJCt^fc4 literal 0 HcmV?d00001 From 737bdd996c5a1fc62bf05da7e3a9f4fa88ef04c2 Mon Sep 17 00:00:00 2001 From: KungPhoo Date: Fri, 21 Apr 2023 14:08:28 +0200 Subject: [PATCH 39/39] -glbasic clock: changed font, so '5' and '6' don't look similar. --- apps/glbasic/ChangeLog | 2 +- apps/glbasic/glbasic.app.js | 75 ++++++++++++++++++++++++++++++------- apps/glbasic/metadata.json | 2 +- 3 files changed, 64 insertions(+), 15 deletions(-) diff --git a/apps/glbasic/ChangeLog b/apps/glbasic/ChangeLog index d97fd44d5..1f3a1b643 100644 --- a/apps/glbasic/ChangeLog +++ b/apps/glbasic/ChangeLog @@ -1,3 +1,3 @@ 0.20: New App! 0.21: Tell clock widgets to hide. - +0.22: Changed font so 5 and 6 are not similar diff --git a/apps/glbasic/glbasic.app.js b/apps/glbasic/glbasic.app.js index c1f82f74c..4f6c9ffb3 100644 --- a/apps/glbasic/glbasic.app.js +++ b/apps/glbasic/glbasic.app.js @@ -1,13 +1,36 @@ -Graphics.prototype.setFontLECO1976Regular42 = function (scale) { + +Graphics.prototype.setFontLECO1976Regular5fix42 = function(scale) { // Actual height 42 (41 - 0) - g.setFontCustom(atob("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH/AAAAAAAAH/AAAAAAAAH/AAAAAAAAH/AAAAAAAAH/AAAAAAAAH/AAAAAAAAH/AAAAAAAAH/AAAAAAAAD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAAAAAA/AAAAAAAAH/AAAAAAAA//AAAAAAAP//AAAAAAB///AAAAAAP///AAAAAB////AAAAAf////AAAAD////4AAAAf////AAAAH////4AAAA////+AAAAA////wAAAAA///+AAAAAA///gAAAAAA//8AAAAAAA//gAAAAAAA/4AAAAAAAA/AAAAAAAAA4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAA/4AAAH/AAA/4AAAH/AAA/4AAAH/AAA/4AAAH/AAA/4AAAH/AAA/4AAAH/AAA/4AAAH/AAA/4AAAH/AAA/4AAAH/AAA/4AAAH/AAA/4AAAH/AAA/4AAAH/AAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/4AAAH/AAA/4AAAH/AAA/4AAAH/AAA/4AAAH/AAA/4AAAH/AAA/4AAAH/AAA/4AAAH/AAA/4AAAH/AAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAAAAAAAH/AAAAAAAAH/AAAAAAAAH/AAAAAAAAH/AAAAAAAAH/AAAAAAAAH/AAAAAAAAH/AAAAAAAAH/AAAAAAAAD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//h////AAA//h////AAA//h////AAA//h////AAA//h////AAA//h////AAA//h////AAA//h////AAA//h////AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA////wH/AAA////wH/AAA////wH/AAA////wH/AAA////wH/AAA////wH/AAA////wH/AAA////wH/AAA////gD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/4AAAH/AAA/4AAAH/AAA/4AAAH/AAA/4AAAH/AAA/4B/gH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////wAAAAA////wAAAAA////wAAAAA////wAAAAA////wAAAAA////wAAAAA////wAAAAA////wAAAAA////wAAAAAAAB/wAAAAAAAB/wAAAAAAAB/wAAAAAAAB/wAAAAAAAB/wAAAAAAAB/wAAAAAAAB/wAAAAAAAB/wAAAAAAAB/wAAAAAAAB/wAAAAAAAB/wAAAAAAAB/wAAAAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////x//AAA////x//AAA////x//AAA////x//AAA////x//AAA////x//AAA////x//AAA////x//AAA////x//AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B////AAA/4B////AAA/4B////AAA/4B////AAA/4B////AAA/4B////AAA/4B////AAA/4B////AAA/wB////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B////AAA/4B////AAA/4B////AAA/4B////AAA/4B////AAA/4B////AAA/4B////AAA/4B////AAA/wB////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//gAAAAAAA//gAAAAAAA//gAAAAAAA//gAAAAAAA//gAAAAAAA//gAAAAAAA//gAAAAAAA//gAAAAAAA//gAAAAAAA/4AAAAAAAA/4AAAAAAAA/4AAAAAAAA/4AAAAAAAA/4AAAAAAAA/4AAAAAAAA/4AAAAAAAA/4AAAAAAAA/4AAAAAAAA/4AAAAAAAA/4AAAAAAAA/4AAAAAAAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////wH/AAA////wH/AAA////wH/AAA////wH/AAA////wH/AAA////wH/AAA////wH/AAA////wH/AAA////wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP+AAH/AAAAP+AAH/AAAAP+AAH/AAAAP+AAH/AAAAP+AAH/AAAAP+AAH/AAAAP+AAH/AAAAP+AAH/AAAAH+AAD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"), 46, atob("ERkmHyYmJiYmJCYmEQ=="), 60 + (scale << 8) + (1 << 16)); + this.setFontCustom( + E.toString(require('heatshrink').decompress(atob('ADMD/gHFv/AAwkHB3QAtngGFj47Fh5KFh//BwkH/4OEgf/BwgGCBwcBAwIOEAwQODAwX/wB7CCos/Awo/BAAPgDgvwJwgGEBwX4LoplFAw0P/yCF/4GFh6YGKgQAhNAZGDAwZ4CB3ibCg4ODZoYO/BwyV/BxIA7YX7C/YRRZCAAZZDB2AAgNAMHO4v4O42PB3P4AIL+EwABBQwQO/BwgABBwgGBB34A0h/wAYMDSogDBSogGBUgoOOd/4O2AAbgEAAIO+AGY7C/AHDIIWAB3wQCBwjiDB34OGf1gOdAGbgDgZKFwF/JQn4g4O3/ABBBwmAB34OLcAgOBd4oO6AGY5CJQoADd4gO5f2wOdf1IOdAEgqBA4v//AOGwAO5AwqGCB34OJAAbRCAwbgDB3QAzO/4OL/ABBg4ODwABBv4O/BwyV/BxIAzHYX4gZKFSogOCSowOxf2gOdf1YOdAGkH/EAgY7DSgMASoSWCCIIO3ADg='))), + 46, + atob("ERkmICYmJiYmJCYmEQ=="), + 60+(scale<<8)+(1<<16) + ); + return this; }; -Graphics.prototype.setFontLECO1976Regular22 = function (scale) { +Graphics.prototype.setFontLECO1976Regular5fix22 = function(scale) { // Actual height 22 (21 - 0) - g.setFontCustom(atob("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAP/nA/+cD/5wP/nAAAAAAAAPwAA/gAD+AAPwAAAAAD+AAP4AA/gAAAAAAAAAAAAAcOAP//A//8D//wP//AHDgAcOAP//A//8D//wP//AHDgAAAAAAAAH/jgf+OB/44H/jj8OP/w4//Dj/8OPxw/4HD/gcP+Bw/4AAAAAAAP+AA/8AD/wQOHHA4c8D//wP/8A//gAD4AAfAAH/8A//wP//A84cDjhwIP/AA/8AB/wAAAAAAAD//wP//A//8D//wOHHA4ccDhxwOHHA4f8Dh/wOH/A4f8ABwAAAAAAAAD8AAP4AA/gAD8AAAAAAAAAAAEAAD+AB//A///v/D//gB/wABwAAAAAADgAA/wAf/4P8///wf/4AP8AAOAAAAAAAAAyAAHcAAPwAD/gAP/AA/8AA/AAH8AAMwAAAAAAAAAAAAADgAAOAAA4AAf8AD/wAP/AA/8AAOAAA4AADgAAAAAAAAAAD8AAfwAB/AAD8AAAAAAAADgAAOAAA4AADgAAOAAA4AADgAAAAAAAAAADgAAOAAA4AADgAAAAAAAAABwAB/AA/8A//gP/gA/wADwAAIAAAAAAD//wP//A//8D//wOAHA4AcDgBwOAHA//8D//wP//A//8AAAAAAAA4AcDgBwOAHA//8D//wP//A//8AABwAAHAAAcAAAAAAAA+f8D5/wPn/A+f8DhxwOHHA4ccDhxwP/HA/8cD/xwP/HAAAAAAAAOAHA4AcDhxwOHHA4ccDhxwOHHA4ccD//wP//A//8D//wAAAAAAAD/wAP/AA/8AD/wAAHAAAcAABwAAHAA//8D//wP//A//8AAAAAAAA/98D/3wP/fA/98DhxwOHHA4ccDhxwOH/A4f8Dh/wOH/AAAAAAAAP//A//8D//wP//A4ccDhxwOHHA4ccDh/wOH/A4f8Dh/wAAAAAAAD4AAPgAA+AADgAAOAAA4AADgAAP//A//8D//wP//AAAAAAAAP//A//8D//wP//A4ccDhxwOHHA4ccD//wP//A//8D//wAAAAAAAD/xwP/HA/8cD/xwOHHA4ccDhxwOHHA//8D//wP//A//8AAAAAAAAOA4A4DgDgOAOA4AAAAAAAAOA/A4H8DgfwOA/AAAAAAAAB4AAPwAA/AAD8AAf4ABzgAPPAA8cAHh4AAAAAAAAAAAAHHAAccABxwAHHAAccABxwAHHAAccABxwAHHAAAAAAAAAOHAA4cADzwAPPAAf4AB/gAD8AAPwAAeAAB4AAAAAAAAA+AAD4AAPgAA+ecDh9wOH3A4fcDhwAP/AA/8AD/wAP/AAAAAAAAAP//4///j//+P//44ADjn/OOf845/zjnHOP8c4//zj//OP/84AAAAAAAP//A//8D//wP//A4cADhwAOHAA4cAD//wP//A//8D//wAAAAAAAD//wP//A//8D//wOHHA4ccDhxwOHHA//8D//wP9/A/j8AAAAAAAA//8D//wP//A//8DgBwOAHA4AcDgBwOAHA4AcDgBwOAHAAAAAAAAP//A//8D//wP//A4AcDgBwOAHA8A8D//wH/+AP/wAf+AAAAAAAAD//wP//A//8D//wOHHA4ccDhxwOHHA4ccDhxwOAHA4AcAAAAAAAA//8D//wP//A//8DhwAOHAA4cADhwAOHAA4cADgAAOAAAAAAD//wP//A//8D//wOAHA4ccDhxwOHHA4f8Dh/wOH/A4f8AAAAAAAA//8D//wP//A//8ABwAAHAAAcAABwAP//A//8D//wP//AAAAAAAAP//A//8D//wP//AAAAAAAAOAHA4AcDgBwOAHA4AcDgBwOAHA//8D//wP//A//8AAAAAAAA//8D//wP//A//8AHwAA/AAP8AB/wAPn/A8f8DB/wIH/AAAAAAAAP//A//8D//wP//AAAcAABwAAHAAAcAABwAAHAAAAAAAAP//A//8D//wP//Af8AAP+AAH/AAD8AAHwAD/AB/wAf8AP+AA//8D//wP//AAAAAAAAP//A//8D//wP//AfwAAfwAAfwAAfwAAfwP//A//8D//wAAAAAAAAAAAP//A//8D//wP//A4AcDgBwOAHA4AcD//wP//A//8D//wAAAAAAAD//wP//A//8D//wOHAA4cADhwAOHAA/8AD/wAP/AA/8AAAAAP//A//8D//wP//A4AcDgBwOAHA4AcD//+P//4///j//+AAA4AADgAAAP//A//8D//wP//A4eADh+AOH8A4f4D/3wP/HA/8MD/wQAAAAAAAD/xwP/HA/8cD/xwOHHA4ccDhxwOHHA4f8Dh/wOH/A4f8AAAAAAAA4AADgAAOAAA//8D//wP//A//8DgAAOAAA4AADgAAAAAA//8D//wP//A//8AABwAAHAAAcAABwP//A//8D//wP//AAAADAAAPgAA/wAD/4AB/8AA/8AAfwAB/AA/8Af+AP/AA/wAD4AAMAAA4AAD+AAP/gA//8AH/wAB/AAf8Af/wP/4A/4AD/gAP/4AH/8AB/wAB/AB/8D//wP/gA/gADgAAIABA4AcDwDwPw/Afn4Af+AA/wAD/AA//AH5+A/D8DwDwOAHAgAEAAAAP/AA/8AD/wAP/AAAf8AB/wAH/AAf8D/wAP/AA/8AD/wAAAAAAAADh/wOH/A4f8Dh/wOHHA4ccDhxwOHHA/8cD/xwP/HA/8cAAAAAAAAf//9///3///f//9wAA3AADcAAMAAAOAAA/gAD/wAH/8AB/8AA/wAAPAAAEAAAAHAADcAANwAB3///f//9///wAA"), 32, atob("BwYLDg4UDwYJCQwMBgkGCQ4MDg4ODg4NDg4GBgwMDA4PDg4ODg4NDg4GDQ4MEg8ODQ8ODgwODhQODg4ICQg="), 22 + (scale << 8) + (1 << 16)); + this.setFontCustom( + E.toString(require('heatshrink').decompress(atob('AAs8AYV8AaQjOgP8AYMPAYV/AYMH/4DBn///EA///4ADB/wSB//gAYQlCCIIABCIIAFDYIjBAaYjBLYIDTF64AH+CDCGdLLV/i7C/wfCAZ/4/BPCAaTiBAaaHBABaPIIaxPMcbxbBAapgCAahPhVYLDTUbA7CAZ/wv5PKN6xPzAof+AaTuXdcCbuJ8H4ngDCE4QDOJ+8PgBPBh+AE4IDPAA4'))), + 46, + atob("CQ0UERQUFBQUExQUCQ=="), + 32+(scale<<8)+(1<<16) + ); + return this; }; +Graphics.prototype.setFontLECO1976Regular5fix11 = function(scale) { + // Actual height 11 (10 - 0) + this.setFontCustom( + E.toString(require('heatshrink').decompress(atob('AAMBwEDgEGgECgF8g/4v/w/+B+ARBg//h/+j/8mEYsEw//h//D/+AgEMg0Yhk/DofggHAFwMAh9+j38nv4scw41h/nD/OH+YdC5kxzAODxgsBw47CIIM/wF/gAGBhkAjBKFCAN/mH+FgUZw0zhl+jH8mP4CAJZEBwVmBwdj+HwgPggfAQoIxBFgJoDSwUDJQhZDO4QsB4CVB+cP80fNAiVGgaWDmAA=='))), + 46, + atob("BAYJCAkJCQkJCQkJBA=="), + 15+(scale<<8)+(1<<16) + ); + return this; +}; require("Font7x11Numeric7Seg").add(Graphics); @@ -60,7 +83,7 @@ function drawCal() { const CAL_Y = g.getHeight() - 44; // Bangle.appRect.y+this.DATE_FONT_SIZE()+10+this.TIME_FONT_SIZE()+3; const CAL_AREA_H = 44; // g.getHeight()-CAL_Y+24; //+24: top widgtes only const CELL_W = g.getWidth() / 7; //cell width - const CELL_H = (CAL_AREA_H - DAY_NAME_FONT_SIZE) / 3; //cell heigth + const CELL_H = 1+parseInt((CAL_AREA_H - DAY_NAME_FONT_SIZE) / 3); //cell heigth const DAY_NUM_FONT_SIZE = Math.min(CELL_H + 3, 15); //size down, max 15 const wdStrt = 1; @@ -73,11 +96,14 @@ function drawCal() { const tdyNumClr = 0; // today fg g.setFont("Vector", DAY_NAME_FONT_SIZE + 3); + + + g.setColor(nrgb[1]); g.setFontAlign(-1, -1); // g.clearRect(Bangle.appRect.x, CAL_Y, Bangle.appRect.x2, CAL_Y+CAL_AREA_H); - //draw grid & Headline + // == draw grid & Headline == const dNames = ABR_DAY.map((a) => a.length <= 2 ? a : a.substr(0, 2)); //force shrt 2 for (var dNo = 0; dNo < dNames.length; dNo++) { const dIdx = wdStrt >= 0 ? ((wdStrt + dNo) % 7) : ((dNo + d.getDay() + 4) % 7); @@ -103,9 +129,10 @@ function drawCal() { // horizontal lines // for(i=0; i<3; i++){ const y=nextY+i*CELL_H; g.drawLine(Bangle.appRect.x, y, Bangle.appRect.x2, y); } - g.setFont("Vector", DAY_NUM_FONT_SIZE); + // g.setFont("Vector", DAY_NUM_FONT_SIZE); - g.setFont("7x11Numeric7Seg", 1); + // g.setFont("7x11Numeric7Seg", 1); + g.setFontLECO1976Regular5fix11(); //write days const tdyDate = d.getDate(); @@ -113,16 +140,38 @@ function drawCal() { var rD = new Date(d.getTime()); rD.setDate(rD.getDate() - days); var rDate = rD.getDate(); + + // == today background rectangle == for (var y = 0; y < 3; y++) { for (var x = 0; x < dNames.length; x++) { if (rDate === tdyDate) { //today g.setColor(nrgb[tdyMrkClr]); //today marker color or fg color // rectangle - g.fillRect(x * CELL_W, nextY + CELL_H - 1, x * CELL_W + CELL_W, nextY + CELL_H + CELL_H - 1); - g.setColor(nrgb[tdyNumClr]); //today color or fg color + var frm=3; // fame pixels + g.drawRect(x * CELL_W-frm, nextY + CELL_H - 1-frm, x * CELL_W + CELL_W+frm, nextY + CELL_H + CELL_H - 1+frm); + } + rD.setDate(rDate + 1); + rDate = rD.getDate(); + } + } + + // == individual days == + rD = new Date(d.getTime()); + rD.setDate(rD.getDate() - days); + rDate = rD.getDate(); + for (var y = 0; y < 3; y++) { + for (var x = 0; x < dNames.length; x++) { + if (rDate === tdyDate) { //today + g.setColor(nrgb[tdyMrkClr]); //today marker color or fg color + + // rectangle + // g.fillRect(x * CELL_W, nextY + CELL_H - 1, x * CELL_W + CELL_W, nextY + CELL_H + CELL_H - 1); + // g.setColor(nrgb[tdyNumClr]); //today color or fg color + // g.drawRect(x * CELL_W, nextY + CELL_H - 1, x * CELL_W + CELL_W, nextY + CELL_H + CELL_H - 1); // simulate "bold" + // g.setColor(nrgb[tdyNumClr]); //today color or fg color g.drawString(rDate, 1 + x * CELL_W + ((CELL_W - g.stringWidth(rDate)) / 2) + 2, nextY + ((CELL_H - DAY_NUM_FONT_SIZE + 2) / 2) + (CELL_H * y)); } else if (IS_SUNDAY[rD.getDay()]) { //sundays @@ -153,7 +202,7 @@ function draw() { // g.setFont('Vector', 30); // g.setFont("7x11Numeric7Seg", 5); - g.setFontLECO1976Regular42(); + g.setFontLECO1976Regular5fix42(); g.setFontAlign(0, -1); g.drawString(timeString(h, m), g.getWidth() / 2, 28); g.drawString(dayString(d), g.getWidth() * 3 / 4, 88); @@ -162,7 +211,7 @@ function draw() { g.reset(); // Steps - g.setFontLECO1976Regular22(); + g.setFontLECO1976Regular5fix22(); g.setFontAlign(-1, -1); g.drawString(getSteps(), 8, 88); @@ -200,4 +249,4 @@ Bangle.on('lcdPower', on => { }); -Bangle.drawWidgets(); +Bangle.drawWidgets(); \ No newline at end of file diff --git a/apps/glbasic/metadata.json b/apps/glbasic/metadata.json index 6d4c562a3..2636deefa 100644 --- a/apps/glbasic/metadata.json +++ b/apps/glbasic/metadata.json @@ -2,7 +2,7 @@ "id": "glbasic", "name": "GLBasic Clock", "shortName": "GLBasic", - "version": "0.21", + "version": "0.22", "description": "A clock with large numbers", "dependencies": {"widpedom":"app"}, "icon": "icon48.png",