From 90b440e635ace58b3ed9de7bb822421779483f7a Mon Sep 17 00:00:00 2001 From: thyttan <6uuxstm66@mozmail.com⁩> Date: Sat, 11 Jan 2025 21:16:23 +0100 Subject: [PATCH 01/56] msgtwscr: new app! Temporarily activate scroll on twist function when a new message triggers the message app. --- apps/msgtwscr/ChangeLog | 1 + apps/msgtwscr/README.md | 19 +++++++++++++++++++ apps/msgtwscr/app.png | Bin 0 -> 1466 bytes apps/msgtwscr/boot.js | 31 +++++++++++++++++++++++++++++++ apps/msgtwscr/metadata.json | 13 +++++++++++++ 5 files changed, 64 insertions(+) create mode 100644 apps/msgtwscr/ChangeLog create mode 100644 apps/msgtwscr/README.md create mode 100644 apps/msgtwscr/app.png create mode 100644 apps/msgtwscr/boot.js create mode 100644 apps/msgtwscr/metadata.json diff --git a/apps/msgtwscr/ChangeLog b/apps/msgtwscr/ChangeLog new file mode 100644 index 000000000..5560f00bc --- /dev/null +++ b/apps/msgtwscr/ChangeLog @@ -0,0 +1 @@ +0.01: New App! diff --git a/apps/msgtwscr/README.md b/apps/msgtwscr/README.md new file mode 100644 index 000000000..e97b8b2f1 --- /dev/null +++ b/apps/msgtwscr/README.md @@ -0,0 +1,19 @@ +# Message Scroll on Twist + +Temporarily activate scroll on twist function when a new message triggers the message app. This way it's possible to scroll through a message in the message scroller hands free. + +## Usage + +This is a bootloader app and only needs to be installed to add the functionality to the watch. + +## Notes + +Tried with [a development version "Message UI" app](https://github.com/espruino/BangleApps/pull/3685) centered around the message scroller. Should work with the standard version as well. + +## Requests + +Mention @thyttan in an issue on the espruino/BangleApps repository. + +## Creator + +thyttan diff --git a/apps/msgtwscr/app.png b/apps/msgtwscr/app.png new file mode 100644 index 0000000000000000000000000000000000000000..83d7e9add5396af12aa2b860375291aea1507a30 GIT binary patch literal 1466 zcmV;r1x5OaP)L8%qoKz;CEPmD*nSzLYFL?6DI{Vw)shTeX#9egKdnMBvO@of#)F*fBPC z9OsiB${20NIg5npF%qT>;%qCk-wISbVFnT=Ai=IN`>l{*GlG1a zvL6G)*;d5a4C2N$#Mm=??X$lNN#n;znmvfIM|OR#sPQPGdJn?v!RpB;%ull$aszSW z@v015Xs#v02}Jc9i0Xl;?g_$;m4`sw>=oZ6*$o*pU9XC5p}8XZ8;IzzMOg2te9#zs z1aaE=Y=9NR*Hy7CG}n^;v?#6vmUJ%>)*PwV-LBceKRr5#1LugJRti6Us%@<6q3h8DGQq8xJvb;vx0;Fui>Ze~%G8FmWxc3$?jG7?m3@Yo;hVjcPg*9Cv=F4srAf!wZB|)e#YnJXoY=e0 zC(NX5=~bi1N|t3K!E%lN3H)hkM$)|g-qM1&VVkJo8Nym~?E)m&pWc*a%a?vc(TfNl zF8z0CAxU``hX>5JC!dhTSJ6ekXzgJZ{EQn{( z{8pJlqxu9NO_iUs>g&=X22ZI|QJwykbkET-0_1@@S#VBH z*-8S63<)UK5NN3Ec#5!Ys;G3HaB*p#vOrOT%&Vs=k}EBM_G-z}I|=7V^OSiJ%&V{L zet?Hf$KFeNAxC;XhY&?2fROyyt_R45cu*~AJ}5#s#bQn5g#e39_VT4wdD49L)kr}= zZmV5@`^<-Ap)p;lG*1aALHzPG9kXTugb)krj<+{q>C%dA{0d-B(Oy$|Apn>UNJt%g zUuh9J$Xr8^j#cvjLWq$1GZIvha;5n>5prKnFem$b_eDA72@+IZM@V)0?PnyY_@x|a zf%^>t1_!NJETQq;P1*n?n-awjWZ*; zLFM@w5ll;}aJ3j}JV-dj6WU$kSG!r0<+SSdE-pUj+1HW20tSK znUXxgjI^cV0K&kWv;}^p8*_?+e<^NjRBuYl3QBK5yL+2a6&!2&z+p^D+*Ok=wep4Y zr9~v*rzK$Ot@=kVVrb$!j9k2ek&9O`Jo!Ba#xKD)G6~P%7+k(#INklQ^>|@*^wwVh z-^e5e#x7xS;<6BAaQrg*M=!uTGy(U(D0=#a;BfoU)$PG~yQ}^Jcm~H_^$kzLH+n%3 zr-4LyvHRVg0oYxA=ybZ#(bc`d)LXfHBmdH+;u#!=cW7K#Hnj7Cymt_eULR~d9%1>M z>vI0X)LV6X25!3ghSBSzj0oa%+0f35@?La0d(mO*!MRSy4@|vPmuujV!`=Ua3R9d^ z+}$rMn@#!i_8y$GI$pH5J3e9Rv20F{-R|{if (Bangle.CLOCK && msg.new) { + setTimeout(()=>{ + if (global.__FILE__=="messagegui.new.js") { + onTwistEmitDrag(); + } + },700) // It feels like there's a more elegant solution than checking the filename after 700 milliseconds. But this at least seems to work w/o sometimes activating when it shouldn't. + }}); + + // twistThreshold How much acceleration to register a twist of the watch strap? Can be negative for opposite direction. default = 800 + // twistMaxY Maximum acceleration in Y to trigger a twist (low Y means watch is facing the right way up). default = -800 + // twistTimeout How little time (in ms) must a twist take from low->high acceleration? default = 1000 + function onTwistEmitDrag() { + Bangle.setOptions({twistThreshold:2500, twistMaxY:-800, twistTimeout:400}); + Bangle.on("twist", ()=>{ + let i = 25; + const int = setInterval(() => { + Bangle.emit("drag", {dy:-3}) + i--; + if (i<1) clearInterval(int); + }, 10); + }); + + } +} diff --git a/apps/msgtwscr/metadata.json b/apps/msgtwscr/metadata.json new file mode 100644 index 000000000..0bd79e55a --- /dev/null +++ b/apps/msgtwscr/metadata.json @@ -0,0 +1,13 @@ +{ "id": "msgtwscr", + "name": "Message Scroll on Twist", + "version":"0.01", + "description": "Temporarily activate scroll on twist function when a new message triggers the message app.", + "icon": "app.png", + "tags": "messages,tweak, scroll", + "type": "bootloader", + "supports" : ["BANGLEJS2"], + "readme": "README.md", + "storage": [ + {"name":"msgtwscr.boot.js","url":"boot.js"} + ] +} From 4a60ee4f8ecef8cc3fc0028865d927902c38f1c5 Mon Sep 17 00:00:00 2001 From: thyttan <6uuxstm66@mozmail.com⁩> Date: Tue, 21 Jan 2025 21:49:16 +0100 Subject: [PATCH 02/56] msgtwscr: tweak app name. --- apps/msgtwscr/README.md | 2 +- apps/msgtwscr/metadata.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/msgtwscr/README.md b/apps/msgtwscr/README.md index e97b8b2f1..2fbdda240 100644 --- a/apps/msgtwscr/README.md +++ b/apps/msgtwscr/README.md @@ -1,4 +1,4 @@ -# Message Scroll on Twist +# Message Twist to Scroll Temporarily activate scroll on twist function when a new message triggers the message app. This way it's possible to scroll through a message in the message scroller hands free. diff --git a/apps/msgtwscr/metadata.json b/apps/msgtwscr/metadata.json index 0bd79e55a..5bf1e9736 100644 --- a/apps/msgtwscr/metadata.json +++ b/apps/msgtwscr/metadata.json @@ -1,5 +1,5 @@ { "id": "msgtwscr", - "name": "Message Scroll on Twist", + "name": "Message Twist to Scroll", "version":"0.01", "description": "Temporarily activate scroll on twist function when a new message triggers the message app.", "icon": "app.png", From 3ff442700baa45fcaf210373be7b9bb5e5afcd2c Mon Sep 17 00:00:00 2001 From: thyttan <6uuxstm66@mozmail.com⁩> Date: Sat, 15 Feb 2025 03:25:46 +0100 Subject: [PATCH 03/56] msgtwscr: fix formatting of metadata tags --- apps/msgtwscr/metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/msgtwscr/metadata.json b/apps/msgtwscr/metadata.json index 5bf1e9736..6f267ea01 100644 --- a/apps/msgtwscr/metadata.json +++ b/apps/msgtwscr/metadata.json @@ -3,7 +3,7 @@ "version":"0.01", "description": "Temporarily activate scroll on twist function when a new message triggers the message app.", "icon": "app.png", - "tags": "messages,tweak, scroll", + "tags": "messages,tweak,scroll", "type": "bootloader", "supports" : ["BANGLEJS2"], "readme": "README.md", From c51919045b7a18bb4434608303a59ce5e8ed307f Mon Sep 17 00:00:00 2001 From: thyttan <6uuxstm66@mozmail.com⁩> Date: Sat, 15 Feb 2025 03:42:00 +0100 Subject: [PATCH 04/56] msgtwscr: unlock the watch on twist as well Maybe implement this in a separate app instead. --- apps/msgtwscr/boot.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/msgtwscr/boot.js b/apps/msgtwscr/boot.js index 821561bdc..22bc03bcc 100644 --- a/apps/msgtwscr/boot.js +++ b/apps/msgtwscr/boot.js @@ -19,6 +19,8 @@ function onTwistEmitDrag() { Bangle.setOptions({twistThreshold:2500, twistMaxY:-800, twistTimeout:400}); Bangle.on("twist", ()=>{ + Bangle.setLocked(false); + Bangle.setLCDPower(true); let i = 25; const int = setInterval(() => { Bangle.emit("drag", {dy:-3}) From 1b88dd2d196320aae84358a35ee2cdecb579d981 Mon Sep 17 00:00:00 2001 From: thyttan <6uuxstm66@mozmail.com⁩> Date: Mon, 26 May 2025 23:55:03 +0200 Subject: [PATCH 05/56] msgtwscr: tweak to work with recent messagegui updates --- apps/msgtwscr/boot.js | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/apps/msgtwscr/boot.js b/apps/msgtwscr/boot.js index 22bc03bcc..714aa0cbc 100644 --- a/apps/msgtwscr/boot.js +++ b/apps/msgtwscr/boot.js @@ -10,7 +10,12 @@ if (global.__FILE__=="messagegui.new.js") { onTwistEmitDrag(); } - },700) // It feels like there's a more elegant solution than checking the filename after 700 milliseconds. But this at least seems to work w/o sometimes activating when it shouldn't. + },1000) + // It feels like there's a more elegant solution than checking the filename + // after 1000 milliseconds. But this at least seems to work w/o sometimes + // activating when it shouldn't. + // Maybe we could add events for when fast load and/or Bangle.uiRemove occurs? + // Then that could be used similarly to boot code and/or the `kill` event. }}); // twistThreshold How much acceleration to register a twist of the watch strap? Can be negative for opposite direction. default = 800 @@ -18,16 +23,30 @@ // twistTimeout How little time (in ms) must a twist take from low->high acceleration? default = 1000 function onTwistEmitDrag() { Bangle.setOptions({twistThreshold:2500, twistMaxY:-800, twistTimeout:400}); - Bangle.on("twist", ()=>{ + let twistHandler = ()=>{ Bangle.setLocked(false); Bangle.setLCDPower(true); + Bangle.emit("swipe",0,-1); let i = 25; const int = setInterval(() => { Bangle.emit("drag", {dy:-3}) i--; if (i<1) clearInterval(int); }, 10); - }); + } + Bangle.on("twist", twistHandler); + // Give messagegui some extra time to add its remove function to + // Bangle.uiRemove, then attach msgtwscr remove logic. + setTimeout( + ()=>{if (Bangle.uiRemove) { + let showMessageUIRemove = Bangle.uiRemove; + Bangle.uiRemove = function () { + Bangle.removeListener("twist", twistHandler) + showMessageUIRemove(); + } + }}, + 500 + ) } } From 591c0efd4043387108dd67c5684777347ec930b8 Mon Sep 17 00:00:00 2001 From: thyttan <6uuxstm66@mozmail.com⁩> Date: Tue, 27 May 2025 00:06:49 +0200 Subject: [PATCH 06/56] msgtwscr: rm out of date README section --- apps/msgtwscr/README.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/apps/msgtwscr/README.md b/apps/msgtwscr/README.md index 2fbdda240..ea92ce76f 100644 --- a/apps/msgtwscr/README.md +++ b/apps/msgtwscr/README.md @@ -6,10 +6,6 @@ Temporarily activate scroll on twist function when a new message triggers the me This is a bootloader app and only needs to be installed to add the functionality to the watch. -## Notes - -Tried with [a development version "Message UI" app](https://github.com/espruino/BangleApps/pull/3685) centered around the message scroller. Should work with the standard version as well. - ## Requests Mention @thyttan in an issue on the espruino/BangleApps repository. From 79e7f634f533bc40e81e91746d482d1aa2fad385 Mon Sep 17 00:00:00 2001 From: thyttan <6uuxstm66@mozmail.com⁩> Date: Tue, 27 May 2025 00:09:07 +0200 Subject: [PATCH 07/56] msgtwscr: rebalance timeouts --- apps/msgtwscr/boot.js | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/apps/msgtwscr/boot.js b/apps/msgtwscr/boot.js index 714aa0cbc..0a7923c05 100644 --- a/apps/msgtwscr/boot.js +++ b/apps/msgtwscr/boot.js @@ -10,9 +10,9 @@ if (global.__FILE__=="messagegui.new.js") { onTwistEmitDrag(); } - },1000) + },700) // It feels like there's a more elegant solution than checking the filename - // after 1000 milliseconds. But this at least seems to work w/o sometimes + // after 700 milliseconds. But this at least seems to work w/o sometimes // activating when it shouldn't. // Maybe we could add events for when fast load and/or Bangle.uiRemove occurs? // Then that could be used similarly to boot code and/or the `kill` event. @@ -45,8 +45,6 @@ showMessageUIRemove(); } }}, - 500 - ) - + 800) } } From 7608697377101ee47f0c79dac9cb78c5073cc39d Mon Sep 17 00:00:00 2001 From: thyttan <6uuxstm66@mozmail.com⁩> Date: Tue, 27 May 2025 00:50:12 +0200 Subject: [PATCH 08/56] msgtwscr: adapt to the recent messagegui updates --- apps/msgtwscr/boot.js | 34 +++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/apps/msgtwscr/boot.js b/apps/msgtwscr/boot.js index 0a7923c05..fa4e4edd6 100644 --- a/apps/msgtwscr/boot.js +++ b/apps/msgtwscr/boot.js @@ -4,8 +4,7 @@ onTwistEmitDrag(); } - // If Fastload Utils is installed this is used: - Bangle.on("message", (_, msg)=>{if (Bangle.CLOCK && msg.new) { + let attachAfterTimeout = ()=>{ setTimeout(()=>{ if (global.__FILE__=="messagegui.new.js") { onTwistEmitDrag(); @@ -16,6 +15,11 @@ // activating when it shouldn't. // Maybe we could add events for when fast load and/or Bangle.uiRemove occurs? // Then that could be used similarly to boot code and/or the `kill` event. + } + + // If Fastload Utils is installed this is used: + Bangle.on("message", (_, msg)=>{if (Bangle.CLOCK && msg.new) { + attachAfterTimeout(); }}); // twistThreshold How much acceleration to register a twist of the watch strap? Can be negative for opposite direction. default = 800 @@ -23,16 +27,22 @@ // twistTimeout How little time (in ms) must a twist take from low->high acceleration? default = 1000 function onTwistEmitDrag() { Bangle.setOptions({twistThreshold:2500, twistMaxY:-800, twistTimeout:400}); + let isTwistDragging = false; let twistHandler = ()=>{ - Bangle.setLocked(false); - Bangle.setLCDPower(true); - Bangle.emit("swipe",0,-1); - let i = 25; - const int = setInterval(() => { - Bangle.emit("drag", {dy:-3}) - i--; - if (i<1) clearInterval(int); - }, 10); + if (!isTwistDragging) { + isTwistDragging = true; + Bangle.setLocked(false); + Bangle.setLCDPower(true); + let i = 25; + const int = setInterval(() => { + Bangle.emit("drag", {dy:-3, b:i===0?0:1}) + i--; + if (i<0) { + clearInterval(int); + isTwistDragging = false; + } + }, 10); + } } Bangle.on("twist", twistHandler); // Give messagegui some extra time to add its remove function to @@ -43,6 +53,8 @@ Bangle.uiRemove = function () { Bangle.removeListener("twist", twistHandler) showMessageUIRemove(); + // Reset twist drag logic if we go to next message. + attachAfterTimeout(); } }}, 800) From d5453990fdbc9b2fa1f5a0d3ec33ccbb988bc8a6 Mon Sep 17 00:00:00 2001 From: Logan B <3870583+thinkpoop@users.noreply.github.com> Date: Tue, 10 Jun 2025 16:02:59 -0500 Subject: [PATCH 09/56] [owmweather] only set last update timestamp on success --- apps/owmweather/boot.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/apps/owmweather/boot.js b/apps/owmweather/boot.js index dc206be38..60fcd5991 100644 --- a/apps/owmweather/boot.js +++ b/apps/owmweather/boot.js @@ -10,10 +10,14 @@ return settings.refresh * 1000 * 60 + 1; // +1 <- leave some slack }; - let onCompleted = function () { + let onCompleted = function (result) { loading = false; - settings.updated = Date.now(); - require('Storage').writeJSON("owmweather.json", settings); + if(typeof result === "string") { + console.log("owmweather error: " + result); + } else { + settings.updated = Date.now(); + require('Storage').writeJSON("owmweather.json", settings); + } if (timeoutRef) clearTimeout(timeoutRef); timeoutRef = setTimeout(loadIfDueAndReschedule, refreshMillis()); }; From 7cc837d595f5f4183e8ff4b1012165acd24bf3b6 Mon Sep 17 00:00:00 2001 From: Logan B <3870583+thinkpoop@users.noreply.github.com> Date: Tue, 10 Jun 2025 16:13:39 -0500 Subject: [PATCH 10/56] [owmweather] create more explicit errorCallback function --- apps/owmweather/ChangeLog | 3 ++- apps/owmweather/boot.js | 17 ++++++++++------- apps/owmweather/lib.js | 6 +++--- apps/owmweather/metadata.json | 2 +- 4 files changed, 16 insertions(+), 12 deletions(-) diff --git a/apps/owmweather/ChangeLog b/apps/owmweather/ChangeLog index a2251f83b..6a5706af1 100644 --- a/apps/owmweather/ChangeLog +++ b/apps/owmweather/ChangeLog @@ -6,4 +6,5 @@ 0.06: Fix One Call API 3.0 not returning city names, which are required by the weather app 0.07: Update weather after reconnecting bluetooth if update is due, refactor code 0.08: Undo change to One Call API 3.0 -0.09: Fix infinite loop when settings.updated is not defined \ No newline at end of file +0.09: Fix infinite loop when settings.updated is not defined +0.10: Fix settings.updated being updated even when OWM call failed \ No newline at end of file diff --git a/apps/owmweather/boot.js b/apps/owmweather/boot.js index 60fcd5991..a2a880fee 100644 --- a/apps/owmweather/boot.js +++ b/apps/owmweather/boot.js @@ -12,12 +12,15 @@ let onCompleted = function (result) { loading = false; - if(typeof result === "string") { - console.log("owmweather error: " + result); - } else { - settings.updated = Date.now(); - require('Storage').writeJSON("owmweather.json", settings); - } + settings.updated = Date.now(); + require('Storage').writeJSON("owmweather.json", settings); + if (timeoutRef) clearTimeout(timeoutRef); + timeoutRef = setTimeout(loadIfDueAndReschedule, refreshMillis()); + }; + + let onError = function(e) { + console.log("owmweather error:", e); + loading = false; if (timeoutRef) clearTimeout(timeoutRef); timeoutRef = setTimeout(loadIfDueAndReschedule, refreshMillis()); }; @@ -34,7 +37,7 @@ if (!MillisUntilDue || MillisUntilDue <= 0) { if (!loading) { loading = true; - require("owmweather").pull(onCompleted); + require("owmweather").pull(onCompleted, onError); } } else { // called to early, reschedule diff --git a/apps/owmweather/lib.js b/apps/owmweather/lib.js index baa9555d0..d3f3d798c 100644 --- a/apps/owmweather/lib.js +++ b/apps/owmweather/lib.js @@ -33,7 +33,7 @@ function parseWeather(response) { } } -exports.pull = function(completionCallback) { +exports.pull = function(completionCallback, errorCallback) { let location = require("Storage").readJSON("mylocation.json", 1) || { "lat": 51.50, "lon": 0.12, @@ -46,9 +46,9 @@ exports.pull = function(completionCallback) { let result = parseWeather(event.resp); if (completionCallback) completionCallback(result); }).catch((e)=>{ - if (completionCallback) completionCallback(e); + if (errorCallback) errorCallback(e); }); } else { - if (completionCallback) completionCallback(/*LANG*/"No http method found"); + if (errorCallback) errorCallback(/*LANG*/"No http method found"); } }; diff --git a/apps/owmweather/metadata.json b/apps/owmweather/metadata.json index 8dfa4fe9c..1e514e6bb 100644 --- a/apps/owmweather/metadata.json +++ b/apps/owmweather/metadata.json @@ -1,7 +1,7 @@ { "id": "owmweather", "name": "OpenWeatherMap weather provider", "shortName":"OWM Weather", - "version": "0.09", + "version": "0.10", "description": "Pulls weather from OpenWeatherMap (OWM) API", "icon": "app.png", "type": "bootloader", From 3d10dc9745f2a23ed6e5206e915eb251a26bd62c Mon Sep 17 00:00:00 2001 From: Randy Heydon Date: Tue, 10 Jun 2025 20:54:12 -0400 Subject: [PATCH 11/56] agenda: Show full title in clockinfo instead of truncated Previously, all event titles would be truncated to 12 characters when displayed in a clock info. This hides some information, and completely breaks event titles containing embedded images (i.e. converted emojis). This change simply removes the truncation, allowing the full title and full images to be shown. --- apps/agenda/ChangeLog | 1 + apps/agenda/agenda.clkinfo.js | 2 +- apps/agenda/metadata.json | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/agenda/ChangeLog b/apps/agenda/ChangeLog index 327b18e34..ebbbbebb8 100644 --- a/apps/agenda/ChangeLog +++ b/apps/agenda/ChangeLog @@ -18,3 +18,4 @@ 0.16: Correct date for all day events in negative timezones, improve locale display 0.17: Fixed "Today" and "Tomorrow" labels displaying in non-current weeks 0.18: Correct date in clockinfo for all-day events in negative timezones +0.19: Show full title in clockinfo instead of truncated diff --git a/apps/agenda/agenda.clkinfo.js b/apps/agenda/agenda.clkinfo.js index fe56257b0..a9e371bff 100644 --- a/apps/agenda/agenda.clkinfo.js +++ b/apps/agenda/agenda.clkinfo.js @@ -64,7 +64,7 @@ agenda.forEach((entry, i) => { - var title = entry.title.slice(0,12); + var title = entry.title; // All day events are always in UTC and always start at 00:00:00, so we // need to "undo" the timezone offsetting to make sure that the day is // correct. diff --git a/apps/agenda/metadata.json b/apps/agenda/metadata.json index b841ecaff..bfa529ea5 100644 --- a/apps/agenda/metadata.json +++ b/apps/agenda/metadata.json @@ -1,7 +1,7 @@ { "id": "agenda", "name": "Agenda", - "version": "0.18", + "version": "0.19", "description": "Simple agenda", "icon": "agenda.png", "screenshots": [{"url":"screenshot_agenda_overview.png"}, {"url":"screenshot_agenda_event1.png"}, {"url":"screenshot_agenda_event2.png"}], From c389727eafcd36bda2f945ec9cfaf80d29da71b5 Mon Sep 17 00:00:00 2001 From: Logan B <3870583+thinkpoop@users.noreply.github.com> Date: Wed, 11 Jun 2025 16:34:23 -0500 Subject: [PATCH 12/56] [owmweather] handle error msg from parseWeather --- apps/owmweather/lib.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/apps/owmweather/lib.js b/apps/owmweather/lib.js index d3f3d798c..b4893d484 100644 --- a/apps/owmweather/lib.js +++ b/apps/owmweather/lib.js @@ -44,7 +44,11 @@ exports.pull = function(completionCallback, errorCallback) { if (Bangle.http){ Bangle.http(uri, {timeout:10000}).then(event => { let result = parseWeather(event.resp); - if (completionCallback) completionCallback(result); + if (result === undefined) { + if (completionCallback) completionCallback(); + } else { + if (errorCallback) errorCallback(result); + } }).catch((e)=>{ if (errorCallback) errorCallback(e); }); From eca3bbb14bb9ead9f4957a0055323b3b3f325620 Mon Sep 17 00:00:00 2001 From: Logan B <3870583+thinkpoop@users.noreply.github.com> Date: Wed, 11 Jun 2025 16:36:37 -0500 Subject: [PATCH 13/56] [owmweather] handle error msg from parseWeather --- apps/owmweather/boot.js | 2 +- apps/owmweather/lib.js | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/apps/owmweather/boot.js b/apps/owmweather/boot.js index a2a880fee..82e3a280a 100644 --- a/apps/owmweather/boot.js +++ b/apps/owmweather/boot.js @@ -10,7 +10,7 @@ return settings.refresh * 1000 * 60 + 1; // +1 <- leave some slack }; - let onCompleted = function (result) { + let onCompleted = function () { loading = false; settings.updated = Date.now(); require('Storage').writeJSON("owmweather.json", settings); diff --git a/apps/owmweather/lib.js b/apps/owmweather/lib.js index d3f3d798c..b4893d484 100644 --- a/apps/owmweather/lib.js +++ b/apps/owmweather/lib.js @@ -44,7 +44,11 @@ exports.pull = function(completionCallback, errorCallback) { if (Bangle.http){ Bangle.http(uri, {timeout:10000}).then(event => { let result = parseWeather(event.resp); - if (completionCallback) completionCallback(result); + if (result === undefined) { + if (completionCallback) completionCallback(); + } else { + if (errorCallback) errorCallback(result); + } }).catch((e)=>{ if (errorCallback) errorCallback(e); }); From bd047f31f855e41a3a643adddb33e44c44bb615d Mon Sep 17 00:00:00 2001 From: Logan B <3870583+thinkpoop@users.noreply.github.com> Date: Thu, 12 Jun 2025 18:39:18 -0500 Subject: [PATCH 14/56] [owmweather] simplify error handling --- apps/owmweather/lib.js | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/apps/owmweather/lib.js b/apps/owmweather/lib.js index b4893d484..2f6af5f7b 100644 --- a/apps/owmweather/lib.js +++ b/apps/owmweather/lib.js @@ -27,9 +27,8 @@ function parseWeather(response) { json.weather = weather; require("Storage").writeJSON('weather.json', json); if (require("Storage").read("weather")!==undefined) require("weather").emit("update", json.weather); - return undefined; } else { - return /*LANG*/"Not OWM data"; + throw /*LANG*/"Not OWM data"; } } @@ -43,12 +42,8 @@ exports.pull = function(completionCallback, errorCallback) { let uri = "https://api.openweathermap.org/data/2.5/weather?lat=" + location.lat.toFixed(2) + "&lon=" + location.lon.toFixed(2) + "&exclude=hourly,daily&appid=" + settings.apikey; if (Bangle.http){ Bangle.http(uri, {timeout:10000}).then(event => { - let result = parseWeather(event.resp); - if (result === undefined) { - if (completionCallback) completionCallback(); - } else { - if (errorCallback) errorCallback(result); - } + parseWeather(event.resp); + if (completionCallback) completionCallback(); }).catch((e)=>{ if (errorCallback) errorCallback(e); }); From dfde5c8ffbf94d2a8478b62b1bfd19e38042ca8e Mon Sep 17 00:00:00 2001 From: spycat111 Date: Sat, 14 Jun 2025 15:44:32 +0200 Subject: [PATCH 15/56] Update crsclock.js --- apps/crsclock/crsclock.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/crsclock/crsclock.js b/apps/crsclock/crsclock.js index 5a7c1bf9d..9904235a2 100644 --- a/apps/crsclock/crsclock.js +++ b/apps/crsclock/crsclock.js @@ -610,7 +610,7 @@ function calibrateBT() { Bangle.setUI(uiOpts); }); })(d); - m["−" + d + "h"] = (() => () => { + m["-" + d + "h"] = (() => () => { S.phaseOffset -= d; saveSettings(); E.showAlert("Offset now: " + (S.phaseOffset>=0? "+"+S.phaseOffset : S.phaseOffset) + "h").then(() => { @@ -711,7 +711,7 @@ function setBioTimeReference() { E.showMenu(m); function promptRefTime() { - E.showPrompt("Hour (0–23)?").then(h => { + E.showPrompt("Hour (0-23)?").then(h => { if (h===undefined || h<0 || h>23) { E.showAlert("Invalid hour").then(() => { drawClock(); @@ -720,7 +720,7 @@ function setBioTimeReference() { return; } S.bioTimeRefHour = h; - E.showPrompt("Minute (0–59)?").then(m => { + E.showPrompt("Minute (0-59)?").then(m => { if (m===undefined || m<0 || m>59) { E.showAlert("Invalid minute").then(() => { drawClock(); From 3f3a0e7a10e512666f2eae1de1780826ee047a06 Mon Sep 17 00:00:00 2001 From: spycat111 Date: Sat, 14 Jun 2025 21:18:07 +0200 Subject: [PATCH 16/56] Update README.md --- apps/crsclock/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/crsclock/README.md b/apps/crsclock/README.md index 17302cce0..0f3039994 100644 --- a/apps/crsclock/README.md +++ b/apps/crsclock/README.md @@ -113,6 +113,8 @@ Unless otherwise stated, this project is released under the MIT license. Use of the patented method may be subject to licensing or permission. For inquiries, contact the author. +Note: The patented method does not require licensing for non-commercial, research, educational, or personal use within the open-source community. Commercial or broad distribution beyond these uses may require permission or licensing. For such use cases, please contact the author. + ### **Summary** The Circadian Rhythm Clock transforms the Bangle.js 2 into a **bio-aware, personalized circadian dashboard**, guiding users toward better alignment with their biological clock and modern life. From 906e4ed64c803685f81294393f82d083a46e97c5 Mon Sep 17 00:00:00 2001 From: spycat111 Date: Sun, 15 Jun 2025 22:45:10 +0200 Subject: [PATCH 17/56] Removing non-ASCII characters --- apps/crsclock/crsclock.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/crsclock/crsclock.js b/apps/crsclock/crsclock.js index 5a7c1bf9d..e42cbd902 100644 --- a/apps/crsclock/crsclock.js +++ b/apps/crsclock/crsclock.js @@ -83,7 +83,7 @@ const STATS_FONT_SIZE = 16; function getSleepWindowStr() { let a = ("0"+S.sleepStart).substr(-2) + ":00"; let b = ("0"+S.sleepEnd).substr(-2) + ":00"; - return a + "–" + b; + return a + "-" + b; } function stability(arr, key, hours) { @@ -518,7 +518,7 @@ function confirmResetAllData() { }); } -// Menu logic: Sleep window, hydration, BT calibration, theme, notifications, bio ref, about — unchanged, use as before +// Menu logic: Sleep window, hydration, BT calibration, theme, notifications, bio ref, about - unchanged, use as before function setSleepWindow() { let menu = { "": { title: "Select Start Hour" } }; @@ -743,7 +743,7 @@ function showAbout() { E.showAlert( "Circadian Wellness Clock v" + VERSION + "\n" + "Displays your CRS and BioTime.\n" + - "© 2025" + "Copyright 2025" ).then(()=>{ drawClock(); Bangle.setUI(uiOpts); From dd4573d176adabc76f1a9e97f55ac93cafec3ffe Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Mon, 16 Jun 2025 10:52:43 +0100 Subject: [PATCH 18/56] Fix issue caused by pretokenising of UTF8 strings (which get converted after the pretokenise step and cause the length to be wrong) Even if length were correct, pretokenising the string stops the scan for UTF8 char patterns so the string wouldn't be treated correctly --- core | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core b/core index 7e7475ba3..7502f4c00 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit 7e7475ba3ab253099481a81e487aaacb9384f974 +Subproject commit 7502f4c006f52c9b2fe8078bb1dc0bf6b0c400a5 From b7842755896dfbed43dad5bb51c70b02b9f85b4a Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Mon, 16 Jun 2025 16:41:47 +0100 Subject: [PATCH 19/56] clock_info 0.17: Fix BLE icon alignment and border on some clocks --- apps/clock_info/ChangeLog | 1 + apps/clock_info/lib.js | 2 +- apps/clock_info/metadata.json | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/clock_info/ChangeLog b/apps/clock_info/ChangeLog index 49227c76d..963c2bb35 100644 --- a/apps/clock_info/ChangeLog +++ b/apps/clock_info/ChangeLog @@ -15,3 +15,4 @@ 0.14: Check for .clkinfocache and use that if exists (from boot 0.64) 0.15: Fix error when displaying a category with only one clockinfo (fix #3728) 0.16: Add BLE clkinfo entry +0.17: Fix BLE icon alignment and border on some clocks diff --git a/apps/clock_info/lib.js b/apps/clock_info/lib.js index 9fdacab55..b58e73089 100644 --- a/apps/clock_info/lib.js +++ b/apps/clock_info/lib.js @@ -128,7 +128,7 @@ exports.load = function() { get: function() { return { text: this.isOn() ? "On" : "Off", - img: atob("CxQBBgDgFgJgR4jZMawfAcA4D4NYybEYIwTAsBwDAA==") + img: atob("GBiBAAAAAAAAAAAYAAAcAAAWAAATAAARgAMRgAGTAADWAAB8AAA4AAA4AAB8AADWAAGTAAMRgAARgAATAAAWAAAcAAAYAAAAAAAAAA==") }; }, run: function() { diff --git a/apps/clock_info/metadata.json b/apps/clock_info/metadata.json index 3876258b8..4a14b5348 100644 --- a/apps/clock_info/metadata.json +++ b/apps/clock_info/metadata.json @@ -1,7 +1,7 @@ { "id": "clock_info", "name": "Clock Info Module", "shortName": "Clock Info", - "version":"0.16", + "version":"0.17", "description": "A library used by clocks to provide extra information on the clock face (Altitude, BPM, etc)", "icon": "app.png", "type": "module", From 1b50cdf31d9c41cb2c4dd33298ef1f8ecf47187c Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Mon, 16 Jun 2025 16:56:53 +0100 Subject: [PATCH 20/56] pebblepp 0.11: Make the border on clockinfos the default Fix clockinfos when too long (previously just output '...') --- apps/pebblepp/ChangeLog | 6 ++++-- apps/pebblepp/app.js | 6 +++--- apps/pebblepp/metadata.json | 2 +- apps/pebblepp/settings.js | 2 +- 4 files changed, 9 insertions(+), 7 deletions(-) diff --git a/apps/pebblepp/ChangeLog b/apps/pebblepp/ChangeLog index b44914451..3042937f1 100644 --- a/apps/pebblepp/ChangeLog +++ b/apps/pebblepp/ChangeLog @@ -1,6 +1,6 @@ 0.01: First release 0.02: clock_info now uses app name to maintain settings specifically for this clock face - ensure clockinfo text is usppercase (font doesn't render lowercase) + ensure clockinfo text is uppercase (font doesn't render lowercase) 0.03: Use smaller font if clock_info test doesn't fit in area 0.04: Ensure we only scale down clockinfo text if it really won't fit 0.05: Minor code improvements @@ -10,4 +10,6 @@ 0.09: Add date on the bottom 0.10: Fix size of bottom bar after 0.09 Make date toggleable with settings - Optional border around clockinfos (available from settings) \ No newline at end of file + Optional border around clockinfos (available from settings) +0.11: Make the border on clockinfos the default + Fix clockinfos when too long (previously just output '...') \ No newline at end of file diff --git a/apps/pebblepp/app.js b/apps/pebblepp/app.js index 7c01fcade..f242cba33 100644 --- a/apps/pebblepp/app.js +++ b/apps/pebblepp/app.js @@ -20,7 +20,7 @@ Graphics.prototype.setFontLECO1976Regular14 = function() { { const SETTINGS_FILE = "pebblepp.json"; -let settings = Object.assign({'theme':'System', 'showdate':true, 'clkinfoborder': false}, require("Storage").readJSON(SETTINGS_FILE,1)||{}); +let settings = Object.assign({'theme':'System', 'showdate':true, 'clkinfoborder': true}, require("Storage").readJSON(SETTINGS_FILE,1)||{}); let background = require("clockbg"); let theme; let drawTimeout; @@ -102,7 +102,7 @@ let clockInfoDraw = (itm, info, options) => { g.setFontLECO1976Regular14(); if (g.stringWidth(txt) > options.w) {// if still too big, split to 2 lines var l = g.wrapString(txt, options.w); - txt = l.slice(0,2).join("\n") + (l.length>2)?"...":""; + txt = l.slice(0,2).join("\n") + ((l.length>2)?"...":""); } y = options.y+options.h-12; if (settings.clkinfoborder) { @@ -147,4 +147,4 @@ background.fillRect(Bangle.appRect); // start off with completely clear backgrou g.setColor(theme.fg).fillRect(0, h2 - 6, w, h3 + 6); draw(); -} \ No newline at end of file +} diff --git a/apps/pebblepp/metadata.json b/apps/pebblepp/metadata.json index c2187483c..e26500fc9 100644 --- a/apps/pebblepp/metadata.json +++ b/apps/pebblepp/metadata.json @@ -2,7 +2,7 @@ "id": "pebblepp", "name": "Pebble++ Clock", "shortName": "Pebble++", - "version": "0.10", + "version": "0.11", "description": "A Pebble style clock (based on the 'Pebble Clock' app) but with two configurable ClockInfo items at the top and custom backgrounds. Date/theme/borders be reconfigured using settings page.", "icon": "app.png", "screenshots": [{"url":"screenshot.png"},{"url":"screenshot2.png"}], diff --git a/apps/pebblepp/settings.js b/apps/pebblepp/settings.js index f2384577e..1ae7ed4d4 100644 --- a/apps/pebblepp/settings.js +++ b/apps/pebblepp/settings.js @@ -2,7 +2,7 @@ const SETTINGS_FILE = "pebblepp.json"; // Initialize with default settings... - let settings = {'theme':'System', 'showdate':true, 'clkinfoborder':false} + let settings = {'theme':'System', 'showdate':true, 'clkinfoborder':true} // ...and overwrite them with any saved values // This way saved values are preserved if a new version adds more settings const storage = require('Storage'); From eb937a6f67ba9dc8b0cb69db369e9ae50297aa7b Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Tue, 17 Jun 2025 09:59:31 +0100 Subject: [PATCH 21/56] altimeter 0.05: Prompt before resetting calibration (stops long-press of button resetting calibration) --- apps/altimeter/ChangeLog | 1 + apps/altimeter/app.js | 52 +++++++++++++++++++++--------------- apps/altimeter/metadata.json | 2 +- apps/lint_exemptions.js | 12 --------- 4 files changed, 33 insertions(+), 34 deletions(-) diff --git a/apps/altimeter/ChangeLog b/apps/altimeter/ChangeLog index 905152382..77f64d029 100644 --- a/apps/altimeter/ChangeLog +++ b/apps/altimeter/ChangeLog @@ -2,3 +2,4 @@ 0.02: Actually upload correct code 0.03: Display sea-level pressure, too, and allow calibration 0.04: Switch to using system code for pressure calibration +0.05: Prompt before resetting calibration (stops long-press of button resetting calibration) \ No newline at end of file diff --git a/apps/altimeter/app.js b/apps/altimeter/app.js index 6e44161da..222ed2d21 100644 --- a/apps/altimeter/app.js +++ b/apps/altimeter/app.js @@ -7,6 +7,7 @@ var R = Bangle.appRect; var y = R.y + R.h/2; var MEDIANLENGTH = 20; var avr = []; +var updateDisplay = true; function fmt(t) { if ((t > -100) && (t < 1000)) @@ -19,48 +20,57 @@ function fmt(t) { Bangle.on('pressure', function(e) { while (avr.length>MEDIANLENGTH) avr.pop(); avr.unshift(e.altitude); - let median = avr.slice().sort(); + if (!updateDisplay) return; + let median = avr.slice().sort(), value; g.reset().clearRect(0,y-30,g.getWidth()-10,R.h); if (median.length>10) { var mid = median.length>>1; - var value = E.sum(median.slice(mid-4,mid+5)) / 9; + value = E.sum(median.slice(mid-4,mid+5)) / 9; } else { - var value = median[median.length>>1]; + value = median[median.length>>1]; } - t = fmt(value); + var t = fmt(value); g.setFont("Vector",50).setFontAlign(0,0).drawString(t, g.getWidth()/2, y); let o = Bangle.getOptions(); let sea = o.seaLevelPressure; t = sea.toFixed(1) + " " + e.temperature.toFixed(1); - if (0) { + /*if (0) { print("alt raw:", value.toFixed(1)); print("temperature:", e.temperature); print("pressure:", e.pressure); print("sea pressure:", sea); - } + }*/ g.setFont("Vector",25).setFontAlign(-1,0).drawString(t, 10, R.y+R.h - 35); }); function setPressure(m, a) { - o = Bangle.getOptions(); - print(o); + var o = Bangle.getOptions(); + //print(o); o.seaLevelPressure = o.seaLevelPressure * m + a; Bangle.setOptions(o); avr = []; } -print(g.getFonts()); -g.reset(); -g.setFont("Vector:15"); -g.setFontAlign(0,0); -g.drawString(/*LANG*/"ALTITUDE (m)", g.getWidth()/2, y-40); -g.drawString(/*LANG*/"SEA L (hPa) TEMP (C)", g.getWidth()/2, y+62); -g.flip(); -g.setFont("6x8").setFontAlign(0,0,3).drawString(/*LANG*/"STD", g.getWidth()-5, g.getHeight()/2); -Bangle.setUI("updown", btn=> { - if (!btn) setPressure(0, 1013.25); - if (btn<0) setPressure(1, 1); - if (btn>0) setPressure(1, -1); -}); +function start() { + g.reset(); + g.setFont("Vector:15"); + g.setFontAlign(0,0); + g.drawString(/*LANG*/"ALTITUDE (m)", g.getWidth()/2, y-40); + g.drawString(/*LANG*/"SEA L (hPa) TEMP (C)", g.getWidth()/2, y+62); + g.setFont("6x8").setFontAlign(0,0,3).drawString(/*LANG*/"STD", g.getWidth()-5, g.getHeight()/2); + updateDisplay = true; + Bangle.setUI("updown", btn => { + if (!btn) { + updateDisplay = false; + E.showPrompt(/*LANG*/"Set calibration to default?",{title:/*LANG*/"Altitude"}).then(function(reset) { + start(); + if (reset) setPressure(0, 1013.25); + }); + } + if (btn<0) setPressure(1, 1); + if (btn>0) setPressure(1, -1); + }); +} +start(); \ No newline at end of file diff --git a/apps/altimeter/metadata.json b/apps/altimeter/metadata.json index ff5eb9935..2c8bf06ec 100644 --- a/apps/altimeter/metadata.json +++ b/apps/altimeter/metadata.json @@ -1,6 +1,6 @@ { "id": "altimeter", "name": "Altimeter", - "version":"0.04", + "version":"0.05", "description": "Simple altimeter that can display height changed using Bangle.js 2's built in pressure sensor.", "icon": "app.png", "tags": "tool,outdoors", diff --git a/apps/lint_exemptions.js b/apps/lint_exemptions.js index 6b64d6149..980164b09 100644 --- a/apps/lint_exemptions.js +++ b/apps/lint_exemptions.js @@ -925,12 +925,6 @@ module.exports = { "no-undef" ] }, - "apps/fileman/fileman.app.js": { - "hash": "f378179e7dd3655ba7e9ce03e1f7fd5a2d1768ad7d9083b22e7d740405be842a", - "rules": [ - "no-undef" - ] - }, "apps/flappy/app.js": { "hash": "e24b0c5e0469070e02dae00887bf50569c2c141a80c7c356b36987ddf68ce9cc", "rules": [ @@ -1051,12 +1045,6 @@ module.exports = { "no-undef" ] }, - "apps/altimeter/app.js": { - "hash": "054ac328db51034aa339f1d10b4d264badd49438b95f08bc6fbfb90bd88c6ae0", - "rules": [ - "no-undef" - ] - }, "apps/alpinenav/app.js": { "hash": "f8e59724d282f7c5c989adf64974a3728dc521aa8fbe047b7c37dae09213095a", "rules": [ From be50617d11a30198e08b975b8edb430da7e19225 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Tue, 17 Jun 2025 10:21:59 +0100 Subject: [PATCH 22/56] 0.79: Ensure that tapping on pressure/altitude doesn't cause a menu to display temporarily --- apps/setting/ChangeLog | 1 + apps/setting/metadata.json | 2 +- apps/setting/settings.js | 4 ++-- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/apps/setting/ChangeLog b/apps/setting/ChangeLog index 17098b069..03ee8db12 100644 --- a/apps/setting/ChangeLog +++ b/apps/setting/ChangeLog @@ -87,3 +87,4 @@ of 'Select Clock' 0.76: Add altitude calibration menu (and update README after menu changed) 0.77: Save altitude calibration when user exits via reset 0.78: Fix menu scroll restore on BangleJS1 +0.79: Ensure that tapping on pressure/altitude doesn't cause a menu to display temporarily diff --git a/apps/setting/metadata.json b/apps/setting/metadata.json index 4940b5f70..e255a0dcb 100644 --- a/apps/setting/metadata.json +++ b/apps/setting/metadata.json @@ -1,7 +1,7 @@ { "id": "setting", "name": "Settings", - "version": "0.78", + "version": "0.79", "description": "A menu for setting up Bangle.js", "icon": "settings.png", "tags": "tool,system", diff --git a/apps/setting/settings.js b/apps/setting/settings.js index 3d7f35cd8..45b971e32 100644 --- a/apps/setting/settings.js +++ b/apps/setting/settings.js @@ -1033,8 +1033,8 @@ function showTouchscreenCalibration() { // Calibrate altitude - Bangle.js2 only function showAltitude() { function onPressure(pressure) { - menuPressure.value = Math.round(pressure.pressure); - menuAltitude.value = Math.round(pressure.altitude); + menuPressure.value = Math.round(pressure.pressure).toString(); // toString stops tapping on the item bringing up an adjustment menu + menuAltitude.value = Math.round(pressure.altitude).toString(); m.draw(); } function altitudeDone() { From 14fca983fc200d3e66a8ba9d6d6ab99207fd9c06 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Thu, 19 Jun 2025 10:10:20 +0100 Subject: [PATCH 23/56] Fix regression where removing an app would remove the app before the yes/no prompt was answered! fix https://github.com/espruino/BangleApps/issues/3891 --- core | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core b/core index 7502f4c00..e095a18ed 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit 7502f4c006f52c9b2fe8078bb1dc0bf6b0c400a5 +Subproject commit e095a18ed586e2bc4d93e49d9c4564e40497d126 From eb594038bae772e24bc53d7fac6f5005eb4b164b Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Thu, 19 Jun 2025 10:47:01 +0100 Subject: [PATCH 24/56] recorder 0.46: Ensure altitude graph draws properly (or any graph using the last column of CSV data) Lower accuracy of barometer data to ~1cm (saves about 15b/record) --- apps/recorder/ChangeLog | 4 +++- apps/recorder/app.js | 10 +++++----- apps/recorder/lib.js | 6 +++--- apps/recorder/metadata.json | 2 +- 4 files changed, 12 insertions(+), 10 deletions(-) diff --git a/apps/recorder/ChangeLog b/apps/recorder/ChangeLog index 33986f219..6a17dc603 100644 --- a/apps/recorder/ChangeLog +++ b/apps/recorder/ChangeLog @@ -55,4 +55,6 @@ 0.43: Fix interaction on clocks without widgets 0.44: List tracks in reverse chronological order. 0.45: Move recorder from widget into library - Improve recorder ClockInfo icons \ No newline at end of file + Improve recorder ClockInfo icons +0.46: Ensure altitude graph draws properly (or any graph using the last column of CSV data) + Lower accuracy of barometer data to ~1cm (saves about 15b/record) \ No newline at end of file diff --git a/apps/recorder/app.js b/apps/recorder/app.js index 6d672cd85..795eb905f 100644 --- a/apps/recorder/app.js +++ b/apps/recorder/app.js @@ -333,14 +333,14 @@ function plotGraph(info, style) { "ram" var factor = 1; // multiplier used for values when graphing var timeIdx = info.fields.indexOf("Time"); if (l!==undefined) { - c = l.split(","); + c = l.trim().split(","); strt = c[timeIdx]; } if (style=="Heartrate") { title = /*LANG*/"Heartrate (bpm)"; var hrmIdx = info.fields.indexOf("Heartrate"); while(l!==undefined) { - c=l.split(",");l = f.readLine(f); + c=l.trim().split(",");l = f.readLine(f); if (c[hrmIdx]=="") continue; i = Math.round(80*(c[timeIdx] - strt)/dur); infn[i]+=+c[hrmIdx]; @@ -351,7 +351,7 @@ function plotGraph(info, style) { "ram" var altIdx = info.fields.indexOf("Barometer Altitude"); if (altIdx<0) altIdx = info.fields.indexOf("Altitude"); while(l!==undefined) { - c=l.split(",");l = f.readLine(f); + c=l.trim().split(",");l = f.readLine(f); if (c[altIdx]=="") continue; i = Math.round(80*(c[timeIdx] - strt)/dur); infn[i]+=+c[altIdx]; @@ -368,14 +368,14 @@ function plotGraph(info, style) { "ram" var lonIdx = info.fields.indexOf("Longitude"); // skip until we find our first data while(l!==undefined && c[latIdx]=="") { - c = l.split(","); + c = l.trim().split(","); l = f.readLine(f); } // now iterate var p,lp = Bangle.project({lat:c[1],lon:c[2]}); var t,dx,dy,d,lt = c[timeIdx]; while(l!==undefined) { - c=l.split(","); + c=l.trim().split(","); l = f.readLine(f); if (c[latIdx] == "") { continue; diff --git a/apps/recorder/lib.js b/apps/recorder/lib.js index 9f477e9ec..01838fe38 100644 --- a/apps/recorder/lib.js +++ b/apps/recorder/lib.js @@ -120,9 +120,9 @@ exports.getRecorders = function() { recorders['baro'] = function() { var temp="",press="",alt=""; function onPress(c) { - temp=c.temperature; - press=c.pressure; - alt=c.altitude; + temp=c.temperature.toFixed(1); + press=c.pressure.toFixed(2); + alt=c.altitude.toFixed(2); } return { name : "Baro", diff --git a/apps/recorder/metadata.json b/apps/recorder/metadata.json index 5a7ded5d4..364fb4f54 100644 --- a/apps/recorder/metadata.json +++ b/apps/recorder/metadata.json @@ -2,7 +2,7 @@ "id": "recorder", "name": "Recorder", "shortName": "Recorder", - "version": "0.45", + "version": "0.46", "description": "Record GPS position, heart rate and more in the background, then download to your PC.", "icon": "app.png", "tags": "tool,outdoors,gps,widget,clkinfo", From 15047bcce1fcbf04844d213721c50a3695d04949 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Thu, 19 Jun 2025 13:41:52 +0100 Subject: [PATCH 25/56] Fix issue with pretokeniser and large negative numbers (<-32768) --- core | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core b/core index e095a18ed..091675693 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit e095a18ed586e2bc4d93e49d9c4564e40497d126 +Subproject commit 0916756932699d626555171ce8e0a2989b151c89 From 782c71e85eece966fee16a8678022aeba3fc945e Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Thu, 19 Jun 2025 14:58:02 +0100 Subject: [PATCH 26/56] recorder 0.47: Fix 'blip' on speed map on some recordings --- apps/recorder/ChangeLog | 3 ++- apps/recorder/app.js | 3 ++- apps/recorder/metadata.json | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/apps/recorder/ChangeLog b/apps/recorder/ChangeLog index 6a17dc603..4e39cef42 100644 --- a/apps/recorder/ChangeLog +++ b/apps/recorder/ChangeLog @@ -57,4 +57,5 @@ 0.45: Move recorder from widget into library Improve recorder ClockInfo icons 0.46: Ensure altitude graph draws properly (or any graph using the last column of CSV data) - Lower accuracy of barometer data to ~1cm (saves about 15b/record) \ No newline at end of file + Lower accuracy of barometer data to ~1cm (saves about 15b/record) +0.47: Fix 'blip' on speed map on some recordings \ No newline at end of file diff --git a/apps/recorder/app.js b/apps/recorder/app.js index 795eb905f..463d08004 100644 --- a/apps/recorder/app.js +++ b/apps/recorder/app.js @@ -325,6 +325,7 @@ function plotGraph(info, style) { "ram" var lt = 0; // last time //var tn = 0; // count for each time period var strt, dur = info.duration; + if (dur<1) dur=1; var f = require("Storage").open(filename,"r"); if (f===undefined) return; var l = f.readLine(f); @@ -372,7 +373,7 @@ function plotGraph(info, style) { "ram" l = f.readLine(f); } // now iterate - var p,lp = Bangle.project({lat:c[1],lon:c[2]}); + var p,lp = Bangle.project({lat:c[latIdx],lon:c[lonIdx]}); var t,dx,dy,d,lt = c[timeIdx]; while(l!==undefined) { c=l.trim().split(","); diff --git a/apps/recorder/metadata.json b/apps/recorder/metadata.json index 364fb4f54..2d7e54bdd 100644 --- a/apps/recorder/metadata.json +++ b/apps/recorder/metadata.json @@ -2,7 +2,7 @@ "id": "recorder", "name": "Recorder", "shortName": "Recorder", - "version": "0.46", + "version": "0.47", "description": "Record GPS position, heart rate and more in the background, then download to your PC.", "icon": "app.png", "tags": "tool,outdoors,gps,widget,clkinfo", From de57e73fdcaaaee1b7d70bcbe5c21ef04377f3b3 Mon Sep 17 00:00:00 2001 From: RKBoss6 Date: Thu, 19 Jun 2025 10:49:11 -0400 Subject: [PATCH 27/56] Update metadata.json --- apps/sleeplog/metadata.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/sleeplog/metadata.json b/apps/sleeplog/metadata.json index ff3d5a18f..95d9846ed 100644 --- a/apps/sleeplog/metadata.json +++ b/apps/sleeplog/metadata.json @@ -3,10 +3,10 @@ "name":"Sleep Log", "shortName": "SleepLog", "version": "0.19", - "description": "Log and view your sleeping habits. This app is using the built in movement calculation.", + "description": "Log and view your sleeping habits. This app uses built in movement calculations. View data from Bangle, or from the web app.", "icon": "app.png", "type": "app", - "tags": "tool,boot", + "tags": "tool,boot,health", "supports": ["BANGLEJS2"], "readme": "README.md", "interface": "interface.html", From 1cdbc5c9cf8117d08a312144245b685059c8b427 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Thu, 19 Jun 2025 16:10:04 +0100 Subject: [PATCH 28/56] recorder: Ensure Battery voltage is only stored to 0.01v + Add graphs for Steps+Battery --- apps/recorder/ChangeLog | 4 +++- apps/recorder/app.js | 43 +++++++++++++++++++++++++++++++++-------- apps/recorder/lib.js | 2 +- 3 files changed, 39 insertions(+), 10 deletions(-) diff --git a/apps/recorder/ChangeLog b/apps/recorder/ChangeLog index 4e39cef42..f5c0803bb 100644 --- a/apps/recorder/ChangeLog +++ b/apps/recorder/ChangeLog @@ -58,4 +58,6 @@ Improve recorder ClockInfo icons 0.46: Ensure altitude graph draws properly (or any graph using the last column of CSV data) Lower accuracy of barometer data to ~1cm (saves about 15b/record) -0.47: Fix 'blip' on speed map on some recordings \ No newline at end of file +0.47: Fix 'blip' on speed map on some recordings + Ensure Battery voltage is only stored to 0.01v + Add graphs for Steps+Battery \ No newline at end of file diff --git a/apps/recorder/app.js b/apps/recorder/app.js index 463d08004..37fa5cb3b 100644 --- a/apps/recorder/app.js +++ b/apps/recorder/app.js @@ -197,6 +197,14 @@ function viewTrack(filename, info) { menu[/*LANG*/'Plot HRM'] = function() { plotGraph(info, "Heartrate"); }; + if (info.fields.includes("Steps")) + menu[/*LANG*/'Plot Steps'] = function() { + plotGraph(info, "Steps"); + }; + if (info.fields.includes("Battery Percentage")) + menu[/*LANG*/'Plot Battery'] = function() { + plotGraph(info, "Battery"); + }; // TODO: steps, heart rate? menu[/*LANG*/'Erase'] = function() { E.showPrompt(/*LANG*/"Delete Track?").then(function(v) { @@ -358,12 +366,34 @@ function plotGraph(info, style) { "ram" infn[i]+=+c[altIdx]; infc[i]++; } + } else if (style=="Steps") { + title = /*LANG*/"Steps/min"; + var stpIdx = info.fields.indexOf("Steps"); + var t,lt = c[timeIdx]; + while(l!==undefined) { + c=l.trim().split(",");l = f.readLine(f); + if (c[stpIdx]=="") continue; + t = c[timeIdx]; + i = Math.round(80*(t - strt)/dur); + infn[i]+=60*c[stpIdx]; + infc[i]+=t-lt; + lt = t; + } + } else if (style=="Battery") { + title = /*LANG*/"Battery %"; + var batIdx = info.fields.indexOf("Battery Percentage"); + while(l!==undefined) { + c=l.trim().split(",");l = f.readLine(f); + if (c[batIdx]=="") continue; + i = Math.round(80*(c[timeIdx] - strt)/dur); + infn[i]+=+c[batIdx]; + infc[i]++; + } } else if (style=="Speed") { // use locate to work out units var localeStr = require("locale").speed(1,5); // get what 1kph equates to let units = localeStr.replace(/[0-9.]*/,""); factor = parseFloat(localeStr)*3.6; // m/sec to whatever out units are - // title title = /*LANG*/"Speed"+` (${units})`; var latIdx = info.fields.indexOf("Latitude"); var lonIdx = info.fields.indexOf("Longitude"); @@ -378,19 +408,15 @@ function plotGraph(info, style) { "ram" while(l!==undefined) { c=l.trim().split(","); l = f.readLine(f); - if (c[latIdx] == "") { - continue; - } + if (c[latIdx] == "") continue; t = c[timeIdx]; i = Math.round(80*(t - strt)/dur); p = Bangle.project({lat:c[latIdx],lon:c[lonIdx]}); dx = p.x-lp.x; dy = p.y-lp.y; d = Math.sqrt(dx*dx+dy*dy); - if (t!=lt) { - infn[i]+=d / (t-lt); // speed - infc[i]++; - } + infn[i]+=d; // speed + infc[i]+=t-lt; lp = p; lt = t; } @@ -406,6 +432,7 @@ function plotGraph(info, style) { "ram" if (n>max) max=n; if (n { - return [E.getBattery(), NRF.getBattery(), Bangle.isCharging()]; + return [E.getBattery(), NRF.getBattery().toFixed(2), Bangle.isCharging()]; }, start : () => { }, From 808b794dc710ec47a4c46cb30200986b78f72a7b Mon Sep 17 00:00:00 2001 From: f-elle Date: Thu, 19 Jun 2025 21:23:50 +0200 Subject: [PATCH 29/56] =?UTF-8?q?Add=20icons=20for=20Bereal,=20Nextcloud,?= =?UTF-8?q?=20Thunderbird=20(Blue=20mail=20icon),=20Davx=E2=81=B5,=20Klein?= =?UTF-8?q?anzeigen,=20Element=20X?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/messageicons/icons.img | Bin 5548 -> 5928 bytes apps/messageicons/icons/bereal.png | Bin 0 -> 209 bytes apps/messageicons/icons/generate.js | 6 +++++- apps/messageicons/icons/icon_names.json | 6 ++++++ apps/messageicons/icons/kleinanzeigen.png | Bin 0 -> 248 bytes apps/messageicons/icons/nextcloud.png | Bin 0 -> 195 bytes apps/messageicons/icons/sync.png | Bin 0 -> 448 bytes apps/messageicons/lib.js | 8 ++++++-- 8 files changed, 17 insertions(+), 3 deletions(-) create mode 100644 apps/messageicons/icons/bereal.png create mode 100644 apps/messageicons/icons/kleinanzeigen.png create mode 100644 apps/messageicons/icons/nextcloud.png create mode 100644 apps/messageicons/icons/sync.png diff --git a/apps/messageicons/icons.img b/apps/messageicons/icons.img index bb74d05d962eb81062100dc8e83185879bd4bbb5..39bb2339d1cfacc1f9e014ee5bfdf4bb2201b65a 100644 GIT binary patch delta 592 zcmbV|KTE?<6va;x``YTGsfhThG1(R5f`b`~1qT;rzk)dGAVjE5w2Kr$%R?7IL=YU@ z@&yV7ySO;l!L5r(#ttR%#j4b?!tcW6+&|oV9+w|hF7D+u%gb9fF?KWxy!mmt;YaWX z@MCxtc;*OpDt?!oFFhN0zc{v^*nVvLeLFnVcJ<97U;#B~Nsvuo4vJ=xYe|T=l`92tx;H%FI~nQd8FG?-B^fBM*HK-=`)d1{dYo#U1SkAK PwW($q6z0P2^o#Kcaf!C> delta 284 zcmZ3Xw?=!yQZxSl1@iwZAV`jZK`yC6Zd!$$Pz8tqBqxCx3>6GOss9yn{|n^)C-D7u zn0R}|=JSkkOq0)waBgm5Nn$dvVX&!Uh^uC}XWe)w`tYsn=huq=pR4|VulE1Gn*Vk+ zb#^s2b~Ox81XMgZfLCL)4f_-(d!W$}!2kb){Qn>5=mCfP{SWf@U&!CTA%A~|{QU~~ zdq3pw{*b@@L;m^?{`Vg?M|1TvS_4gB{>Q-opMj5oLE`@b>Hi;u|9=qw|AQR~G5`Mn oM2!CrF#KQu`N#sOl!1X`@<9>N%~m{`jGNc<#;|S<7rw|00G_*gH2?qr diff --git a/apps/messageicons/icons/bereal.png b/apps/messageicons/icons/bereal.png new file mode 100644 index 0000000000000000000000000000000000000000..46a0d129f522c355b4fbf6edf85246406f52922e GIT binary patch literal 209 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjjKx9jP7LeL$-D$|x;7%scUP5zo`Td=F?s%6D@ zH{W}V!rZnJGn>v{J^G3(jqP;T)x6(6n^Z5~XG;(%|59#yC|FK8Y$CrC&{+(gu6{1- HoD!M<{ZLZB literal 0 HcmV?d00001 diff --git a/apps/messageicons/icons/generate.js b/apps/messageicons/icons/generate.js index a07b7af44..c69e6d007 100755 --- a/apps/messageicons/icons/generate.js +++ b/apps/messageicons/icons/generate.js @@ -102,6 +102,7 @@ exports.getColor = function(msg,options) { */""} "bibel": "#54342c", "bring": "#455a64", + "davx⁵": "#8bc34a", "discord": "#5865f2", // https://discord.com/branding "etar": "#36a18b", "facebook": "#1877f2", // https://www.facebook.com/brand/resources/facebookapp/logo @@ -111,7 +112,8 @@ exports.getColor = function(msg,options) { "google home": "#fbbc05", // "home assistant": "#41bdf5", // ha-blue is #41bdf5, but that's the background "instagram": "#ff0069", // https://about.instagram.com/brand/gradient - "jira": "#0052cc", //https://atlassian.design/resources/logo-library + "jira": "#0052cc", // https://atlassian.design/resources/logo-library + "kleinanzeigen": "#69bd2f", // https://themen.kleinanzeigen.de/medien/mediathek/kleinanzeigen-guideline-nutzung-logo/ "leboncoin": "#fa7321", "lieferando": "#ff8000", "linkedin": "#0a66c2", // https://brand.linkedin.com/ @@ -121,6 +123,7 @@ exports.getColor = function(msg,options) { "mattermost": "#00f", "n26": "#36a18b", "nextbike": "#00f", + "nextcloud": "#0082c9", // https://nextcloud.com/brand/ "newpipe": "#f00", "nina": "#e57004", "opentasks": "#409f8f", @@ -137,6 +140,7 @@ exports.getColor = function(msg,options) { "teams": "#6264a7", // https://developer.microsoft.com/en-us/fluentui#/styles/web/colors/products "telegram": "#0088cc", "telegram foss": "#0088cc", + "thunderbird": "#1582e4", "to do": "#3999e5", "twitch": "#9146ff", // https://brand.twitch.tv/ "twitter": "#1d9bf0", // https://about.twitter.com/en/who-we-are/brand-toolkit diff --git a/apps/messageicons/icons/icon_names.json b/apps/messageicons/icons/icon_names.json index 89f81be08..460f313c4 100644 --- a/apps/messageicons/icons/icon_names.json +++ b/apps/messageicons/icons/icon_names.json @@ -5,6 +5,7 @@ { "app":"alarm", "icon":"alarm.png" }, { "app":"alarmclockreceiver", "icon":"alarm.png" }, { "app":"amazon shopping", "icon":"amazon.png" }, + { "app":"bereal.", "icon":"bereal.png" }, { "app":"bibel", "icon":"bibel.png" }, { "app":"bitwarden", "icon":"security.png" }, { "app":"1password", "icon":"security.png" }, @@ -24,9 +25,11 @@ { "app":"rabobank", "icon":"bank.png" }, { "app":"scotiabank", "icon":"bank.png" }, { "app":"td (canada)", "icon":"bank.png" }, + { "app":"davx⁵", "icon":"sync.png" }, { "app":"discord", "icon":"discord.png" }, { "app":"drive", "icon":"google drive.png" }, { "app":"element", "icon":"matrix element.png" }, + { "app":"element x", "icon":"matrix element.png" }, { "app":"facebook", "icon":"facebook.png" }, { "app":"messenger", "icon":"facebook messenger.png" }, { "app":"firefox", "icon":"firefox.png" }, @@ -47,6 +50,7 @@ { "app":"jira", "icon":"jira.png" }, { "app":"kalender", "icon":"kalender.png" }, { "app":"keep notes", "icon":"google keep.png" }, + { "app":"kleinanzeigen", "icon":"kleinanzeigen.png" }, { "app":"leboncoin", "icon":"leboncoin.png" }, { "app":"lieferando", "icon":"lieferando.png" }, { "app":"linkedin", "icon":"linkedin.png" }, @@ -69,6 +73,7 @@ { "app":"la presse", "icon":"news.png" }, { "app":"nbc news", "icon":"news.png" }, { "app":"nextbike", "icon":"nextbike.png" }, + { "app":"nextcloud", "icon":"nextcloud.png" }, { "app":"nina", "icon":"nina.png" }, { "app":"outlook mail", "icon":"outlook.png" }, { "app":"paypal", "icon":"paypal.png" }, @@ -95,6 +100,7 @@ { "app":"telegram foss", "icon":"telegram.png" }, { "app":"threema", "icon":"threema.png" }, { "app":"threema libre", "icon":"threema.png" }, + { "app":"thunderbird", "icon":"mail.png" }, { "app":"tiktok", "icon":"tiktok.png" }, { "app":"to do", "icon":"task.png" }, { "app":"opentasks", "icon":"task.png" }, diff --git a/apps/messageicons/icons/kleinanzeigen.png b/apps/messageicons/icons/kleinanzeigen.png new file mode 100644 index 0000000000000000000000000000000000000000..bffee2e3a0e19965722b4553d10211a1f96170b7 GIT binary patch literal 248 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjjKx9jP7LeL$-D$|HhH=@hIn+| zof^o0Sb?J@@#g>kr{8!MroSYk88u(;ML|%dfJf^oPERYDlzEdbU{Myzj+& z##OruZJKy)GbJz{N$#GYEcjsK*(~N6&wtomi)Kij^D<&(1lyZ$tuk|yFNgQ;YuaSh wa{p9az}1?V-Q7PXDXr-_RUsGt`^*_T+qg*M326-bfUaloboFyt=akR{0P!_uivR!s literal 0 HcmV?d00001 diff --git a/apps/messageicons/icons/nextcloud.png b/apps/messageicons/icons/nextcloud.png new file mode 100644 index 0000000000000000000000000000000000000000..1b0d8a32d9769881b712ee7869ccec0117adde38 GIT binary patch literal 195 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjjKx9jP7LeL$-D$|YCT;XLp(a) zPQA@_z<|T~?2G^ZKixd6u_N!+M(*Ur`&KGynk`~@b8yBy6?rD-2lF&+8KkP_L>~NBDdj>qxXZ)89b85p5HIOn6ho|^7G2#sWU?PAFS#A s22{AWy5O{2O5s}UFI9?&5Sp00i_>zopr00|CHlK=n! literal 0 HcmV?d00001 diff --git a/apps/messageicons/icons/sync.png b/apps/messageicons/icons/sync.png new file mode 100644 index 0000000000000000000000000000000000000000..8193cffe2d1e907c03fbcf9aa2e8c7df281f9eab GIT binary patch literal 448 zcmV;x0YCnUP)gqthFz2O3PM#Et zp0;d}F1(x%Cbs`MaYN~)_SqV%^G;Y|@%QUq96`WK7vst9Yn2vF@}imGu% zehe(~kn53-{>&nky{EPu5MVXQGnJ=yr%0c`sKN7_t?0PA(WGfjlvK-ad3!lGCYtJd z!!sA%Ox$&4U@aJ@tgHDXIes#R;vRv>yRM89jP4y$ppw8`>NZIR6udDa0k45mU>fMl qV%~xDgp3c#zx?=nhB4qWMDY!9=%-8()$cU`0000 Date: Thu, 19 Jun 2025 15:29:05 -0400 Subject: [PATCH 30/56] agenda: Change clockinfo title truncation to preserve images. The previous commit to remove truncation caused long titles that were not well handled by some clocks. This commit instead uses truncation based on string wrapping, which maintains limited-length titles, but now preserves images (e.g. emojis) embedded in the titles. --- apps/agenda/ChangeLog | 2 +- apps/agenda/agenda.clkinfo.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/agenda/ChangeLog b/apps/agenda/ChangeLog index ebbbbebb8..4d2e28096 100644 --- a/apps/agenda/ChangeLog +++ b/apps/agenda/ChangeLog @@ -18,4 +18,4 @@ 0.16: Correct date for all day events in negative timezones, improve locale display 0.17: Fixed "Today" and "Tomorrow" labels displaying in non-current weeks 0.18: Correct date in clockinfo for all-day events in negative timezones -0.19: Show full title in clockinfo instead of truncated +0.19: Change clockinfo title truncation to preserve images diff --git a/apps/agenda/agenda.clkinfo.js b/apps/agenda/agenda.clkinfo.js index a9e371bff..07c48e751 100644 --- a/apps/agenda/agenda.clkinfo.js +++ b/apps/agenda/agenda.clkinfo.js @@ -64,7 +64,7 @@ agenda.forEach((entry, i) => { - var title = entry.title; + var title = g.setFont("6x8").wrapString(entry.title,100)[0]; // All day events are always in UTC and always start at 00:00:00, so we // need to "undo" the timezone offsetting to make sure that the day is // correct. From 910476e6687c7c6d9d901f150876b00a6f37a9b6 Mon Sep 17 00:00:00 2001 From: f-elle Date: Thu, 19 Jun 2025 21:36:10 +0200 Subject: [PATCH 31/56] =?UTF-8?q?Add=20icons=20for=20Bereal,=20Nextcloud,?= =?UTF-8?q?=20Thunderbird=20(Blue=20mail=20icon),=20Davx=E2=81=B5,=20Klein?= =?UTF-8?q?anzeigen,=20Element=20X?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/messageicons/icons/bereal.png | Bin 209 -> 184 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/apps/messageicons/icons/bereal.png b/apps/messageicons/icons/bereal.png index 46a0d129f522c355b4fbf6edf85246406f52922e..172c8228d234cd66173667e21a5e1835d626198f 100644 GIT binary patch delta 143 zcmV;A0C4}&0k{E>F@JJNL_t(YiDO`(F<^w!|H;rpGYd$vh=~k?VSp${;qn1C*Woe{ zuTMzv0V5&9D7AnrF!C%QCNZD@79tHI8&DENLocJ@GL&i=ji6!FumGDSc!O%t<%7Xz x0j`XO3lK_07^!hk=VS&33d$mi4W=6a0Du$@Gbl-T7ytkO00>D%PDHLkV1no5G!Fm( delta 168 zcmV;Z09XIG0nq`FF@K9mL_t(YiS3i&4uBvCgpbzyzw-4*n-T)*zvgYNGUSsufTN>b zNx3ulJ}Z{Ji~y^knosT^Q3UoR0B~i39FTVa0)Va{n}Ei%u3p;3nI2HB>-P>C{h|zX zWB}7eUX%4{J#e~$)j4?gMor!U6AL{UnS#yL#p()X2Fr@oZXx?jvL(~s24EC-^mjeN WQywE$kq<%u0000 Date: Thu, 19 Jun 2025 18:45:02 -0400 Subject: [PATCH 32/56] Update app.js for settings/show charge/time --- apps/chargeanim/app.js | 77 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 74 insertions(+), 3 deletions(-) diff --git a/apps/chargeanim/app.js b/apps/chargeanim/app.js index 68d0cdff5..d971bfc11 100644 --- a/apps/chargeanim/app.js +++ b/apps/chargeanim/app.js @@ -1,8 +1,19 @@ + +var settings = Object.assign({ + // default values + showBatPercent: true, + showTime: true, + keepScreenOn:false, + + }, require("Storage").readJSON("chargeAnimSettings.json", true) || {}); + + g.setBgColor(0, 0, 0); g.clear().flip(); var imgbat = require("heatshrink").decompress(atob("nFYhBC/AH4A/AGUeACA22HEo3/G8YrTAC422HBQ2tHBI3/G/43/G/43/G/43/G/43/G/43/G+fTG+vSN+w326Q31GwI3/G9g2WG742CG/43rGwY3yGwg33RKo3bNzQ3bGwo3/G9A2GG942dG/43QGw43uGxA34IKw3VGyY3iG0I3pb8pBRG+wYPG8wYQG/42uG8oZSG/43bDKY3iDKg3cNzI3iRKo3gGyo3/G7A2WG7g2aG/43WGzA3dGzI3/G6fTGzRvcG/43/G/43/G/43/G/43/G/43/G/437HFw2IHFo2KAH4A/AH4Aa")); var imgbubble = require("heatshrink").decompress(atob("i0UhAebgoAFCaYXNBocjAAIWNCYoVHCw4UFIZwqELJQWFKZQVOChYVzABwVaCx7wKCqIWNCg4WMChIXJCZgAnA==")); - +require("Font8x12").add(Graphics); +var batteryPercentStr=""; var W=g.getWidth(),H=g.getHeight(); var b2v = (W != 240)?-1:1; var b2rot = (W != 240)?Math.PI:0; @@ -12,11 +23,58 @@ for (var i=0;i<10;i++) { bubbles.push({y:Math.random()*H,ly:0,x:(0.5+(i<5?i:i+8))*W/18,v:0.6+Math.random(),s:0.5+Math.random()}); } + +var clockStr=""; +var x=g.getWidth()/2; +var cy=g.getHeight()-(g.getHeight()/7) +var by=g.getHeight()-(g.getHeight()/3.500) + + +function calculateTime(){ + g.setFont("Vector",22); + g.setFontAlign(0,0); + var d=new Date(); + clockStr = require("locale").time(d, 1); // Hour and minute + var meridian=require("locale").meridian(d); + if(meridian!=""){ + //Meridian active + clockStr=clockStr+" "+meridian; + } + +} +function calculate(){ + if(settings.showTime==true){ + calculateTime(); + } + if(settings.showBatPercent==true){ + batteryPercentStr=E.getBattery()+"%"; + } + + +} +function drawClock(){ + + + +} +function drawBatPercent(){ + + + +} function anim() { /* we don't use any kind of buffering here. Just draw one image at a time (image contains a background) too, and there is minimal flicker. */ - var mx = W/2.0, my = H/2.0; + var mx = W/2.0; + var my; + if(settings.showBatPercent){ + var my = H/2.5; + }else{ + var my = H/2.0; + } + + bubbles.forEach(f=>{ f.y-=f.v * b2v; if (f.y<-24) @@ -27,9 +85,22 @@ function anim() { }); g.drawImage(imgbat, mx,my,{scale:b2scale, rotate:Math.sin(getTime()*2)*0.5-Math.PI/2 + b2rot}); g.flip(); + if(settings.showTime==true){ + g.drawString(clockStr,x,cy); + } + if(settings.showBatPercent==true){ + g.drawString(batteryPercentStr,x,by,true); + } +} + +if(settings.showBatPercent||settings.showTime){ + //Eliminate unnesccesary need for calculation + calculate(); + setInterval(calculate,20000); } -setInterval(anim,20); +setInterval(anim,15); + Bangle.on("charging", isCharging => { if (!isCharging) load(); From 8459c3f7b51b68f4a2e69101c211a0b64599e84f Mon Sep 17 00:00:00 2001 From: RKBoss6 Date: Thu, 19 Jun 2025 18:46:24 -0400 Subject: [PATCH 33/56] Create settings.js --- apps/chargeanim/settings.js | 53 +++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 apps/chargeanim/settings.js diff --git a/apps/chargeanim/settings.js b/apps/chargeanim/settings.js new file mode 100644 index 000000000..7380fc0c0 --- /dev/null +++ b/apps/chargeanim/settings.js @@ -0,0 +1,53 @@ +(function(back) { + var FILE = "chargeAnimSettings.json"; + // Load settings + + var settings = Object.assign({ + // default values + showBatPercent: true, + showTime: true, + keepScreenOn:false, + + }, require('Storage').readJSON(FILE, true) || {}); + + function writeSettings() { + require('Storage').writeJSON(FILE, settings); + } + + // Show the menu + E.showMenu({ + "" : { "title" : "Charge Animation" }, + "< Back" : () => back(), + 'Show Percent Charged': { + value: !!settings.showBatPercent, // !! converts undefined to false + onchange: v => { + settings.showBatPercent = v; + writeSettings(); + } + // format: ... may be specified as a function which converts the value to a string + // if the value is a boolean, showMenu() will convert this automatically, which + // keeps settings menus consistent + }, + 'Show Time': { + value: !!settings.showTime, // !! converts undefined to false + onchange: v => { + settings.showTime = v; + writeSettings(); + } + // format: ... may be specified as a function which converts the value to a string + // if the value is a boolean, showMenu() will convert this automatically, which + // keeps settings menus consistent + }, + 'Keep Backlight On': { + value: !!settings.keepScreenOn, // !! converts undefined to false + onchange: v => { + settings.keepScreenOn = v; + writeSettings(); + } + // format: ... may be specified as a function which converts the value to a string + // if the value is a boolean, showMenu() will convert this automatically, which + // keeps settings menus consistent + }, + + }); +}) From 1c04fff6e8918f6a0628c8420d8b4c2680bc809d Mon Sep 17 00:00:00 2001 From: RKBoss6 Date: Thu, 19 Jun 2025 18:48:58 -0400 Subject: [PATCH 34/56] Update metadata.json --- apps/chargeanim/metadata.json | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/apps/chargeanim/metadata.json b/apps/chargeanim/metadata.json index 05d894e00..6d7952254 100644 --- a/apps/chargeanim/metadata.json +++ b/apps/chargeanim/metadata.json @@ -1,8 +1,8 @@ { "id": "chargeanim", "name": "Charge Animation", - "version": "0.02", - "description": "When charging, show a sideways charging animation and keep the screen on. When removed from the charger load the clock again.", + "version": "0.03", + "description": "When charging, show a sideways charging animation and optionally, keep the screen on, show time, or show battery percentage. When removed from the charger load the clock again.", "icon": "icon.png", "tags": "battery", "supports": ["BANGLEJS", "BANGLEJS2"], @@ -11,6 +11,8 @@ "storage": [ {"name":"chargeanim.app.js","url":"app.js"}, {"name":"chargeanim.boot.js","url":"boot.js"}, + {"name":"chargeanim.settings.js","url":"settings.js"}, {"name":"chargeanim.img","url":"app-icon.js","evaluate":true} - ] + ], + "data": [{"name":"chargeAnimSettings.json"}] } From 99768ab55ec87c21a50f78016da7f1f7f5a7b6e3 Mon Sep 17 00:00:00 2001 From: RKBoss6 Date: Thu, 19 Jun 2025 18:50:13 -0400 Subject: [PATCH 35/56] Update ChangeLog --- apps/chargeanim/ChangeLog | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/chargeanim/ChangeLog b/apps/chargeanim/ChangeLog index a7262b0c9..74381da61 100644 --- a/apps/chargeanim/ChangeLog +++ b/apps/chargeanim/ChangeLog @@ -1,2 +1,3 @@ 0.01: New App! 0.02: Bangle.js 2 compatibility +0.03: Add settings menu for showing time and battery percent with animation, as well as setting for keeping backlight on or not. From b234abdd2ee9adc95a7e6de1bb12a876494baddc Mon Sep 17 00:00:00 2001 From: RKBoss6 Date: Thu, 19 Jun 2025 18:50:44 -0400 Subject: [PATCH 36/56] Update app.js --- apps/chargeanim/app.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/chargeanim/app.js b/apps/chargeanim/app.js index d971bfc11..671b0a889 100644 --- a/apps/chargeanim/app.js +++ b/apps/chargeanim/app.js @@ -26,8 +26,8 @@ for (var i=0;i<10;i++) { var clockStr=""; var x=g.getWidth()/2; -var cy=g.getHeight()-(g.getHeight()/7) -var by=g.getHeight()-(g.getHeight()/3.500) +var cy=g.getHeight()-(g.getHeight()/7); +var by=g.getHeight()-(g.getHeight()/3.500); function calculateTime(){ From 39f2eb4db83bfcbeef18e4adac8119749b8ff154 Mon Sep 17 00:00:00 2001 From: RKBoss6 Date: Thu, 19 Jun 2025 20:35:56 -0400 Subject: [PATCH 37/56] Fix bug with font not setting when battery percent is shown --- apps/chargeanim/app.js | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/apps/chargeanim/app.js b/apps/chargeanim/app.js index 671b0a889..fcdfe895e 100644 --- a/apps/chargeanim/app.js +++ b/apps/chargeanim/app.js @@ -23,16 +23,17 @@ for (var i=0;i<10;i++) { bubbles.push({y:Math.random()*H,ly:0,x:(0.5+(i<5?i:i+8))*W/18,v:0.6+Math.random(),s:0.5+Math.random()}); } +g.setFont("Vector",22); +g.setFontAlign(0,0); var clockStr=""; var x=g.getWidth()/2; -var cy=g.getHeight()-(g.getHeight()/7); -var by=g.getHeight()-(g.getHeight()/3.500); +var cy=g.getHeight()-(g.getHeight()/7) +var by=g.getHeight()-(g.getHeight()/3.500) function calculateTime(){ - g.setFont("Vector",22); - g.setFontAlign(0,0); + var d=new Date(); clockStr = require("locale").time(d, 1); // Hour and minute var meridian=require("locale").meridian(d); @@ -52,16 +53,7 @@ function calculate(){ } -function drawClock(){ - - -} -function drawBatPercent(){ - - - -} function anim() { /* we don't use any kind of buffering here. Just draw one image at a time (image contains a background) too, and there is minimal @@ -85,6 +77,7 @@ function anim() { }); g.drawImage(imgbat, mx,my,{scale:b2scale, rotate:Math.sin(getTime()*2)*0.5-Math.PI/2 + b2rot}); g.flip(); + if(settings.showTime==true){ g.drawString(clockStr,x,cy); } From fda3b1ba94c4a8aa5550d01d1ef64f13fdf05aa8 Mon Sep 17 00:00:00 2001 From: RKBoss6 Date: Thu, 19 Jun 2025 20:38:30 -0400 Subject: [PATCH 38/56] Update metadata.json --- apps/chargeanim/metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/chargeanim/metadata.json b/apps/chargeanim/metadata.json index 6d7952254..efe380ce6 100644 --- a/apps/chargeanim/metadata.json +++ b/apps/chargeanim/metadata.json @@ -7,7 +7,7 @@ "tags": "battery", "supports": ["BANGLEJS", "BANGLEJS2"], "allow_emulator": true, - "screenshots": [{"url":"bangle2-charge-animation-screenshot.png"},{"url":"bangle-charge-animation-screenshot.png"}], + "screenshots": [{"url":"Screenshot1"},{"url":"Screenshot2"},{"url":"Screenshot3"}], "storage": [ {"name":"chargeanim.app.js","url":"app.js"}, {"name":"chargeanim.boot.js","url":"boot.js"}, From f9279967d683a7bd4fb4c7e4d6d5a5eaa659ba30 Mon Sep 17 00:00:00 2001 From: RKBoss6 Date: Thu, 19 Jun 2025 20:44:34 -0400 Subject: [PATCH 39/56] Delete old screenshot --- .../bangle-charge-animation-screenshot.png | Bin 3401 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 apps/chargeanim/bangle-charge-animation-screenshot.png diff --git a/apps/chargeanim/bangle-charge-animation-screenshot.png b/apps/chargeanim/bangle-charge-animation-screenshot.png deleted file mode 100644 index 83ef1dbdae1ebf16ee9df2f05fbc9220ac0a77a9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3401 zcmb7HdpMNa8XwE2z9D==822&bk}yoAP%;>dONiVGP1w6mW@p%9RNB5YG?~(fqLfNf z2@|=bQD3`}X}fmMCWftCLzHx)&g^rZ^E~I@^T%56dVbIQu4k?F-hPW8=xs`@6Z0iqIS&r?sgKwq8T3`C z@oQi#S^5_5@>}s2p7e523=NJ%8j%Ix{;0n6XB*H47ZNQ*3H1YVy?4zkQwP?7-R8M< zCLE207wH3kp&ERjign)Ew$Vwb=6fxkG*dg*HD+PKu@Q|2iq%2~W9*<6c#_D( z&&`!|4qIwvUb)bn?omjD6fD38eaC$|p3&vSh&G4;u(f9k9ezRKP-gCLo#IuUU6XQ$ zidqfSKkwi9VLcSBqh*mvHw39e7gHCa;-IS29x1a-V3Bsdf%bz+11>dt9FkRmPQa4k zhLnRFhHd$TMo;se77BjP#l?-lP3Cn*CA*42pKV{dxAZ-~P%YB3eDa+uL~W{GP`I*l z+K)1m>629&O75N;o%+(Y2dc^so}VQFc=1x)uP;8sOqXxX8y&0B*A;mGbp!?I;;IO? z76^k5n7xlR9mfMDn8ZO%MLZ|yle*&Ybd(jXA?W>xz>uhU$|vx%?)>+qIa*$#C4riW zbvU;?Um~L4l>xeT{Di$KzOOGpTuI^*F%HG@GUA}LG3QUh!l7n{i(+!*?eVfZ7nQ+8 z5v_CuD!f

J$-eTS?J>s_6jVI)Jct;L*?GA_awD0Q)UpZ?o!1iw2zqovd^SU28^K zTKu$kEA{f0U{^bM6i>1<4Bu(rzRKg0*N}bF^qFN4HAKL^mYd-@w13z`c7N}#P)87i zzRuG@+qB5~dX!5K&T`q!!k+a9-)S5$UEa>iIG6DuQwP4~kJBV|`(oc8sz6g6N^_)3 z=BytwB~Wo1gWyldOxg@U4<pi>g>?IUnk>H1}5oXOZGs~2lVx|OIMoNDq)=}0ik zS9p3Y^CL1!nK@Q2+;_3>4d1@Z`HK9?Zn2?10iNyUf#jV9jk_0*McyU#oIi;J6I_}e zD1+NgMB|1d+B=;%ImmA%*;ph{k8+y!c9o_5ar#2N+~aaMo4yOckq(Y*RbT_)KC)!M zB(M-O0O!H5y~xu4NSOv*wr$Z`4W$8|QoovcbHX-&c3NGQ6yAkNGm&3o8jyt(I1r2= zg@yD)G_|Jm?6b(t0gq6h>0R9%7-?aUw$bRro7F27w0ASwlkd-15PV% zq9xX=DYyfe4WAA~j+tj*PbCrRAPYj?Am*1z$QB%0%C9y0pESe)FU{S~Fi{>T?uAE> z(AOzIC(Sz#AaNV>rEV!- z@T5Ah@WU~>2cE= zb0eO@(LNlXHYSZI@{7_zYiABB`+0T#v3H>fHsCFCQ$vo*jjp#}tIEXs7fOFhPc_bW^sv~)M2@Z@BO zf=MFbjp7`8_L6Yb zt%&-kWY8$yxa!Dt*gE5d!O)xZa-^_r{AWH_mCjPBsRBRxWZ5m7OJll)rOXEicV%6v zxV19<@X~T}t~tB%E6f&l;rOX&`NZSitTCx}NQ$l^TG{R7duSz>G4$dGfm9Pxw`9B= zwGl4!?V}{!#Kb*6Mf~!k#f{~AwG$-la88XmAqkD@TcK;1Ml=KJltpEPR9%PZeXX>M zdh9y9PYm~+m|90;$~N+Mtcl(~^~%6%-H^jEYtK4$2Ft!C2anF)*W?cLy!6_V3MjWd z6oy;qvaRzEXQz5!!e94IZXEM^n%q&YQXw)CDTf{YQUD)1le8Lb=%CzgTulfU+&n4P zq#e5iMyn_l~Nvx0!Wl#cHoG_tfec0WN1>hNG` zRsCWIDugdJ!)L2L-L0sES0AvhOV;Qo2$tU>UP zv;@R~LPB^TnrSp($WiJ?`7!uW7`#x zMi1#<)0#fwU3TeVdTCo$tDsx#QkE4lhdVX<1Ke4fS7G*%L^~-&KL6cQb5>2ey?P90 zXFVfzLuCEpyo5eGbYU(0pUkY0Chx3WqL;Y#|^7`ZvxpY z>K$gj6gJ39hSVNLatHxJ;RfqL*dVKE)Xj)Y;e^)^99HcA$h*bx?C)k!IIE_Haw3=l z?6S9~EU@pi^((72vso5I^pP;&&ZW>eNG*U0vMD7TSH4twJ}(^df4F(<$~41MmVcGZ zQJ#OI<9uAuc;gAvdV&{oNTNh~h;D)>^ zYPsaNvjjMh`!RMs6eO>Os}E~8Sj_amUw1u-i(x?iN4uWAg4AZGx~z9@t`?t^!0ae@ ziLdF58D~yqIpRR`wpK;0{-!YlD{HbO$t-sGQEX)5<)pZ^lsrS`j}YS#2e@zYelMTE zJt6+}xQG0}Wd1O*%e4ES3!{EKwZ(R)!52I{(=6J(--aOOhcp`WoI8U9@qC&QXo2sT zMwfqkhUOF)_1-q+n9XjVC5wJ)MpOVE;;I(oE|{6HJaA|w^V;LIFHH%}ZI8FTXwmkP z#o(VNj3lcJYRh^rFqyYToLW~v7byV=DVBE?@o0I#T!#X}9dGv;eye^=5?ro_hWQPg z#nhY9ervHlSr1?AcLsdmOEmfu(E>Zp3 zrDoLPC`^i-JpK)d`Og2NiJhKH9xMthN>{8e*PbF+H!{Ymr1uP z4&8W(rUXLdt-iodqz)$|beY;7Ka{Qonj8G<=ey!%+9u!C6cpv{7bipzsX5Cm=|kte z;P;*7iB+=X!*c6RaE>)`uu;?=PNSG^c*8xqEtc=D%8=rfHujo{EnH}iNB2niP` zqb=8oL{AwCz9jD&R;^%a2NAf}v5l0Ao Date: Thu, 19 Jun 2025 20:44:43 -0400 Subject: [PATCH 40/56] Delete apps/chargeanim/bangle2-charge-animation-screenshot.png --- .../bangle2-charge-animation-screenshot.png | Bin 2031 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 apps/chargeanim/bangle2-charge-animation-screenshot.png diff --git a/apps/chargeanim/bangle2-charge-animation-screenshot.png b/apps/chargeanim/bangle2-charge-animation-screenshot.png deleted file mode 100644 index c3fb7c8c823c5c6033b8808c45fde56c7d231137..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2031 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 Az5oCK From fecb70fde789fb6b80713d123b7236a389ed3852 Mon Sep 17 00:00:00 2001 From: RKBoss6 Date: Thu, 19 Jun 2025 20:45:07 -0400 Subject: [PATCH 41/56] Add files via upload --- apps/chargeanim/Screenshot1.png | Bin 0 -> 14178 bytes apps/chargeanim/Screenshot2.png | Bin 0 -> 12721 bytes apps/chargeanim/Screenshot3.png | Bin 0 -> 16179 bytes 3 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 apps/chargeanim/Screenshot1.png create mode 100644 apps/chargeanim/Screenshot2.png create mode 100644 apps/chargeanim/Screenshot3.png diff --git a/apps/chargeanim/Screenshot1.png b/apps/chargeanim/Screenshot1.png new file mode 100644 index 0000000000000000000000000000000000000000..047ab2ca60015a0926c97d0f5b182d9dc289bb41 GIT binary patch literal 14178 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 Z&yiBwF$MP>ASnt`Rn$_bl(Pu^e*nA(%L4!a literal 0 HcmV?d00001 diff --git a/apps/chargeanim/Screenshot2.png b/apps/chargeanim/Screenshot2.png new file mode 100644 index 0000000000000000000000000000000000000000..ba6b543fe55394ef3069d4a386b35bd34fd4db4c GIT binary patch literal 12721 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 literal 0 HcmV?d00001 diff --git a/apps/chargeanim/Screenshot3.png b/apps/chargeanim/Screenshot3.png new file mode 100644 index 0000000000000000000000000000000000000000..d1c6bcb0b77978434586bee4a51952cb3c44e675 GIT binary patch literal 16179 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 Date: Thu, 19 Jun 2025 20:47:15 -0400 Subject: [PATCH 42/56] Update settings.js --- apps/chargeanim/settings.js | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/apps/chargeanim/settings.js b/apps/chargeanim/settings.js index 7380fc0c0..39fc2333b 100644 --- a/apps/chargeanim/settings.js +++ b/apps/chargeanim/settings.js @@ -6,7 +6,7 @@ // default values showBatPercent: true, showTime: true, - keepScreenOn:false, + }, require('Storage').readJSON(FILE, true) || {}); @@ -37,17 +37,8 @@ // format: ... may be specified as a function which converts the value to a string // if the value is a boolean, showMenu() will convert this automatically, which // keeps settings menus consistent - }, - 'Keep Backlight On': { - value: !!settings.keepScreenOn, // !! converts undefined to false - onchange: v => { - settings.keepScreenOn = v; - writeSettings(); - } - // format: ... may be specified as a function which converts the value to a string - // if the value is a boolean, showMenu() will convert this automatically, which - // keeps settings menus consistent - }, + } + }); }) From e41e85a442389b01efea35fde0203ce10850c7f3 Mon Sep 17 00:00:00 2001 From: RKBoss6 Date: Thu, 19 Jun 2025 20:47:36 -0400 Subject: [PATCH 43/56] Update app.js --- apps/chargeanim/app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/chargeanim/app.js b/apps/chargeanim/app.js index fcdfe895e..9e528eb47 100644 --- a/apps/chargeanim/app.js +++ b/apps/chargeanim/app.js @@ -3,7 +3,7 @@ var settings = Object.assign({ // default values showBatPercent: true, showTime: true, - keepScreenOn:false, + }, require("Storage").readJSON("chargeAnimSettings.json", true) || {}); From 4bfeabae0b9a4b6a140705d87245042b5c2451f0 Mon Sep 17 00:00:00 2001 From: RKBoss6 Date: Thu, 19 Jun 2025 20:52:36 -0400 Subject: [PATCH 44/56] Update metadata.json --- apps/chargeanim/metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/chargeanim/metadata.json b/apps/chargeanim/metadata.json index efe380ce6..2b491c519 100644 --- a/apps/chargeanim/metadata.json +++ b/apps/chargeanim/metadata.json @@ -2,7 +2,7 @@ "id": "chargeanim", "name": "Charge Animation", "version": "0.03", - "description": "When charging, show a sideways charging animation and optionally, keep the screen on, show time, or show battery percentage. When removed from the charger load the clock again.", + "description": "When charging, show a sideways charging animation and optionally, show time, or show battery percentage. When removed from the charger, clock loads again.", "icon": "icon.png", "tags": "battery", "supports": ["BANGLEJS", "BANGLEJS2"], From 4e3857508205d182872edddad452cbec2c0f9ce4 Mon Sep 17 00:00:00 2001 From: RKBoss6 Date: Thu, 19 Jun 2025 21:32:10 -0400 Subject: [PATCH 45/56] Update metadata.json --- apps/chargeanim/metadata.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/chargeanim/metadata.json b/apps/chargeanim/metadata.json index 2b491c519..fdba38ea2 100644 --- a/apps/chargeanim/metadata.json +++ b/apps/chargeanim/metadata.json @@ -7,7 +7,10 @@ "tags": "battery", "supports": ["BANGLEJS", "BANGLEJS2"], "allow_emulator": true, - "screenshots": [{"url":"Screenshot1"},{"url":"Screenshot2"},{"url":"Screenshot3"}], + "screenshots": [ + {"url":"Screenshot1"}, + {"url":"Screenshot2"}, + {"url":"Screenshot3"}], "storage": [ {"name":"chargeanim.app.js","url":"app.js"}, {"name":"chargeanim.boot.js","url":"boot.js"}, From bf1f2de8448919c59544667c0d1f3c0beb21c9f4 Mon Sep 17 00:00:00 2001 From: RKBoss6 Date: Thu, 19 Jun 2025 21:32:31 -0400 Subject: [PATCH 46/56] Update metadata.json --- apps/chargeanim/metadata.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/chargeanim/metadata.json b/apps/chargeanim/metadata.json index fdba38ea2..d8c5fa18f 100644 --- a/apps/chargeanim/metadata.json +++ b/apps/chargeanim/metadata.json @@ -8,9 +8,9 @@ "supports": ["BANGLEJS", "BANGLEJS2"], "allow_emulator": true, "screenshots": [ - {"url":"Screenshot1"}, - {"url":"Screenshot2"}, - {"url":"Screenshot3"}], + {"url":"Screenshot1.png"}, + {"url":"Screenshot2.png"}, + {"url":"Screenshot3.png"}], "storage": [ {"name":"chargeanim.app.js","url":"app.js"}, {"name":"chargeanim.boot.js","url":"boot.js"}, From b95ee7bb4aa10553722d792f0831aff817bfe14f Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Thu, 19 Jun 2025 16:29:10 +0100 Subject: [PATCH 47/56] boot 0.66: Ensure __FILE__ is set even after a fresh boot (fix #3857) --- apps/boot/ChangeLog | 3 ++- apps/boot/bootloader.js | 3 ++- apps/boot/metadata.json | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/apps/boot/ChangeLog b/apps/boot/ChangeLog index 5b0fcc583..fa1967d11 100644 --- a/apps/boot/ChangeLog +++ b/apps/boot/ChangeLog @@ -75,4 +75,5 @@ 0.64: Automatically create .widcache and .clkinfocache to speed up loads Bangle.loadWidgets overwritten with fast version on success Refuse to work on firmware <2v16 and remove old polyfills -0.65: Only display interpreter errors if log is nonzero \ No newline at end of file +0.65: Only display interpreter errors if log is nonzero +0.66: Ensure __FILE__ is set even after a fresh boot (fix #3857) \ No newline at end of file diff --git a/apps/boot/bootloader.js b/apps/boot/bootloader.js index 6e6466f48..8228ab482 100644 --- a/apps/boot/bootloader.js +++ b/apps/boot/bootloader.js @@ -23,7 +23,8 @@ if (!_clkApp) { require("Storage").writeJSON("setting.json", s); } } +if (s.clock) __FILE__=s.clock; delete s; if (!_clkApp) _clkApp=`E.showMessage("No Clock Found");setWatch(()=>{Bangle.showLauncher();}, global.BTN2||BTN, {repeat:false,edge:"falling"});`; eval(_clkApp); -delete _clkApp; +delete _clkApp; \ No newline at end of file diff --git a/apps/boot/metadata.json b/apps/boot/metadata.json index afe576e71..93d699c15 100644 --- a/apps/boot/metadata.json +++ b/apps/boot/metadata.json @@ -1,7 +1,7 @@ { "id": "boot", "name": "Bootloader", - "version": "0.65", + "version": "0.66", "description": "This is needed by Bangle.js to automatically load the clock, menu, widgets and settings", "icon": "bootloader.png", "type": "bootloader", From 8442f27c36c54e7b97a687affdb1b6cbb19e95bd Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Fri, 20 Jun 2025 11:21:24 +0100 Subject: [PATCH 48/56] ptlaunch 0.16: Fix issue adding new patterns (fix #3858) Display message if tapping manage when there are no patterns Speed improvements --- apps/ptlaunch/ChangeLog | 3 ++ apps/ptlaunch/app.js | 58 ++++++++++++++----------------------- apps/ptlaunch/boot.js | 14 ++------- apps/ptlaunch/metadata.json | 2 +- 4 files changed, 28 insertions(+), 49 deletions(-) diff --git a/apps/ptlaunch/ChangeLog b/apps/ptlaunch/ChangeLog index 5871b1fdc..9755c5ee7 100644 --- a/apps/ptlaunch/ChangeLog +++ b/apps/ptlaunch/ChangeLog @@ -7,3 +7,6 @@ 0.13: Improve pattern rendering by HughB http://forum.espruino.com/profiles/167235/ 0.14: Update setUI to work with new Bangle.js 2v13 menu style 0.15: Update to support clocks in custom setUI mode +0.16: Fix issue adding new patterns (fix #3858) + Display message if tapping manage when there are no patterns + Speed improvements \ No newline at end of file diff --git a/apps/ptlaunch/app.js b/apps/ptlaunch/app.js index 5db3a335b..ced3a8441 100644 --- a/apps/ptlaunch/app.js +++ b/apps/ptlaunch/app.js @@ -9,10 +9,10 @@ var showMainMenu = () => { var mainmenu = { "": { title: "Pattern Launcher", - }, - "< Back": () => { - log("cancel"); - load(); + back: () => { + log("showMainMenu cancel"); + load(); + } }, "Add Pattern": () => { log("creating pattern"); @@ -83,11 +83,11 @@ var showMainMenu = () => { var settingsmenu = { "": { title: "Pattern Settings", - }, - "< Back": () => { - log("cancel"); - load(); - }, + back: () => { + log("settings cancel"); + showMainMenu(); + }, + } }; if (settings.lockDisabled) { @@ -116,12 +116,7 @@ var showMainMenu = () => { var recognizeAndDrawPattern = () => { return new Promise((resolve) => { - E.showMenu(); - g.clear(); - drawCirclesWithPattern([]); - var pattern = []; - var isFinished = false; var finishHandler = () => { if (pattern.length === 0 || isFinished) { @@ -129,15 +124,12 @@ var recognizeAndDrawPattern = () => { } log("Pattern is finished."); isFinished = true; - Bangle.removeListener("drag", dragHandler); - Bangle.removeListener("tap", finishHandler); + Bangle.setUI(); resolve(pattern.join("")); }; - setWatch(() => finishHandler(), BTN); - // setTimeout(() => Bangle.on("tap", finishHandler), 250); var positions = []; - var getPattern = (positions) => { + var getPattern = (positions) => { "ram";/*faster*/ var circles = [ { x: 25, y: 25, i: 0 }, { x: 87, y: 25, i: 1 }, @@ -151,18 +143,8 @@ var recognizeAndDrawPattern = () => { ]; return positions.reduce((pattern, p, i, arr) => { var idx = circles.findIndex((c) => { - var dx = p.x > c.x ? p.x - c.x : c.x - p.x; - if (dx > CIRCLE_RADIUS) { - return false; - } - var dy = p.y > c.y ? p.y - c.y : c.y - p.y; - if (dy > CIRCLE_RADIUS) { - return false; - } - if (dx + dy <= CIRCLE_RADIUS) { - return true; - } - return dx * dx + dy * dy <= CIRCLE_RADIUS_2; + var dx = p.x - c.x, dy = p.y - c.y; + return dx*dx + dy*dy <= CIRCLE_RADIUS_2; }); if (idx >= 0) { pattern += circles[idx].i; @@ -183,7 +165,9 @@ var recognizeAndDrawPattern = () => { positions = []; } }; - Bangle.on("drag", dragHandler); + g.clear(); + drawCirclesWithPattern([]); + Bangle.setUI({mode:"custom", drag:dragHandler, btn :finishHandler}); }); }; @@ -215,14 +199,14 @@ var getAppList = () => { }; var getSelectedApp = () => { - E.showMessage("Loading apps..."); + E.showMessage(/*LANG*/"Loading apps..."); return new Promise((resolve) => { var selectAppMenu = { "": { - title: "Select App", + title: /*LANG*/"Select App", }, "< Cancel": () => { - log("cancel"); + log("getSelectedApp cancel"); showMainMenu(); }, }; @@ -286,6 +270,8 @@ var drawAppWithPattern = (i, r, storedPatterns) => { var showScrollerContainingAppsWithPatterns = () => { var storedPatternsArray = getStoredPatternsArray(); + if (!storedPatternsArray.length) + return E.showAlert(/*LANG*/"No Patterns",{title:/*LANG*/"Patterns"}).then(() => ({ pattern: "back", appName:"" })); log("drawing scroller for stored patterns"); log(storedPatternsArray); log(storedPatternsArray.length); @@ -485,4 +471,4 @@ var log = (message) => { // run main function ////// -showMainMenu(); +showMainMenu(); \ No newline at end of file diff --git a/apps/ptlaunch/boot.js b/apps/ptlaunch/boot.js index 885962761..9014da9d2 100644 --- a/apps/ptlaunch/boot.js +++ b/apps/ptlaunch/boot.js @@ -24,18 +24,8 @@ ]; return positions.reduce((pattern, p, i, arr) => { var idx = circles.findIndex((c) => { - var dx = p.x > c.x ? p.x - c.x : c.x - p.x; - if (dx > CIRCLE_RADIUS) { - return false; - } - var dy = p.y > c.y ? p.y - c.y : c.y - p.y; - if (dy > CIRCLE_RADIUS) { - return false; - } - if (dx + dy <= CIRCLE_RADIUS) { - return true; - } - return dx * dx + dy * dy <= CIRCLE_RADIUS_2; + var dx = p.x - c.x, dy = p.y - c.y; + return dx*dx + dy*dy <= CIRCLE_RADIUS_2; }); if (idx >= 0) { pattern += circles[idx].i; diff --git a/apps/ptlaunch/metadata.json b/apps/ptlaunch/metadata.json index 6f8a9e16f..e3dbb5701 100644 --- a/apps/ptlaunch/metadata.json +++ b/apps/ptlaunch/metadata.json @@ -2,7 +2,7 @@ "id": "ptlaunch", "name": "Pattern Launcher", "shortName": "Pattern Launcher", - "version": "0.15", + "version": "0.16", "description": "Directly launch apps from the clock screen with custom patterns.", "icon": "app.png", "screenshots": [{"url":"manage_patterns_light.png"}], From 07ce498e5c2f705ca89ebba6e317bc6c3c568e01 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Fri, 20 Jun 2025 11:26:24 +0100 Subject: [PATCH 49/56] ptlaunch: Add widgets to app (work around E.showMenu(back) bug with no widgets in Espruino 2v27) --- apps/ptlaunch/ChangeLog | 3 ++- apps/ptlaunch/app.js | 5 +++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/apps/ptlaunch/ChangeLog b/apps/ptlaunch/ChangeLog index 9755c5ee7..3d8fb6361 100644 --- a/apps/ptlaunch/ChangeLog +++ b/apps/ptlaunch/ChangeLog @@ -9,4 +9,5 @@ 0.15: Update to support clocks in custom setUI mode 0.16: Fix issue adding new patterns (fix #3858) Display message if tapping manage when there are no patterns - Speed improvements \ No newline at end of file + Speed improvements + Add widgets to app (work around E.showMenu(back) bug with no widgets in Espruino 2v27) \ No newline at end of file diff --git a/apps/ptlaunch/app.js b/apps/ptlaunch/app.js index ced3a8441..d9504e20b 100644 --- a/apps/ptlaunch/app.js +++ b/apps/ptlaunch/app.js @@ -124,6 +124,8 @@ var recognizeAndDrawPattern = () => { } log("Pattern is finished."); isFinished = true; + g.clear(); + require("widget_utils").show(); Bangle.setUI(); resolve(pattern.join("")); }; @@ -165,6 +167,7 @@ var recognizeAndDrawPattern = () => { positions = []; } }; + require("widget_utils").hide(); g.clear(); drawCirclesWithPattern([]); Bangle.setUI({mode:"custom", drag:dragHandler, btn :finishHandler}); @@ -471,4 +474,6 @@ var log = (message) => { // run main function ////// +Bangle.loadWidgets(); +Bangle.drawWidgets(); showMainMenu(); \ No newline at end of file From 7537dd4ede30ffd32f39725b496eec95b610a191 Mon Sep 17 00:00:00 2001 From: stweedo Date: Mon, 23 Jun 2025 10:15:05 -0500 Subject: [PATCH 50/56] ios 0.19: Convert numeric weather values to int from BangleDumpWeather shortcut --- apps/ios/ChangeLog | 3 ++- apps/ios/boot.js | 5 +++++ apps/ios/metadata.json | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/apps/ios/ChangeLog b/apps/ios/ChangeLog index 904ad1f7d..f16ff9af6 100644 --- a/apps/ios/ChangeLog +++ b/apps/ios/ChangeLog @@ -16,4 +16,5 @@ 0.15: Enable calendar and weather updates via custom notifications (via shortcuts app) 0.16: Always request Current Time service from iOS 0.17: Default to passing full UTF8 strings into messages app (which can now process them with an international font) -0.18: Fix UTF8 conversion (check for `font` library, not `fonts`) \ No newline at end of file +0.18: Fix UTF8 conversion (check for `font` library, not `fonts`) +0.19: Convert numeric weather values to int from BangleDumpWeather shortcut \ No newline at end of file diff --git a/apps/ios/boot.js b/apps/ios/boot.js index fe9cde77d..1054a735f 100644 --- a/apps/ios/boot.js +++ b/apps/ios/boot.js @@ -191,6 +191,11 @@ E.on('notify',msg=>{ wdir: d.wdir, loc: d.loc } + // Convert string fields to numbers for iOS weather shortcut + const numFields = ['code', 'wdir', 'temp', 'hi', 'lo', 'hum', 'wind', 'uv', 'rain']; + numFields.forEach(field => { + if (weatherEvent[field] != null) weatherEvent[field] = +weatherEvent[field]; + }); require("weather").update(weatherEvent); NRF.ancsAction(msg.uid, false); return; diff --git a/apps/ios/metadata.json b/apps/ios/metadata.json index 6efcac15e..03b116640 100644 --- a/apps/ios/metadata.json +++ b/apps/ios/metadata.json @@ -1,7 +1,7 @@ { "id": "ios", "name": "iOS Integration", - "version": "0.18", + "version": "0.19", "description": "Display notifications/music/etc from iOS devices", "icon": "app.png", "tags": "tool,system,ios,apple,messages,notifications", From 9b1a48c0f8e890c5e5a21102d7dd6b152e04c716 Mon Sep 17 00:00:00 2001 From: RKBoss6 Date: Mon, 23 Jun 2025 14:53:08 -0400 Subject: [PATCH 51/56] Fix flicker --- apps/chargeanim/app.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/apps/chargeanim/app.js b/apps/chargeanim/app.js index 9e528eb47..8913bda4a 100644 --- a/apps/chargeanim/app.js +++ b/apps/chargeanim/app.js @@ -76,14 +76,15 @@ function anim() { g.drawImage(imgbubble,f.y,f.x,{scale:f.s * b2scale, rotate:b2rot}); }); g.drawImage(imgbat, mx,my,{scale:b2scale, rotate:Math.sin(getTime()*2)*0.5-Math.PI/2 + b2rot}); - g.flip(); - if(settings.showTime==true){ g.drawString(clockStr,x,cy); } if(settings.showBatPercent==true){ g.drawString(batteryPercentStr,x,by,true); } + g.flip(); + + } if(settings.showBatPercent||settings.showTime){ @@ -92,7 +93,7 @@ if(settings.showBatPercent||settings.showTime){ setInterval(calculate,20000); } -setInterval(anim,15); +setInterval(anim,22); Bangle.on("charging", isCharging => { From 53c2977fd534807a53d73ab1966ed3901ff99a26 Mon Sep 17 00:00:00 2001 From: RKBoss6 Date: Mon, 23 Jun 2025 14:53:24 -0400 Subject: [PATCH 52/56] Update ChangeLog --- apps/chargeanim/ChangeLog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/chargeanim/ChangeLog b/apps/chargeanim/ChangeLog index 74381da61..42e2cc260 100644 --- a/apps/chargeanim/ChangeLog +++ b/apps/chargeanim/ChangeLog @@ -1,3 +1,3 @@ 0.01: New App! 0.02: Bangle.js 2 compatibility -0.03: Add settings menu for showing time and battery percent with animation, as well as setting for keeping backlight on or not. +0.03: Add settings menu for showing time and battery percent with animation. From fb9c4173ff8f65329148a1fe544698af93e31b49 Mon Sep 17 00:00:00 2001 From: thyttan <97237430+thyttan@users.noreply.github.com> Date: Tue, 24 Jun 2025 11:23:09 +0200 Subject: [PATCH 53/56] msgtwscr: fix function used before declared --- apps/msgtwscr/boot.js | 47 ++++++++++++++++++++++--------------------- 1 file changed, 24 insertions(+), 23 deletions(-) diff --git a/apps/msgtwscr/boot.js b/apps/msgtwscr/boot.js index fa4e4edd6..2b3884d2e 100644 --- a/apps/msgtwscr/boot.js +++ b/apps/msgtwscr/boot.js @@ -1,27 +1,4 @@ { - // If doing regular loads, not Bangle.load, this is used: - if (global.__FILE__=="messagegui.new.js") { - onTwistEmitDrag(); - } - - let attachAfterTimeout = ()=>{ - setTimeout(()=>{ - if (global.__FILE__=="messagegui.new.js") { - onTwistEmitDrag(); - } - },700) - // It feels like there's a more elegant solution than checking the filename - // after 700 milliseconds. But this at least seems to work w/o sometimes - // activating when it shouldn't. - // Maybe we could add events for when fast load and/or Bangle.uiRemove occurs? - // Then that could be used similarly to boot code and/or the `kill` event. - } - - // If Fastload Utils is installed this is used: - Bangle.on("message", (_, msg)=>{if (Bangle.CLOCK && msg.new) { - attachAfterTimeout(); - }}); - // twistThreshold How much acceleration to register a twist of the watch strap? Can be negative for opposite direction. default = 800 // twistMaxY Maximum acceleration in Y to trigger a twist (low Y means watch is facing the right way up). default = -800 // twistTimeout How little time (in ms) must a twist take from low->high acceleration? default = 1000 @@ -59,4 +36,28 @@ }}, 800) } + + // If doing regular loads, not Bangle.load, this is used: + if (global.__FILE__=="messagegui.new.js") { + onTwistEmitDrag(); + } + + let attachAfterTimeout = ()=>{ + setTimeout(()=>{ + if (global.__FILE__=="messagegui.new.js") { + onTwistEmitDrag(); + } + },700) + // It feels like there's a more elegant solution than checking the filename + // after 700 milliseconds. But this at least seems to work w/o sometimes + // activating when it shouldn't. + // Maybe we could add events for when fast load and/or Bangle.uiRemove occurs? + // Then that could be used similarly to boot code and/or the `kill` event. + } + + // If Fastload Utils is installed this is used: + Bangle.on("message", (_, msg)=>{if (Bangle.CLOCK && msg.new) { + attachAfterTimeout(); + }}); + } From c6b1c0c1e6b1f7920ec1e07cf384fc0e045e70e4 Mon Sep 17 00:00:00 2001 From: thyttan <97237430+thyttan@users.noreply.github.com> Date: Tue, 24 Jun 2025 11:31:33 +0200 Subject: [PATCH 54/56] msgtwscr: don't pollute global scope --- apps/msgtwscr/boot.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/msgtwscr/boot.js b/apps/msgtwscr/boot.js index 2b3884d2e..4b43102a9 100644 --- a/apps/msgtwscr/boot.js +++ b/apps/msgtwscr/boot.js @@ -2,7 +2,7 @@ // twistThreshold How much acceleration to register a twist of the watch strap? Can be negative for opposite direction. default = 800 // twistMaxY Maximum acceleration in Y to trigger a twist (low Y means watch is facing the right way up). default = -800 // twistTimeout How little time (in ms) must a twist take from low->high acceleration? default = 1000 - function onTwistEmitDrag() { + let onTwistEmitDrag = ()=>{ Bangle.setOptions({twistThreshold:2500, twistMaxY:-800, twistTimeout:400}); let isTwistDragging = false; let twistHandler = ()=>{ From 6307ae4d8a6559be02d155e75d8639daaa585076 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Tue, 24 Jun 2025 14:36:18 +0100 Subject: [PATCH 55/56] remove tabs --- apps/messageicons/icons/icon_names.json | 78 ++++++++++++------------- 1 file changed, 39 insertions(+), 39 deletions(-) diff --git a/apps/messageicons/icons/icon_names.json b/apps/messageicons/icons/icon_names.json index 460f313c4..63866b355 100644 --- a/apps/messageicons/icons/icon_names.json +++ b/apps/messageicons/icons/icon_names.json @@ -3,41 +3,41 @@ { "app":"airbnb", "icon":"airbnb.png" }, { "app":"agenda", "icon":"agenda.png" }, { "app":"alarm", "icon":"alarm.png" }, - { "app":"alarmclockreceiver", "icon":"alarm.png" }, + { "app":"alarmclockreceiver", "icon":"alarm.png" }, { "app":"amazon shopping", "icon":"amazon.png" }, { "app":"bereal.", "icon":"bereal.png" }, { "app":"bibel", "icon":"bibel.png" }, { "app":"bitwarden", "icon":"security.png" }, - { "app":"1password", "icon":"security.png" }, - { "app":"lastpass", "icon":"security.png" }, - { "app":"dashlane", "icon":"security.png" }, + { "app":"1password", "icon":"security.png" }, + { "app":"lastpass", "icon":"security.png" }, + { "app":"dashlane", "icon":"security.png" }, { "app":"bring", "icon":"bring.png" }, { "app":"calendar", "icon":"etar.png" }, - { "app":"etar", "icon":"etar.png" }, + { "app":"etar", "icon":"etar.png" }, { "app":"chat", "icon":"google chat.png" }, { "app":"chrome", "icon":"chrome.png" }, { "app":"clock", "icon":"alarm.png" }, { "app":"corona-warn", "icon":"coronavirus.png" }, { "app":"bmo", "icon":"bank.png" }, - { "app":"desjardins", "icon":"bank.png" }, - { "app":"rbc mobile", "icon":"bank.png" }, - { "app":"nbc", "icon":"bank.png" }, - { "app":"rabobank", "icon":"bank.png" }, - { "app":"scotiabank", "icon":"bank.png" }, - { "app":"td (canada)", "icon":"bank.png" }, + { "app":"desjardins", "icon":"bank.png" }, + { "app":"rbc mobile", "icon":"bank.png" }, + { "app":"nbc", "icon":"bank.png" }, + { "app":"rabobank", "icon":"bank.png" }, + { "app":"scotiabank", "icon":"bank.png" }, + { "app":"td (canada)", "icon":"bank.png" }, { "app":"davx⁵", "icon":"sync.png" }, { "app":"discord", "icon":"discord.png" }, { "app":"drive", "icon":"google drive.png" }, { "app":"element", "icon":"matrix element.png" }, - { "app":"element x", "icon":"matrix element.png" }, + { "app":"element x", "icon":"matrix element.png" }, { "app":"facebook", "icon":"facebook.png" }, { "app":"messenger", "icon":"facebook messenger.png" }, { "app":"firefox", "icon":"firefox.png" }, - { "app":"firefox beta", "icon":"firefox.png" }, - { "app":"firefox nightly", "icon":"firefox.png" }, + { "app":"firefox beta", "icon":"firefox.png" }, + { "app":"firefox nightly", "icon":"firefox.png" }, { "app":"f-droid", "icon":"security.png" }, - { "app":"neo store", "icon":"security.png" }, - { "app":"aurora droid", "icon":"security.png" }, + { "app":"neo store", "icon":"security.png" }, + { "app":"aurora droid", "icon":"security.png" }, { "app":"github", "icon":"github.png" }, { "app":"gitlab", "icon":"gitlab.png" }, { "app":"gmail", "icon":"gmail.png" }, @@ -55,23 +55,23 @@ { "app":"lieferando", "icon":"lieferando.png" }, { "app":"linkedin", "icon":"linkedin.png" }, { "app":"maps", "icon":"map.png" }, - { "app":"organic maps", "icon":"map.png" }, - { "app":"osmand", "icon":"map.png" }, + { "app":"organic maps", "icon":"map.png" }, + { "app":"osmand", "icon":"map.png" }, { "app":"mastodon", "icon":"mastodon.png" }, - { "app":"fedilab", "icon":"mastodon.png" }, - { "app":"tooot", "icon":"mastodon.png" }, - { "app":"tusky", "icon":"mastodon.png" }, + { "app":"fedilab", "icon":"mastodon.png" }, + { "app":"tooot", "icon":"mastodon.png" }, + { "app":"tusky", "icon":"mastodon.png" }, { "app":"mattermost", "icon":"mattermost.png" }, { "app":"messages", "icon":"messages.png" }, { "app":"n26", "icon":"n26.png" }, { "app":"netflix", "icon":"netflix.png" }, { "app":"news", "icon":"news.png" }, - { "app":"cbc news", "icon":"news.png" }, - { "app":"rc info", "icon":"news.png" }, - { "app":"reuters", "icon":"news.png" }, - { "app":"ap news", "icon":"news.png" }, - { "app":"la presse", "icon":"news.png" }, - { "app":"nbc news", "icon":"news.png" }, + { "app":"cbc news", "icon":"news.png" }, + { "app":"rc info", "icon":"news.png" }, + { "app":"reuters", "icon":"news.png" }, + { "app":"ap news", "icon":"news.png" }, + { "app":"la presse", "icon":"news.png" }, + { "app":"nbc news", "icon":"news.png" }, { "app":"nextbike", "icon":"nextbike.png" }, { "app":"nextcloud", "icon":"nextcloud.png" }, { "app":"nina", "icon":"nina.png" }, @@ -83,11 +83,11 @@ { "app":"post & dhl", "icon":"delivery.png" }, { "app":"proton mail", "icon":"protonmail.png" }, { "app":"reddit", "icon":"reddit.png" }, - { "app":"sync pro", "icon":"reddit.png" }, - { "app":"sync dev", "icon":"reddit.png" }, - { "app":"boost", "icon":"reddit.png" }, - { "app":"infinity", "icon":"reddit.png" }, - { "app":"slide", "icon":"reddit.png" }, + { "app":"sync pro", "icon":"reddit.png" }, + { "app":"sync dev", "icon":"reddit.png" }, + { "app":"boost", "icon":"reddit.png" }, + { "app":"infinity", "icon":"reddit.png" }, + { "app":"slide", "icon":"reddit.png" }, { "app":"signal", "icon":"signal.png" }, { "app":"molly", "icon":"signal.png" }, { "app":"skype", "icon":"skype.png" }, @@ -97,28 +97,28 @@ { "app":"steam", "icon":"steam.png" }, { "app":"teams", "icon":"teams.png" }, { "app":"telegram", "icon":"telegram.png" }, - { "app":"telegram foss", "icon":"telegram.png" }, + { "app":"telegram foss", "icon":"telegram.png" }, { "app":"threema", "icon":"threema.png" }, { "app":"threema libre", "icon":"threema.png" }, { "app":"thunderbird", "icon":"mail.png" }, { "app":"tiktok", "icon":"tiktok.png" }, { "app":"to do", "icon":"task.png" }, - { "app":"opentasks", "icon":"task.png" }, - { "app":"tasks", "icon":"task.png" }, + { "app":"opentasks", "icon":"task.png" }, + { "app":"tasks", "icon":"task.png" }, { "app":"transit", "icon":"transit.png" }, { "app":"twitch", "icon":"twitch.png" }, { "app":"twitter", "icon":"twitter.png" }, { "app":"uber", "icon":"taxi.png" }, - { "app":"lyft", "icon":"taxi.png" }, + { "app":"lyft", "icon":"taxi.png" }, { "app":"vlc", "icon":"vlc.png" }, { "app":"warnapp", "icon":"warnapp.png" }, { "app":"whatsapp", "icon":"whatsapp.png" }, { "app":"wordfeud", "icon":"wordfeud.png" }, { "app":"youtube", "icon":"youtube.png" }, - { "app":"newpipe", "icon":"youtube.png" }, + { "app":"newpipe", "icon":"youtube.png" }, { "app":"zoom", "icon":"videoconf.png" }, - { "app":"meet", "icon":"videoconf.png" }, + { "app":"meet", "icon":"videoconf.png" }, { "app":"music", "icon":"music.png" }, { "app":"sms message", "icon":"default.png" }, - { "app":"mail", "icon":"default.png" } + { "app":"mail", "icon":"default.png" } ] From d0e4d3455b1ca439c41c3c5f66711a41d9e16b05 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Tue, 24 Jun 2025 14:38:29 +0100 Subject: [PATCH 56/56] bump version for #3895 --- apps/messageicons/ChangeLog | 3 ++- apps/messageicons/metadata.json | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/messageicons/ChangeLog b/apps/messageicons/ChangeLog index ede169914..7bb8d1f70 100644 --- a/apps/messageicons/ChangeLog +++ b/apps/messageicons/ChangeLog @@ -6,4 +6,5 @@ 0.05: Add message icon for 'jira' 0.06: Add message icon for 'molly' and 'threema libre' 0.07: Minor code improvements -0.08: Add more icons including GMail, Google Messages, Google Agenda \ No newline at end of file +0.08: Add more icons including GMail, Google Messages, Google Agenda +0.09: Add Bereal, Nextcloud, Thunderbird, Davx⁵, Kleinanzeigen, Element X diff --git a/apps/messageicons/metadata.json b/apps/messageicons/metadata.json index 356eeba79..afa511aad 100644 --- a/apps/messageicons/metadata.json +++ b/apps/messageicons/metadata.json @@ -1,7 +1,7 @@ { "id": "messageicons", "name": "Message Icons", - "version": "0.08", + "version": "0.09", "description": "Library containing a list of icons and colors for apps", "icon": "app.png", "type": "module",