From d55417d90fc668ed5c3f6463b07f8235003fefcb Mon Sep 17 00:00:00 2001 From: hughbarney Date: Fri, 1 Oct 2021 13:35:58 +0100 Subject: [PATCH 01/26] Gbridge added troubleshooting section to README --- apps/gbridge/README.md | 59 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/apps/gbridge/README.md b/apps/gbridge/README.md index 867b736ab..03bf883d7 100644 --- a/apps/gbridge/README.md +++ b/apps/gbridge/README.md @@ -52,3 +52,62 @@ Activity reporting You'll need a Gadgetbridge release *after* version 0.50.0 for Actvity Reporting to be enabled. By default heart rate isn't reported, but it can be enabled from `Settings`, `App/Widget Settings`, `Gadgetbridge`, `Record HRM` + + +## Troubleshooting + +1. Switch to using one of the stock watch faces like s7clk or wave on a Bangle 2. + +2. Check that the battery charge level is being seen by the Gadgetbridge App on the phone. This proves that data is getting to your phone. + +### You can test the notifications on the Bangle + +First disconnect from Gadgetbridge on your phone. Then connect +through the IDE and enter the following code. You should get a pop +up screen on your Bangle. This proves that the watch is correctly +setup for notifications. + + + GB({"t":"notify","id":1575479849,"src":"Hangouts","title":"A Name","body":"message contents"}) + + +NOTE: On a Bangle 2, this will fail if you have not installed 'Notifications Fullscreen'. + +### Check that notifications are getting through to your Bangle + +* Disconnect your Bangle from Gadgetbridge on your phone. +* Connect through the IDE +* Run the following bit of code + + var log = []; + function GB(d) { + log.push(JSON.stringify(d)); + } + +* Disconnect from the IDE +* Connect your Bangle to Gadgetbridge +* Call your phone to get a missed call +* Disonnect your Bangle to Gadgetbridge +* Connect through the IDE +* Run the following bit of code + + log; + +If notifications are getting through then you should see something like. + + + >log + =[ + "{\"t\":\"call\",\"cmd\"" ... "r\":\"0191xxxxxxx\"}", + "{\"t\":\"call\",\"cmd\"" ... "r\":\"0191xxxxxxx\"}" + ] + + +IMPORTANT: Now reset your Bangle using a BTN3 long press so that the GB() function is restored. + +## References + +[Bangle Gadgetbridge Page](https://www.espruino.com/Gadgetbridge) + +[Gadgetbridge Project Home](https://codeberg.org/Freeyourgadget/Gadgetbridge/wiki/Home) + From a78672662215a0807fb6d2b258e2927269f2ac91 Mon Sep 17 00:00:00 2001 From: Richard de Boer Date: Sat, 2 Oct 2021 14:54:25 +0200 Subject: [PATCH 02/26] barclock: use theme colors --- apps.json | 2 +- apps/barclock/ChangeLog | 1 + apps/barclock/clock-bar.js | 12 ++---------- apps/barclock/screenshot.png | Bin 2764 -> 7183 bytes apps/barclock/screenshot_pm.png | Bin 2595 -> 6495 bytes 5 files changed, 4 insertions(+), 11 deletions(-) diff --git a/apps.json b/apps.json index 11b1ea146..23b570203 100644 --- a/apps.json +++ b/apps.json @@ -1381,7 +1381,7 @@ { "id": "barclock", "name": "Bar Clock", "icon": "clock-bar.png", - "version":"0.07", + "version":"0.08", "description": "A simple digital clock showing seconds as a bar", "tags": "clock", "type":"clock", diff --git a/apps/barclock/ChangeLog b/apps/barclock/ChangeLog index 9589a1902..314ef89f2 100644 --- a/apps/barclock/ChangeLog +++ b/apps/barclock/ChangeLog @@ -5,3 +5,4 @@ 0.05: Clock does not start if app Languages is not installed 0.06: Improve accuracy 0.07: Update to use Bangle.setUI instead of setWatch +0.08: Use theme colors \ No newline at end of file diff --git a/apps/barclock/clock-bar.js b/apps/barclock/clock-bar.js index 5069faa39..396c2984a 100644 --- a/apps/barclock/clock-bar.js +++ b/apps/barclock/clock-bar.js @@ -28,7 +28,6 @@ const screen = { // hardcoded "settings" const settings = { time: { - color: -1, font: '6x8', size: (is12Hour && locale.hasMeridian) ? 6 : 8, middle: screen.middle, @@ -40,14 +39,12 @@ const settings = { }, }, date: { - color: -1, font: 'Vector', size: 20, middle: screen.height - 20, // at bottom of screen center: screen.center, }, bar: { - color: -1, top: 155, // just below time thickness: 6, // matches 24h time "pixel" size }, @@ -82,13 +79,11 @@ const dateText = function (date) { const drawDateTime = function (date) { const t = settings.time - g.setColor(t.color) g.setFont(t.font, t.size) g.setFontAlign(0, 0) // centered g.drawString(timeText(date), t.center, t.middle, true) if (is12Hour && locale.hasMeridian) { const a = settings.time.ampm - g.setColor(a.color) g.setFont(a.font, a.size) g.setFontAlign(1, -1) // right top // at right edge of screen, aligned with time bottom @@ -98,7 +93,6 @@ const drawDateTime = function (date) { } const d = settings.date - g.setColor(d.color) g.setFont(d.font, d.size) g.setFontAlign(0, 0) // centered g.drawString(dateText(date), d.center, d.middle, true) @@ -113,14 +107,12 @@ const drawBar = function (date) { } const fraction = seconds / SECONDS_PER_MINUTE, width = fraction * screen.width - g.setColor(b.color) - g.fillRect(0, b.top, width, b.top + b.thickness) + g.setColor(g.theme.fg2).fillRect(0, b.top, width, b.top + b.thickness) } const clearScreen = function () { - g.setColor(0) const timeTop = settings.time.middle - (settings.time.size * 4) - g.fillRect(0, timeTop, screen.width, screen.height) + g.clearRect(0, timeTop, screen.width, screen.height) } let lastSeconds, tTick diff --git a/apps/barclock/screenshot.png b/apps/barclock/screenshot.png index d37ee9cae2680e73889600e8eb29f87ba2956f87..9c2b7a50f707be2ca5ddcc2bf88fd9b000d5a960 100644 GIT binary patch literal 7183 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 W0$kbz>U96Qnex&qQsok#0{;y^kc`3r literal 2764 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 From 346eb8f77b0038c8ee2a23c72a3dcf7d3e0087fb Mon Sep 17 00:00:00 2001 From: Richard de Boer Date: Sat, 2 Oct 2021 14:55:41 +0200 Subject: [PATCH 03/26] barclock: coding style (add semicolons) --- apps/barclock/clock-bar.js | 190 ++++++++++++++++++------------------- 1 file changed, 95 insertions(+), 95 deletions(-) diff --git a/apps/barclock/clock-bar.js b/apps/barclock/clock-bar.js index 396c2984a..52affac5d 100644 --- a/apps/barclock/clock-bar.js +++ b/apps/barclock/clock-bar.js @@ -3,159 +3,159 @@ * A simple digital clock showing seconds as a bar **/ // Check settings for what type our clock should be -const is12Hour = (require('Storage').readJSON('setting.json', 1) || {})['12hour'] -let locale = require('locale') +const is12Hour = (require("Storage").readJSON("setting.json", 1) || {})["12hour"]; +let locale = require("locale"); { // add some more info to locale - let date = new Date() - date.setFullYear(1111) - date.setMonth(1, 3) // februari: months are zero-indexed - const localized = locale.date(date, true) - locale.dayFirst = /3.*2/.test(localized) + let date = new Date(); + date.setFullYear(1111); + date.setMonth(1, 3); // februari: months are zero-indexed + const localized = locale.date(date, true); + locale.dayFirst = /3.*2/.test(localized); - locale.hasMeridian = false - if(typeof locale.meridian === 'function') { // function does not exists if languages app is not installed - locale.hasMeridian = (locale.meridian(date) !== '') + locale.hasMeridian = false; + if (typeof locale.meridian==="function") { // function does not exists if languages app is not installed + locale.hasMeridian = (locale.meridian(date)!==""); } } const screen = { width: g.getWidth(), height: g.getWidth(), - middle: g.getWidth() / 2, - center: g.getHeight() / 2, -} + middle: g.getWidth()/2, + center: g.getHeight()/2, +}; // hardcoded "settings" const settings = { time: { - font: '6x8', + font: "6x8", size: (is12Hour && locale.hasMeridian) ? 6 : 8, middle: screen.middle, center: screen.center, ampm: { color: -1, - font: '6x8', + font: "6x8", size: 2, }, }, date: { - font: 'Vector', + font: "Vector", size: 20, - middle: screen.height - 20, // at bottom of screen + middle: screen.height-20, // at bottom of screen center: screen.center, }, bar: { top: 155, // just below time thickness: 6, // matches 24h time "pixel" size }, -} +}; -const SECONDS_PER_MINUTE = 60 +const SECONDS_PER_MINUTE = 60; -const timeText = function (date) { +const timeText = function(date) { if (!is12Hour) { - return locale.time(date, true) + return locale.time(date, true); } - const date12 = new Date(date.getTime()) - const hours = date12.getHours() - if (hours === 0) { - date12.setHours(12) - } else if (hours > 12) { - date12.setHours(hours - 12) + const date12 = new Date(date.getTime()); + const hours = date12.getHours(); + if (hours===0) { + date12.setHours(12); + } else if (hours>12) { + date12.setHours(hours-12); } - return locale.time(date12, true) -} -const ampmText = function (date) { - return is12Hour ? locale.meridian(date) : '' -} + return locale.time(date12, true); +}; +const ampmText = function(date) { + return is12Hour ? locale.meridian(date) : ""; +}; -const dateText = function (date) { +const dateText = function(date) { const dayName = locale.dow(date, true), month = locale.month(date, true), - day = date.getDate() - const dayMonth = locale.dayFirst ? `${day} ${month}` : `${month} ${day}` - return `${dayName} ${dayMonth}` -} + day = date.getDate(); + const dayMonth = locale.dayFirst ? `${day} ${month}` : `${month} ${day}`; + return `${dayName} ${dayMonth}`; +}; -const drawDateTime = function (date) { - const t = settings.time - g.setFont(t.font, t.size) - g.setFontAlign(0, 0) // centered - g.drawString(timeText(date), t.center, t.middle, true) +const drawDateTime = function(date) { + const t = settings.time; + g.setFont(t.font, t.size); + g.setFontAlign(0, 0); // centered + g.drawString(timeText(date), t.center, t.middle, true); if (is12Hour && locale.hasMeridian) { - const a = settings.time.ampm - g.setFont(a.font, a.size) - g.setFontAlign(1, -1) // right top + const a = settings.time.ampm; + g.setFont(a.font, a.size); + g.setFontAlign(1, -1); // right top // at right edge of screen, aligned with time bottom - const left = screen.width - a.size * 2, - top = t.middle + t.size - a.size - g.drawString(ampmText(date), left, top, true) + const left = screen.width-a.size*2, + top = t.middle+t.size-a.size; + g.drawString(ampmText(date), left, top, true); } - const d = settings.date - g.setFont(d.font, d.size) - g.setFontAlign(0, 0) // centered - g.drawString(dateText(date), d.center, d.middle, true) -} + const d = settings.date; + g.setFont(d.font, d.size); + g.setFontAlign(0, 0); // centered + g.drawString(dateText(date), d.center, d.middle, true); +}; -const drawBar = function (date) { - const b = settings.bar - const seconds = date.getSeconds() - if (seconds === 0) { +const drawBar = function(date) { + const b = settings.bar; + const seconds = date.getSeconds(); + if (seconds===0) { // zero-size rect stills draws one line of pixels, we don't want that - return + return; } - const fraction = seconds / SECONDS_PER_MINUTE, - width = fraction * screen.width - g.setColor(g.theme.fg2).fillRect(0, b.top, width, b.top + b.thickness) -} + const fraction = seconds/SECONDS_PER_MINUTE, + width = fraction*screen.width; + g.setColor(g.theme.fg2).fillRect(0, b.top, width, b.top+b.thickness); +}; -const clearScreen = function () { - const timeTop = settings.time.middle - (settings.time.size * 4) - g.clearRect(0, timeTop, screen.width, screen.height) -} +const clearScreen = function() { + const timeTop = settings.time.middle-(settings.time.size*4); + g.clearRect(0, timeTop, screen.width, screen.height); +}; -let lastSeconds, tTick -const tick = function () { - g.reset() - const date = new Date() - const seconds = date.getSeconds() - if (lastSeconds > seconds) { +let lastSeconds, tTick; +const tick = function() { + g.reset(); + const date = new Date(); + const seconds = date.getSeconds(); + if (lastSeconds>seconds) { // new minute - clearScreen() - drawDateTime(date) + clearScreen(); + drawDateTime(date); } // the bar only gets larger, so drawing on top of the previous one is fine - drawBar(date) - lastSeconds = seconds + drawBar(date); + lastSeconds = seconds; // schedule next update - const millis = date.getMilliseconds() - tTick = setTimeout(tick, 1000-millis) -} + const millis = date.getMilliseconds(); + tTick = setTimeout(tick, 1000-millis); +}; -const start = function () { - lastSeconds = 99 // force redraw - tick() -} -const stop = function () { +const start = function() { + lastSeconds = 99; // force redraw + tick(); +}; +const stop = function() { if (tTick) { - clearTimeout(tTick) - tTick = undefined + clearTimeout(tTick); + tTick = undefined; } -} +}; // clean app screen -g.clear() -Bangle.loadWidgets() -Bangle.drawWidgets() +g.clear(); +Bangle.loadWidgets(); +Bangle.drawWidgets(); // Show launcher when button pressed Bangle.setUI("clock"); -Bangle.on('lcdPower', function (on) { +Bangle.on("lcdPower", function(on) { if (on) { - start() + start(); } else { - stop() + stop(); } -}) -start() +}); +start(); From de3feaff456cc10fba5a87736b14f4a5ddbb638c Mon Sep 17 00:00:00 2001 From: Richard de Boer Date: Sat, 2 Oct 2021 15:11:32 +0200 Subject: [PATCH 04/26] barclock: simplify redraw logic --- apps/barclock/clock-bar.js | 37 ++++++++++--------------------------- 1 file changed, 10 insertions(+), 27 deletions(-) diff --git a/apps/barclock/clock-bar.js b/apps/barclock/clock-bar.js index 52affac5d..627028875 100644 --- a/apps/barclock/clock-bar.js +++ b/apps/barclock/clock-bar.js @@ -110,19 +110,17 @@ const drawBar = function(date) { g.setColor(g.theme.fg2).fillRect(0, b.top, width, b.top+b.thickness); }; -const clearScreen = function() { - const timeTop = settings.time.middle-(settings.time.size*4); - g.clearRect(0, timeTop, screen.width, screen.height); -}; -let lastSeconds, tTick; -const tick = function() { +let lastSeconds; +const draw = function(redraw) { + if (!Bangle.isLCDOn()) {return;} g.reset(); const date = new Date(); const seconds = date.getSeconds(); - if (lastSeconds>seconds) { - // new minute - clearScreen(); + if (redraw||lastSeconds>seconds) { + // force redraw at start of new minute + g.clear(); + Bangle.drawWidgets(); drawDateTime(date); } // the bar only gets larger, so drawing on top of the previous one is fine @@ -130,32 +128,17 @@ const tick = function() { lastSeconds = seconds; // schedule next update const millis = date.getMilliseconds(); - tTick = setTimeout(tick, 1000-millis); + setTimeout(draw, 1000-millis); }; -const start = function() { - lastSeconds = 99; // force redraw - tick(); -}; -const stop = function() { - if (tTick) { - clearTimeout(tTick); - tTick = undefined; - } -}; -// clean app screen -g.clear(); Bangle.loadWidgets(); -Bangle.drawWidgets(); // Show launcher when button pressed Bangle.setUI("clock"); Bangle.on("lcdPower", function(on) { if (on) { - start(); - } else { - stop(); + draw(true); } }); -start(); +draw(true); From 6817cafba4afac0d21c432c6f29587642ccb4c55 Mon Sep 17 00:00:00 2001 From: hughbarney Date: Sat, 2 Oct 2021 14:13:20 +0100 Subject: [PATCH 05/26] Findphone - fix for Bangle 2 --- apps.json | 2 +- apps/findphone/ChangeLog | 1 + apps/findphone/README.md | 5 +++++ apps/findphone/app.js | 35 ++++++++++++++++++++++++++++------- 4 files changed, 35 insertions(+), 8 deletions(-) diff --git a/apps.json b/apps.json index 11b1ea146..832a480cf 100644 --- a/apps.json +++ b/apps.json @@ -2058,7 +2058,7 @@ "name": "Find Phone", "shortName":"Find Phone", "icon": "app.png", - "version":"0.02", + "version":"0.03", "description": "Find your phone via Gadgetbridge. Click any button to let your phone ring. 📳 Note: The functionality is available even without this app, just go to Settings, App Settings, Gadgetbridge, Find Phone.", "tags": "tool,android", "readme": "README.md", diff --git a/apps/findphone/ChangeLog b/apps/findphone/ChangeLog index 86558abf5..29100f3c1 100644 --- a/apps/findphone/ChangeLog +++ b/apps/findphone/ChangeLog @@ -1,2 +1,3 @@ 0.01: First Version 0.02: Remove HID requirement, update screen +0.03: Fix for Bangle 2, toggle find with top half of screen, exit touch bottom half of screen diff --git a/apps/findphone/README.md b/apps/findphone/README.md index c655457a2..64e719d6a 100644 --- a/apps/findphone/README.md +++ b/apps/findphone/README.md @@ -6,3 +6,8 @@ Ring your phone via GadgetBridge if you lost it somewhere. 2. Lose phone 3. Open app 4. Click any button or screen + +## On a Bangle 2 + +- You can touch the top half of the screen to toggle Find / Stop +- You can touch the bottom half of the screen to exit the app. diff --git a/apps/findphone/app.js b/apps/findphone/app.js index 34f729bc7..36c3f1884 100644 --- a/apps/findphone/app.js +++ b/apps/findphone/app.js @@ -1,13 +1,15 @@ //notify your phone +const fontSize = g.getWidth() / 8; var finding = false; function draw() { // show message - g.clear(1); - require("Font8x12").add(Graphics); - g.setFont("8x12",3); + g.clear(g.theme.bg); + g.setColor(g.theme.fg); + g.setFont("Vector", fontSize); g.setFontAlign(0,0); + if (finding) { g.drawString("Finding...", g.getWidth()/2, (g.getHeight()/2)-20); g.drawString("Click to stop", g.getWidth()/2, (g.getHeight()/2)+20); @@ -27,7 +29,26 @@ draw(); //register all buttons and screen to find phone setWatch(find, BTN1, {repeat:true}); -setWatch(find, BTN2, {repeat:true}); -setWatch(find, BTN3, {repeat:true}); -setWatch(find, BTN4, {repeat:true}); -setWatch(find, BTN5, {repeat:true}); + +if (process.env.HWVERSION == 1) { + setWatch(find, BTN2, {repeat:true}); + setWatch(find, BTN3, {repeat:true}); + setWatch(find, BTN4, {repeat:true}); + setWatch(find, BTN5, {repeat:true}); +} + +if (process.env.HWVERSION == 2) { + Bangle.on('touch', function(button, xy) { + + // click top part of the screen to stop start + if (xy.y < g.getHeight() / 2) { + find(); + return; + } else { + // exit app + Bluetooth.println("\n"+JSON.stringify({t:"findPhone", n:false})); + load(); + } + }); +} + From eb8d9940ddd031f3fdce3829edcfa7a8a69c5413 Mon Sep 17 00:00:00 2001 From: hughbarney Date: Sat, 2 Oct 2021 15:41:12 +0100 Subject: [PATCH 06/26] findphone tweak to code --- apps/findphone/app.js | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/apps/findphone/app.js b/apps/findphone/app.js index 36c3f1884..e5e32739a 100644 --- a/apps/findphone/app.js +++ b/apps/findphone/app.js @@ -19,10 +19,14 @@ function draw() { g.flip(); } +function findPhone(v) { + Bluetooth.println(JSON.stringify({t:"findPhone", n:v})); +} + function find(){ finding = !finding; draw(); - Bluetooth.println("\n"+JSON.stringify({t:"findPhone", n:finding})); + findPhone(finding); } draw(); @@ -43,12 +47,9 @@ if (process.env.HWVERSION == 2) { // click top part of the screen to stop start if (xy.y < g.getHeight() / 2) { find(); - return; } else { - // exit app - Bluetooth.println("\n"+JSON.stringify({t:"findPhone", n:false})); - load(); + findPhone(false); + setTimeout(load, 100); // exit in 100ms } }); } - From 3401dd99c407410955743acb753c3e4dba8a08b5 Mon Sep 17 00:00:00 2001 From: Richard de Boer Date: Sat, 2 Oct 2021 16:52:36 +0200 Subject: [PATCH 07/26] barclock: use Layout library --- apps/barclock/ChangeLog | 2 +- apps/barclock/clock-bar.js | 150 ++++++++++++++----------------------- 2 files changed, 56 insertions(+), 96 deletions(-) diff --git a/apps/barclock/ChangeLog b/apps/barclock/ChangeLog index 314ef89f2..c56967d3d 100644 --- a/apps/barclock/ChangeLog +++ b/apps/barclock/ChangeLog @@ -5,4 +5,4 @@ 0.05: Clock does not start if app Languages is not installed 0.06: Improve accuracy 0.07: Update to use Bangle.setUI instead of setWatch -0.08: Use theme colors \ No newline at end of file +0.08: Use theme colors, Layout library \ No newline at end of file diff --git a/apps/barclock/clock-bar.js b/apps/barclock/clock-bar.js index 627028875..c2b4bde12 100644 --- a/apps/barclock/clock-bar.js +++ b/apps/barclock/clock-bar.js @@ -13,46 +13,48 @@ let locale = require("locale"); locale.dayFirst = /3.*2/.test(localized); locale.hasMeridian = false; - if (typeof locale.meridian==="function") { // function does not exists if languages app is not installed + if (typeof locale.meridian==="function") { // function does not exist if languages app is not installed locale.hasMeridian = (locale.meridian(date)!==""); } - } -const screen = { - width: g.getWidth(), - height: g.getWidth(), - middle: g.getWidth()/2, - center: g.getHeight()/2, -}; +Bangle.loadWidgets(); +function renderBar(l) { + if (!this.fraction) { + // zero-size fillRect stills draws one line of pixels, we don't want that + return; + } + const width = this.fraction*l.w; + g.fillRect(l.x, l.y, width-1, l.y+l.height-1); +} -// hardcoded "settings" -const settings = { - time: { - font: "6x8", - size: (is12Hour && locale.hasMeridian) ? 6 : 8, - middle: screen.middle, - center: screen.center, - ampm: { - color: -1, - font: "6x8", - size: 2, +const Layout = require("Layout"); +const layout = new Layout({ + type: "v", c: [ + { + type: "h", c: [ + {id: "time", label: "88:88", type: "txt", font: "6x8:5", bgCol: g.theme.bg}, // size updated below + {id: "ampm", label: " ", type: "txt", font: "6x8:2", bgCol: g.theme.bg}, + ], }, - }, - date: { - font: "Vector", - size: 20, - middle: screen.height-20, // at bottom of screen - center: screen.center, - }, - bar: { - top: 155, // just below time - thickness: 6, // matches 24h time "pixel" size - }, -}; + {id: "bar", type: "custom", fraction: 0, fillx: 1, height: 6, col: g.theme.fg2, render: renderBar}, + {height: 40}, + {id: "date", type: "txt", font: "10%", valign: 1}, + ], +}, false, {lazy: true}); +// adjustments based on screen size and whether we display am/pm +let thickness; // bar thickness, same as time font "pixel block" size +if (is12Hour) { + // Maximum font size = ( - ) / (5chars * 6px) + thickness = Math.floor((g.getWidth()-24)/(5*6)); +} else { + layout.ampm.label = ""; + thickness = Math.floor(g.getWidth()/(5*6)); +} +layout.bar.height = thickness+1; +layout.time.font = "6x8:"+thickness; +layout.update(); -const SECONDS_PER_MINUTE = 60; - -const timeText = function(date) { +function timeText(date) { if (!is12Hour) { return locale.time(date, true); } @@ -64,81 +66,39 @@ const timeText = function(date) { date12.setHours(hours-12); } return locale.time(date12, true); -}; -const ampmText = function(date) { - return is12Hour ? locale.meridian(date) : ""; -}; - -const dateText = function(date) { +} +function ampmText(date) { + return (is12Hour && locale.hasMeridian)? locale.meridian(date) : ""; +} +function dateText(date) { const dayName = locale.dow(date, true), month = locale.month(date, true), day = date.getDate(); const dayMonth = locale.dayFirst ? `${day} ${month}` : `${month} ${day}`; return `${dayName} ${dayMonth}`; -}; +} -const drawDateTime = function(date) { - const t = settings.time; - g.setFont(t.font, t.size); - g.setFontAlign(0, 0); // centered - g.drawString(timeText(date), t.center, t.middle, true); - if (is12Hour && locale.hasMeridian) { - const a = settings.time.ampm; - g.setFont(a.font, a.size); - g.setFontAlign(1, -1); // right top - // at right edge of screen, aligned with time bottom - const left = screen.width-a.size*2, - top = t.middle+t.size-a.size; - g.drawString(ampmText(date), left, top, true); - } - - const d = settings.date; - g.setFont(d.font, d.size); - g.setFontAlign(0, 0); // centered - g.drawString(dateText(date), d.center, d.middle, true); -}; - -const drawBar = function(date) { - const b = settings.bar; - const seconds = date.getSeconds(); - if (seconds===0) { - // zero-size rect stills draws one line of pixels, we don't want that - return; - } - const fraction = seconds/SECONDS_PER_MINUTE, - width = fraction*screen.width; - g.setColor(g.theme.fg2).fillRect(0, b.top, width, b.top+b.thickness); -}; - - -let lastSeconds; -const draw = function(redraw) { - if (!Bangle.isLCDOn()) {return;} - g.reset(); +draw = function draw() { + if (!Bangle.isLCDOn()) {return;} // no drawing, also no new update scheduled const date = new Date(); - const seconds = date.getSeconds(); - if (redraw||lastSeconds>seconds) { - // force redraw at start of new minute - g.clear(); - Bangle.drawWidgets(); - drawDateTime(date); - } - // the bar only gets larger, so drawing on top of the previous one is fine - drawBar(date); - lastSeconds = seconds; - // schedule next update + layout.time.label = timeText(date); + layout.ampm.label = ampmText(date); + layout.date.label = dateText(date); + const SECONDS_PER_MINUTE = 60; + layout.bar.fraction = date.getSeconds()/SECONDS_PER_MINUTE; + layout.render(); + // schedule update at start of next second const millis = date.getMilliseconds(); setTimeout(draw, 1000-millis); }; - -Bangle.loadWidgets(); // Show launcher when button pressed Bangle.setUI("clock"); - Bangle.on("lcdPower", function(on) { if (on) { - draw(true); + draw(); } }); -draw(true); +g.reset().clear(); +Bangle.drawWidgets(); +draw(); From 97d5b1077365b9d08bee04e318499c601444bd97 Mon Sep 17 00:00:00 2001 From: Francisco Trigo Date: Sat, 2 Oct 2021 20:12:12 -0500 Subject: [PATCH 08/26] Fix translation slidingtext.locale.es.js Fixed the words for 7, SEITO is now SIETE. 20, VEINTA is now VEINTE --- apps/slidingtext/slidingtext.locale.es.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/slidingtext/slidingtext.locale.es.js b/apps/slidingtext/slidingtext.locale.es.js index e1f3bc18b..1b6f6d11b 100644 --- a/apps/slidingtext/slidingtext.locale.es.js +++ b/apps/slidingtext/slidingtext.locale.es.js @@ -7,7 +7,7 @@ const spanishNumberStr = [ ["ZERO"], // 0 ["CUATRO",''], //4 ["CINCO",''], //5 ["SEIS",''], //6 - ["SEITO",''], //7 + ["SIETE",''], //7 ["OCHO",''], //8 ["NUEVE",''], // 9, ["DIEZ",''], // 10 @@ -20,7 +20,7 @@ const spanishNumberStr = [ ["ZERO"], // 0 ["DIECI",'SIETE'], // 17 ["DIECI",'OCHO'], // 18 ["DIECI",'NEUVE'], // 19 - ["VEINTA",''], // 20 + ["VEINTE",''], // 20 ["VEINTI",'UNO'], // 21 ["VEINTI",'DOS'], // 22 ["VEINTI",'TRES'], // 23 @@ -74,4 +74,4 @@ class SpanishDateFormatter extends DateFormatter { } } -module.exports = SpanishDateFormatter; \ No newline at end of file +module.exports = SpanishDateFormatter; From 5443fc760aef35e5a71c643be0befbcde921f8fa Mon Sep 17 00:00:00 2001 From: Richard de Boer Date: Sat, 2 Oct 2021 17:11:35 +0200 Subject: [PATCH 09/26] launch: small theme colour fix --- apps.json | 2 +- apps/launch/ChangeLog | 1 + apps/launch/app.js | 6 ++++-- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/apps.json b/apps.json index 11b1ea146..df8bb0b7e 100644 --- a/apps.json +++ b/apps.json @@ -42,7 +42,7 @@ "name": "Launcher (Default)", "shortName":"Launcher", "icon": "app.png", - "version":"0.06", + "version":"0.07", "description": "This is needed by Bangle.js to display a menu allowing you to choose your own applications. You can replace this with a customised launcher.", "tags": "tool,system,launcher,b2", "type":"launch", diff --git a/apps/launch/ChangeLog b/apps/launch/ChangeLog index b56c9f6bb..09569d8da 100644 --- a/apps/launch/ChangeLog +++ b/apps/launch/ChangeLog @@ -4,3 +4,4 @@ 0.04: Now displays widgets 0.05: Use g.theme for colours 0.06: Use Bangle.setUI for buttons +0.07: Theme colours fix \ No newline at end of file diff --git a/apps/launch/app.js b/apps/launch/app.js index ab1a89fc0..449e16e62 100644 --- a/apps/launch/app.js +++ b/apps/launch/app.js @@ -33,8 +33,10 @@ function drawMenu() { if (i+menuScroll==selected) { g.setColor(g.theme.bgH).fillRect(0,y,w-1,y+63); g.setColor(g.theme.fgH).drawRect(0,y,w-1,y+63); - } else - g.clearRect(0,y,w-1,y+63); + } else { + g.clearRect(0, y, w-1, y+63); + g.setColor(g.theme.fg); + } g.drawString(app.name,64,y+32); var icon=undefined; if (app.icon) icon = s.read(app.icon); From 1bbb0cb0d603da2ea7ea9236d1577513960e21b3 Mon Sep 17 00:00:00 2001 From: hughbarney Date: Mon, 4 Oct 2021 12:41:59 +0100 Subject: [PATCH 10/26] notifyfs - use theme for title and adjust font --- apps.json | 2 +- apps/notifyfs/ChangeLog | 1 + apps/notifyfs/notify.js | 6 +++--- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/apps.json b/apps.json index 832a480cf..b6311a48f 100644 --- a/apps.json +++ b/apps.json @@ -107,7 +107,7 @@ "name": "Fullscreen Notifications", "shortName":"Notifications", "icon": "notify.png", - "version":"0.11", + "version":"0.12", "description": "Provides a replacement for the `Notifications (default)` `notify` module. This version is used by applications to display notifications fullscreen. This may not fully restore the screen after on some apps. See `Notifications (default)` for more information about the notify module.", "tags": "widget,b2", "type": "notify", diff --git a/apps/notifyfs/ChangeLog b/apps/notifyfs/ChangeLog index 1c39bcbd5..cf0a13866 100644 --- a/apps/notifyfs/ChangeLog +++ b/apps/notifyfs/ChangeLog @@ -9,3 +9,4 @@ 0.09: Add onHide callback 0.10: Ensure dismissing a notification dismissal doesn't enter launcher if in clock mode 0.11: Improvements to help notifications work with themes, Bangle.js 2 support +0.12: More use of themes, title now uses theme highlight colors, font adjusts diff --git a/apps/notifyfs/notify.js b/apps/notifyfs/notify.js index a45d889f0..9cadbb124 100644 --- a/apps/notifyfs/notify.js +++ b/apps/notifyfs/notify.js @@ -1,7 +1,7 @@ let oldg; let id = null; let hideCallback = null; - +const titleFont = g.getWidth() / 8; /** * See notify/notify.js */ @@ -63,8 +63,8 @@ exports.show = function(options) { // top bar if (options.title||options.src) { const title = options.title || options.src; - g.setColor(options.titleBgColor||"#333").fillRect(x, y, x+w-1, y+30); - g.setColor(g.theme.fg).setFontAlign(-1, -1, 0).setFont("6x8", 3); + g.setColor(options.titleBgColor||g.theme.bgH).fillRect(x, y, x+w-1, y+30); + g.setColor(g.theme.fgH).setFontAlign(-1, -1, 0).setFont("Vector", titleFont); g.drawString(title.trim().substring(0, 13), x+5, y+3); if (options.title && options.src) { g.setColor(g.theme.fg).setFontAlign(1, 1, 0).setFont("6x8", 2); From 46ccfe86e352d9f4a3464b0a7bd2d587224e6d5f Mon Sep 17 00:00:00 2001 From: Ben Whittaker Date: Mon, 4 Oct 2021 09:23:12 -0400 Subject: [PATCH 11/26] weather: Fix crash when weather.json is absent --- apps.json | 2 +- apps/weather/ChangeLog | 3 ++- apps/weather/lib.js | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/apps.json b/apps.json index 10b37e5b1..83690cf3e 100644 --- a/apps.json +++ b/apps.json @@ -585,7 +585,7 @@ { "id": "weather", "name": "Weather", "icon": "icon.png", - "version":"0.08", + "version":"0.09", "description": "Show Gadgetbridge weather report", "readme": "readme.md", "tags": "widget,outdoors", diff --git a/apps/weather/ChangeLog b/apps/weather/ChangeLog index fd5d4d146..09e159045 100644 --- a/apps/weather/ChangeLog +++ b/apps/weather/ChangeLog @@ -4,4 +4,5 @@ 0.05: Add wind direction. 0.06: Use setUI for launcher. 0.07: Add theme support and unknown icon. -0.08: Refactor and reduce widget ram usage. \ No newline at end of file +0.08: Refactor and reduce widget ram usage. +0.09: Fix crash when weather.json is absent. \ No newline at end of file diff --git a/apps/weather/lib.js b/apps/weather/lib.js index f08df4a4a..299009e74 100644 --- a/apps/weather/lib.js +++ b/apps/weather/lib.js @@ -47,7 +47,7 @@ global.GB = (event) => { }; exports.get = function() { - return storage.readJSON('weather.json').weather; + return (storage.readJSON('weather.json')||{}).weather; } scheduleExpiry(storage.readJSON('weather.json')||{}); From ad2baeb6519a2ae208b3b8d0cd4a2f5f1e78f2c4 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Mon, 4 Oct 2021 16:30:37 +0100 Subject: [PATCH 12/26] work for bangle.js 1 too --- ...{build_bangle2_c.js => firmwaremaker_c.js} | 29 +++++++++++++++---- 1 file changed, 24 insertions(+), 5 deletions(-) rename bin/{build_bangle2_c.js => firmwaremaker_c.js} (86%) diff --git a/bin/build_bangle2_c.js b/bin/firmwaremaker_c.js similarity index 86% rename from bin/build_bangle2_c.js rename to bin/firmwaremaker_c.js index 5b4464691..2cb993d00 100755 --- a/bin/build_bangle2_c.js +++ b/bin/firmwaremaker_c.js @@ -11,16 +11,35 @@ var SETTINGS = { pretokenise : true }; +var DEVICE = process.argv[2]; + var path = require('path'); var ROOTDIR = path.join(__dirname, '..'); var APPDIR = ROOTDIR+'/apps'; var APPJSON = ROOTDIR+'/apps.json'; -var OUTFILE = path.join(ROOTDIR, '../Espruino/libs/banglejs/banglejs2_storage_default.c'); -var APPS = [ // IDs of apps to install - "boot","launchb2","s7clk","setting", - "about","alarm","widlock","widbat","widbt" -]; var MINIFY = true; +var OUTFILE, APPS; + +if (DEVICE=="BANGLEJS") { + var OUTFILE = path.join(ROOTDIR, '../Espruino/libs/banglejs/banglejs1_storage_default.c'); + var APPS = [ // IDs of apps to install + "boot","launch","mclock","setting", + "about","alarm","widbat","widbt","welcome" + ]; +} else if (DEVICE=="BANGLEJS2") { + var OUTFILE = path.join(ROOTDIR, '../Espruino/libs/banglejs/banglejs2_storage_default.c'); + var APPS = [ // IDs of apps to install + "boot","launchb2","s7clk","setting", + "about","alarm","widlock","widbat","widbt" + ]; +} else { + console.log("USAGE:"); + console.log(" bin/firmwaremaker_c.js BANGLEJS"); + console.log(" bin/firmwaremaker_c.js BANGLEJS2"); + process.exit(1); +} +console.log("Device = ",DEVICE); + var fs = require("fs"); global.Const = { From 202690de40057ee224eb3dcaedad57204f8db37c Mon Sep 17 00:00:00 2001 From: Ben Whittaker Date: Mon, 4 Oct 2021 15:48:43 -0400 Subject: [PATCH 13/26] Layout: Implement text wrapping --- modules/Layout.js | 39 ++++++++++++++++++++++++++++---- tests/Layout/tests/wrapping.bmp | Bin 0 -> 15562 bytes tests/Layout/tests/wrapping.js | 7 ++++++ 3 files changed, 42 insertions(+), 4 deletions(-) create mode 100644 tests/Layout/tests/wrapping.bmp create mode 100644 tests/Layout/tests/wrapping.js diff --git a/modules/Layout.js b/modules/Layout.js index 5ac0cab16..69f257b3b 100644 --- a/modules/Layout.js +++ b/modules/Layout.js @@ -36,6 +36,8 @@ layoutObject has: * A `id` field. If specified the object is added with this name to the returned `layout` object, so can be referenced as `layout.foo` * A `font` field, eg `6x8` or `30%` to use a percentage of screen height +* A `wrap` field to enable line wrapping. Requires some combination of `width`/`height` + and `fillx`/`filly` to be set. Not compatible with text rotation. * A `col` field, eg `#f00` for red * A `bgCol` field for background color (will automatically fill on render) * A `halign` field to set horizontal alignment. `-1`=left, `1`=right, `0`=center @@ -152,6 +154,24 @@ Layout.prototype.remove = function (l) { } }; +function wrappedLines(str, maxWidth) { + var lines = []; + for (var unwrappedLine of str.split("\n")) { + var words = unwrappedLine.split(" "); + var line = words.shift(); + for (var word of words) { + if (g.stringWidth(line + " " + word) > maxWidth) { + lines.push(line); + line = word; + } else { + line += " " + word; + } + } + lines.push(line); + } + return lines; +} + function prepareLazyRender(l, rectsToClear, drawList, rects, parentBg) { var bgCol = l.bgCol == null ? parentBg : g.toColor(l.bgCol); if (bgCol != parentBg || l.type == "txt" || l.type == "btn" || l.type == "img" || l.type == "custom") { @@ -187,7 +207,14 @@ Layout.prototype.render = function (l) { var cb = { "":function(){}, "txt":function(l){ - g.setFont(l.font,l.fsz).setFontAlign(0,0,l.r).drawString(l.label, l.x+(l.w>>1), l.y+(l.h>>1)); + if (l.wrap) { + g.setFont(l.font,l.fsz).setFontAlign(0,-1); + var lines = wrappedLines(l.label, l.w); + var y = l.y+((l.h-g.getFontHeight()*lines.length)>>1); + lines.forEach((line, i) => g.drawString(line, l.x+(l.w>>1), y+g.getFontHeight()*i)); + } else { + g.setFont(l.font,l.fsz).setFontAlign(0,0,l.r).drawString(l.label, l.x+(l.w>>1), l.y+(l.h>>1)); + } }, "btn":function(l){ var x = l.x+(0|l.pad); var y = l.y+(0|l.pad); @@ -305,9 +332,13 @@ Layout.prototype.update = function() { l.font = f[0]; l.fsz = f[1]; } - g.setFont(l.font,l.fsz); - l._h = g.getFontHeight(); - l._w = g.stringWidth(l.label); + if (l.wrap) { + l._h = l._w = 0; + } else { + g.setFont(l.font,l.fsz); + l._h = g.getFontHeight(); + l._w = g.stringWidth(l.label); + } }, "btn": function(l) { l._h = 24; l._w = 14 + l.label.length*8; diff --git a/tests/Layout/tests/wrapping.bmp b/tests/Layout/tests/wrapping.bmp new file mode 100644 index 0000000000000000000000000000000000000000..a0d80cc5be495c0a20ea7178ea36ff16e032372d GIT binary patch literal 15562 zcmeHN%Wd2+5M_WI1E>`jkb@EA6d*n1;9^{YOYkvAmk^|al(EM>7*O7OGo&ajwbF`G z5GUly)M!XP4j+d@ef;U`&yPXr3-S;6`;Onc@SeK+&-agyk1sDTcMnhD?pt^W;W?b2 z!jBMe{S?k2{0a}}@OnPKLT;%sa1;aG6u1lg^{1{sv8eAMBgZB6NL|m2bx@?klve+Q zYHT%wOSS!VfKVk0&<1s9N?a$U2_2G@ZWbF@V!7(5e@HxJwX_*72LZdhGZPF~_DUa7 z%>dRhHO}#fy1`yAV%w9KvND-q(SS(_3K9yAa(n9_xJN!D zy(wHgIdmsJK7^ijn^aFrkEbg_+oj_?OP1A`3ksa#L~7mxq7#<%v3folv@FXuA2`E|LhMvJ#d zx5giB3k*1VDJ6ls27k(Qg4*h>H%|36P9ZQza;q5QO0^!7H6!j|?~b?vkM?q#o7gMW z2757bA2@gr{+I`;{t{fe5Z^{xmM&bE72RkrL%I0_*{}=otGfuhnb_hF+%M6Ze|*EM z3&*98K}|ELGC)$1{A3q<5{YUb1rAOSmf|4F|R+C0q<}&wGXe*FxL8Eg+Vj zs}C~ddi>evXAR#JM6W6^_oXwk6%j5XyWY;w}ZX#m;DNcWEyzu1R!laq2#DPfIFgEkeI)1_j= zMX5dWtinaKWrHmKS{O>85NM71RLD)8np$K)oS1825m>N-h7eW%D3Ae@T8&kWtqXR? z0pL)UNcVPzD|@v%gv%^Tn{X8%ZOI9f_Lgvs4YSeuRCiD_7J!G$5Qs!k{52jhCJ5uX zWhm#Iljta+r6RnkxreaQZAnekmHbRl1FmL$8MoBwc!-mEi#CocMeWt|xXD^vi(wpz zY)!(@RSm91U0@|)H(aw9xYL=fv)5xz^;Qwb2_P51I!3y;TUr8` z(Ouvcm&ItRR&{cL3oj~p{)|~s%?JS52CjEeMDcGJ(BioLbrb+|T#T3zl~bZjGeb75 z*J#SBbI1RVb9?v1 Date: Tue, 5 Oct 2021 14:58:21 +0100 Subject: [PATCH 14/26] emulator --- apps.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps.json b/apps.json index 83690cf3e..a7577945e 100644 --- a/apps.json +++ b/apps.json @@ -3524,6 +3524,7 @@ "description": "A simple clock using the bold Anton font.", "tags":"clock,b2", "type":"clock", + "allow_emulator":true, "storage": [ {"name":"antonclk.app.js","url":"app.js"}, {"name":"antonclk.img","url":"app-icon.js","evaluate":true} @@ -3536,6 +3537,7 @@ "description": "A clock using a wave image by [Lillith May](https://www.instagram.com/_lilustrations_/). **Note: This requires a bugfix for #2049 on Bangle.js 1**", "tags":"clock,b2", "type":"clock", + "allow_emulator":true, "storage": [ {"name":"waveclk.app.js","url":"app.js"}, {"name":"waveclk.img","url":"app-icon.js","evaluate":true} From f37b744ed56c68a3a935b71a03ccdfb06fbab0b8 Mon Sep 17 00:00:00 2001 From: Ben Whittaker Date: Mon, 4 Oct 2021 18:45:57 -0400 Subject: [PATCH 15/26] Layout: defer initial update until first render --- modules/Layout.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/modules/Layout.js b/modules/Layout.js index 69f257b3b..087aff249 100644 --- a/modules/Layout.js +++ b/modules/Layout.js @@ -140,7 +140,7 @@ function Layout(layout, buttons, options) { if (l.c) l.c.forEach(idRecurser); } idRecurser(layout); - this.update(); + this.updateNeeded = true; } Layout.prototype.remove = function (l) { @@ -196,6 +196,7 @@ function prepareLazyRender(l, rectsToClear, drawList, rects, parentBg) { Layout.prototype.render = function (l) { if (!l) l = this._l; + if (this.updateNeeded) this.update(); function render(l) {"ram" g.reset(); @@ -309,6 +310,7 @@ Layout.prototype.debug = function(l,c) { if (l.c) l.c.forEach(n => this.debug(n,c)); }; Layout.prototype.update = function() { + delete this.updateNeeded; var l = this._l; var w = g.getWidth(); var y = this.yOffset; From e088b3be339733129d3eee9c60fa355700e4d1cb Mon Sep 17 00:00:00 2001 From: Ben Whittaker Date: Mon, 27 Sep 2021 13:53:23 -0400 Subject: [PATCH 16/26] weather: Use Layout library --- apps/weather/app.js | 169 +++++++++++++++++++++++--------------------- 1 file changed, 90 insertions(+), 79 deletions(-) diff --git a/apps/weather/app.js b/apps/weather/app.js index 9d64583e9..634a669b4 100644 --- a/apps/weather/app.js +++ b/apps/weather/app.js @@ -1,96 +1,107 @@ -(() => { - const weather = require('weather'); - let current = weather.get(); +const Layout = require('Layout'); +const locale = require('locale'); +const weather = require('weather'); +let current = weather.get(); - function formatDuration(millis) { - let pluralize = (n, w) => n + " " + w + (n == 1 ? "" : "s"); - if (millis < 60000) return "< 1 minute"; - if (millis < 3600000) return pluralize(Math.floor(millis/60000), "minute"); - if (millis < 86400000) return pluralize(Math.floor(millis/3600000), "hour"); - return pluralize(Math.floor(millis/86400000), "day"); - } +Bangle.loadWidgets(); - function draw() { - g.reset(); - g.clearRect(0, 24, 239, 239); +var layout = new Layout({type:"v", bgCol: g.theme.bg, c: [ + {filly: 1}, + {type: "h", filly: 0, c: [ + {type: "custom", width: g.getWidth()/2, height: g.getWidth()/2, valign: -1, txt: "unknown", id: "icon", + render: l => weather.drawIcon(l.txt, l.x+l.w/2, l.y+l.h/2, l.w/2-5)}, + {type: "v", c: [ + {type: "h", pad: 2, c: [ + {type: "txt", font: "18%", id: "temp", label: "000"}, + {type: "txt", font: "12%", valign: -1, id: "tempUnit", label: "°C"}, + ]}, + {filly: 1}, + {type: "txt", font: "6x8", pad: 2, halign: 1, label: "Humidity"}, + {type: "txt", font: "9%", pad: 2, halign: 1, id: "hum", label: "000%"}, + {filly: 1}, + {type: "txt", font: "6x8", pad: 2, halign: -1, label: "Wind"}, + {type: "h", halign: -1, c: [ + {type: "txt", font: "9%", pad: 2, id: "wind", label: "00"}, + {type: "txt", font: "6x8", pad: 2, valign: -1, id: "windUnit", label: "km/h"}, + ]}, + ]}, + ]}, + {filly: 1}, + {type: "txt", font: "9%", id: "cond", label: "Weather line 1"}, + {filly: 1}, + {type: "h", c: [ + {type: "txt", font: "6x8", pad: 2, id: "loc", label: "Toronto"}, + {fillx: 1}, + {type: "txt", font: "6x8", pad: 2, id: "updateTime", label: "15 minutes ago"}, + ]}, + {filly: 1}, +]}, null, {lazy: true}); - weather.drawIcon(current.txt, 65, 90, 55); - const locale = require("locale"); +function formatDuration(millis) { + let pluralize = (n, w) => n + " " + w + (n == 1 ? "" : "s"); + if (millis < 60000) return "< 1 minute"; + if (millis < 3600000) return pluralize(Math.floor(millis/60000), "minute"); + if (millis < 86400000) return pluralize(Math.floor(millis/3600000), "hour"); + return pluralize(Math.floor(millis/86400000), "day"); +} - g.reset(); +function draw() { + layout.icon.txt = current.txt; + const temp = locale.temp(current.temp-273.15).match(/^(\D*\d*)(.*)$/); + layout.temp.label = temp[1]; + layout.tempUnit.label = temp[2]; + layout.hum.label = current.hum+"%"; + const wind = locale.speed(current.wind).match(/^(\D*\d*)(.*)$/); + layout.wind.label = wind[1]; + layout.windUnit.label = wind[2] + " " + current.wrose.toUpperCase(); + // TODO: split long weather conditions across multiple lines + layout.cond.label = current.txt.charAt(0).toUpperCase()+current.txt.slice(1); + layout.loc.label = current.loc; + layout.updateTime.label = `${formatDuration(Date.now() - current.time)} ago`; + layout.update(); + layout.render(); +} - const temp = locale.temp(current.temp-273.15).match(/^(\D*\d*)(.*)$/); - let width = g.setFont("Vector", 40).stringWidth(temp[1]); - width += g.setFont("Vector", 20).stringWidth(temp[2]); - g.setFont("Vector", 40).setFontAlign(-1, -1, 0); - g.drawString(temp[1], 180-width/2, 70); - g.setFont("Vector", 20).setFontAlign(1, -1, 0); - g.drawString(temp[2], 180+width/2, 70); +function drawUpdateTime() { + if (!current || !current.time) return; + layout.updateTime.label = `${formatDuration(Date.now() - current.time)} ago`; + layout.update(); + layout.render(); +} - g.setFont("6x8", 1); - g.setFontAlign(-1, 0, 0); - g.drawString("Humidity", 135, 130); - g.setFontAlign(1, 0, 0); - g.drawString(current.hum+"%", 225, 130); - if ('wind' in current) { - g.setFontAlign(-1, 0, 0); - g.drawString("Wind", 135, 142); - g.setFontAlign(1, 0, 0); - g.drawString(locale.speed(current.wind)+' '+current.wrose.toUpperCase(), 225, 142); - } - - g.setFont("6x8", 2).setFontAlign(0, 0, 0); - g.drawString(current.loc, 120, 170); - - g.setFont("6x8", 1).setFontAlign(0, 0, 0); - g.drawString(current.txt.charAt(0).toUpperCase()+current.txt.slice(1), 120, 190); - - drawUpdateTime(); - - g.flip(); - } - - function drawUpdateTime() { - if (!current || !current.time) return; - let text = `Last update received ${formatDuration(Date.now() - current.time)} ago`; - g.reset(); - g.clearRect(0, 202, 239, 210); - g.setFont("6x8", 1).setFontAlign(0, 0, 0); - g.drawString(text, 120, 206); - } - - function update() { - current = weather.get(); - NRF.removeListener("connect", update); - if (current) { - draw(); - } else if (NRF.getSecurityStatus().connected) { +function update() { + current = weather.get(); + NRF.removeListener("connect", update); + if (current) { + draw(); + } else { + delete layout.rects; + if (NRF.getSecurityStatus().connected) { E.showMessage("Weather unknown\n\nIs Gadgetbridge\nweather reporting\nset up on your\nphone?"); } else { E.showMessage("Weather unknown\n\nGadgetbridge\nnot connected"); NRF.on("connect", update); } } +} - let interval = setInterval(drawUpdateTime, 60000); - Bangle.on('lcdPower', (on) => { - if (interval) { - clearInterval(interval); - interval = undefined; - } - if (on) { - drawUpdateTime(); - interval = setInterval(drawUpdateTime, 60000); - } - }); +let interval = setInterval(drawUpdateTime, 60000); +Bangle.on('lcdPower', (on) => { + if (interval) { + clearInterval(interval); + interval = undefined; + } + if (on) { + drawUpdateTime(); + interval = setInterval(drawUpdateTime, 60000); + } +}); - weather.on("update", update); +weather.on("update", update); - update(); +update(); - // Show launcher when middle button pressed - Bangle.setUI("clock"); +// Show launcher when middle button pressed +Bangle.setUI("clock"); - Bangle.loadWidgets(); - Bangle.drawWidgets(); -})() +Bangle.drawWidgets(); From 3cfd94314e8ad563ff247814f87085de2b1672a4 Mon Sep 17 00:00:00 2001 From: Ben Whittaker Date: Mon, 4 Oct 2021 16:19:11 -0400 Subject: [PATCH 17/26] weather: Use wrapping text for condition --- apps/weather/app.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/weather/app.js b/apps/weather/app.js index 634a669b4..0f0512ba7 100644 --- a/apps/weather/app.js +++ b/apps/weather/app.js @@ -27,7 +27,7 @@ var layout = new Layout({type:"v", bgCol: g.theme.bg, c: [ ]}, ]}, {filly: 1}, - {type: "txt", font: "9%", id: "cond", label: "Weather line 1"}, + {type: "txt", font: "9%", wrap: true, height: g.getHeight()*0.18, fillx: 1, id: "cond", label: "Weather condition"}, {filly: 1}, {type: "h", c: [ {type: "txt", font: "6x8", pad: 2, id: "loc", label: "Toronto"}, @@ -54,7 +54,6 @@ function draw() { const wind = locale.speed(current.wind).match(/^(\D*\d*)(.*)$/); layout.wind.label = wind[1]; layout.windUnit.label = wind[2] + " " + current.wrose.toUpperCase(); - // TODO: split long weather conditions across multiple lines layout.cond.label = current.txt.charAt(0).toUpperCase()+current.txt.slice(1); layout.loc.label = current.loc; layout.updateTime.label = `${formatDuration(Date.now() - current.time)} ago`; From cdf95566bd6d6b544dc26f61e5e9708067692bcc Mon Sep 17 00:00:00 2001 From: Ben Whittaker Date: Tue, 5 Oct 2021 20:57:10 -0400 Subject: [PATCH 18/26] Layout: Add `forgetLazyState` method --- apps/weather/app.js | 2 +- modules/Layout.js | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/apps/weather/app.js b/apps/weather/app.js index 0f0512ba7..aab71f703 100644 --- a/apps/weather/app.js +++ b/apps/weather/app.js @@ -74,7 +74,7 @@ function update() { if (current) { draw(); } else { - delete layout.rects; + layout.forgetLazyState(); if (NRF.getSecurityStatus().connected) { E.showMessage("Weather unknown\n\nIs Gadgetbridge\nweather reporting\nset up on your\nphone?"); } else { diff --git a/modules/Layout.js b/modules/Layout.js index 087aff249..09e2a3d8c 100644 --- a/modules/Layout.js +++ b/modules/Layout.js @@ -73,6 +73,7 @@ Other functions: * `layout.update()` - update positions of everything if contents have changed * `layout.debug(obj)` - draw outlines for objects on screen * `layout.clear(obj)` - clear the given object (you can also just specify `bgCol` to clear before each render) +* `layout.forgetLazyState()` - if lazy rendering is enabled, makes the next call to `render()` perform a full re-render */ @@ -258,6 +259,10 @@ Layout.prototype.render = function (l) { } }; +Layout.prototype.forgetLazyState = function () { + this.rects = {}; +} + Layout.prototype.layout = function (l) { // l = current layout element // exw,exh = extra width/height available From a84588aca1c07ce2763585485bf2e62906be957a Mon Sep 17 00:00:00 2001 From: Ben Whittaker Date: Tue, 5 Oct 2021 21:04:21 -0400 Subject: [PATCH 19/26] weather: tweaks + changelog --- apps.json | 2 +- apps/weather/ChangeLog | 3 ++- apps/weather/app.js | 10 +++++----- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/apps.json b/apps.json index a7577945e..f3b8badd5 100644 --- a/apps.json +++ b/apps.json @@ -585,7 +585,7 @@ { "id": "weather", "name": "Weather", "icon": "icon.png", - "version":"0.09", + "version":"0.10", "description": "Show Gadgetbridge weather report", "readme": "readme.md", "tags": "widget,outdoors", diff --git a/apps/weather/ChangeLog b/apps/weather/ChangeLog index 09e159045..8f997a83e 100644 --- a/apps/weather/ChangeLog +++ b/apps/weather/ChangeLog @@ -5,4 +5,5 @@ 0.06: Use setUI for launcher. 0.07: Add theme support and unknown icon. 0.08: Refactor and reduce widget ram usage. -0.09: Fix crash when weather.json is absent. \ No newline at end of file +0.09: Fix crash when weather.json is absent. +0.10: Use new Layout library \ No newline at end of file diff --git a/apps/weather/app.js b/apps/weather/app.js index aab71f703..6dba14143 100644 --- a/apps/weather/app.js +++ b/apps/weather/app.js @@ -10,7 +10,7 @@ var layout = new Layout({type:"v", bgCol: g.theme.bg, c: [ {type: "h", filly: 0, c: [ {type: "custom", width: g.getWidth()/2, height: g.getWidth()/2, valign: -1, txt: "unknown", id: "icon", render: l => weather.drawIcon(l.txt, l.x+l.w/2, l.y+l.h/2, l.w/2-5)}, - {type: "v", c: [ + {type: "v", fillx: 1, c: [ {type: "h", pad: 2, c: [ {type: "txt", font: "18%", id: "temp", label: "000"}, {type: "txt", font: "12%", valign: -1, id: "tempUnit", label: "°C"}, @@ -30,9 +30,9 @@ var layout = new Layout({type:"v", bgCol: g.theme.bg, c: [ {type: "txt", font: "9%", wrap: true, height: g.getHeight()*0.18, fillx: 1, id: "cond", label: "Weather condition"}, {filly: 1}, {type: "h", c: [ - {type: "txt", font: "6x8", pad: 2, id: "loc", label: "Toronto"}, + {type: "txt", font: "6x8", pad: 4, id: "loc", label: "Toronto"}, {fillx: 1}, - {type: "txt", font: "6x8", pad: 2, id: "updateTime", label: "15 minutes ago"}, + {type: "txt", font: "6x8", pad: 4, id: "updateTime", label: "15 minutes ago"}, ]}, {filly: 1}, ]}, null, {lazy: true}); @@ -76,9 +76,9 @@ function update() { } else { layout.forgetLazyState(); if (NRF.getSecurityStatus().connected) { - E.showMessage("Weather unknown\n\nIs Gadgetbridge\nweather reporting\nset up on your\nphone?"); + E.showMessage("Weather\nunknown\n\nIs Gadgetbridge\nweather\nreporting set\nup on your\nphone?"); } else { - E.showMessage("Weather unknown\n\nGadgetbridge\nnot connected"); + E.showMessage("Weather\nunknown\n\nGadgetbridge\nnot connected"); NRF.on("connect", update); } } From f78c9b7c22964d05f0c8a5dcc58ef7ae66313e7e Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Wed, 6 Oct 2021 09:45:12 +0100 Subject: [PATCH 20/26] settings 0.29: Move '< Back' to the top of menus --- apps.json | 2 +- apps/setting/ChangeLog | 1 + apps/setting/settings.js | 14 +++++++------- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/apps.json b/apps.json index a7577945e..cb77a7290 100644 --- a/apps.json +++ b/apps.json @@ -185,7 +185,7 @@ { "id": "setting", "name": "Settings", "icon": "settings.png", - "version":"0.28", + "version":"0.29", "description": "A menu for setting up Bangle.js", "tags": "tool,system,b2", "readme": "README.md", diff --git a/apps/setting/ChangeLog b/apps/setting/ChangeLog index 5a96451f2..0ecac7e42 100644 --- a/apps/setting/ChangeLog +++ b/apps/setting/ChangeLog @@ -31,3 +31,4 @@ 0.26: Use Bangle.softOff if available as this keeps the time 0.27: Add Theme menu 0.28: Update Quiet Mode widget (if present) +0.29: Move '< Back' to the top of menus diff --git a/apps/setting/settings.js b/apps/setting/settings.js index 1b1cc5478..d3c7d42c7 100644 --- a/apps/setting/settings.js +++ b/apps/setting/settings.js @@ -75,6 +75,7 @@ function showMainMenu() { var beepN = ["Off", "Piezo", "Vibrate"]; const mainmenu = { '': { 'title': 'Settings' }, + '< Back': ()=>load(), 'Make Connectable': ()=>makeConnectable(), 'App/Widget Settings': ()=>showAppSettingsMenu(), 'BLE': ()=>showBLEMenu(), @@ -117,7 +118,6 @@ function showMainMenu() { 'Theme': ()=>showThemeMenu(), 'Reset Settings': ()=>showResetMenu(), 'Turn Off': ()=>{ if (Bangle.softOff) Bangle.softOff(); else Bangle.off() }, - '< Back': ()=>load() }; return E.showMenu(mainmenu); } @@ -126,6 +126,7 @@ function showBLEMenu() { var hidV = [false, "kbmedia", "kb", "joy"]; var hidN = ["Off", "Kbrd & Media", "Kbrd","Joystick"]; E.showMenu({ + '< Back': ()=>showMainMenu(), 'BLE': { value: settings.ble, format: boolFormat, @@ -158,8 +159,7 @@ function showBLEMenu() { 'Whitelist': { value: settings.whitelist?(settings.whitelist.length+" devs"):"off", onchange: () => setTimeout(showWhitelistMenu) // graphical_menu redraws after the call - }, - '< Back': ()=>showMainMenu() + } }); } @@ -178,6 +178,7 @@ function showThemeMenu() { m.draw(); } var m = E.showMenu({ + '< Back': ()=>showMainMenu(), 'Dark BW': ()=>{ upd({ fg:cl("#fff"), bg:cl("#000"), @@ -193,13 +194,13 @@ function showThemeMenu() { fgH:cl("#000"), bgH:cl("#0ff"), dark:false }); - }, - '< Back': ()=>showMainMenu() + } }); } function showPasskeyMenu() { var menu = { + "< Back" : ()=>showBLEMenu(), "Disable" : () => { settings.passkey = undefined; updateSettings(); @@ -220,12 +221,12 @@ function showPasskeyMenu() { } }; })(i); - menu['< Back']=()=>showBLEMenu(); E.showMenu(menu); } function showWhitelistMenu() { var menu = { + "< Back" : ()=>showBLEMenu(), "Disable" : () => { settings.whitelist = undefined; updateSettings(); @@ -257,7 +258,6 @@ function showWhitelistMenu() { showWhitelistMenu(); }); }; - menu['< Back']=()=>showBLEMenu(); E.showMenu(menu); } From ce358e4b55cc65f5d16c424ae550df0e5de2b4f0 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Wed, 6 Oct 2021 09:47:37 +0100 Subject: [PATCH 21/26] Add timer capability to alarms app --- apps.json | 6 ++-- apps/alarm/alarm.js | 2 +- apps/alarm/app.js | 80 +++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 78 insertions(+), 10 deletions(-) diff --git a/apps.json b/apps.json index cb77a7290..49b144412 100644 --- a/apps.json +++ b/apps.json @@ -199,11 +199,11 @@ "sortorder" : -2 }, { "id": "alarm", - "name": "Default Alarm", + "name": "Default Alarm & Timer", "shortName":"Alarms", "icon": "app.png", - "version":"0.12", - "description": "Set and respond to alarms", + "version":"0.13", + "description": "Set and respond to alarms and timers", "tags": "tool,alarm,widget,b2", "storage": [ {"name":"alarm.app.js","url":"app.js"}, diff --git a/apps/alarm/alarm.js b/apps/alarm/alarm.js index 26345e887..3598909fc 100644 --- a/apps/alarm/alarm.js +++ b/apps/alarm/alarm.js @@ -19,7 +19,7 @@ function showAlarm(alarm) { if (alarm.msg) msg += "\n"+alarm.msg; E.showPrompt(msg,{ - title:"ALARM!", + title:alarm.timer ? "TIMER!" : "ALARM!", buttons : {"Sleep":true,"Ok":false} // default is sleep so it'll come back in 10 mins }).then(function(sleep) { buzzCount = 0; diff --git a/apps/alarm/app.js b/apps/alarm/app.js index b6019ca08..343eb5b21 100644 --- a/apps/alarm/app.js +++ b/apps/alarm/app.js @@ -9,6 +9,7 @@ var alarms = require("Storage").readJSON("alarm.json",1)||[]; last : 0, // last day of the month we alarmed on - so we don't alarm twice in one day! rp : true, // repeat as : false, // auto snooze + timer : 5, // OPTIONAL - if set, this is a timer and it's the time in minutes } ];*/ @@ -18,6 +19,12 @@ function formatTime(t) { return hrs+":"+("0"+mins).substr(-2); } +function formatMins(t) { + mins = (0|t)%60; + hrs = 0|(t/60); + return hrs+":"+("0"+mins).substr(-2); +} + function getCurrentHr() { var time = new Date(); return time.getHours()+(time.getMinutes()/60)+(time.getSeconds()/3600); @@ -25,14 +32,20 @@ function getCurrentHr() { function showMainMenu() { const menu = { - '': { 'title': 'Alarms' }, - 'New Alarm': ()=>editAlarm(-1) + '': { 'title': 'Alarm/Timer' }, + 'New Alarm': ()=>editAlarm(-1), + 'New Timer': ()=>editTimer(-1) }; alarms.forEach((alarm,idx)=>{ - txt = (alarm.on?"on ":"off ")+formatTime(alarm.hr); - if (alarm.rp) txt += " (repeat)"; + if (alarm.timer) { + txt = "TIMER "+(alarm.on?"on ":"off ")+formatMins(alarm.timer); + } else { + txt = "ALARM "+(alarm.on?"on ":"off ")+formatTime(alarm.hr); + if (alarm.rp) txt += " (repeat)"; + } menu[txt] = function() { - editAlarm(idx); + if (alarm.timer) editTimer(idx); + else editAlarm(idx); }; }); menu['< Back'] = ()=>{load();}; @@ -55,7 +68,7 @@ function editAlarm(alarmIndex) { as = a.as; } const menu = { - '': { 'title': 'Alarms' }, + '': { 'title': 'Alarm' }, 'Hours': { value: hrs, onchange: function(v){if (v<0)v=23;if (v>23)v=0;hrs=v;this.value=v;} // no arrow fn -> preserve 'this' @@ -109,4 +122,59 @@ function editAlarm(alarmIndex) { return E.showMenu(menu); } +function editTimer(alarmIndex) { + var newAlarm = alarmIndex<0; + var hrs = 0; + var mins = 5; + var en = true; + if (!newAlarm) { + var a = alarms[alarmIndex]; + mins = (0|a.timer)%60; + hrs = 0|(a.timer/60); + en = a.on; + } + const menu = { + '': { 'title': 'Timer' }, + 'Hours': { + value: hrs, + onchange: function(v){if (v<0)v=23;if (v>23)v=0;hrs=v;this.value=v;} // no arrow fn -> preserve 'this' + }, + 'Minutes': { + value: mins, + onchange: function(v){if (v<0)v=59;if (v>59)v=0;mins=v;this.value=v;} // no arrow fn -> preserve 'this' + }, + 'Enabled': { + value: en, + format: v=>v?"On":"Off", + onchange: v=>en=v + } + }; + function getTimer() { + var d = new Date(Date.now() + ((hrs*60)+mins)*60000); + var hr = d.getHours() + (d.getMinutes()/60) + (d.getSeconds()/3600); + // Save alarm + return { + on : en, + timer : (hrs*60)+mins, + hr : hr, + rp : false, as: false + }; + } + menu["> Save"] = function() { + if (newAlarm) alarms.push(getTimer()); + else alarms[alarmIndex] = getTimer(); + require("Storage").write("alarm.json",JSON.stringify(alarms)); + showMainMenu(); + }; + if (!newAlarm) { + menu["> Delete"] = function() { + alarms.splice(alarmIndex,1); + require("Storage").write("alarm.json",JSON.stringify(alarms)); + showMainMenu(); + }; + } + menu['< Back'] = showMainMenu; + return E.showMenu(menu); +} + showMainMenu(); From e53099aea6c1d159ad1717693e13f0b82c4a8c1d Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Wed, 6 Oct 2021 10:05:15 +0100 Subject: [PATCH 22/26] Widgets now shown on Alarm screen Alarm widget state now updates when setting/resetting an alarm --- apps/alarm/ChangeLog | 2 ++ apps/alarm/alarm.js | 2 ++ apps/alarm/app.js | 1 + apps/alarm/widget.js | 18 +++++++----------- 4 files changed, 12 insertions(+), 11 deletions(-) diff --git a/apps/alarm/ChangeLog b/apps/alarm/ChangeLog index 4084a7d3f..a151fd07e 100644 --- a/apps/alarm/ChangeLog +++ b/apps/alarm/ChangeLog @@ -10,3 +10,5 @@ 0.10: Fix auto-snooze option (this stopped new alarms being added) (fix #506) 0.11: Respect Quiet Mode 0.12: Fix widget for bangle 2, now uses theme + Widgets now shown on Alarm screen + Alarm widget state now updates when setting/resetting an alarm diff --git a/apps/alarm/alarm.js b/apps/alarm/alarm.js index 3598909fc..bb5722106 100644 --- a/apps/alarm/alarm.js +++ b/apps/alarm/alarm.js @@ -18,6 +18,8 @@ function showAlarm(alarm) { var buzzCount = 10; if (alarm.msg) msg += "\n"+alarm.msg; + Bangle.loadWidgets(); + Bangle.drawWidgets(); E.showPrompt(msg,{ title:alarm.timer ? "TIMER!" : "ALARM!", buttons : {"Sleep":true,"Ok":false} // default is sleep so it'll come back in 10 mins diff --git a/apps/alarm/app.js b/apps/alarm/app.js index 343eb5b21..fdb7784f7 100644 --- a/apps/alarm/app.js +++ b/apps/alarm/app.js @@ -49,6 +49,7 @@ function showMainMenu() { }; }); menu['< Back'] = ()=>{load();}; + if (WIDGETS["alarm"]) WIDGETS["alarm"].reload(); return E.showMenu(menu); } diff --git a/apps/alarm/widget.js b/apps/alarm/widget.js index 7b9a88bb9..e8bb79fc7 100644 --- a/apps/alarm/widget.js +++ b/apps/alarm/widget.js @@ -1,11 +1,7 @@ -(() => { - var alarms = require('Storage').readJSON('alarm.json',1)||[]; - alarms = alarms.filter(alarm=>alarm.on); - if (!alarms.length) return; // no alarms, no widget! - delete alarms; - // add the widget - WIDGETS["alarm"]={area:"tl",width:24,draw:function() { - g.setColor(g.theme.fg); - g.drawImage(atob("GBgBAAAAAAAAABgADhhwDDwwGP8YGf+YMf+MM//MM//MA//AA//AA//AA//AA//AA//AB//gD//wD//wAAAAADwAABgAAAAAAAAA"),this.x,this.y); - }}; -})() +WIDGETS["alarm"]={area:"tl",width:0,draw:function() { + if (this.width) g.reset().drawImage(atob("GBgBAAAAAAAAABgADhhwDDwwGP8YGf+YMf+MM//MM//MA//AA//AA//AA//AA//AA//AB//gD//wD//wAAAAADwAABgAAAAAAAAA"),this.x,this.y); + },reload:function() { + WIDGETS["alarm"].width = (require('Storage').readJSON('alarm.json',1)||[]).some(alarm=>alarm.on) ? 24 : 0; + } +}; +WIDGETS["alarm"].reload(); From 48d8031442ee452643135fb111a89e162f689dc7 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Wed, 6 Oct 2021 10:13:26 +0100 Subject: [PATCH 23/26] widclk 0.06: Use 7 segment font, update *on* the minute, use less memory --- apps.json | 2 +- apps/widclk/ChangeLog | 1 + apps/widclk/widget.js | 44 +++++++++++++++---------------------------- 3 files changed, 17 insertions(+), 30 deletions(-) diff --git a/apps.json b/apps.json index 49b144412..c182da13c 100644 --- a/apps.json +++ b/apps.json @@ -1187,7 +1187,7 @@ { "id": "widclk", "name": "Digital clock widget", "icon": "widget.png", - "version":"0.05", + "version":"0.06", "description": "A simple digital clock widget", "tags": "widget,clock", "type":"widget", diff --git a/apps/widclk/ChangeLog b/apps/widclk/ChangeLog index 655679515..c74857ab4 100644 --- a/apps/widclk/ChangeLog +++ b/apps/widclk/ChangeLog @@ -2,3 +2,4 @@ 0.03: Ensure redrawing works with variable size widget system 0.04: Fix regression stopping correct widget updates 0.05: Don't show clock widget if already showing clock app +0.06: Use 7 segment font, update *on* the minute, use less memory diff --git a/apps/widclk/widget.js b/apps/widclk/widget.js index cd4b29367..da3f60ce8 100644 --- a/apps/widclk/widget.js +++ b/apps/widclk/widget.js @@ -1,30 +1,16 @@ -(function() { - // don't show widget if we know we have a clock app running - if (Bangle.CLOCK) return; +/* Simple clock that appears in the widget bar if no other clock +is running. We update once per minute, but don't bother stopping +if the */ - let intervalRef = null; - var width = 5 * 6*2 - - function draw() { - g.reset().setFont("6x8", 2).setFontAlign(-1, 0); - var time = require("locale").time(new Date(),1); - g.drawString(time, this.x, this.y+11, true); // 5 * 6*2 = 60 - } - function clearTimers(){ - if(intervalRef) { - clearInterval(intervalRef); - intervalRef = null; - } - } - function startTimers(){ - intervalRef = setInterval(()=>WIDGETS["wdclk"].draw(), 60*1000); - WIDGETS["wdclk"].draw(); - } - Bangle.on('lcdPower', (on) => { - clearTimers(); - if (on) startTimers(); - }); - - WIDGETS["wdclk"]={area:"tr",width:width,draw:draw}; - if (Bangle.isLCDOn) intervalRef = setInterval(()=>WIDGETS["wdclk"].draw(), 60*1000); -})() +// don't show widget if we know we have a clock app running +if (!Bangle.CLOCK) WIDGETS["wdclk"]={area:"tl",width:52/* g.stringWidth("00:00") */,draw:function() { + g.reset().setFontCustom(atob("AAAAAAAAAAIAAAQCAQAAAd0BgMBdwAAAAAAAdwAB0RiMRcAAAERiMRdwAcAQCAQdwAcERiMRBwAd0RiMRBwAAEAgEAdwAd0RiMRdwAcERiMRdwAFAAd0QiEQdwAdwRCIRBwAd0BgMBAAABwRCIRdwAd0RiMRAAAd0QiEQAAAAAAAAAA="), 32, atob("BgAAAAAAAAAAAAAAAAYCAAYGBgYGBgYGBgYCAAAAAAAABgYGBgYG"), 512+9); + var time = require("locale").time(new Date(),1); + g.drawString(time, this.x, this.y+3, true); // 5 * 6*2 = 60 + // queue draw in one minute + if (drawTimeout) clearTimeout(drawTimeout); + this.drawTimeout = setTimeout(()=>{ + this.drawTimeout = undefined; + this.draw(); + }, 60000 - (Date.now() % 60000)); +}}; From 70702560c648e0463e55e4db32d31541ca50bd5d Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Wed, 6 Oct 2021 10:15:16 +0100 Subject: [PATCH 24/26] antonclk/waveclk 0.02: Load widgets after setUI so widclk knows when to hide --- apps.json | 4 ++-- apps/antonclk/ChangeLog | 1 + apps/antonclk/app.js | 9 ++++----- apps/waveclk/ChangeLog | 1 + apps/waveclk/app.js | 6 +++--- 5 files changed, 11 insertions(+), 10 deletions(-) diff --git a/apps.json b/apps.json index c182da13c..35dfb9653 100644 --- a/apps.json +++ b/apps.json @@ -3520,7 +3520,7 @@ { "id": "antonclk", "name": "Anton Clock", "icon": "app.png", - "version":"0.01", + "version":"0.02", "description": "A simple clock using the bold Anton font.", "tags":"clock,b2", "type":"clock", @@ -3533,7 +3533,7 @@ { "id": "waveclk", "name": "Wave Clock", "icon": "app.png", - "version":"0.01", + "version":"0.02", "description": "A clock using a wave image by [Lillith May](https://www.instagram.com/_lilustrations_/). **Note: This requires a bugfix for #2049 on Bangle.js 1**", "tags":"clock,b2", "type":"clock", diff --git a/apps/antonclk/ChangeLog b/apps/antonclk/ChangeLog index 5560f00bc..8c2a33143 100644 --- a/apps/antonclk/ChangeLog +++ b/apps/antonclk/ChangeLog @@ -1 +1,2 @@ 0.01: New App! +0.02: Load widgets after setUI so widclk knows when to hide diff --git a/apps/antonclk/app.js b/apps/antonclk/app.js index 1b92d4a8b..f6fcf1708 100644 --- a/apps/antonclk/app.js +++ b/apps/antonclk/app.js @@ -19,7 +19,7 @@ function queueDraw() { function draw() { var x = g.getWidth()/2; var y = g.getHeight()/2; - g.reset(); + g.reset(); var date = new Date(); var timeStr = require("locale").time(date,1); var dateStr = require("locale").date(date).toUpperCase(); @@ -33,7 +33,7 @@ function draw() { g.clearRect(0,y-8,g.getWidth(),y+8); // clear the background g.drawString(dateStr,x,y); // queue draw in one minute - queueDraw(); + queueDraw(); } // Clear the screen once, at startup @@ -49,9 +49,8 @@ Bangle.on('lcdPower',on=>{ drawTimeout = undefined; } }); +// Show launcher when middle button pressed +Bangle.setUI("clock"); // Load widgets Bangle.loadWidgets(); Bangle.drawWidgets(); -// Show launcher when middle button pressed -Bangle.setUI("clock"); - diff --git a/apps/waveclk/ChangeLog b/apps/waveclk/ChangeLog index 5560f00bc..8c2a33143 100644 --- a/apps/waveclk/ChangeLog +++ b/apps/waveclk/ChangeLog @@ -1 +1,2 @@ 0.01: New App! +0.02: Load widgets after setUI so widclk knows when to hide diff --git a/apps/waveclk/app.js b/apps/waveclk/app.js index 7e1870aa7..f1c67ce2f 100644 --- a/apps/waveclk/app.js +++ b/apps/waveclk/app.js @@ -28,7 +28,7 @@ function queueDraw() { function draw() { var x = g.getWidth()/2; var y = 24+20; - + g.reset().clearRect(0,24,g.getWidth(),g.getHeight()-IMAGEHEIGHT); if (g.getWidth() == IMAGEWIDTH) g.drawImage(getImg(),0,g.getHeight()-IMAGEHEIGHT); @@ -65,8 +65,8 @@ Bangle.on('lcdPower',on=>{ drawTimeout = undefined; } }); +// Show launcher when middle button pressed +Bangle.setUI("clock"); // Load widgets Bangle.loadWidgets(); Bangle.drawWidgets(); -// Show launcher when middle button pressed -Bangle.setUI("clock"); \ No newline at end of file From 192e8470d1c0f59000d4e2d02c9902dd61d41ff8 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Wed, 6 Oct 2021 16:08:11 +0100 Subject: [PATCH 25/26] demoapp 0.02: Minor adjustment to fix out of memory errors --- apps.json | 4 ++-- apps/demoapp/ChangeLog | 1 + apps/demoapp/app.js | 5 ++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/apps.json b/apps.json index 35dfb9653..d45e8c947 100644 --- a/apps.json +++ b/apps.json @@ -1236,9 +1236,9 @@ { "id": "demoapp", "name": "Demo Loop", "icon": "app.png", - "version":"0.01", + "version":"0.02", "description": "Simple demo app - displays Bangle.js, JS logo, graphics, and Bangle.js information", - "tags": "", + "tags": "bno2", "type":"app", "allow_emulator":true, "storage": [ diff --git a/apps/demoapp/ChangeLog b/apps/demoapp/ChangeLog index 5560f00bc..53e9cf268 100644 --- a/apps/demoapp/ChangeLog +++ b/apps/demoapp/ChangeLog @@ -1 +1,2 @@ 0.01: New App! +0.02: Minor adjustment to fix out of memory errors diff --git a/apps/demoapp/app.js b/apps/demoapp/app.js index 13c043587..f1cf5af07 100644 --- a/apps/demoapp/app.js +++ b/apps/demoapp/app.js @@ -60,8 +60,8 @@ var scenes = [ }; }, function() { + Bangle.setLCDMode("120x120"); var img = require("heatshrink").decompress(atob("oNBxH+5wA/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AHGpAAoQKv4ADCBQAeqsrAAejBw9/B4oABqt/IGepHw5CEQspALH5hBC5pAvv4/MAALFkIBWpPI6IHqpAu0Z3GfYOpRYdPQEhALYIp2FBYNVI4JAvvL4LH0yBYAFJAQQQ5Ay1JAFftBAQBYxCDv+qIGiCHIQiGnIBfOv5BJIQRAyIJkrvKEkIBrFBB4qEGIGRCNYsZAQIQV/IZDEiICRCDQVJAUIQVPC4lVIF6yJQYpAZ5t/FYvNIBepqtVIJGjIDoqBDY2pdYo3DfAhBIQLmpvIcDvIrC5oJEIAhTCGQmj5qgEC4t5e7YrBqt5BI6UFBg15v4XHbQwAQb4oAKv7NKABdVRoYATUAwnICqjZFIMdVE4+jXI4XGYCxBFFZN/M5OpCxUrvJ/ZFYmjvNVAAY+KCwpDBC6YAV5vNC9oA/AH4A/AHYA==")); - g.clear(); y = 0; var step = 4; @@ -70,8 +70,7 @@ var scenes = [ g.clear(); g.drawImage(img,60,60,{rotate:Math.sin(y*0.03)*0.5}); g.flip(); - }, 20); - Bangle.setLCDMode("120x120"); + }, 20); return function() { if (i) clearInterval(i); }; From 0be85f8b24ac101eb462a0e888321713a1834fa7 Mon Sep 17 00:00:00 2001 From: Sven Klomp Date: Wed, 6 Oct 2021 20:01:27 +0200 Subject: [PATCH 26/26] Grocery: Refactor to store grocery list in separate file --- apps.json | 5 ++-- apps/grocery/ChangeLog | 1 + apps/grocery/app.js | 29 +++++++++++++++++++++++ apps/grocery/grocery.html | 49 +-------------------------------------- 4 files changed, 33 insertions(+), 51 deletions(-) create mode 100644 apps/grocery/app.js diff --git a/apps.json b/apps.json index a7577945e..f85f54eea 100644 --- a/apps.json +++ b/apps.json @@ -1328,14 +1328,13 @@ "id": "grocery", "name": "Grocery", "icon": "grocery.png", - "version":"0.01", + "version":"0.02", "description": "Simple grocery (shopping) list - Display a list of product and track if you already put them in your cart.", "tags": "tool,outdoors,shopping,list", "type": "app", "custom":"grocery.html", "storage": [ - {"name":"grocery"}, - {"name":"grocery.app.js"}, + {"name":"grocery.app.js", "url":"app.js"}, {"name":"grocery.img","url":"grocery-icon.js","evaluate":true} ] }, diff --git a/apps/grocery/ChangeLog b/apps/grocery/ChangeLog index 5560f00bc..906046782 100644 --- a/apps/grocery/ChangeLog +++ b/apps/grocery/ChangeLog @@ -1 +1,2 @@ 0.01: New App! +0.02: Refactor code to store grocery list in separate file diff --git a/apps/grocery/app.js b/apps/grocery/app.js new file mode 100644 index 000000000..481efc3d9 --- /dev/null +++ b/apps/grocery/app.js @@ -0,0 +1,29 @@ +var filename = 'grocery_list.json'; +var settings = require("Storage").readJSON(filename,1)|| { products: [] }; + +function updateSettings() { + require("Storage").writeJSON(filename, settings); + Bangle.buzz(); +} + +function twoChat(n){ + if(n<10) return '0'+n; + return ''+n; +} + +const mainMenu = settings.products.reduce(function(m, p, i){ + const name = twoChat(p.quantity)+' '+p.name; + m[name] = { + value: p.ok, + format: v => v?'[x]':'[ ]', + onchange: v => { + settings.products[i].ok = v; + updateSettings(); + } + }; + return m; +}, { + '': { 'title': 'Grocery list' } +}); +mainMenu['< Back'] = ()=>{load();}; +E.showMenu(mainMenu); diff --git a/apps/grocery/grocery.html b/apps/grocery/grocery.html index 14c406d75..e717dee2e 100644 --- a/apps/grocery/grocery.html +++ b/apps/grocery/grocery.html @@ -105,56 +105,9 @@ } document.getElementById("upload").addEventListener("click", function() { - - - var app = ` -var newTime = ${Date.now()} -var products = ${JSON.stringify(products)} -var newTime = newTime; -var filename = 'grocery'; -var settings = require("Storage").readJSON(filename,1)|| null; -function getSettings(){ - return { - products : products, - date: newTime - }; -} -if(!settings || !settings.date || settings.date < newTime){ - settings = getSettings(); - Bangle.buzz(500); -} -function updateSettings() { - require("Storage").writeJSON(filename, settings); - Bangle.buzz(); -} -function twoChat(n){ - if(n<10) return '0'+n; - return ''+n; -} -const mainMenu = settings.products.reduce(function(m, p, i){ - const name = twoChat(p.quantity)+' '+p.name; - m[name] = { - value: p.ok, - format: v => v?'[x]':'[ ]', - onchange: v => { - settings.products[i].ok = v; - updateSettings(); - } - }; - return m; -}, { - '': { 'title': 'Grocery list' } -}); -mainMenu['< Back'] = ()=>{load();}; -E.showMenu(mainMenu); -`; - - var icon = `require("heatshrink").decompress(atob("mEwxH+AH4A/AH4AQ0QACF1nGAAIxpFoYwqFwwwnRggwGB4eFAggACLzwHCMAeF1WGAgOGw2x2IGCLzYGEF4YpBwotCFwJfWFwo1GSAYtBAIIABRq4vFMhAwBzoAFdzIuKAAOc4IAGGC4qEMZOiF44wXFxovleBYvIGCwmB0WjE4V/AgfG1IvCzujFQOjwoECF6WFwovBDYOFEwN/AgIwCAgOFBwYrBBAQEBzodCF6AAHww1CBpIODAAYvRDAWG2IEBAYYJFBxICCF6Ox1WxAAQfBAYQlCAAIOJAQIvUADQvn1WGR4RfbP4gAFBwgFCF7a5EdwQADF46/cL9wAQF94AGF85bB1TvmF47vdJ4bvFF8qPRFgLv/L7jPCaQq/fYYrvgJgoAGd/7v/F/4v/F5oAdF54weFyAA/AH4A3A="))`; sendCustomizedApp({ storage:[ - {name:"grocery.app.js", url:"app.js", content:app}, - {name:"grocery.img", content:icon, evaluate:true}, - {name:"grocery"} + { name:"grocery_list.json", content: JSON.stringify({products: products}) } ] }); });