From 80877a071c552bbbe9a493fc5ce8cf9f36f2f88f Mon Sep 17 00:00:00 2001 From: David Holdeman Date: Fri, 17 Oct 2025 22:01:18 +0800 Subject: [PATCH 1/7] Normalize whitespace --- apps/mtnclock/app.js | 163 +++++++++++++++++++++---------------------- 1 file changed, 81 insertions(+), 82 deletions(-) diff --git a/apps/mtnclock/app.js b/apps/mtnclock/app.js index dccade31f3..959f41f05a 100644 --- a/apps/mtnclock/app.js +++ b/apps/mtnclock/app.js @@ -9,17 +9,17 @@ try { //seeded RNG to generate stars, snow, etc function sfc32(a, b, c, d) { - return function() { - a >>>= 0; b >>>= 0; c >>>= 0; d >>>= 0; - var t = (a + b) | 0; - a = b ^ b >>> 9; - b = c + (c << 3) | 0; - c = (c << 21 | c >>> 11); - d = d + 1 | 0; - t = t + d | 0; - c = c + t | 0; - return (t >>> 0) / 4294967296; - }; + return function() { + a >>>= 0; b >>>= 0; c >>>= 0; d >>>= 0; + var t = (a + b) | 0; + a = b ^ b >>> 9; + b = c + (c << 3) | 0; + c = (c << 21 | c >>> 11); + d = d + 1 | 0; + t = t + d | 0; + c = c + t | 0; + return (t >>> 0) / 4294967296; + }; } //scale x, y coords to screen @@ -79,12 +79,11 @@ function drawSnow(color, coord, size) { } function draw(color) { + var seed; + var rand; -var seed; -var rand; - -g.clear(); -//background + g.clear(); + //background g.setColor(color.bg1).fillRect( px(0),py(0), px(100),py(45) @@ -96,20 +95,20 @@ g.clear(); //lightning if (color.ltn) { g.setColor(color.ltn).fillPoly([ - px(70),py(20), - px(60),py(28), - px(71),py(29), - px(63),py(40), - px(75),py(28), - px(64),py(27) + px(70),py(20), + px(60),py(28), + px(71),py(29), + px(63),py(40), + px(75),py(28), + px(64),py(27) ]); g.fillPoly([ - px(40),py(20), - px(30),py(28), - px(41),py(29), - px(33),py(40), - px(45),py(28), - px(34),py(27) + px(40),py(20), + px(30),py(28), + px(41),py(29), + px(33),py(40), + px(45),py(28), + px(34),py(27) ]); } //stars @@ -117,7 +116,7 @@ g.clear(); seed = 4; rand = sfc32(0x9E3779B9, 0x243F6A88, 0xB7E15162, seed); for (let i = 0; i < 40; i++) { - g.setColor(color.star).drawCircle(Math.floor(rand() * px(100)),Math.floor(rand() * py(33)),Math.floor(rand() * 2)); + g.setColor(color.star).drawCircle(Math.floor(rand() * px(100)),Math.floor(rand() * py(33)),Math.floor(rand() * 2)); } } //birds @@ -216,13 +215,13 @@ function setWeather() { if (new Date().getHours() >= 7 && new Date().getHours() <= 19) { //day-clear a = { - bg1:0x4FFF, bg2:0x03E0, - sun:0xFD20, - path:0x8200, - mtn1:0x045f, mtn2:0x000F, - lake:0x000F, - tree1:0x07E0, tree2:0, tree3:0x7BE0, - bird:0xFFFF + bg1:0x4FFF, bg2:0x03E0, + sun:0xFD20, + path:0x8200, + mtn1:0x045f, mtn2:0x000F, + lake:0x000F, + tree1:0x07E0, tree2:0, tree3:0x7BE0, + bird:0xFFFF }; //day-cloudy if (data.code == 801 || data.code == 802) a.cloud1 = 0xFFFF; @@ -230,13 +229,13 @@ function setWeather() { else { //night-clear a = { - bg1:0, bg2:0x0005, - sun:0xC618, - path:0, - mtn1:0x0210, mtn2:0x0010, - lake:0x000F, - tree1:0x0200, tree2:0, tree3:0x59E0, - star:0xFFFF + bg1:0, bg2:0x0005, + sun:0xC618, + path:0, + mtn1:0x0210, mtn2:0x0010, + lake:0x000F, + tree1:0x0200, tree2:0, tree3:0x59E0, + star:0xFFFF }; //night-cloudy if (data.code == 801 || data.code == 802) a.cloud1 = 0x4208; @@ -246,12 +245,12 @@ function setWeather() { if (new Date().getHours() >= 7 && new Date().getHours() <= 19) { //day-overcast a = { - bg1:0xC618, bg2:0x0200, - path:0x3000, - mtn1:0x3B38, mtn2:0x0005, - lake:0x000F, - tree1:0x03E0, tree2:0, tree3:0x59E0, - cloud1:0x7BEF, cloud2:1 + bg1:0xC618, bg2:0x0200, + path:0x3000, + mtn1:0x3B38, mtn2:0x0005, + lake:0x000F, + tree1:0x03E0, tree2:0, tree3:0x59E0, + cloud1:0x7BEF, cloud2:1 }; //day-lightning if (data.code >= 200 && data.code < 300) a.ltn = 0xFFFF; @@ -263,12 +262,12 @@ function setWeather() { else { //night-overcast a = { - bg1:0, bg2:0x0005, - path:0, - mtn1:0x0010, mtn2:0x000F, - lake:0x000F, - tree1:0x0200, tree2:0, tree3:0x59E0, - cloud1:0x4208, cloud2:1 + bg1:0, bg2:0x0005, + path:0, + mtn1:0x0010, mtn2:0x000F, + lake:0x000F, + tree1:0x0200, tree2:0, tree3:0x59E0, + cloud1:0x4208, cloud2:1 }; //night-lightning if (data.code >= 200 && data.code < 300) a.ltn = 0xFFFF; @@ -282,23 +281,23 @@ function setWeather() { if (new Date().getHours() >= 7 && new Date().getHours() <= 19) { //day-fog a = { - bg1:0xC618, bg2:0x0200, - path:0x3000, - mtn1:0x3B38, mtn2:0x0005, - lake:0x000F, - tree1:0x03E0, tree2:0, tree3:0x59E0, - fog:0xFFFF + bg1:0xC618, bg2:0x0200, + path:0x3000, + mtn1:0x3B38, mtn2:0x0005, + lake:0x000F, + tree1:0x03E0, tree2:0, tree3:0x59E0, + fog:0xFFFF }; } else { //night-fog a = { - bg1:0, bg2:0x0005, - path:0, - mtn1:0x0010, mtn2:0x000F, - lake:0x000F, - tree1:0x0200, tree2:0, tree3:0x59E0, - fog:0x7BEF + bg1:0, bg2:0x0005, + path:0, + mtn1:0x0010, mtn2:0x000F, + lake:0x000F, + tree1:0x0200, tree2:0, tree3:0x59E0, + fog:0x7BEF }; } } @@ -306,26 +305,26 @@ function setWeather() { if (new Date().getHours() >= 7 && new Date().getHours() <= 19) { //day-snow a = { - bg1:0, bg2:0x7BEF, - path:0xC618, - mtn1:0xFFFF, mtn2:0x7BEF, - lake:0x07FF, - tree1:0xC618, tree2:0xC618, tree3:0x59E0, - cloud1:0x7BEF, cloud2:1, - snow:0xFFFF, - clock: 0 + bg1:0, bg2:0x7BEF, + path:0xC618, + mtn1:0xFFFF, mtn2:0x7BEF, + lake:0x07FF, + tree1:0xC618, tree2:0xC618, tree3:0x59E0, + cloud1:0x7BEF, cloud2:1, + snow:0xFFFF, + clock: 0 }; } else { //night-snow a = { - bg1:0, bg2:0x0005, - path:0, - mtn1:0x0010, mtn2:0x000F, - lake:0x000F, - tree1:0x39E7, tree2:0x39E7, tree3:0x59E0, - cloud1:0x4208, cloud2:1, - snow:0xFFFF + bg1:0, bg2:0x0005, + path:0, + mtn1:0x0010, mtn2:0x000F, + lake:0x000F, + tree1:0x39E7, tree2:0x39E7, tree3:0x59E0, + cloud1:0x4208, cloud2:1, + snow:0xFFFF }; } } From efe33780e5f05e07b4639d7381d54148bb8fa48f Mon Sep 17 00:00:00 2001 From: David Holdeman Date: Wed, 22 Oct 2025 18:08:08 +0800 Subject: [PATCH 2/7] convert to posix line endings --- apps/mtnclock/README.md | 42 +++++++++++++++--------------- apps/mtnclock/metadata.json | 52 ++++++++++++++++++------------------- 2 files changed, 47 insertions(+), 47 deletions(-) diff --git a/apps/mtnclock/README.md b/apps/mtnclock/README.md index 441754b839..b34be5e394 100644 --- a/apps/mtnclock/README.md +++ b/apps/mtnclock/README.md @@ -1,21 +1,21 @@ -# Mountain Pass Clock - -Based on the Pebble watchface Weather Land. - -Mountain Pass Clock changes depending on time (day/night) and weather conditions. - -This clock requires Gadgetbridge and an app that Gadgetbridge can use to get the current weather from OpenWeatherMap (e.g. Weather Notification), or a Bangle app that will update weather.json such as OWM Weather. To set up Gadgetbridge and weather, see https://codeberg.org/Freeyourgadget/Gadgetbridge/wiki/Weather. - -The scene will change according to the following OpenWeatherMap conditions: clear, cloudy, overcast, lightning, drizzle, rain, fog and snow. Each weather condition has night/day scenes. - -If you choose not to set up weather (or are not connected to Gadgetbridge, for that matter), this clock will default to clear weather, and the scenery will still change from night to day. - -Special thanks to Serj for testing this on the original Bangle. - -## Images - -![](screenshot1.png) -![](screenshot2.png) -![](screenshot3.png) -![](screenshot4.png) -![](screenshot5.png) +# Mountain Pass Clock + +Based on the Pebble watchface Weather Land. + +Mountain Pass Clock changes depending on time (day/night) and weather conditions. + +This clock requires Gadgetbridge and an app that Gadgetbridge can use to get the current weather from OpenWeatherMap (e.g. Weather Notification), or a Bangle app that will update weather.json such as OWM Weather. To set up Gadgetbridge and weather, see https://codeberg.org/Freeyourgadget/Gadgetbridge/wiki/Weather. + +The scene will change according to the following OpenWeatherMap conditions: clear, cloudy, overcast, lightning, drizzle, rain, fog and snow. Each weather condition has night/day scenes. + +If you choose not to set up weather (or are not connected to Gadgetbridge, for that matter), this clock will default to clear weather, and the scenery will still change from night to day. + +Special thanks to Serj for testing this on the original Bangle. + +## Images + +![](screenshot1.png) +![](screenshot2.png) +![](screenshot3.png) +![](screenshot4.png) +![](screenshot5.png) diff --git a/apps/mtnclock/metadata.json b/apps/mtnclock/metadata.json index c5338e8eb0..cb622a2fb3 100644 --- a/apps/mtnclock/metadata.json +++ b/apps/mtnclock/metadata.json @@ -1,26 +1,26 @@ -{ - "id": "mtnclock", - "name": "Mountain Pass Clock", - "shortName": "Mtn Clock", - "version": "0.06", - "description": "A clock that changes scenery based on time and weather.", - "readme":"README.md", - "icon": "app.png", - "screenshots": [ - {"url":"screenshot1.png"}, - {"url":"screenshot2.png"}, - {"url":"screenshot3.png"}, - {"url":"screenshot4.png"}, - {"url":"screenshot5.png"} - ], - "type": "clock", - "tags": "clock", - "supports": ["BANGLEJS","BANGLEJS2"], - "allow_emulator": true, - "storage": [ - {"name":"mtnclock.app.js","url":"app.js"}, - {"name":"mtnclock.settings.js","url":"settings.js"}, - {"name":"mtnclock.img","url":"app-icon.js","evaluate":true} - ], - "data": [{"name":"mtnclock.json"}] -} +{ + "id": "mtnclock", + "name": "Mountain Pass Clock", + "shortName": "Mtn Clock", + "version": "0.06", + "description": "A clock that changes scenery based on time and weather.", + "readme":"README.md", + "icon": "app.png", + "screenshots": [ + {"url":"screenshot1.png"}, + {"url":"screenshot2.png"}, + {"url":"screenshot3.png"}, + {"url":"screenshot4.png"}, + {"url":"screenshot5.png"} + ], + "type": "clock", + "tags": "clock", + "supports": ["BANGLEJS","BANGLEJS2"], + "allow_emulator": true, + "storage": [ + {"name":"mtnclock.app.js","url":"app.js"}, + {"name":"mtnclock.settings.js","url":"settings.js"}, + {"name":"mtnclock.img","url":"app-icon.js","evaluate":true} + ], + "data": [{"name":"mtnclock.json"}] +} From 7132422b9ccea981edb890f001a2ad791c7bad19 Mon Sep 17 00:00:00 2001 From: David Holdeman Date: Sat, 18 Oct 2025 09:32:19 +0800 Subject: [PATCH 3/7] Add clockinfo support to mtnclock --- apps/mtnclock/ChangeLog | 1 + apps/mtnclock/README.md | 2 + apps/mtnclock/app.js | 135 +++++++++++++++++++++++++++++++++++- apps/mtnclock/metadata.json | 5 +- 4 files changed, 138 insertions(+), 5 deletions(-) diff --git a/apps/mtnclock/ChangeLog b/apps/mtnclock/ChangeLog index 532b77e0e1..c7224f5cf8 100644 --- a/apps/mtnclock/ChangeLog +++ b/apps/mtnclock/ChangeLog @@ -4,3 +4,4 @@ 0.04: Adding settings and the ability to show the widgets bar 0.05: Fix the widgets disappearing on weather update 0.06: Fix weather not correctly updating with Weather data v2 +0.07: Add clockinfo slots diff --git a/apps/mtnclock/README.md b/apps/mtnclock/README.md index b34be5e394..cba5b9ee23 100644 --- a/apps/mtnclock/README.md +++ b/apps/mtnclock/README.md @@ -10,6 +10,8 @@ The scene will change according to the following OpenWeatherMap conditions: clea If you choose not to set up weather (or are not connected to Gadgetbridge, for that matter), this clock will default to clear weather, and the scenery will still change from night to day. +You can add up to three clockinfos under the time, date, and weather. Accessing the menu to do so is done by tapping, or long-tapping on the Bangle.js 2. + Special thanks to Serj for testing this on the original Bangle. ## Images diff --git a/apps/mtnclock/app.js b/apps/mtnclock/app.js index 959f41f05a..557413e360 100644 --- a/apps/mtnclock/app.js +++ b/apps/mtnclock/app.js @@ -1,5 +1,15 @@ var data = require("Storage").readJSON("mtnclock.json", 1) || {}; +if (! Array.isArray(data.rows)) { + data.rows = []; + require("Storage").writeJSON("mtnclock.json", data); +} + +let showingSettings = false; +let clockinfosSettings = []; +let clockinfosMain = []; +let clockinfos = require("clock_info").load(); + let weather; try { weather = require('weather'); @@ -166,7 +176,7 @@ function draw(color) { } } //mountains - drawMtn({mtn1:color.mtn2, mtn2:color.mtn1}, {x:px(35), y:py(30)}, {w:px(38), h:py(17)}); + drawMtn({mtn1:color.mtn2, mtn2:color.mtn1}, {x:px(43), y:py(28)}, {w:px(38), h:py(19)}); drawMtn({mtn1:color.mtn2, mtn2:color.mtn1}, {x:px(10), y:py(20)}, {w:px(50), h:py(30)}); drawMtn({mtn1:color.mtn1, mtn2:color.mtn2}, {x:px(90), y:py(20)}, {w:px(70), h:py(30)}); //lake @@ -200,8 +210,25 @@ function draw(color) { //clock text (color.clock == undefined) ? g.setColor(0xFFFF) : g.setColor(color.clock); - g.setFont("Vector", py(20)).setFontAlign(-1, -1).drawString((require("locale").time(new Date(), 1).replace(" ", "")), px(2), py(67)); - g.setFont("Vector", py(10)).drawString(require('locale').dow(new Date(), 1)+" "+new Date().getDate()+" "+require('locale').month(new Date(), 1)+((data.temp == undefined) ? "" : " | "+require('locale').temp(Math.round(data.temp-273.15)).replace(".0", "")), px(2), py(87)); + const start = 87; + for (let r = 0; r < data.rows.length; r++) { + let a = data.rows[r].menuA; + let b = data.rows[r].menuB; + if (clockinfos[a] && clockinfos[a].items[b]) { + let ci = clockinfos[a].items[b]; + let text = ci.get().text; + if (!(clockinfosMain[a] && clockinfosMain[a][b])) { + clockinfosMain[a] = clockinfosMain[a] || []; + clockinfosMain[a][b] = true; + ci.show(); + ci.on("redraw", clockinfoRedraw); + } + g.setFont("Vector", py(10)).setFontAlign(-1, -1).drawString(text, px(2), py((start - (data.rows.length - 1) * 10) + r * 10)); + } + } + + g.setFont("Vector", py(20)).setFontAlign(-1, -1).drawString((require("locale").time(new Date(), 1).replace(" ", "")), px(2), py(start - ((data.rows.length + 2)*10))); + g.setFont("Vector", py(10)).drawString(require('locale').dow(new Date(), 1)+" "+new Date().getDate()+" "+require('locale').month(new Date(), 1)+((data.temp == undefined) ? "" : " | "+require('locale').temp(Math.round(data.temp-273.15)).replace(".0", "")), px(2), py(start - data.rows.length * 10)); if (data.showWidgets) { Bangle.drawWidgets(); @@ -209,6 +236,7 @@ function draw(color) { } function setWeather() { + if (showingSettings) return; var a = {}; //clear day/night is default weather if ((data.code >= 800 && data.code <=802) || data.code == undefined) { @@ -370,7 +398,73 @@ global.GB = (event) => { if (_GB) setTimeout(_GB, 0, event); }; +function drawClkinfoSettings() { + if (drawTimeout) clearTimeout(drawTimeout); + g.clear(); + g.setColor(g.theme.fg); + g.setFont("Vector", py(10)).setFontAlign(-1, -1).drawString(" { + g.reset().clearRect(options.x-1, options.y, options.x+options.w+1, options.y+options.h); + if (options.focus) g.drawRect(options.x-1, options.y, options.x+options.w+1, options.y+options.h); + g.setFont("Vector", py(10)).setFontAlign(-1, 0).drawString(info.text, options.x, options.y+options.h/2); + } + }); +} + +function saveClockinfos() { + data.rows = []; + for (let r = 0; r < clockinfosSettings.length; r++) { + data.rows[r] = { + menuA: clockinfosSettings[r].menuA, + menuB: clockinfosSettings[r].menuB + } + clockinfosSettings[r].remove(); + } + require("Storage").writeJSON("mtnclock.json", data); +} + var drawTimeout; +var redrawTimeout; + +function clockinfoRedraw() { + // Limit redraws to every second + if (!redrawTimeout) { + redrawTimeout = setTimeout(function() { + setWeather(); + clearTimeout(redrawTimeout); + redrawTimeout = undefined; + }, 1000); + } +} //update watchface in next minute function queueDraw() { @@ -383,6 +477,41 @@ function queueDraw() { }, 60000 - (Date.now() % 60000)); } +function checkTouchBack(xy) { + return xy.x <= px(33) && xy.y < py(25); +} + +function checkTouchMinus(xy) { + return xy.x > px(33) && xy.x < px(67) && xy.y < px(25); +} + +function checkTouchPlus(xy) { + return xy.x >= px(67) && xy.y < px(25); +} + +Bangle.on('touch', function(b, xy) { + // Bangle.js 2 supports long touch (type 2) + // On other devices, any touch will show the settings + if (!showingSettings && (xy.type == 2 || process.env.HWVERSION != 2)) { + drawClkinfoSettings(); + showingSettings = true; + } else if (checkTouchBack(xy)) { + showingSettings = false; + saveClockinfos(); + queueDraw(); + // call setWeather after a timeout because for some reason a clockinfo + // can still draw for a little bit despite calling remove() on it + setTimeout(setWeather, 100); + } else if (checkTouchMinus(xy) && clockinfosSettings.length > 0) { + let cl = clockinfosSettings[clockinfosSettings.length - 1]; + cl.remove(); + g.reset().clearRect(cl.x, cl.y, cl.x+cl.w-2, cl.y+cl.h-1); + clockinfosSettings.pop(); + } else if (checkTouchPlus(xy) && clockinfosSettings.length < 3) { + addClockinfo(clockinfosSettings.length) + } +}); + queueDraw(); readWeather(); setWeather(); diff --git a/apps/mtnclock/metadata.json b/apps/mtnclock/metadata.json index cb622a2fb3..c88596d5fa 100644 --- a/apps/mtnclock/metadata.json +++ b/apps/mtnclock/metadata.json @@ -2,7 +2,7 @@ "id": "mtnclock", "name": "Mountain Pass Clock", "shortName": "Mtn Clock", - "version": "0.06", + "version": "0.07", "description": "A clock that changes scenery based on time and weather.", "readme":"README.md", "icon": "app.png", @@ -14,8 +14,9 @@ {"url":"screenshot5.png"} ], "type": "clock", - "tags": "clock", + "tags": "clock,clkinfo", "supports": ["BANGLEJS","BANGLEJS2"], + "dependencies" : { "clock_info":"module"}, "allow_emulator": true, "storage": [ {"name":"mtnclock.app.js","url":"app.js"}, From cebf64e8644b4eb6a924a84eeee8e31ca5343a26 Mon Sep 17 00:00:00 2001 From: David Holdeman Date: Wed, 22 Oct 2025 18:50:46 +0800 Subject: [PATCH 4/7] Add screenshots --- apps/mtnclock/README.md | 2 ++ apps/mtnclock/screenshot6.png | Bin 0 -> 9459 bytes apps/mtnclock/screenshot7.png | Bin 0 -> 2582 bytes 3 files changed, 2 insertions(+) create mode 100644 apps/mtnclock/screenshot6.png create mode 100644 apps/mtnclock/screenshot7.png diff --git a/apps/mtnclock/README.md b/apps/mtnclock/README.md index cba5b9ee23..e4cde8cd6e 100644 --- a/apps/mtnclock/README.md +++ b/apps/mtnclock/README.md @@ -21,3 +21,5 @@ Special thanks to Serj for testing this on the original Bangle. ![](screenshot3.png) ![](screenshot4.png) ![](screenshot5.png) +![](screenshot6.png) +![](screenshot7.png) diff --git a/apps/mtnclock/screenshot6.png b/apps/mtnclock/screenshot6.png new file mode 100644 index 0000000000000000000000000000000000000000..91a87089bfede6404092a7577d3c8b6bd9d700d6 GIT binary patch literal 9459 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 Date: Thu, 23 Oct 2025 17:29:09 +0800 Subject: [PATCH 5/7] Use object instead of array for clockinfosMain --- apps/mtnclock/app.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/mtnclock/app.js b/apps/mtnclock/app.js index 557413e360..d068e0009a 100644 --- a/apps/mtnclock/app.js +++ b/apps/mtnclock/app.js @@ -7,7 +7,7 @@ if (! Array.isArray(data.rows)) { let showingSettings = false; let clockinfosSettings = []; -let clockinfosMain = []; +let clockinfosMain = {}; let clockinfos = require("clock_info").load(); let weather; @@ -218,7 +218,7 @@ function draw(color) { let ci = clockinfos[a].items[b]; let text = ci.get().text; if (!(clockinfosMain[a] && clockinfosMain[a][b])) { - clockinfosMain[a] = clockinfosMain[a] || []; + clockinfosMain[a] = clockinfosMain[a] || {}; clockinfosMain[a][b] = true; ci.show(); ci.on("redraw", clockinfoRedraw); @@ -420,7 +420,7 @@ function drawClkinfoSettings() { } addClockinfo(r) } - clockinfosMain = []; + clockinfosMain = {}; } function addClockinfo(r) { From 11f337faa96636d37ba22670192f0a4b7f998657 Mon Sep 17 00:00:00 2001 From: David Holdeman Date: Thu, 23 Oct 2025 17:49:15 +0800 Subject: [PATCH 6/7] Use forEach as per espruino.com/Performance --- apps/mtnclock/app.js | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/apps/mtnclock/app.js b/apps/mtnclock/app.js index d068e0009a..41cc7e6b15 100644 --- a/apps/mtnclock/app.js +++ b/apps/mtnclock/app.js @@ -211,9 +211,9 @@ function draw(color) { //clock text (color.clock == undefined) ? g.setColor(0xFFFF) : g.setColor(color.clock); const start = 87; - for (let r = 0; r < data.rows.length; r++) { - let a = data.rows[r].menuA; - let b = data.rows[r].menuB; + data.rows.forEach(function(row, r) { + let a = row.menuA; + let b = row.menuB; if (clockinfos[a] && clockinfos[a].items[b]) { let ci = clockinfos[a].items[b]; let text = ci.get().text; @@ -225,7 +225,7 @@ function draw(color) { } g.setFont("Vector", py(10)).setFontAlign(-1, -1).drawString(text, px(2), py((start - (data.rows.length - 1) * 10) + r * 10)); } - } + }); g.setFont("Vector", py(20)).setFontAlign(-1, -1).drawString((require("locale").time(new Date(), 1).replace(" ", "")), px(2), py(start - ((data.rows.length + 2)*10))); g.setFont("Vector", py(10)).drawString(require('locale').dow(new Date(), 1)+" "+new Date().getDate()+" "+require('locale').month(new Date(), 1)+((data.temp == undefined) ? "" : " | "+require('locale').temp(Math.round(data.temp-273.15)).replace(".0", "")), px(2), py(start - data.rows.length * 10)); @@ -409,9 +409,9 @@ function drawClkinfoSettings() { g.setFont("Vector", py(10)).setFontAlign(0, -1).drawString("+", px(83), py(9)); g.drawRect(px(67), 1, px(100)-1, px(25)-1); - for (let r = 0; r < data.rows.length; r++) { - let a = data.rows[r].menuA; - let b = data.rows[r].menuB; + data.rows.forEach(function(row, r) { + let a = row.menuA; + let b = row.menuB; let ci = clockinfos[a].items[b]; if (clockinfosMain[a] && clockinfosMain[a][b]) { clockinfosMain[a][b] = false; @@ -419,7 +419,7 @@ function drawClkinfoSettings() { ci.removeListener("redraw", clockinfoRedraw); } addClockinfo(r) - } + }); clockinfosMain = {}; } @@ -442,13 +442,13 @@ function addClockinfo(r) { function saveClockinfos() { data.rows = []; - for (let r = 0; r < clockinfosSettings.length; r++) { + clockinfosSettings.forEach(function(row, r) { data.rows[r] = { - menuA: clockinfosSettings[r].menuA, - menuB: clockinfosSettings[r].menuB + menuA: row.menuA, + menuB: row.menuB } - clockinfosSettings[r].remove(); - } + row.remove(); + }); require("Storage").writeJSON("mtnclock.json", data); } From 07083dc7efe8a83fcab941fb8d456aaf6f645039 Mon Sep 17 00:00:00 2001 From: David Holdeman Date: Fri, 31 Oct 2025 17:20:40 +0800 Subject: [PATCH 7/7] Move clockinfo config to settings --- apps/mtnclock/app.js | 92 ------------------------------- apps/mtnclock/settings.js | 112 +++++++++++++++++++++++++++++++++++++- 2 files changed, 109 insertions(+), 95 deletions(-) diff --git a/apps/mtnclock/app.js b/apps/mtnclock/app.js index 41cc7e6b15..16535cb5b9 100644 --- a/apps/mtnclock/app.js +++ b/apps/mtnclock/app.js @@ -5,8 +5,6 @@ if (! Array.isArray(data.rows)) { require("Storage").writeJSON("mtnclock.json", data); } -let showingSettings = false; -let clockinfosSettings = []; let clockinfosMain = {}; let clockinfos = require("clock_info").load(); @@ -236,7 +234,6 @@ function draw(color) { } function setWeather() { - if (showingSettings) return; var a = {}; //clear day/night is default weather if ((data.code >= 800 && data.code <=802) || data.code == undefined) { @@ -398,60 +395,6 @@ global.GB = (event) => { if (_GB) setTimeout(_GB, 0, event); }; -function drawClkinfoSettings() { - if (drawTimeout) clearTimeout(drawTimeout); - g.clear(); - g.setColor(g.theme.fg); - g.setFont("Vector", py(10)).setFontAlign(-1, -1).drawString(" { - g.reset().clearRect(options.x-1, options.y, options.x+options.w+1, options.y+options.h); - if (options.focus) g.drawRect(options.x-1, options.y, options.x+options.w+1, options.y+options.h); - g.setFont("Vector", py(10)).setFontAlign(-1, 0).drawString(info.text, options.x, options.y+options.h/2); - } - }); -} - -function saveClockinfos() { - data.rows = []; - clockinfosSettings.forEach(function(row, r) { - data.rows[r] = { - menuA: row.menuA, - menuB: row.menuB - } - row.remove(); - }); - require("Storage").writeJSON("mtnclock.json", data); -} - var drawTimeout; var redrawTimeout; @@ -477,41 +420,6 @@ function queueDraw() { }, 60000 - (Date.now() % 60000)); } -function checkTouchBack(xy) { - return xy.x <= px(33) && xy.y < py(25); -} - -function checkTouchMinus(xy) { - return xy.x > px(33) && xy.x < px(67) && xy.y < px(25); -} - -function checkTouchPlus(xy) { - return xy.x >= px(67) && xy.y < px(25); -} - -Bangle.on('touch', function(b, xy) { - // Bangle.js 2 supports long touch (type 2) - // On other devices, any touch will show the settings - if (!showingSettings && (xy.type == 2 || process.env.HWVERSION != 2)) { - drawClkinfoSettings(); - showingSettings = true; - } else if (checkTouchBack(xy)) { - showingSettings = false; - saveClockinfos(); - queueDraw(); - // call setWeather after a timeout because for some reason a clockinfo - // can still draw for a little bit despite calling remove() on it - setTimeout(setWeather, 100); - } else if (checkTouchMinus(xy) && clockinfosSettings.length > 0) { - let cl = clockinfosSettings[clockinfosSettings.length - 1]; - cl.remove(); - g.reset().clearRect(cl.x, cl.y, cl.x+cl.w-2, cl.y+cl.h-1); - clockinfosSettings.pop(); - } else if (checkTouchPlus(xy) && clockinfosSettings.length < 3) { - addClockinfo(clockinfosSettings.length) - } -}); - queueDraw(); readWeather(); setWeather(); diff --git a/apps/mtnclock/settings.js b/apps/mtnclock/settings.js index d2877e281e..0bf6cbf3a0 100644 --- a/apps/mtnclock/settings.js +++ b/apps/mtnclock/settings.js @@ -7,22 +7,128 @@ var SETTINGS = Object.assign({ // default values showWidgets: false, + rows: [] }, STORAGE.readJSON(FILE, true) || {}); function writeSettings() { STORAGE.writeJSON(FILE, SETTINGS); } + let showingClockinfos = false; + let clockinfosSettings = []; + let clockinfos = require("clock_info").load(); + // Show the menu - E.showMenu({ + let menu = { "" : { "title" : "Mountain Clock" }, "< Back" : () => back(), 'Show widgets': { value: !!SETTINGS.showWidgets, // !! converts undefined to false - onchange: value => { + onchange: (value) => { SETTINGS.showWidgets = value; writeSettings(); } }, - }); + 'Edit Clockinfos': () => { + showingClockinfos = true; + drawClockinfoSettings(); + }, + }; + + E.showMenu(menu); + + function drawClockinfoSettings() { + Bangle.setUI(undefined); + require("widget_utils").hide(); + g.clear(); + g.setColor(g.theme.fg); + g.setFont("Vector", py(10)).setFontAlign(-1, -1).drawString(" { + g.reset().clearRect(options.x-1, options.y, options.x+options.w+1, options.y+options.h); + if (options.focus) g.drawRect(options.x-1, options.y, options.x+options.w+1, options.y+options.h); + g.setFont("Vector", py(10)).setFontAlign(-1, 0).drawString(info.text, options.x, options.y+options.h/2); + } + }); + } + + function saveClockinfos() { + SETTINGS.rows = []; + clockinfosSettings.forEach(function(row, r) { + SETTINGS.rows[r] = { + menuA: row.menuA, + menuB: row.menuB + } + row.remove(); + }); + console.log(JSON.stringify(SETTINGS)); + writeSettings(); + } + + //scale x, y coords to screen + function px(x) { + return x*g.getWidth()/100; + } + + function py(y) { + return y*g.getHeight()/100; + } + + function checkTouchBack(xy) { + return xy.x <= px(33) && xy.y < py(25); + } + + function checkTouchMinus(xy) { + return xy.x > px(33) && xy.x < px(67) && xy.y < px(25); + } + + function checkTouchPlus(xy) { + return xy.x >= px(67) && xy.y < px(25); + } + + Bangle.on('touch', function(b, xy) { + if (!showingClockinfos) return; + // Bangle.js 2 supports long touch (type 2) + // On other devices, any touch will show the settings + if (checkTouchBack(xy)) { + showingClockinfos = false; + saveClockinfos(); + // call setWeather after a timeout because for some reason a clockinfo + // can still draw for a little bit despite calling remove() on it + setTimeout(() => { + Bangle.setUI({ + mode: "custom", + back: back, + }); + require("widget_utils").show(); + E.showMenu(menu); + }, 100); + } else if (checkTouchMinus(xy) && clockinfosSettings.length > 0) { + let cl = clockinfosSettings[clockinfosSettings.length - 1]; + cl.remove(); + g.reset().clearRect(cl.x, cl.y, cl.x+cl.w-2, cl.y+cl.h-1); + clockinfosSettings.pop(); + } else if (checkTouchPlus(xy) && clockinfosSettings.length < 3) { + addClockinfo(clockinfosSettings.length) + } + }); })