From 87f0ffcd96ee6c71432523b5d4ec3440fa757d96 Mon Sep 17 00:00:00 2001 From: Adam Schmalhofer Date: Sat, 18 Dec 2021 00:08:04 +0100 Subject: [PATCH 001/315] widhwt: Ported to Bangle.js2 Tactically all that was needed was to state that it works with Bangle.js2. However the swipe gesture interfered with using the menu on Bangle.js2. So it has been deactivated and we recommend using Pattern Launcher instead. --- apps.json | 7 ++++--- apps/widhwt/ChangeLog | 1 + apps/widhwt/app.js | 11 +++++++++++ apps/widhwt/widget.js | 14 ++++++++++---- 4 files changed, 26 insertions(+), 7 deletions(-) create mode 100644 apps/widhwt/app.js diff --git a/apps.json b/apps.json index 8b4e86d52..f69889d50 100644 --- a/apps.json +++ b/apps.json @@ -1889,12 +1889,13 @@ { "id": "widhwt", "name": "Hand Wash Timer", - "version": "0.01", - "description": "Swipe your wrist over the watch face to start your personal Bangle.js hand wash timer for 35 sec. Start washing after the short buzz and stop after the long buzz.", + "version": "0.02-rc6", + "description": "On Bangle.js 1 swipe your wrist over the watch face to start your personal Bangle.js 1 hand wash timer. On Bangle.js2 the Pattern Launcher is recommended to start the timer. Start washing after the short buzz and stop after the long buzz 35sec. later.", "icon": "widget.png", "type": "widget", "tags": "widget,tool", - "supports": ["BANGLEJS"], + "allow_emulator": true, + "supports": ["BANGLEJS", "BANGLEJS2"], "storage": [ {"name":"widhwt.wid.js","url":"widget.js"} ] diff --git a/apps/widhwt/ChangeLog b/apps/widhwt/ChangeLog index 4c21f3ace..76c4fcec9 100644 --- a/apps/widhwt/ChangeLog +++ b/apps/widhwt/ChangeLog @@ -1 +1,2 @@ 0.01: New Widget! +0.02: Ported to Bangle.js2 diff --git a/apps/widhwt/app.js b/apps/widhwt/app.js new file mode 100644 index 000000000..68555d21d --- /dev/null +++ b/apps/widhwt/app.js @@ -0,0 +1,11 @@ +// Replace the "Loading..." box +// with our own message +g.clearRect(38, 68, 138, 108); +g.drawRect(38, 68, 138, 108); +g.setFontVector(13).drawString("Wash...", 60, 82); + +Bangle.buzz(); +setTimeout(() => { + Bangle.buzz(1E3, 1); + setTimeout(() => load(), 2E3); +}, 35E3); diff --git a/apps/widhwt/widget.js b/apps/widhwt/widget.js index d178a5b5d..5e1f95a41 100644 --- a/apps/widhwt/widget.js +++ b/apps/widhwt/widget.js @@ -6,9 +6,7 @@ g.reset().setColor(color).drawImage(require("heatshrink").decompress(atob("jEYwIKHgwCBhwCBh4CEggPCkACBmAXDBwVZ+EB+F4gEsjl8EgMP+EChk/gEMh+ehkA+YIBxwxBnF/4HggH/wEAj0AA==")), this.x + 1, 0); } - WIDGETS["widhwt"] = { area: "tr", width: 26, draw: draw }; - - Bangle.on('swipe', function() { + function startTimer() { color = 0x41f; Bangle.buzz(); Bangle.drawWidgets(); @@ -17,6 +15,14 @@ Bangle.buzz(1E3, 1); Bangle.drawWidgets(); }, 35E3); + } - }); + if (process.env.HWVERSION == 1) { + WIDGETS["widhwt"] = { + area: "tr", + width: 26, + draw: draw, + }; + Bangle.on('swipe', startTimer); + } })(); From d51c6679fe342ccb6058184b345ebc4e4816a98c Mon Sep 17 00:00:00 2001 From: Adam Schmalhofer Date: Sat, 18 Dec 2021 14:57:19 +0100 Subject: [PATCH 002/315] Bumped hwt version number --- apps.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps.json b/apps.json index f69889d50..b4acc8f0c 100644 --- a/apps.json +++ b/apps.json @@ -1889,7 +1889,7 @@ { "id": "widhwt", "name": "Hand Wash Timer", - "version": "0.02-rc6", + "version": "0.02-rc7", "description": "On Bangle.js 1 swipe your wrist over the watch face to start your personal Bangle.js 1 hand wash timer. On Bangle.js2 the Pattern Launcher is recommended to start the timer. Start washing after the short buzz and stop after the long buzz 35sec. later.", "icon": "widget.png", "type": "widget", From c5536ee49a6508da2e7a1fac1298bdf9ed00ddba Mon Sep 17 00:00:00 2001 From: Adam Schmalhofer Date: Sat, 18 Dec 2021 17:37:04 +0100 Subject: [PATCH 003/315] hwt: Center "Wash ..." text properly --- apps.json | 2 +- apps/widhwt/app.js | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/apps.json b/apps.json index b4acc8f0c..092584ecf 100644 --- a/apps.json +++ b/apps.json @@ -1889,7 +1889,7 @@ { "id": "widhwt", "name": "Hand Wash Timer", - "version": "0.02-rc7", + "version": "0.02-rc8", "description": "On Bangle.js 1 swipe your wrist over the watch face to start your personal Bangle.js 1 hand wash timer. On Bangle.js2 the Pattern Launcher is recommended to start the timer. Start washing after the short buzz and stop after the long buzz 35sec. later.", "icon": "widget.png", "type": "widget", diff --git a/apps/widhwt/app.js b/apps/widhwt/app.js index 68555d21d..2aaf7f08a 100644 --- a/apps/widhwt/app.js +++ b/apps/widhwt/app.js @@ -2,7 +2,9 @@ // with our own message g.clearRect(38, 68, 138, 108); g.drawRect(38, 68, 138, 108); -g.setFontVector(13).drawString("Wash...", 60, 82); +g.setFontVector(13).setFontAlign(0, 0, 0).drawString("Wash...", + g.getWidth()/2, + g.getHeight()/2); Bangle.buzz(); setTimeout(() => { From 51422c44c0fc89874b96fc893b3d06014de0f771 Mon Sep 17 00:00:00 2001 From: Adam Schmalhofer Date: Sat, 18 Dec 2021 18:46:16 +0100 Subject: [PATCH 004/315] hwt: Reduce line lenght --- apps.json | 2 +- apps/widhwt/app.js | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apps.json b/apps.json index 092584ecf..cb991dbed 100644 --- a/apps.json +++ b/apps.json @@ -1889,7 +1889,7 @@ { "id": "widhwt", "name": "Hand Wash Timer", - "version": "0.02-rc8", + "version": "0.02-rc9", "description": "On Bangle.js 1 swipe your wrist over the watch face to start your personal Bangle.js 1 hand wash timer. On Bangle.js2 the Pattern Launcher is recommended to start the timer. Start washing after the short buzz and stop after the long buzz 35sec. later.", "icon": "widget.png", "type": "widget", diff --git a/apps/widhwt/app.js b/apps/widhwt/app.js index 2aaf7f08a..f18e78643 100644 --- a/apps/widhwt/app.js +++ b/apps/widhwt/app.js @@ -2,9 +2,9 @@ // with our own message g.clearRect(38, 68, 138, 108); g.drawRect(38, 68, 138, 108); -g.setFontVector(13).setFontAlign(0, 0, 0).drawString("Wash...", - g.getWidth()/2, - g.getHeight()/2); +g.setFontVector(13); +g.setFontAlign(0, 0, 0); +g.drawString("Wash...", g.getWidth()/2, g.getHeight()/2); Bangle.buzz(); setTimeout(() => { From 505ed38753a1a6611b9f5da7f4aa32789f0f69a0 Mon Sep 17 00:00:00 2001 From: Adam Schmalhofer Date: Sat, 18 Dec 2021 22:14:26 +0100 Subject: [PATCH 005/315] hwt: Add app.js to apps.json --- apps.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps.json b/apps.json index cb991dbed..d572a9aad 100644 --- a/apps.json +++ b/apps.json @@ -1889,7 +1889,7 @@ { "id": "widhwt", "name": "Hand Wash Timer", - "version": "0.02-rc9", + "version": "0.02-rc10", "description": "On Bangle.js 1 swipe your wrist over the watch face to start your personal Bangle.js 1 hand wash timer. On Bangle.js2 the Pattern Launcher is recommended to start the timer. Start washing after the short buzz and stop after the long buzz 35sec. later.", "icon": "widget.png", "type": "widget", @@ -1897,6 +1897,7 @@ "allow_emulator": true, "supports": ["BANGLEJS", "BANGLEJS2"], "storage": [ + {"name":"widhwt.app.js","url":"app.js"}, {"name":"widhwt.wid.js","url":"widget.js"} ] }, From 03a295a4ff40d9c664f155324d139ffb007e76eb Mon Sep 17 00:00:00 2001 From: Adam Schmalhofer Date: Sun, 19 Dec 2021 12:00:43 +0100 Subject: [PATCH 006/315] wohrm: prepare porting to Bangle.js2 --- apps.json | 4 ++-- apps/wohrm/README.md | 5 ++++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/apps.json b/apps.json index e5e9f8f02..07c773725 100644 --- a/apps.json +++ b/apps.json @@ -1714,12 +1714,12 @@ { "id": "wohrm", "name": "Workout HRM", - "version": "0.08", + "version": "0.09-rc1", "description": "Workout heart rate monitor notifies you with a buzz if your heart rate goes above or below the set limits.", "icon": "app.png", "type": "app", "tags": "hrm,workout", - "supports": ["BANGLEJS"], + "supports": ["BANGLEJS", "BANGLEJS2"], "readme": "README.md", "allow_emulator": true, "screenshots": [{"url":"bangle1-workout-HRM-screenshot.png"}], diff --git a/apps/wohrm/README.md b/apps/wohrm/README.md index ad9e82525..87b1a65da 100644 --- a/apps/wohrm/README.md +++ b/apps/wohrm/README.md @@ -8,6 +8,9 @@ and will notify you with a buzz whenever your heart rate falls below or jumps ab [Try it out](https://www.espruino.com/ide/emulator.html?codeurl=https://raw.githubusercontent.com/msdeibel/BangleApps/master/apps/wohrm/app.js&upload) using the [online Espruino emulator](https://www.espruino.com/ide/emulator.html). ## Setting the limits + +Use the settings menu to set the limits. On the Bangle.js1 these can in addition be set with the buttons: + For setting the lower limit press button 4 (left part of the watch's touch screen). Then adjust the value with the buttons 1 (top) and 3 (bottom) of the watch. @@ -22,7 +25,7 @@ the received value: For 85% and above the bars are green, between 84% and 50% th and below 50% they turn red. ## Closing the app -Pressing button 2 (middle) will switch off the HRM of the watch and return you to the launcher. +Pressing middle button will switch off the HRM of the watch and return you to the launcher. # HRM usage The HRM is switched on when the app is started. It stays switch on while the app is running, even From e91324c16bc9b10dde21e14468933a5500979d05 Mon Sep 17 00:00:00 2001 From: Adam Schmalhofer Date: Sun, 19 Dec 2021 12:11:27 +0100 Subject: [PATCH 007/315] wohrm: Prevent crash on BangleJs2 --- apps/wohrm/app.js | 655 +++++++++++++++++++++++----------------------- 1 file changed, 328 insertions(+), 327 deletions(-) diff --git a/apps/wohrm/app.js b/apps/wohrm/app.js index c9c060e99..01fcca63e 100644 --- a/apps/wohrm/app.js +++ b/apps/wohrm/app.js @@ -1,327 +1,328 @@ -/* eslint-disable no-undef */ -const Setter = { - NONE: "none", - UPPER: 'upper', - LOWER: 'lower' -}; - -const shortBuzzTimeInMs = 80; -const longBuzzTimeInMs = 400; - -let upperLimit = 130; -let upperLimitChanged = true; - -let lowerLimit = 100; -let lowerLimitChanged = true; - -let limitSetter = Setter.NONE; - -let currentHeartRate = 0; -let hrConfidence = -1; -let hrChanged = true; -let confidenceChanged = true; - -let setterHighlightTimeout; - -function renderUpperLimitBackground() { - g.setColor(1,0,0); - g.fillRect(125,40, 210, 70); - g.fillRect(180,70, 210, 200); - - //Round top left corner - g.fillEllipse(115,40,135,70); - - //Round top right corner - g.setColor(0,0,0); - g.fillRect(205,40, 210, 45); - g.setColor(1,0,0); - g.fillEllipse(190,40,210,50); - - //Round inner corner - g.fillRect(174,71, 179, 76); - g.setColor(0,0,0); - g.fillEllipse(160,71,179,82); - - //Round bottom - g.setColor(1,0,0); - g.fillEllipse(180,190, 210, 210); -} - -function renderLowerLimitBackground() { - g.setColor(0,0,1); - g.fillRect(10, 180, 100, 210); - g.fillRect(10, 50, 40, 180); - - //Rounded top - g.setColor(0,0,1); - g.fillEllipse(10,40, 40, 60); - - //Round bottom right corner - g.setColor(0,0,1); - g.fillEllipse(90,180,110,210); - - //Round inner corner - g.setColor(0,0,1); - g.fillRect(40,175,45,180); - g.setColor(0,0,0); - g.fillEllipse(41,170,60,179); - - //Round bottom left corner - g.setColor(0,0,0); - g.fillRect(10,205, 15, 210); - g.setColor(0,0,1); - g.fillEllipse(10,200,30,210); -} - -function drawTrainingHeartRate() { - //Only redraw if the display is on - if (Bangle.isLCDOn()) { - renderUpperLimit(); - - renderCurrentHeartRate(); - - renderLowerLimit(); - - renderConfidenceBars(); - } - - buzz(); -} - -function renderUpperLimit() { - if(!upperLimitChanged) { return; } - - g.setColor(1,0,0); - g.fillRect(125,40, 210, 70); - - if(limitSetter === Setter.UPPER){ - g.setColor(255,255, 0); - } else { - g.setColor(255,255,255); - } - g.setFontVector(13); - g.drawString("Upper: " + upperLimit, 125, 50); - - upperLimitChanged = false; -} - -function renderCurrentHeartRate() { - if(!hrChanged) { return; } - - g.setColor(255,255,255); - g.fillRect(55, 110, 165, 150); - - g.setColor(0,0,0); - g.setFontVector(24); - g.setFontAlign(1, -1, 0); - g.drawString(currentHeartRate, 130, 117); - - //Reset alignment to defaults - g.setFontAlign(-1, -1, 0); - - hrChanged = false; -} - -function renderLowerLimit() { - if(!lowerLimitChanged) { return; } - - g.setColor(0,0,1); - g.fillRect(10, 180, 100, 210); - - if(limitSetter === Setter.LOWER){ - g.setColor(255,255, 0); - } else { - g.setColor(255,255,255); - } - g.setFontVector(13); - g.drawString("Lower: " + lowerLimit, 20,190); - - lowerLimitChanged = false; -} - -function renderConfidenceBars(){ - if(!confidenceChanged) { return; } - - if(hrConfidence >= 85){ - g.setColor(0, 255, 0); - } else if (hrConfidence >= 50) { - g.setColor(255, 255, 0); - } else if(hrConfidence >= 0){ - g.setColor(255, 0, 0); - } else { - g.setColor(255, 255, 255); - } - - g.fillRect(45, 110, 55, 150); - g.fillRect(165, 110, 175, 150); - - confidenceChanged = false; -} - -function renderPlusMinusIcons() { - if (limitSetter === Setter.NONE) { - g.setColor(0, 0, 0); - } else { - g.setColor(1, 1, 1); - } - - g.setFontVector(14); - - //+ for Btn1 - g.drawString("+", 222, 50); - - //- for Btn3 - g.drawString("-", 222,165); - - return; -} - -function renderHomeIcon() { - //Home for Btn2 - g.setColor(1, 1, 1); - g.drawLine(220, 118, 227, 110); - g.drawLine(227, 110, 234, 118); - - g.drawPoly([222,117,222,125,232,125,232,117], false); - g.drawRect(226,120,229,125); -} - -function buzz() { - // Do not buzz if not confident - if(hrConfidence < 85) { return; } - - if(currentHeartRate > upperLimit) - { - Bangle.buzz(shortBuzzTimeInMs); - setTimeout(() => { Bangle.buzz(shortBuzzTimeInMs); }, shortBuzzTimeInMs * 2); - } - - if(currentHeartRate < lowerLimit) - { - Bangle.buzz(longBuzzTimeInMs); - } -} - -function onHrm(hrm){ - if(currentHeartRate !== hrm.bpm){ - currentHeartRate = hrm.bpm; - hrChanged = true; - } - - if(hrConfidence !== hrm.confidence) { - hrConfidence = hrm.confidence; - confidenceChanged = true; - } -} - -function setLimitSetterToLower() { - resetHighlightTimeout(); - - limitSetter = Setter.LOWER; - - upperLimitChanged = true; - lowerLimitChanged = true; - - renderUpperLimit(); - renderLowerLimit(); - renderPlusMinusIcons(); -} - -function setLimitSetterToUpper() { - resetHighlightTimeout(); - - limitSetter = Setter.UPPER; - - upperLimitChanged = true; - lowerLimitChanged = true; - - renderLowerLimit(); - renderUpperLimit(); - renderPlusMinusIcons(); -} - -function setLimitSetterToNone() { - limitSetter = Setter.NONE; - - upperLimitChanged = true; - lowerLimitChanged = true; - - renderLowerLimit(); - renderUpperLimit(); - renderPlusMinusIcons(); -} - -function incrementLimit() { - resetHighlightTimeout(); - - if (limitSetter === Setter.UPPER) { - upperLimit++; - renderUpperLimit(); - upperLimitChanged = true; - } else if(limitSetter === Setter.LOWER) { - lowerLimit++; - renderLowerLimit(); - lowerLimitChanged = true; - } -} - -function decrementLimit(){ - resetHighlightTimeout(); - - if (limitSetter === Setter.UPPER) { - upperLimit--; - renderUpperLimit(); - upperLimitChanged = true; - } else if(limitSetter === Setter.LOWER) { - lowerLimit--; - renderLowerLimit(); - lowerLimitChanged = true; - } -} - -function resetHighlightTimeout() { - if (setterHighlightTimeout) { - clearTimeout(setterHighlightTimeout); - } - - setterHighlightTimeout = setTimeout(setLimitSetterToNone, 2000); -} - -function switchOffApp(){ - Bangle.setHRMPower(0,"wohrm"); - Bangle.showLauncher(); -} - -Bangle.on('lcdPower', (on) => { - g.clear(); - if (on) { - Bangle.drawWidgets(); - - renderHomeIcon(); - renderLowerLimitBackground(); - renderUpperLimitBackground(); - lowerLimitChanged = true; - upperLimitChanged = true; - drawTrainingHeartRate(); - } -}); - -Bangle.setHRMPower(1,"wohrm"); -Bangle.on('HRM', onHrm); - -setWatch(incrementLimit, BTN1, {edge:"rising", debounce:50, repeat:true}); -setWatch(decrementLimit, BTN3, {edge:"rising", debounce:50, repeat:true}); -setWatch(setLimitSetterToLower, BTN4, {edge:"rising", debounce:50, repeat:true}); -setWatch(setLimitSetterToUpper, BTN5, { edge: "rising", debounce: 50, repeat: true }); - -setWatch(switchOffApp, BTN2, {edge:"falling", debounce:50, repeat:true}); - -g.clear(); -Bangle.loadWidgets(); -Bangle.drawWidgets(); - -renderHomeIcon(); -renderLowerLimitBackground(); -renderUpperLimitBackground(); - -setInterval(drawTrainingHeartRate, 1000); +/* eslint-disable no-undef */ +const Setter = { + NONE: "none", + UPPER: 'upper', + LOWER: 'lower' +}; + +const shortBuzzTimeInMs = 80; +const longBuzzTimeInMs = 400; + +let upperLimit = 130; +let upperLimitChanged = true; + +let lowerLimit = 100; +let lowerLimitChanged = true; + +let limitSetter = Setter.NONE; + +let currentHeartRate = 0; +let hrConfidence = -1; +let hrChanged = true; +let confidenceChanged = true; + +let setterHighlightTimeout; + +function renderUpperLimitBackground() { + g.setColor(1,0,0); + g.fillRect(125,40, 210, 70); + g.fillRect(180,70, 210, 200); + + //Round top left corner + g.fillEllipse(115,40,135,70); + + //Round top right corner + g.setColor(0,0,0); + g.fillRect(205,40, 210, 45); + g.setColor(1,0,0); + g.fillEllipse(190,40,210,50); + + //Round inner corner + g.fillRect(174,71, 179, 76); + g.setColor(0,0,0); + g.fillEllipse(160,71,179,82); + + //Round bottom + g.setColor(1,0,0); + g.fillEllipse(180,190, 210, 210); +} + +function renderLowerLimitBackground() { + g.setColor(0,0,1); + g.fillRect(10, 180, 100, 210); + g.fillRect(10, 50, 40, 180); + + //Rounded top + g.setColor(0,0,1); + g.fillEllipse(10,40, 40, 60); + + //Round bottom right corner + g.setColor(0,0,1); + g.fillEllipse(90,180,110,210); + + //Round inner corner + g.setColor(0,0,1); + g.fillRect(40,175,45,180); + g.setColor(0,0,0); + g.fillEllipse(41,170,60,179); + + //Round bottom left corner + g.setColor(0,0,0); + g.fillRect(10,205, 15, 210); + g.setColor(0,0,1); + g.fillEllipse(10,200,30,210); +} + +function drawTrainingHeartRate() { + //Only redraw if the display is on + if (Bangle.isLCDOn()) { + renderUpperLimit(); + + renderCurrentHeartRate(); + + renderLowerLimit(); + + renderConfidenceBars(); + } + + buzz(); +} + +function renderUpperLimit() { + if(!upperLimitChanged) { return; } + + g.setColor(1,0,0); + g.fillRect(125,40, 210, 70); + + if(limitSetter === Setter.UPPER){ + g.setColor(255,255, 0); + } else { + g.setColor(255,255,255); + } + g.setFontVector(13); + g.drawString("Upper: " + upperLimit, 125, 50); + + upperLimitChanged = false; +} + +function renderCurrentHeartRate() { + if(!hrChanged) { return; } + + g.setColor(255,255,255); + g.fillRect(55, 110, 165, 150); + + g.setColor(0,0,0); + g.setFontVector(24); + g.setFontAlign(1, -1, 0); + g.drawString(currentHeartRate, 130, 117); + + //Reset alignment to defaults + g.setFontAlign(-1, -1, 0); + + hrChanged = false; +} + +function renderLowerLimit() { + if(!lowerLimitChanged) { return; } + + g.setColor(0,0,1); + g.fillRect(10, 180, 100, 210); + + if(limitSetter === Setter.LOWER){ + g.setColor(255,255, 0); + } else { + g.setColor(255,255,255); + } + g.setFontVector(13); + g.drawString("Lower: " + lowerLimit, 20,190); + + lowerLimitChanged = false; +} + +function renderConfidenceBars(){ + if(!confidenceChanged) { return; } + + if(hrConfidence >= 85){ + g.setColor(0, 255, 0); + } else if (hrConfidence >= 50) { + g.setColor(255, 255, 0); + } else if(hrConfidence >= 0){ + g.setColor(255, 0, 0); + } else { + g.setColor(255, 255, 255); + } + + g.fillRect(45, 110, 55, 150); + g.fillRect(165, 110, 175, 150); + + confidenceChanged = false; +} + +function renderPlusMinusIcons() { + if (limitSetter === Setter.NONE) { + g.setColor(0, 0, 0); + } else { + g.setColor(1, 1, 1); + } + + g.setFontVector(14); + + //+ for Btn1 + g.drawString("+", 222, 50); + + //- for Btn3 + g.drawString("-", 222,165); + + return; +} + +function renderHomeIcon() { + //Home for Btn2 + g.setColor(1, 1, 1); + g.drawLine(220, 118, 227, 110); + g.drawLine(227, 110, 234, 118); + + g.drawPoly([222,117,222,125,232,125,232,117], false); + g.drawRect(226,120,229,125); +} + +function buzz() { + // Do not buzz if not confident + if(hrConfidence < 85) { return; } + + if(currentHeartRate > upperLimit) + { + Bangle.buzz(shortBuzzTimeInMs); + setTimeout(() => { Bangle.buzz(shortBuzzTimeInMs); }, shortBuzzTimeInMs * 2); + } + + if(currentHeartRate < lowerLimit) + { + Bangle.buzz(longBuzzTimeInMs); + } +} + +function onHrm(hrm){ + if(currentHeartRate !== hrm.bpm){ + currentHeartRate = hrm.bpm; + hrChanged = true; + } + + if(hrConfidence !== hrm.confidence) { + hrConfidence = hrm.confidence; + confidenceChanged = true; + } +} + +function setLimitSetterToLower() { + resetHighlightTimeout(); + + limitSetter = Setter.LOWER; + + upperLimitChanged = true; + lowerLimitChanged = true; + + renderUpperLimit(); + renderLowerLimit(); + renderPlusMinusIcons(); +} + +function setLimitSetterToUpper() { + resetHighlightTimeout(); + + limitSetter = Setter.UPPER; + + upperLimitChanged = true; + lowerLimitChanged = true; + + renderLowerLimit(); + renderUpperLimit(); + renderPlusMinusIcons(); +} + +function setLimitSetterToNone() { + limitSetter = Setter.NONE; + + upperLimitChanged = true; + lowerLimitChanged = true; + + renderLowerLimit(); + renderUpperLimit(); + renderPlusMinusIcons(); +} + +function incrementLimit() { + resetHighlightTimeout(); + + if (limitSetter === Setter.UPPER) { + upperLimit++; + renderUpperLimit(); + upperLimitChanged = true; + } else if(limitSetter === Setter.LOWER) { + lowerLimit++; + renderLowerLimit(); + lowerLimitChanged = true; + } +} + +function decrementLimit(){ + resetHighlightTimeout(); + + if (limitSetter === Setter.UPPER) { + upperLimit--; + renderUpperLimit(); + upperLimitChanged = true; + } else if(limitSetter === Setter.LOWER) { + lowerLimit--; + renderLowerLimit(); + lowerLimitChanged = true; + } +} + +function resetHighlightTimeout() { + if (setterHighlightTimeout) { + clearTimeout(setterHighlightTimeout); + } + + setterHighlightTimeout = setTimeout(setLimitSetterToNone, 2000); +} + +function switchOffApp(){ + Bangle.setHRMPower(0,"wohrm"); + Bangle.showLauncher(); +} + +Bangle.on('lcdPower', (on) => { + g.clear(); + if (on) { + Bangle.drawWidgets(); + + renderHomeIcon(); + renderLowerLimitBackground(); + renderUpperLimitBackground(); + lowerLimitChanged = true; + upperLimitChanged = true; + drawTrainingHeartRate(); + } +}); + +Bangle.setHRMPower(1,"wohrm"); +Bangle.on('HRM', onHrm); + +g.clear(); +Bangle.loadWidgets(); +Bangle.drawWidgets(); +renderLowerLimitBackground(); +renderUpperLimitBackground(); + +if (typeof(BTN5) !== typeof(undefined)) { + renderHomeIcon(); + setWatch(incrementLimit, BTN1, {edge:"rising", debounce:50, repeat:true}); + setWatch(decrementLimit, BTN3, {edge:"rising", debounce:50, repeat:true}); + setWatch(setLimitSetterToLower, BTN4, {edge:"rising", debounce:50, repeat:true}); + setWatch(setLimitSetterToUpper, BTN5, { edge: "rising", debounce: 50, repeat: true }); + + setWatch(switchOffApp, BTN2, {edge:"falling", debounce:50, repeat:true}); +} + +setInterval(drawTrainingHeartRate, 1000); From e98690a8533eefd23d23cd017b65c3b2def73aa1 Mon Sep 17 00:00:00 2001 From: Adam Schmalhofer Date: Sun, 19 Dec 2021 14:10:08 +0100 Subject: [PATCH 008/315] wohrm: parameterized renderUpperLimitBackground() --- apps/wohrm/app.js | 44 +++++++++++++++++++++++++++++++------------- 1 file changed, 31 insertions(+), 13 deletions(-) diff --git a/apps/wohrm/app.js b/apps/wohrm/app.js index 01fcca63e..ba037fc7c 100644 --- a/apps/wohrm/app.js +++ b/apps/wohrm/app.js @@ -24,27 +24,45 @@ let confidenceChanged = true; let setterHighlightTimeout; function renderUpperLimitBackground() { - g.setColor(1,0,0); - g.fillRect(125,40, 210, 70); - g.fillRect(180,70, 210, 200); + var minX=125; + var maxX=210; + var minY=40; + var maxY=210; + var rectWidth=30; + var cornerRoundness=5; + var bgColor = 0; + var fgColor = '#f00'; + g.setColor(fgColor); + + g.fillRect(minX,minY, maxX, minY+rectWidth); + g.fillRect(maxX-rectWidth, minY+rectWidth, maxX, maxY-cornerRoundness*2); //Round top left corner - g.fillEllipse(115,40,135,70); + g.fillEllipse(minX-cornerRoundness*2, + minY, + minX+cornerRoundness*2, + minY+rectWidth); //Round top right corner - g.setColor(0,0,0); - g.fillRect(205,40, 210, 45); - g.setColor(1,0,0); - g.fillEllipse(190,40,210,50); + g.setColor(bgColor); + g.fillRect(maxX-cornerRoundness,minY, maxX, minY+cornerRoundness); + g.setColor(fgColor); + g.fillEllipse(maxX-cornerRoundness*4,minY,maxX,minY+cornerRoundness*2); //Round inner corner - g.fillRect(174,71, 179, 76); - g.setColor(0,0,0); - g.fillEllipse(160,71,179,82); + g.fillRect(maxX-rectWidth-cornerRoundness-1, + minY+rectWidth+1, + maxX-rectWidth-1, + minY+rectWidth+cornerRoundness-1); + g.setColor(bgColor); + g.fillEllipse(maxX-rectWidth-cornerRoundness*4, + minY+rectWidth+1, + maxX-rectWidth-1, + minY+rectWidth+cornerRoundness*3-1); //Round bottom - g.setColor(1,0,0); - g.fillEllipse(180,190, 210, 210); + g.setColor(fgColor); + g.fillEllipse(maxX-rectWidth,maxY-cornerRoundness*4, maxX, maxY); } function renderLowerLimitBackground() { From 8c4f37e991fc3ab17ea6c24b7d15d813dc343b53 Mon Sep 17 00:00:00 2001 From: Adam Schmalhofer Date: Sun, 19 Dec 2021 14:30:12 +0100 Subject: [PATCH 009/315] wohrm: renderLshape() from renderUpperLimitBackground() --- apps/wohrm/app.js | 69 ++++++++++++++++++++++++----------------------- 1 file changed, 36 insertions(+), 33 deletions(-) diff --git a/apps/wohrm/app.js b/apps/wohrm/app.js index ba037fc7c..e73307773 100644 --- a/apps/wohrm/app.js +++ b/apps/wohrm/app.js @@ -23,46 +23,49 @@ let confidenceChanged = true; let setterHighlightTimeout; -function renderUpperLimitBackground() { - var minX=125; - var maxX=210; - var minY=40; - var maxY=210; - var rectWidth=30; - var cornerRoundness=5; - var bgColor = 0; - var fgColor = '#f00'; - g.setColor(fgColor); +const upperLshape = { + minX: 125, + maxX: 210, + minY: 40, + maxY: 210, + rectWidth: 30, + cornerRoundness: 5, + bgColor: 0, + fgColor: '#f00' +}; - g.fillRect(minX,minY, maxX, minY+rectWidth); - g.fillRect(maxX-rectWidth, minY+rectWidth, maxX, maxY-cornerRoundness*2); +function renderLshape(p) { + g.setColor(p.fgColor); + + g.fillRect(p.minX,p.minY, p.maxX, p.minY+p.rectWidth); + g.fillRect(p.maxX-p.rectWidth, p.minY+p.rectWidth, p.maxX, p.maxY-p.cornerRoundness*2); //Round top left corner - g.fillEllipse(minX-cornerRoundness*2, - minY, - minX+cornerRoundness*2, - minY+rectWidth); + g.fillEllipse(p.minX-p.cornerRoundness*2, + p.minY, + p.minX+p.cornerRoundness*2, + p.minY+p.rectWidth); //Round top right corner - g.setColor(bgColor); - g.fillRect(maxX-cornerRoundness,minY, maxX, minY+cornerRoundness); - g.setColor(fgColor); - g.fillEllipse(maxX-cornerRoundness*4,minY,maxX,minY+cornerRoundness*2); + g.setColor(p.bgColor); + g.fillRect(p.maxX-p.cornerRoundness,p.minY, p.maxX, p.minY+p.cornerRoundness); + g.setColor(p.fgColor); + g.fillEllipse(p.maxX-p.cornerRoundness*4,p.minY,p.maxX,p.minY+p.cornerRoundness*2); //Round inner corner - g.fillRect(maxX-rectWidth-cornerRoundness-1, - minY+rectWidth+1, - maxX-rectWidth-1, - minY+rectWidth+cornerRoundness-1); - g.setColor(bgColor); - g.fillEllipse(maxX-rectWidth-cornerRoundness*4, - minY+rectWidth+1, - maxX-rectWidth-1, - minY+rectWidth+cornerRoundness*3-1); + g.fillRect(p.maxX-p.rectWidth-p.cornerRoundness-1, + p.minY+p.rectWidth+1, + p.maxX-p.rectWidth-1, + p.minY+p.rectWidth+p.cornerRoundness-1); + g.setColor(p.bgColor); + g.fillEllipse(p.maxX-p.rectWidth-p.cornerRoundness*4, + p.minY+p.rectWidth+1, + p.maxX-p.rectWidth-1, + p.minY+p.rectWidth+p.cornerRoundness*3-1); //Round bottom - g.setColor(fgColor); - g.fillEllipse(maxX-rectWidth,maxY-cornerRoundness*4, maxX, maxY); + g.setColor(p.fgColor); + g.fillEllipse(p.maxX-p.rectWidth,p.maxY-p.cornerRoundness*4, p.maxX, p.maxY); } function renderLowerLimitBackground() { @@ -317,7 +320,7 @@ Bangle.on('lcdPower', (on) => { renderHomeIcon(); renderLowerLimitBackground(); - renderUpperLimitBackground(); + renderLshape(upperLshape); lowerLimitChanged = true; upperLimitChanged = true; drawTrainingHeartRate(); @@ -331,7 +334,7 @@ g.clear(); Bangle.loadWidgets(); Bangle.drawWidgets(); renderLowerLimitBackground(); -renderUpperLimitBackground(); +renderLshape(upperLshape); if (typeof(BTN5) !== typeof(undefined)) { renderHomeIcon(); From f4a7a4f77e78a24cb26490f100e29bdf75e02676 Mon Sep 17 00:00:00 2001 From: Adam Schmalhofer Date: Sun, 19 Dec 2021 15:28:26 +0100 Subject: [PATCH 010/315] wohrt: removed renderLowerLimitBackground() --- apps/wohrm/app.js | 102 ++++++++++++++++++++++++---------------------- 1 file changed, 54 insertions(+), 48 deletions(-) diff --git a/apps/wohrm/app.js b/apps/wohrm/app.js index e73307773..638627e17 100644 --- a/apps/wohrm/app.js +++ b/apps/wohrm/app.js @@ -30,68 +30,74 @@ const upperLshape = { maxY: 210, rectWidth: 30, cornerRoundness: 5, + orientation: -1, bgColor: 0, fgColor: '#f00' }; +const lowerLshape = { + maxX: 10, + minX: 100, + minY: 210, + maxY: 40, + rectWidth: 30, + cornerRoundness: 5, + orientation: 1, + bgColor: 0, + fgColor: '#00f' +}; + +function fillEllipse(x, y, x2, y2) { + g.fillEllipse(Math.min(x, x2), + Math.min(y, y2), + Math.max(x, x2), + Math.max(y, y2)); +} + function renderLshape(p) { g.setColor(p.fgColor); - g.fillRect(p.minX,p.minY, p.maxX, p.minY+p.rectWidth); - g.fillRect(p.maxX-p.rectWidth, p.minY+p.rectWidth, p.maxX, p.maxY-p.cornerRoundness*2); + g.fillRect(p.minX, p.minY, p.maxX, p.minY-p.orientation*p.rectWidth); + g.fillRect(p.maxX+p.orientation*p.rectWidth, + p.minY-p.orientation*p.rectWidth, + p.maxX, + p.maxY+p.orientation*p.cornerRoundness*2); - //Round top left corner - g.fillEllipse(p.minX-p.cornerRoundness*2, - p.minY, - p.minX+p.cornerRoundness*2, - p.minY+p.rectWidth); + //Round end of small line + fillEllipse(p.minX+p.orientation*p.cornerRoundness*2, + p.minY, + p.minX-p.orientation*p.cornerRoundness*2, + p.minY-p.orientation*p.rectWidth); - //Round top right corner + //Round outer corner g.setColor(p.bgColor); - g.fillRect(p.maxX-p.cornerRoundness,p.minY, p.maxX, p.minY+p.cornerRoundness); + g.fillRect(p.maxX+p.orientation*p.cornerRoundness, + p.minY, + p.maxX, + p.minY-p.orientation*p.cornerRoundness); g.setColor(p.fgColor); - g.fillEllipse(p.maxX-p.cornerRoundness*4,p.minY,p.maxX,p.minY+p.cornerRoundness*2); + fillEllipse(p.maxX+p.orientation*p.cornerRoundness*4, + p.minY, + p.maxX, + p.minY-p.orientation*p.cornerRoundness*2); //Round inner corner - g.fillRect(p.maxX-p.rectWidth-p.cornerRoundness-1, - p.minY+p.rectWidth+1, - p.maxX-p.rectWidth-1, - p.minY+p.rectWidth+p.cornerRoundness-1); + g.fillRect(p.maxX+p.orientation*(p.rectWidth+p.cornerRoundness+1), + p.minY-p.orientation*(p.rectWidth+1), + p.maxX+p.orientation*(p.rectWidth+1), + p.minY-p.orientation*(p.rectWidth+p.cornerRoundness-1)); g.setColor(p.bgColor); - g.fillEllipse(p.maxX-p.rectWidth-p.cornerRoundness*4, - p.minY+p.rectWidth+1, - p.maxX-p.rectWidth-1, - p.minY+p.rectWidth+p.cornerRoundness*3-1); + fillEllipse(p.maxX+p.orientation*(p.rectWidth+p.cornerRoundness*4), + p.minY-p.orientation*(p.rectWidth+1), + p.maxX+p.orientation*(p.rectWidth+1), + p.minY-p.orientation*(p.rectWidth+p.cornerRoundness*3-1)); - //Round bottom + //Round end of long line g.setColor(p.fgColor); - g.fillEllipse(p.maxX-p.rectWidth,p.maxY-p.cornerRoundness*4, p.maxX, p.maxY); -} - -function renderLowerLimitBackground() { - g.setColor(0,0,1); - g.fillRect(10, 180, 100, 210); - g.fillRect(10, 50, 40, 180); - - //Rounded top - g.setColor(0,0,1); - g.fillEllipse(10,40, 40, 60); - - //Round bottom right corner - g.setColor(0,0,1); - g.fillEllipse(90,180,110,210); - - //Round inner corner - g.setColor(0,0,1); - g.fillRect(40,175,45,180); - g.setColor(0,0,0); - g.fillEllipse(41,170,60,179); - - //Round bottom left corner - g.setColor(0,0,0); - g.fillRect(10,205, 15, 210); - g.setColor(0,0,1); - g.fillEllipse(10,200,30,210); + fillEllipse(p.maxX+p.orientation*p.rectWidth, + p.maxY+p.orientation*p.cornerRoundness*4, + p.maxX, + p.maxY); } function drawTrainingHeartRate() { @@ -319,7 +325,7 @@ Bangle.on('lcdPower', (on) => { Bangle.drawWidgets(); renderHomeIcon(); - renderLowerLimitBackground(); + renderLshape(lowerLshape); renderLshape(upperLshape); lowerLimitChanged = true; upperLimitChanged = true; @@ -333,7 +339,7 @@ Bangle.on('HRM', onHrm); g.clear(); Bangle.loadWidgets(); Bangle.drawWidgets(); -renderLowerLimitBackground(); +renderLshape(lowerLshape); renderLshape(upperLshape); if (typeof(BTN5) !== typeof(undefined)) { From 3e0e590b86a3a2282fd22ca03c37232410a35d94 Mon Sep 17 00:00:00 2001 From: Adam Schmalhofer Date: Sun, 19 Dec 2021 15:41:06 +0100 Subject: [PATCH 011/315] Add home buttom for Bangle.js2 --- apps/wohrm/app.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/wohrm/app.js b/apps/wohrm/app.js index 638627e17..de3db14e2 100644 --- a/apps/wohrm/app.js +++ b/apps/wohrm/app.js @@ -350,6 +350,8 @@ if (typeof(BTN5) !== typeof(undefined)) { setWatch(setLimitSetterToUpper, BTN5, { edge: "rising", debounce: 50, repeat: true }); setWatch(switchOffApp, BTN2, {edge:"falling", debounce:50, repeat:true}); +} else { + setWatch(switchOffApp, BTN1, {edge:"falling", debounce:50, repeat:true}); } setInterval(drawTrainingHeartRate, 1000); From 616f1f784f8780adce5f586ecc51e54b0c8a1a2a Mon Sep 17 00:00:00 2001 From: Adam Schmalhofer Date: Sun, 19 Dec 2021 15:46:56 +0100 Subject: [PATCH 012/315] wohrm: Don't draw home-icon on Banglejs2 --- apps/wohrm/app.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/wohrm/app.js b/apps/wohrm/app.js index de3db14e2..8e041fa98 100644 --- a/apps/wohrm/app.js +++ b/apps/wohrm/app.js @@ -320,11 +320,13 @@ function switchOffApp(){ } Bangle.on('lcdPower', (on) => { - g.clear(); if (on) { + g.clear(); Bangle.drawWidgets(); - renderHomeIcon(); + if (typeof(BTN5) !== typeof(undefined)) { + renderHomeIcon(); + } renderLshape(lowerLshape); renderLshape(upperLshape); lowerLimitChanged = true; From 9f33ded981cb117537350698292509eac4f4e24b Mon Sep 17 00:00:00 2001 From: Adam Schmalhofer Date: Sun, 19 Dec 2021 15:56:03 +0100 Subject: [PATCH 013/315] wohrm: Fixed rounding of outer corner --- apps/wohrm/app.js | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/apps/wohrm/app.js b/apps/wohrm/app.js index 8e041fa98..0681a3b33 100644 --- a/apps/wohrm/app.js +++ b/apps/wohrm/app.js @@ -118,8 +118,7 @@ function drawTrainingHeartRate() { function renderUpperLimit() { if(!upperLimitChanged) { return; } - g.setColor(1,0,0); - g.fillRect(125,40, 210, 70); + renderLshape(upperLshape); if(limitSetter === Setter.UPPER){ g.setColor(255,255, 0); @@ -152,8 +151,7 @@ function renderCurrentHeartRate() { function renderLowerLimit() { if(!lowerLimitChanged) { return; } - g.setColor(0,0,1); - g.fillRect(10, 180, 100, 210); + renderLshape(lowerLshape); if(limitSetter === Setter.LOWER){ g.setColor(255,255, 0); @@ -341,8 +339,6 @@ Bangle.on('HRM', onHrm); g.clear(); Bangle.loadWidgets(); Bangle.drawWidgets(); -renderLshape(lowerLshape); -renderLshape(upperLshape); if (typeof(BTN5) !== typeof(undefined)) { renderHomeIcon(); From 0d172f1db04b957f6b9520b61affde4f6952e92c Mon Sep 17 00:00:00 2001 From: Adam Schmalhofer Date: Sun, 19 Dec 2021 16:23:56 +0100 Subject: [PATCH 014/315] wohrm: place Upper/Lower relative to "L" --- apps/wohrm/app.js | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/apps/wohrm/app.js b/apps/wohrm/app.js index 0681a3b33..f761c421e 100644 --- a/apps/wohrm/app.js +++ b/apps/wohrm/app.js @@ -125,8 +125,10 @@ function renderUpperLimit() { } else { g.setColor(255,255,255); } - g.setFontVector(13); - g.drawString("Upper: " + upperLimit, 125, 50); + g.setFontVector(13).setFontAlign(-1, 0, 0); + g.drawString("Upper: " + upperLimit, + upperLshape.minX, + upperLshape.minY+upperLshape.rectWidth/2); upperLimitChanged = false; } @@ -158,8 +160,10 @@ function renderLowerLimit() { } else { g.setColor(255,255,255); } - g.setFontVector(13); - g.drawString("Lower: " + lowerLimit, 20,190); + g.setFontVector(13).setFontAlign(-1, 0, 0); + g.drawString("Lower: " + lowerLimit, + lowerLshape.maxX + lowerLshape.rectWidth/2, + lowerLshape.minY - lowerLshape.rectWidth/2); lowerLimitChanged = false; } From 09e7330ae0547eaa5270e2a175756167e04ccb2d Mon Sep 17 00:00:00 2001 From: Adam Schmalhofer Date: Sun, 19 Dec 2021 17:25:05 +0100 Subject: [PATCH 015/315] wohrm: parameterized centerBar --- apps/wohrm/app.js | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/apps/wohrm/app.js b/apps/wohrm/app.js index f761c421e..ef4a3013d 100644 --- a/apps/wohrm/app.js +++ b/apps/wohrm/app.js @@ -47,6 +47,14 @@ const lowerLshape = { fgColor: '#00f' }; +const centerBar = { + minY: (upperLshape.minY + upperLshape.maxY - upperLshape.rectWidth)/2, + maxY: (upperLshape.minY + upperLshape.maxY + upperLshape.rectWidth)/2, + confidenceWidth: 10, + minX: 55, + maxX: 165 +}; + function fillEllipse(x, y, x2, y2) { g.fillEllipse(Math.min(x, x2), Math.min(y, y2), @@ -136,13 +144,16 @@ function renderUpperLimit() { function renderCurrentHeartRate() { if(!hrChanged) { return; } - g.setColor(255,255,255); - g.fillRect(55, 110, 165, 150); + g.setColor(1, 1, 1); + g.fillRect(centerBar.minX, centerBar.minY, + centerBar.maxX, centerBar.maxY); g.setColor(0,0,0); g.setFontVector(24); - g.setFontAlign(1, -1, 0); - g.drawString(currentHeartRate, 130, 117); + g.setFontAlign(1, 0, 0); + g.drawString(currentHeartRate, + upperLshape.minX+upperLshape.cornerRoundness, + (centerBar.minY+centerBar.maxY)/2); //Reset alignment to defaults g.setFontAlign(-1, -1, 0); @@ -181,8 +192,8 @@ function renderConfidenceBars(){ g.setColor(255, 255, 255); } - g.fillRect(45, 110, 55, 150); - g.fillRect(165, 110, 175, 150); + g.fillRect(centerBar.minX-centerBar.confidenceWidth, centerBar.minY, centerBar.minX, centerBar.maxY); + g.fillRect(centerBar.maxX, centerBar.minY, centerBar.maxX+centerBar.confidenceWidth, centerBar.maxY); confidenceChanged = false; } From 0456843385231a1e817100386adf24026065204a Mon Sep 17 00:00:00 2001 From: Adam Schmalhofer Date: Sun, 19 Dec 2021 17:45:38 +0100 Subject: [PATCH 016/315] wohrm: Use theme colors --- apps/wohrm/app.js | 40 +++++++++++++++++++--------------------- 1 file changed, 19 insertions(+), 21 deletions(-) diff --git a/apps/wohrm/app.js b/apps/wohrm/app.js index ef4a3013d..63194f390 100644 --- a/apps/wohrm/app.js +++ b/apps/wohrm/app.js @@ -31,8 +31,7 @@ const upperLshape = { rectWidth: 30, cornerRoundness: 5, orientation: -1, - bgColor: 0, - fgColor: '#f00' + color: '#f00' }; const lowerLshape = { @@ -43,8 +42,7 @@ const lowerLshape = { rectWidth: 30, cornerRoundness: 5, orientation: 1, - bgColor: 0, - fgColor: '#00f' + color: '#00f' }; const centerBar = { @@ -63,7 +61,7 @@ function fillEllipse(x, y, x2, y2) { } function renderLshape(p) { - g.setColor(p.fgColor); + g.setColor(p.color); g.fillRect(p.minX, p.minY, p.maxX, p.minY-p.orientation*p.rectWidth); g.fillRect(p.maxX+p.orientation*p.rectWidth, @@ -78,12 +76,12 @@ function renderLshape(p) { p.minY-p.orientation*p.rectWidth); //Round outer corner - g.setColor(p.bgColor); + g.setColor(g.theme.bg); g.fillRect(p.maxX+p.orientation*p.cornerRoundness, p.minY, p.maxX, p.minY-p.orientation*p.cornerRoundness); - g.setColor(p.fgColor); + g.setColor(p.color); fillEllipse(p.maxX+p.orientation*p.cornerRoundness*4, p.minY, p.maxX, @@ -94,14 +92,14 @@ function renderLshape(p) { p.minY-p.orientation*(p.rectWidth+1), p.maxX+p.orientation*(p.rectWidth+1), p.minY-p.orientation*(p.rectWidth+p.cornerRoundness-1)); - g.setColor(p.bgColor); + g.setColor(g.theme.bg); fillEllipse(p.maxX+p.orientation*(p.rectWidth+p.cornerRoundness*4), p.minY-p.orientation*(p.rectWidth+1), p.maxX+p.orientation*(p.rectWidth+1), p.minY-p.orientation*(p.rectWidth+p.cornerRoundness*3-1)); //Round end of long line - g.setColor(p.fgColor); + g.setColor(p.color); fillEllipse(p.maxX+p.orientation*p.rectWidth, p.maxY+p.orientation*p.cornerRoundness*4, p.maxX, @@ -129,9 +127,9 @@ function renderUpperLimit() { renderLshape(upperLshape); if(limitSetter === Setter.UPPER){ - g.setColor(255,255, 0); + g.setColor(1,1,0); } else { - g.setColor(255,255,255); + g.setColor(g.theme.fg); } g.setFontVector(13).setFontAlign(-1, 0, 0); g.drawString("Upper: " + upperLimit, @@ -144,11 +142,11 @@ function renderUpperLimit() { function renderCurrentHeartRate() { if(!hrChanged) { return; } - g.setColor(1, 1, 1); + g.setColor(g.theme.fg); g.fillRect(centerBar.minX, centerBar.minY, centerBar.maxX, centerBar.maxY); - g.setColor(0,0,0); + g.setColor(g.theme.bg); g.setFontVector(24); g.setFontAlign(1, 0, 0); g.drawString(currentHeartRate, @@ -167,9 +165,9 @@ function renderLowerLimit() { renderLshape(lowerLshape); if(limitSetter === Setter.LOWER){ - g.setColor(255,255, 0); + g.setColor(1,1,0); } else { - g.setColor(255,255,255); + g.setColor(g.theme.fg); } g.setFontVector(13).setFontAlign(-1, 0, 0); g.drawString("Lower: " + lowerLimit, @@ -183,13 +181,13 @@ function renderConfidenceBars(){ if(!confidenceChanged) { return; } if(hrConfidence >= 85){ - g.setColor(0, 255, 0); + g.setColor(0, 1, 0); } else if (hrConfidence >= 50) { - g.setColor(255, 255, 0); + g.setColor(1, 1, 0); } else if(hrConfidence >= 0){ - g.setColor(255, 0, 0); + g.setColor(1, 0, 0); } else { - g.setColor(255, 255, 255); + g.setColor(g.theme.fg); } g.fillRect(centerBar.minX-centerBar.confidenceWidth, centerBar.minY, centerBar.minX, centerBar.maxY); @@ -200,9 +198,9 @@ function renderConfidenceBars(){ function renderPlusMinusIcons() { if (limitSetter === Setter.NONE) { - g.setColor(0, 0, 0); + g.setColor(g.theme.bg); } else { - g.setColor(1, 1, 1); + g.setColor(g.theme.fg); } g.setFontVector(14); From b513772692f129ad676b8f1dac15ecdf1419ce8f Mon Sep 17 00:00:00 2001 From: Adam Schmalhofer Date: Sun, 19 Dec 2021 17:51:55 +0100 Subject: [PATCH 017/315] wohrm: parameterized font sizes --- apps/wohrm/app.js | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/apps/wohrm/app.js b/apps/wohrm/app.js index 63194f390..bb21b5d59 100644 --- a/apps/wohrm/app.js +++ b/apps/wohrm/app.js @@ -53,6 +53,11 @@ const centerBar = { maxX: 165 }; +const fontSizes = { + limits: 13, + heartRate: 24 +}; + function fillEllipse(x, y, x2, y2) { g.fillEllipse(Math.min(x, x2), Math.min(y, y2), @@ -131,7 +136,7 @@ function renderUpperLimit() { } else { g.setColor(g.theme.fg); } - g.setFontVector(13).setFontAlign(-1, 0, 0); + g.setFontVector(fontSizes.limits).setFontAlign(-1, 0, 0); g.drawString("Upper: " + upperLimit, upperLshape.minX, upperLshape.minY+upperLshape.rectWidth/2); @@ -147,7 +152,7 @@ function renderCurrentHeartRate() { centerBar.maxX, centerBar.maxY); g.setColor(g.theme.bg); - g.setFontVector(24); + g.setFontVector(fontSizes.heartRate); g.setFontAlign(1, 0, 0); g.drawString(currentHeartRate, upperLshape.minX+upperLshape.cornerRoundness, @@ -169,7 +174,7 @@ function renderLowerLimit() { } else { g.setColor(g.theme.fg); } - g.setFontVector(13).setFontAlign(-1, 0, 0); + g.setFontVector(fontSizes.limits).setFontAlign(-1, 0, 0); g.drawString("Lower: " + lowerLimit, lowerLshape.maxX + lowerLshape.rectWidth/2, lowerLshape.minY - lowerLshape.rectWidth/2); From d5e08477e1692a7867f0c715070e58f0b7fddffd Mon Sep 17 00:00:00 2001 From: Adam Schmalhofer Date: Sun, 19 Dec 2021 17:59:57 +0100 Subject: [PATCH 018/315] wohrm: deduplicate --- apps/wohrm/app.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/wohrm/app.js b/apps/wohrm/app.js index bb21b5d59..6ebcdabc3 100644 --- a/apps/wohrm/app.js +++ b/apps/wohrm/app.js @@ -37,10 +37,10 @@ const upperLshape = { const lowerLshape = { maxX: 10, minX: 100, - minY: 210, - maxY: 40, - rectWidth: 30, - cornerRoundness: 5, + minY: upperLshape.maxY, + maxY: upperLshape.minY, + rectWidth: upperLshape.rectWidth, + cornerRoundness: upperLshape.cornerRoundness, orientation: 1, color: '#00f' }; From b120f7572f454426ab8bb912830e758f177134dd Mon Sep 17 00:00:00 2001 From: Adam Schmalhofer Date: Sun, 19 Dec 2021 19:32:19 +0100 Subject: [PATCH 019/315] wohrm: resize on Bangls.js2 --- apps/wohrm/app.js | 32 +++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/apps/wohrm/app.js b/apps/wohrm/app.js index 6ebcdabc3..75d48c7ff 100644 --- a/apps/wohrm/app.js +++ b/apps/wohrm/app.js @@ -23,7 +23,8 @@ let confidenceChanged = true; let setterHighlightTimeout; -const upperLshape = { +const isB1 = process.env.HWVERSION==1; +const upperLshape = isB1 ? { minX: 125, maxX: 210, minY: 40, @@ -32,10 +33,19 @@ const upperLshape = { cornerRoundness: 5, orientation: -1, color: '#f00' +} : { + minX: Bangle.appRect.x2-100, + maxX: Bangle.appRect.x2, + minY: Bangle.appRect.y, + maxY: Bangle.appRect.y2, + rectWidth: 26, + cornerRoundness: 4, + orientation: -1, + color: '#f00' }; const lowerLshape = { - maxX: 10, + maxX: isB1 ? 10 : Bangle.appRect.x, minX: 100, minY: upperLshape.maxY, maxY: upperLshape.minY, @@ -48,14 +58,17 @@ const lowerLshape = { const centerBar = { minY: (upperLshape.minY + upperLshape.maxY - upperLshape.rectWidth)/2, maxY: (upperLshape.minY + upperLshape.maxY + upperLshape.rectWidth)/2, - confidenceWidth: 10, - minX: 55, - maxX: 165 + confidenceWidth: isB1 ? 10 : 8, + minX: isB1 ? 55 : upperLshape.rectWidth + 14, + maxX: isB1 ? 165 : Bangle.appRect.x2 - upperLshape.rectWidth - 14 }; -const fontSizes = { - limits: 13, - heartRate: 24 +const fontSizes = isB1 ? { + limits: 13, + heartRate: 24 +} : { + limits: 12, + heartRate: 20 }; function fillEllipse(x, y, x2, y2) { @@ -155,7 +168,8 @@ function renderCurrentHeartRate() { g.setFontVector(fontSizes.heartRate); g.setFontAlign(1, 0, 0); g.drawString(currentHeartRate, - upperLshape.minX+upperLshape.cornerRoundness, + Math.max(upperLshape.minX+upperLshape.cornerRoundness, + lowerLshape.minX-lowerLshape.cornerRoundness), (centerBar.minY+centerBar.maxY)/2); //Reset alignment to defaults From 3ae35376fcd3db363c33030b01d88e254a0781d5 Mon Sep 17 00:00:00 2001 From: Adam Schmalhofer Date: Sun, 19 Dec 2021 20:45:11 +0100 Subject: [PATCH 020/315] wohrm: fixes after running on Bangle.js2 - set to dark theme as doesn't look good with white in the corners) - leave space for widgets --- apps.json | 2 +- apps/wohrm/app.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps.json b/apps.json index 07c773725..2acd3b981 100644 --- a/apps.json +++ b/apps.json @@ -1714,7 +1714,7 @@ { "id": "wohrm", "name": "Workout HRM", - "version": "0.09-rc1", + "version": "0.09-rc2", "description": "Workout heart rate monitor notifies you with a buzz if your heart rate goes above or below the set limits.", "icon": "app.png", "type": "app", diff --git a/apps/wohrm/app.js b/apps/wohrm/app.js index 75d48c7ff..429b9f565 100644 --- a/apps/wohrm/app.js +++ b/apps/wohrm/app.js @@ -36,7 +36,7 @@ const upperLshape = isB1 ? { } : { minX: Bangle.appRect.x2-100, maxX: Bangle.appRect.x2, - minY: Bangle.appRect.y, + minY: 24, maxY: Bangle.appRect.y2, rectWidth: 26, cornerRoundness: 4, @@ -368,7 +368,7 @@ Bangle.on('lcdPower', (on) => { Bangle.setHRMPower(1,"wohrm"); Bangle.on('HRM', onHrm); -g.clear(); +g.setTheme({bg:"#000",fg:"#fff",dark:true}).clear(); Bangle.loadWidgets(); Bangle.drawWidgets(); From 9e1dd8eda39fb1bc76b9c52e1851072158cb4982 Mon Sep 17 00:00:00 2001 From: Adam Schmalhofer Date: Sun, 19 Dec 2021 21:01:47 +0100 Subject: [PATCH 021/315] wohrm: Fix bgcolor --- apps.json | 2 +- apps/wohrm/app.js | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/apps.json b/apps.json index 2acd3b981..ed616c952 100644 --- a/apps.json +++ b/apps.json @@ -1714,7 +1714,7 @@ { "id": "wohrm", "name": "Workout HRM", - "version": "0.09-rc2", + "version": "0.09-rc3", "description": "Workout heart rate monitor notifies you with a buzz if your heart rate goes above or below the set limits.", "icon": "app.png", "type": "app", diff --git a/apps/wohrm/app.js b/apps/wohrm/app.js index 429b9f565..115849fa6 100644 --- a/apps/wohrm/app.js +++ b/apps/wohrm/app.js @@ -351,7 +351,6 @@ function switchOffApp(){ Bangle.on('lcdPower', (on) => { if (on) { - g.clear(); Bangle.drawWidgets(); if (typeof(BTN5) !== typeof(undefined)) { @@ -368,7 +367,9 @@ Bangle.on('lcdPower', (on) => { Bangle.setHRMPower(1,"wohrm"); Bangle.on('HRM', onHrm); -g.setTheme({bg:"#000",fg:"#fff",dark:true}).clear(); +g.setTheme({bg:"#000",fg:"#fff",dark:true}); +g.reset() +g.clear(); Bangle.loadWidgets(); Bangle.drawWidgets(); From 288a204b9d608d90bb33cf82ec005f8a980df01e Mon Sep 17 00:00:00 2001 From: Adam Schmalhofer Date: Sun, 19 Dec 2021 21:13:39 +0100 Subject: [PATCH 022/315] wohrm: Add ChangeLog entry --- apps/wohrm/ChangeLog | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/wohrm/ChangeLog b/apps/wohrm/ChangeLog index 084ca6ed5..156d32740 100644 --- a/apps/wohrm/ChangeLog +++ b/apps/wohrm/ChangeLog @@ -5,4 +5,5 @@ 0.05: Improved buzz timing and rendering 0.06: Removed debug outputs, fixed rendering for upper limit, improved rendering for +/- icons, changelog version order fixed 0.07: Home button fixed and README added -0.08: tag HRM power requests to allow this ot work alongside other widgets/apps (fix #799) +0.08: tag HRM power requests to allow this to work alongside other widgets/apps (fix #799) +0.09: Ported to Bangle.js2 From 15df1205060eaf866fb3b2eb0c4db861a0d7bc90 Mon Sep 17 00:00:00 2001 From: Adam Schmalhofer Date: Sun, 19 Dec 2021 21:29:16 +0100 Subject: [PATCH 023/315] wohrm: Home returns to clock, instead of menu --- apps.json | 2 +- apps/wohrm/ChangeLog | 1 + apps/wohrm/app.js | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/apps.json b/apps.json index ed616c952..4d98ce731 100644 --- a/apps.json +++ b/apps.json @@ -1714,7 +1714,7 @@ { "id": "wohrm", "name": "Workout HRM", - "version": "0.09-rc3", + "version": "0.09-rc4", "description": "Workout heart rate monitor notifies you with a buzz if your heart rate goes above or below the set limits.", "icon": "app.png", "type": "app", diff --git a/apps/wohrm/ChangeLog b/apps/wohrm/ChangeLog index 156d32740..b177c1902 100644 --- a/apps/wohrm/ChangeLog +++ b/apps/wohrm/ChangeLog @@ -7,3 +7,4 @@ 0.07: Home button fixed and README added 0.08: tag HRM power requests to allow this to work alongside other widgets/apps (fix #799) 0.09: Ported to Bangle.js2 + Home returns to clock, instead of menu diff --git a/apps/wohrm/app.js b/apps/wohrm/app.js index 115849fa6..646dab58f 100644 --- a/apps/wohrm/app.js +++ b/apps/wohrm/app.js @@ -346,7 +346,7 @@ function resetHighlightTimeout() { function switchOffApp(){ Bangle.setHRMPower(0,"wohrm"); - Bangle.showLauncher(); + load(); } Bangle.on('lcdPower', (on) => { From 0caa10b7052a639ba80d2f35d061b6026cef6bf7 Mon Sep 17 00:00:00 2001 From: Adam Schmalhofer Date: Sun, 19 Dec 2021 22:01:08 +0100 Subject: [PATCH 024/315] wohrm: Add settings --- apps.json | 3 ++- apps/wohrm/ChangeLog | 1 + apps/wohrm/app.js | 26 ++++++++++++++------------ apps/wohrm/settings.js | 35 +++++++++++++++++++++++++++++++++++ 4 files changed, 52 insertions(+), 13 deletions(-) create mode 100644 apps/wohrm/settings.js diff --git a/apps.json b/apps.json index 4d98ce731..1d4f98c1e 100644 --- a/apps.json +++ b/apps.json @@ -1714,7 +1714,7 @@ { "id": "wohrm", "name": "Workout HRM", - "version": "0.09-rc4", + "version": "0.09-rc7", "description": "Workout heart rate monitor notifies you with a buzz if your heart rate goes above or below the set limits.", "icon": "app.png", "type": "app", @@ -1725,6 +1725,7 @@ "screenshots": [{"url":"bangle1-workout-HRM-screenshot.png"}], "storage": [ {"name":"wohrm.app.js","url":"app.js"}, + {"name":"wohrm.settings.js","url":"settings.js"}, {"name":"wohrm.img","url":"app-icon.js","evaluate":true} ] }, diff --git a/apps/wohrm/ChangeLog b/apps/wohrm/ChangeLog index b177c1902..2ca405365 100644 --- a/apps/wohrm/ChangeLog +++ b/apps/wohrm/ChangeLog @@ -8,3 +8,4 @@ 0.08: tag HRM power requests to allow this to work alongside other widgets/apps (fix #799) 0.09: Ported to Bangle.js2 Home returns to clock, instead of menu + Add settings diff --git a/apps/wohrm/app.js b/apps/wohrm/app.js index 646dab58f..26e7b7eae 100644 --- a/apps/wohrm/app.js +++ b/apps/wohrm/app.js @@ -4,14 +4,16 @@ const Setter = { UPPER: 'upper', LOWER: 'lower' }; +const SETTINGS_FILE = "wohrm.setting.json"; +var settings = require('Storage').readJSON(SETTINGS_FILE, 1) || { + upperLimit: 130, + lowerLimit: 100 +}; const shortBuzzTimeInMs = 80; const longBuzzTimeInMs = 400; -let upperLimit = 130; let upperLimitChanged = true; - -let lowerLimit = 100; let lowerLimitChanged = true; let limitSetter = Setter.NONE; @@ -150,7 +152,7 @@ function renderUpperLimit() { g.setColor(g.theme.fg); } g.setFontVector(fontSizes.limits).setFontAlign(-1, 0, 0); - g.drawString("Upper: " + upperLimit, + g.drawString("Upper: " + settings.upperLimit, upperLshape.minX, upperLshape.minY+upperLshape.rectWidth/2); @@ -189,7 +191,7 @@ function renderLowerLimit() { g.setColor(g.theme.fg); } g.setFontVector(fontSizes.limits).setFontAlign(-1, 0, 0); - g.drawString("Lower: " + lowerLimit, + g.drawString("Lower: " + settings.lowerLimit, lowerLshape.maxX + lowerLshape.rectWidth/2, lowerLshape.minY - lowerLshape.rectWidth/2); @@ -247,13 +249,13 @@ function buzz() { // Do not buzz if not confident if(hrConfidence < 85) { return; } - if(currentHeartRate > upperLimit) + if(currentHeartRate > settings.upperLimit) { Bangle.buzz(shortBuzzTimeInMs); setTimeout(() => { Bangle.buzz(shortBuzzTimeInMs); }, shortBuzzTimeInMs * 2); } - if(currentHeartRate < lowerLimit) + if(currentHeartRate < settings.lowerLimit) { Bangle.buzz(longBuzzTimeInMs); } @@ -312,11 +314,11 @@ function incrementLimit() { resetHighlightTimeout(); if (limitSetter === Setter.UPPER) { - upperLimit++; + settings.upperLimit++; renderUpperLimit(); upperLimitChanged = true; } else if(limitSetter === Setter.LOWER) { - lowerLimit++; + settings.lowerLimit++; renderLowerLimit(); lowerLimitChanged = true; } @@ -326,11 +328,11 @@ function decrementLimit(){ resetHighlightTimeout(); if (limitSetter === Setter.UPPER) { - upperLimit--; + settings.upperLimit--; renderUpperLimit(); upperLimitChanged = true; } else if(limitSetter === Setter.LOWER) { - lowerLimit--; + settings.lowerLimit--; renderLowerLimit(); lowerLimitChanged = true; } @@ -368,7 +370,7 @@ Bangle.setHRMPower(1,"wohrm"); Bangle.on('HRM', onHrm); g.setTheme({bg:"#000",fg:"#fff",dark:true}); -g.reset() +g.reset(); g.clear(); Bangle.loadWidgets(); Bangle.drawWidgets(); diff --git a/apps/wohrm/settings.js b/apps/wohrm/settings.js new file mode 100644 index 000000000..6d31688f4 --- /dev/null +++ b/apps/wohrm/settings.js @@ -0,0 +1,35 @@ +(function menu(back) { + const SETTINGS_FILE = "wohrm.setting.json"; + + // initialize with default settings... + const storage = require('Storage'); + var settings = storage.readJSON(SETTINGS_FILE, 1) || { + upperLimit: 130, + lowerLimit: 100 + }; + + function save() { + storage.write(SETTINGS_FILE, settings); + } + + E.showMenu({ + '': { 'title': 'Workout HRM' }, + '< Back': back, + 'Upper limit': { + value: settings.upperLimit, + min: 100, max: 200, + onchange: v => { + settings.upperLimit = v; + save(); + } + }, + 'Lower limit': { + value: settings.lowerLimit, + min: 50, max: 150, + onchange: v => { + settings.lowerLimit = v; + save(); + } + } + }); +}) From 964fa27bfb9a5b1ef72a612d9b90e0891b21b9b0 Mon Sep 17 00:00:00 2001 From: The Dod Date: Tue, 21 Dec 2021 01:01:10 +0200 Subject: [PATCH 025/315] Add Four Twenty Clock app --- apps.json | 18 ++ apps/ftclock/ChangeLog | 1 + apps/ftclock/app-icon.js | 1 + apps/ftclock/app.js | 52 ++++ apps/ftclock/app.png | Bin 0 -> 6742 bytes apps/ftclock/fourTwenty.js | 45 +++ apps/ftclock/fourTwentyTz.js | 536 +++++++++++++++++++++++++++++++++ apps/ftclock/mkFourTwentyTz.py | 46 +++ apps/ftclock/screenshot.png | Bin 0 -> 17635 bytes 9 files changed, 699 insertions(+) create mode 100644 apps/ftclock/ChangeLog create mode 100644 apps/ftclock/app-icon.js create mode 100644 apps/ftclock/app.js create mode 100644 apps/ftclock/app.png create mode 100644 apps/ftclock/fourTwenty.js create mode 100644 apps/ftclock/fourTwentyTz.js create mode 100644 apps/ftclock/mkFourTwentyTz.py create mode 100644 apps/ftclock/screenshot.png diff --git a/apps.json b/apps.json index e5e9f8f02..3dc4c3577 100644 --- a/apps.json +++ b/apps.json @@ -5062,5 +5062,23 @@ {"name":"ltherm.app.js","url":"app.js"}, {"name":"ltherm.img","url":"icon.js","evaluate":true} ] + }, + { + "id": "ftclock", + "name": "Four Twenty Clock", + "version": "0.01", + "description": "A clock that tells when and where it's going to be 4:20 next", + "icon": "app.png", + "screenshots": [{"url":"screenshot.png"}], + "type": "clock", + "tags": "clock", + "supports": ["BANGLEJS","BANGLEJS2"], + "allow_emulator": true, + "storage": [ + {"name":"ftclock.app.js","url":"app.js"}, + {"name":"fourTwenty","url":"fourTwenty.js"}, + {"name":"fourTwentyTz","url":"fourTwentyTz.js"}, + {"name":"ftclock.img","url":"app-icon.js","evaluate":true} + ] } ] diff --git a/apps/ftclock/ChangeLog b/apps/ftclock/ChangeLog new file mode 100644 index 000000000..9db0e26c5 --- /dev/null +++ b/apps/ftclock/ChangeLog @@ -0,0 +1 @@ +0.01: first release diff --git a/apps/ftclock/app-icon.js b/apps/ftclock/app-icon.js new file mode 100644 index 000000000..297847e95 --- /dev/null +++ b/apps/ftclock/app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwghC/AH4A/AH4A/AAMHu4ACuwHBs4HDsEGBIQLCsADBgwPDCAQGEuwXFBwI0GEAMHuAGCCoMHC4pMHEAIXEAgIGEBwI9BC4wSCC8IVCMAwIBs4XKUQJfITQgXCDwp8EHAqaECoLFEu4cDBIggBs6uFZozuGBAVmC4g+FMgZQEZQ5vGC4iRIC5IrDN4h5EC5J3BCoIKGgyaEC44VBC46yEDgoeDgxqLC5SCMAgoTFY47GFC4xFBdwwPBD4oWFAH4A/AH4A/AH4AjA==")) diff --git a/apps/ftclock/app.js b/apps/ftclock/app.js new file mode 100644 index 000000000..1aed8da54 --- /dev/null +++ b/apps/ftclock/app.js @@ -0,0 +1,52 @@ +let getNextFourTwenty = require("fourTwenty").getNextFourTwenty; +require("FontTeletext10x18Ascii").add(Graphics); +let leaf_img = "\x17\x18\x81\x00\x00\x10\x00\x00 \x00\x00@\x00\x01\xc0\x00\x03\x80\x00\x0f\x80\x00\x1f\x00\x00>\x00\x00|\x00\xc0\xf8\x19\xe1\xf0\xf1\xe3\xe3\xc3\xf7\xdf\x83\xff\xfe\x03\xff\xf8\x03\xff\xe0\x03\xff\x80\x03\xfe\x00\x7f\xff\xc0\xff\xff\xc0\x06\xe0\x00\x18\xc0\x00 \x80\x00\x00\x00"; + +// timeout used to update every minute +let drawTimeout; + +// schedule a draw for the next minute +function queueDraw() { + if (drawTimeout) clearTimeout(drawTimeout); + drawTimeout = setTimeout(function() { + drawTimeout = undefined; + draw(); + }, 60000 - (Date.now() % 60000)); +} + + +function draw() { + g.reset(); + g.setBgColor("#ffffff"); + let date = new Date(); + let timeStr = require("locale").time(date,1); + let next420 = getNextFourTwenty(); + g.clearRect(0,26,g.getWidth(),g.getHeight()); + g.setColor("#00ff00").setFontAlign(0,-1).setFont("Teletext10x18Ascii",2); + g.drawString(next420.minutes? timeStr: `\0${leaf_img}${timeStr}\0${leaf_img}`, g.getWidth()/2, 28); + g.setColor("#000000"); + g.setFontAlign(-1,-1).setFont("Teletext10x18Ascii"); + g.drawString(g.wrapString(next420.text, g.getWidth()-8).join("\n"),4,60); + + // queue draw in one minute + queueDraw(); +} + +// Clear the screen once, at startup +g.clear(); +// Load widgets +Bangle.loadWidgets(); +Bangle.drawWidgets(); +// draw immediately at first, queue update +draw(); +// Stop updates when LCD is off, restart when on +Bangle.on('lcdPower',on=>{ + if (on) { + draw(); // draw immediately, queue redraw + } else { // stop draw timer + if (drawTimeout) clearTimeout(drawTimeout); + drawTimeout = undefined; + } +}); +// Show launcher when middle button pressed +Bangle.setUI("clock"); diff --git a/apps/ftclock/app.png b/apps/ftclock/app.png new file mode 100644 index 0000000000000000000000000000000000000000..0553837ca47ff2061105cd49c40a86d8f66d4b7b GIT binary patch literal 6742 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 && current_min<25) { + current_time -= current_min-20; // 5 minutes grace period + } + let offset = 16*60+20-current_time; + if (offset<0) { + offset += 24*60; + } + return offset; +} + +function makeFourTwentyText(minutes, places) { + //let plural = minutes==1? "": "s"; + //let msgprefix = minutes? `${minutes} minute${plural} to`: "It is now"; + let msgprefix = minutes? `${minutes}m to`: "It is now"; + let msgsuffix = places.length>1? ", and other fine places": ""; + let msgplace = places[Math.floor(Math.random()*places.length)]; + return `${msgprefix} 4:20 at ${msgplace}${msgsuffix}.`; +} + +function getNextFourTwenty() { + let offs = get420offset(); + for (let i=0; i2: # e.g. America/North_Dakota/New_Salem + country = parts[1] # e.g. North Dakota + else: # e.g. America/Denver + country = countries[r[1]] # e.g. United States + if country==city: # Avoid awkward searches like "Anguilla, Anguilla" + country = r[1] # Use code instead + zones[int(r[0])] = {"name":', '.join((city,country))} +now = int(time.time()) +for r in csv.reader(open("timezone.csv")): + code = int(r[0]) + if code not in zones: + continue + starttime = int(r[2] or "0") # Bugger. They're feeding us blanks for UTC now + offs = int(r[3]) + if offs < 0: + offs += 60*60*24 + d = zones[code] + if starttime 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 W_a_}>UQb*A0000 Date: Tue, 21 Dec 2021 01:34:30 +0200 Subject: [PATCH 026/315] ftclock README and better screenshots --- apps.json | 3 ++- apps/ftclock/README.md | 16 ++++++++++++++++ apps/ftclock/mkFourTwentyTz.py | 4 ++-- apps/ftclock/screenshot.png | Bin 17635 -> 15457 bytes apps/ftclock/screenshot1.png | Bin 0 -> 19973 bytes 5 files changed, 20 insertions(+), 3 deletions(-) create mode 100644 apps/ftclock/README.md create mode 100644 apps/ftclock/screenshot1.png diff --git a/apps.json b/apps.json index 3dc4c3577..6a9fc7309 100644 --- a/apps.json +++ b/apps.json @@ -5069,11 +5069,12 @@ "version": "0.01", "description": "A clock that tells when and where it's going to be 4:20 next", "icon": "app.png", - "screenshots": [{"url":"screenshot.png"}], + "screenshots": [{"url":"screenshot.png"}, {"url":"screenshot1.png"}], "type": "clock", "tags": "clock", "supports": ["BANGLEJS","BANGLEJS2"], "allow_emulator": true, + "readme": "README.md", "storage": [ {"name":"ftclock.app.js","url":"app.js"}, {"name":"fourTwenty","url":"fourTwenty.js"}, diff --git a/apps/ftclock/README.md b/apps/ftclock/README.md new file mode 100644 index 000000000..ed3b7b3bd --- /dev/null +++ b/apps/ftclock/README.md @@ -0,0 +1,16 @@ +# Four Twenty Clock + +A clock that tells when and where it's going to be [4:20](https://en.wikipedia.org/wiki/420_(cannabis_culture%29) next + +![screensot](screenshot.png) ![screenshot at 4:20](screenshot1.png) + +## Note + +Once in a while, there'd be updates to the [timezone database](https://timezonedb.com/download) which +would require updating `fourTwentyTz.js`. I'll do my best to release a new version every time this happens, +but if you ever need to do this yourself, just run `python mkFourTwentyTz.py` (after downloading the timezone CSV files. +See comment at the top of the script). + +## Creator + +[Nimrod Kerrett](zzzen.com) diff --git a/apps/ftclock/mkFourTwentyTz.py b/apps/ftclock/mkFourTwentyTz.py index 4de17c3cf..713b68059 100644 --- a/apps/ftclock/mkFourTwentyTz.py +++ b/apps/ftclock/mkFourTwentyTz.py @@ -1,4 +1,4 @@ -# Generates tz.js[on] from time zone csv files +# Generates fourTwentyTz.js from time zone csv files # get latest files from https://timezonedb.com/download import csv,json,time,os,math countries = {} @@ -35,7 +35,7 @@ for k in zones: continue offsdict[d["offs"]] = offsdict.get(d["offs"],[])+[d["name"]] res = sorted([[k,sorted(offsdict[k])] for k in offsdict],key=lambda x:-x[0]) -js = open("tz.js","w") +js = open("fourTwentyTz.js","w") js.write("// Generated by mk420tz.py - see https://github.com/thedod/BangleApps/420clock\n") js.write("// (version: {0})\n".format(time.ctime(time.time()))) js.write("// Data source: https://timezonedb.com/files/timezonedb.csv.zip\n") diff --git a/apps/ftclock/screenshot.png b/apps/ftclock/screenshot.png index e04f766463b05d0ff9826cbc8b8f10c1034d8307..9247e0e04a55b533955a24369e4d29d293f3b38d 100644 GIT binary patch literal 15457 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 X3LR-t-PP6E00000NkvXXu0mjf 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 W_a_}>UQb*A0000 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 ULn*~EGXMYp07*qoM6N<$f|JYjo&W#< literal 0 HcmV?d00001 From d80ebe08ede97b367932925bce540d8ed5a14d33 Mon Sep 17 00:00:00 2001 From: The Dod Date: Tue, 21 Dec 2021 10:56:37 +0200 Subject: [PATCH 027/315] README edit (gh markdown chokes on "(" in url) --- apps/ftclock/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/ftclock/README.md b/apps/ftclock/README.md index ed3b7b3bd..665a7693d 100644 --- a/apps/ftclock/README.md +++ b/apps/ftclock/README.md @@ -1,6 +1,6 @@ # Four Twenty Clock -A clock that tells when and where it's going to be [4:20](https://en.wikipedia.org/wiki/420_(cannabis_culture%29) next +A clock that tells when and where it's going to be [4:20](https://en.wikipedia.org/wiki/420_%28cannabis_culture%29) next ![screensot](screenshot.png) ![screenshot at 4:20](screenshot1.png) From 4f16d6ce35cfc3ea49075a5fa0c4d9cda9c67754 Mon Sep 17 00:00:00 2001 From: Adam Schmalhofer Date: Mon, 20 Dec 2021 11:08:08 +0100 Subject: [PATCH 028/315] wohrm: Refactor renderLshape() rename variables and document renderLshape() --- apps.json | 2 +- apps/wohrm/app.js | 110 +++++++++++++++++++++++++--------------------- 2 files changed, 61 insertions(+), 51 deletions(-) diff --git a/apps.json b/apps.json index 1d4f98c1e..7898ba786 100644 --- a/apps.json +++ b/apps.json @@ -1714,7 +1714,7 @@ { "id": "wohrm", "name": "Workout HRM", - "version": "0.09-rc7", + "version": "0.09-rc10", "description": "Workout heart rate monitor notifies you with a buzz if your heart rate goes above or below the set limits.", "icon": "app.png", "type": "app", diff --git a/apps/wohrm/app.js b/apps/wohrm/app.js index 26e7b7eae..ab579463c 100644 --- a/apps/wohrm/app.js +++ b/apps/wohrm/app.js @@ -27,30 +27,30 @@ let setterHighlightTimeout; const isB1 = process.env.HWVERSION==1; const upperLshape = isB1 ? { - minX: 125, - maxX: 210, - minY: 40, - maxY: 210, + right: 125, + left: 210, + bottom: 40, + top: 210, rectWidth: 30, cornerRoundness: 5, orientation: -1, color: '#f00' } : { - minX: Bangle.appRect.x2-100, - maxX: Bangle.appRect.x2, - minY: 24, - maxY: Bangle.appRect.y2, + right: Bangle.appRect.x2-100, + left: Bangle.appRect.x2, + bottom: 24, + top: Bangle.appRect.y2, rectWidth: 26, cornerRoundness: 4, - orientation: -1, + orientation: -1, // rotated 180° color: '#f00' }; const lowerLshape = { - maxX: isB1 ? 10 : Bangle.appRect.x, - minX: 100, - minY: upperLshape.maxY, - maxY: upperLshape.minY, + left: isB1 ? 10 : Bangle.appRect.x, + right: 100, + bottom: upperLshape.top, + top: upperLshape.bottom, rectWidth: upperLshape.rectWidth, cornerRoundness: upperLshape.cornerRoundness, orientation: 1, @@ -58,8 +58,8 @@ const lowerLshape = { }; const centerBar = { - minY: (upperLshape.minY + upperLshape.maxY - upperLshape.rectWidth)/2, - maxY: (upperLshape.minY + upperLshape.maxY + upperLshape.rectWidth)/2, + minY: (upperLshape.bottom + upperLshape.top - upperLshape.rectWidth)/2, + maxY: (upperLshape.bottom + upperLshape.top + upperLshape.rectWidth)/2, confidenceWidth: isB1 ? 10 : 8, minX: isB1 ? 55 : upperLshape.rectWidth + 14, maxX: isB1 ? 165 : Bangle.appRect.x2 - upperLshape.rectWidth - 14 @@ -80,50 +80,60 @@ function fillEllipse(x, y, x2, y2) { Math.max(y, y2)); } +/** + * @param p.left: the X coordinate of the left side of the L in its orientation + * @param p.right: the X coordinate of the right side of the L in its orientation + * @param p.top: the Y coordinate of the top side of the L in its orientation + * @param p.bottom: the Y coordinate of the bottom side of the L in its orientation + * @param p.strokeWidth: how thick we draw the letter. + * @param p.cornerRoundness: how much the corners should be rounded + * @param p.orientation: 1 == turned 0°; -1 == turned 180° + * @param p.color: the color to draw the shape + */ function renderLshape(p) { g.setColor(p.color); - g.fillRect(p.minX, p.minY, p.maxX, p.minY-p.orientation*p.rectWidth); - g.fillRect(p.maxX+p.orientation*p.rectWidth, - p.minY-p.orientation*p.rectWidth, - p.maxX, - p.maxY+p.orientation*p.cornerRoundness*2); + g.fillRect(p.right, p.bottom, p.left, p.bottom-p.orientation*p.rectWidth); + g.fillRect(p.left+p.orientation*p.rectWidth, + p.bottom-p.orientation*p.rectWidth, + p.left, + p.top+p.orientation*p.cornerRoundness*2); //Round end of small line - fillEllipse(p.minX+p.orientation*p.cornerRoundness*2, - p.minY, - p.minX-p.orientation*p.cornerRoundness*2, - p.minY-p.orientation*p.rectWidth); + fillEllipse(p.right+p.orientation*p.cornerRoundness*2, + p.bottom, + p.right-p.orientation*p.cornerRoundness*2, + p.bottom-p.orientation*p.rectWidth); //Round outer corner g.setColor(g.theme.bg); - g.fillRect(p.maxX+p.orientation*p.cornerRoundness, - p.minY, - p.maxX, - p.minY-p.orientation*p.cornerRoundness); + g.fillRect(p.left+p.orientation*p.cornerRoundness, + p.bottom, + p.left, + p.bottom-p.orientation*p.cornerRoundness); g.setColor(p.color); - fillEllipse(p.maxX+p.orientation*p.cornerRoundness*4, - p.minY, - p.maxX, - p.minY-p.orientation*p.cornerRoundness*2); + fillEllipse(p.left+p.orientation*p.cornerRoundness*4, + p.bottom, + p.left, + p.bottom-p.orientation*p.cornerRoundness*2); //Round inner corner - g.fillRect(p.maxX+p.orientation*(p.rectWidth+p.cornerRoundness+1), - p.minY-p.orientation*(p.rectWidth+1), - p.maxX+p.orientation*(p.rectWidth+1), - p.minY-p.orientation*(p.rectWidth+p.cornerRoundness-1)); + g.fillRect(p.left+p.orientation*(p.rectWidth+p.cornerRoundness+1), + p.bottom-p.orientation*(p.rectWidth+1), + p.left+p.orientation*(p.rectWidth+1), + p.bottom-p.orientation*(p.rectWidth+p.cornerRoundness-1)); g.setColor(g.theme.bg); - fillEllipse(p.maxX+p.orientation*(p.rectWidth+p.cornerRoundness*4), - p.minY-p.orientation*(p.rectWidth+1), - p.maxX+p.orientation*(p.rectWidth+1), - p.minY-p.orientation*(p.rectWidth+p.cornerRoundness*3-1)); + fillEllipse(p.left+p.orientation*(p.rectWidth+p.cornerRoundness*4), + p.bottom-p.orientation*(p.rectWidth+1), + p.left+p.orientation*(p.rectWidth+1), + p.bottom-p.orientation*(p.rectWidth+p.cornerRoundness*3-1)); //Round end of long line g.setColor(p.color); - fillEllipse(p.maxX+p.orientation*p.rectWidth, - p.maxY+p.orientation*p.cornerRoundness*4, - p.maxX, - p.maxY); + fillEllipse(p.left+p.orientation*p.rectWidth, + p.top+p.orientation*p.cornerRoundness*4, + p.left, + p.top); } function drawTrainingHeartRate() { @@ -153,8 +163,8 @@ function renderUpperLimit() { } g.setFontVector(fontSizes.limits).setFontAlign(-1, 0, 0); g.drawString("Upper: " + settings.upperLimit, - upperLshape.minX, - upperLshape.minY+upperLshape.rectWidth/2); + upperLshape.right, + upperLshape.bottom+upperLshape.rectWidth/2); upperLimitChanged = false; } @@ -170,8 +180,8 @@ function renderCurrentHeartRate() { g.setFontVector(fontSizes.heartRate); g.setFontAlign(1, 0, 0); g.drawString(currentHeartRate, - Math.max(upperLshape.minX+upperLshape.cornerRoundness, - lowerLshape.minX-lowerLshape.cornerRoundness), + Math.max(upperLshape.right+upperLshape.cornerRoundness, + lowerLshape.right-lowerLshape.cornerRoundness), (centerBar.minY+centerBar.maxY)/2); //Reset alignment to defaults @@ -192,8 +202,8 @@ function renderLowerLimit() { } g.setFontVector(fontSizes.limits).setFontAlign(-1, 0, 0); g.drawString("Lower: " + settings.lowerLimit, - lowerLshape.maxX + lowerLshape.rectWidth/2, - lowerLshape.minY - lowerLshape.rectWidth/2); + lowerLshape.left + lowerLshape.rectWidth/2, + lowerLshape.bottom - lowerLshape.rectWidth/2); lowerLimitChanged = false; } From fcf8a0b1f097466f8e6688e645b1977f2ef8cee7 Mon Sep 17 00:00:00 2001 From: Danny <31635744+DDDanny@users.noreply.github.com> Date: Sat, 25 Dec 2021 23:58:46 +0100 Subject: [PATCH 029/315] added ISO weeknumber * update changelog, screenshots and readme * created a settings dialog --- apps/ffcniftya/ChangeLog | 1 + apps/ffcniftya/README.md | 5 +++ apps/ffcniftya/app.js | 37 +++++++++++++------ apps/ffcniftya/ffcniftya.settings.js | 25 +++++++++++++ apps/ffcniftya/screenshot_nifty.png | Bin 3487 -> 52362 bytes apps/ffcniftya/screenshot_settings_nifty.png | Bin 0 -> 46504 bytes 6 files changed, 57 insertions(+), 11 deletions(-) create mode 100644 apps/ffcniftya/ffcniftya.settings.js create mode 100644 apps/ffcniftya/screenshot_settings_nifty.png diff --git a/apps/ffcniftya/ChangeLog b/apps/ffcniftya/ChangeLog index 18bc264a3..bf70a213b 100644 --- a/apps/ffcniftya/ChangeLog +++ b/apps/ffcniftya/ChangeLog @@ -1 +1,2 @@ 0.01: New Clock Nifty A +0.02: Shows the current week number, can be disabled via settings "" diff --git a/apps/ffcniftya/README.md b/apps/ffcniftya/README.md index f1fee9b1f..5ec8ab681 100644 --- a/apps/ffcniftya/README.md +++ b/apps/ffcniftya/README.md @@ -1,4 +1,9 @@ # Nifty-A Clock +## This is the clock ![](screenshot_nifty.png) +## The week number can be turned On/Off via settings +![](screenshot_settings_nifty.png) +default is "On" + diff --git a/apps/ffcniftya/app.js b/apps/ffcniftya/app.js index 31742f64a..33722b3a3 100644 --- a/apps/ffcniftya/app.js +++ b/apps/ffcniftya/app.js @@ -1,5 +1,6 @@ const locale = require("locale"); const is12Hour = (require("Storage").readJSON("setting.json", 1) || {})["12hour"]; +const CFG = require('Storage').readJSON("ffcniftya.json", true) || {showWeek: true}; /* Clock *********************************************/ const scale = g.getWidth() / 176; @@ -16,6 +17,18 @@ const center = { y: Math.round(((viewport.height - widget) / 2) + widget), } +function ISO8601_week_no(date) { //copied from: https://gist.github.com/IamSilviu/5899269#gistcomment-3035480 + var tdt = new Date(date.valueOf()); + var dayn = (date.getDay() + 6) % 7; + tdt.setDate(tdt.getDate() - dayn + 3); + var firstThursday = tdt.valueOf(); + tdt.setMonth(0, 1); + if (tdt.getDay() !== 4) { + tdt.setMonth(0, 1 + ((4 - tdt.getDay()) + 7) % 7); + } + return 1 + Math.ceil((firstThursday - tdt) / 604800000); +} + function d02(value) { return ('0' + value).substr(-2); } @@ -29,23 +42,25 @@ function draw() { const minutes = d02(now.getMinutes()); const day = d02(now.getDate()); const month = d02(now.getMonth() + 1); - const year = now.getFullYear(); - - const month2 = locale.month(now, 3); - const day2 = locale.dow(now, 3); + const year = now.getFullYear(now); + const monthName = locale.month(now, 3); + const dayName = locale.dow(now, 3); + const centerTimeScaleX = center.x + 32 * scale; g.setFontAlign(1, 0).setFont("Vector", 90 * scale); - g.drawString(hour, center.x + 32 * scale, center.y - 31 * scale); - g.drawString(minutes, center.x + 32 * scale, center.y + 46 * scale); + g.drawString(hour, centerTimeScaleX, center.y - 31 * scale); + g.drawString(minutes, centerTimeScaleX, center.y + 46 * scale); g.fillRect(center.x + 30 * scale, center.y - 72 * scale, center.x + 32 * scale, center.y + 74 * scale); + const centerDatesScaleX = center.x + 40 * scale; g.setFontAlign(-1, 0).setFont("Vector", 16 * scale); - g.drawString(year, center.x + 40 * scale, center.y - 62 * scale); - g.drawString(month, center.x + 40 * scale, center.y - 44 * scale); - g.drawString(day, center.x + 40 * scale, center.y - 26 * scale); - g.drawString(month2, center.x + 40 * scale, center.y + 48 * scale); - g.drawString(day2, center.x + 40 * scale, center.y + 66 * scale); + g.drawString(year, centerDatesScaleX, center.y - 62 * scale); + g.drawString(month, centerDatesScaleX, center.y - 44 * scale); + g.drawString(day, centerDatesScaleX, center.y - 26 * scale); + if (CFG.showWeek) g.drawString(d02(ISO8601_week_no(now)), centerDatesScaleX, center.y + 15 * scale); + g.drawString(monthName, centerDatesScaleX, center.y + 48 * scale); + g.drawString(dayName, centerDatesScaleX, center.y + 66 * scale); } diff --git a/apps/ffcniftya/ffcniftya.settings.js b/apps/ffcniftya/ffcniftya.settings.js new file mode 100644 index 000000000..d9a1c9fca --- /dev/null +++ b/apps/ffcniftya/ffcniftya.settings.js @@ -0,0 +1,25 @@ +(function(back) { + var FILE = "\ffcniftya.json"; + // Load settings + var cfg = Object.assign({ + showWeekNum: true, + }, require('Storage').readJSON(FILE, true) || {}); + + function writeSettings() { + require('Storage').writeJSON(FILE, cfg); + } + + // Show the menu + E.showMenu({ + "" : { "title" : "Nifty-A Clock" }, + "< Back" : () => back(), + 'week number?': { + value: cfg.showWeekNum, + format: v => v?"On":"Off", + onchange: v => { + cfg.showWeekNum = v; + writeSettings(); + } + } + }); +}) \ No newline at end of file diff --git a/apps/ffcniftya/screenshot_nifty.png b/apps/ffcniftya/screenshot_nifty.png index 0df056223c087638f940b2095330944c87df9906..3e394dced2b1a7907ff52ce3006ea83bed111d22 100644 GIT binary patch literal 52362 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 AM*si- diff --git a/apps/ffcniftya/screenshot_settings_nifty.png b/apps/ffcniftya/screenshot_settings_nifty.png new file mode 100644 index 0000000000000000000000000000000000000000..a13f6c16f0c70ab52566343e9ce842b57422ce3a GIT binary patch literal 46504 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 literal 0 HcmV?d00001 From 5ad730fb87a50a975a72be55acf766e06e915d45 Mon Sep 17 00:00:00 2001 From: Danny <31635744+DDDanny@users.noreply.github.com> Date: Sun, 26 Dec 2021 01:04:59 +0100 Subject: [PATCH 030/315] fix settings + added screenshots and changed README --- apps/ffcniftya/README.md | 16 ++++++++++++++-- apps/ffcniftya/ffcniftya.settings.js | 2 +- apps/ffcniftya/photo_nifty.png | Bin 0 -> 52362 bytes apps/ffcniftya/photo_settings_nifty.png | Bin 0 -> 46504 bytes apps/ffcniftya/screenshot_nifty.png | Bin 52362 -> 2379 bytes apps/ffcniftya/screenshot_settings_nifty.png | Bin 46504 -> 1431 bytes 6 files changed, 15 insertions(+), 3 deletions(-) create mode 100644 apps/ffcniftya/photo_nifty.png create mode 100644 apps/ffcniftya/photo_settings_nifty.png diff --git a/apps/ffcniftya/README.md b/apps/ffcniftya/README.md index 5ec8ab681..122483243 100644 --- a/apps/ffcniftya/README.md +++ b/apps/ffcniftya/README.md @@ -1,9 +1,21 @@ # Nifty-A Clock +Colors are black/white - photos have non correct camera color "blue" + ## This is the clock ![](screenshot_nifty.png) +[i]emulated[/i] + +![](phptp_nifty.png) +[i]photo[/i] + +## The week number can be turned of in settings +(default is [b]"On"[/b]) -## The week number can be turned On/Off via settings ![](screenshot_settings_nifty.png) -default is "On" +[i]emulated[/i] + +![](photo_settings_nifty.png) +[i]photo[/i] + diff --git a/apps/ffcniftya/ffcniftya.settings.js b/apps/ffcniftya/ffcniftya.settings.js index d9a1c9fca..f4112c9d7 100644 --- a/apps/ffcniftya/ffcniftya.settings.js +++ b/apps/ffcniftya/ffcniftya.settings.js @@ -22,4 +22,4 @@ } } }); -}) \ No newline at end of file +})(load); \ No newline at end of file diff --git a/apps/ffcniftya/photo_nifty.png b/apps/ffcniftya/photo_nifty.png new file mode 100644 index 0000000000000000000000000000000000000000..3e394dced2b1a7907ff52ce3006ea83bed111d22 GIT binary patch literal 52362 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 literal 0 HcmV?d00001 diff --git a/apps/ffcniftya/screenshot_nifty.png b/apps/ffcniftya/screenshot_nifty.png index 3e394dced2b1a7907ff52ce3006ea83bed111d22..de6ba651d3a25034c1fc4006efb5e3ca4dfdc860 100644 GIT binary patch literal 2379 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 Pg(-ultDnm{r-UW|MyW+1 literal 46504 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 From ece0c1c1de6403821fefd5ef94f149327f5cafc1 Mon Sep 17 00:00:00 2001 From: Danny <31635744+DDDanny@users.noreply.github.com> Date: Sun, 26 Dec 2021 01:13:55 +0100 Subject: [PATCH 031/315] fix settings, missing in apps.json --- apps.json | 4 +++- apps/ffcniftya/ffcniftya.settings.js | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/apps.json b/apps.json index e5e9f8f02..f2c5bbce0 100644 --- a/apps.json +++ b/apps.json @@ -4328,7 +4328,9 @@ "storage": [ {"name":"ffcniftya.app.js","url":"app.js"}, {"name":"ffcniftya.img","url":"app-icon.js","evaluate":true} - ] + {"name":"ffcniftya.settings.js","url":"settings.js"}, + ], + "data": [{"name":"ffcniftya.json"}] }, { "id": "ffcniftyb", diff --git a/apps/ffcniftya/ffcniftya.settings.js b/apps/ffcniftya/ffcniftya.settings.js index f4112c9d7..03d9f76f9 100644 --- a/apps/ffcniftya/ffcniftya.settings.js +++ b/apps/ffcniftya/ffcniftya.settings.js @@ -22,4 +22,4 @@ } } }); -})(load); \ No newline at end of file +}); \ No newline at end of file From 026a55f4fe96264953744e04bd2a4f740f5fe5c1 Mon Sep 17 00:00:00 2001 From: Danny <31635744+DDDanny@users.noreply.github.com> Date: Sun, 26 Dec 2021 01:18:14 +0100 Subject: [PATCH 032/315] settings and apps.json --- apps.json | 4 ++-- apps/ffcniftya/ffcniftya.settings.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps.json b/apps.json index f2c5bbce0..6c516bae5 100644 --- a/apps.json +++ b/apps.json @@ -4327,8 +4327,8 @@ "allow_emulator": true, "storage": [ {"name":"ffcniftya.app.js","url":"app.js"}, - {"name":"ffcniftya.img","url":"app-icon.js","evaluate":true} - {"name":"ffcniftya.settings.js","url":"settings.js"}, + {"name":"ffcniftya.img","url":"app-icon.js","evaluate":true}, + {"name":"ffcniftya.settings.js","url":"settings.js"} ], "data": [{"name":"ffcniftya.json"}] }, diff --git a/apps/ffcniftya/ffcniftya.settings.js b/apps/ffcniftya/ffcniftya.settings.js index 03d9f76f9..d9a1c9fca 100644 --- a/apps/ffcniftya/ffcniftya.settings.js +++ b/apps/ffcniftya/ffcniftya.settings.js @@ -22,4 +22,4 @@ } } }); -}); \ No newline at end of file +}) \ No newline at end of file From 1fb1489577a09e24a6f9b23ee734f795e4475d00 Mon Sep 17 00:00:00 2001 From: Danny <31635744+DDDanny@users.noreply.github.com> Date: Sun, 26 Dec 2021 01:27:13 +0100 Subject: [PATCH 033/315] fix settings filename --- apps/ffcniftya/{ffcniftya.settings.js => settings.js} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename apps/ffcniftya/{ffcniftya.settings.js => settings.js} (100%) diff --git a/apps/ffcniftya/ffcniftya.settings.js b/apps/ffcniftya/settings.js similarity index 100% rename from apps/ffcniftya/ffcniftya.settings.js rename to apps/ffcniftya/settings.js From aadc5eb65dde7a4f6f3b0ab3aff8975ca180f7a4 Mon Sep 17 00:00:00 2001 From: Danny <31635744+DDDanny@users.noreply.github.com> Date: Sun, 26 Dec 2021 01:30:48 +0100 Subject: [PATCH 034/315] Update README.md --- apps/ffcniftya/README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/ffcniftya/README.md b/apps/ffcniftya/README.md index 122483243..0c5e88b3d 100644 --- a/apps/ffcniftya/README.md +++ b/apps/ffcniftya/README.md @@ -4,18 +4,18 @@ Colors are black/white - photos have non correct camera color "blue" ## This is the clock ![](screenshot_nifty.png) -[i]emulated[/i] +*emulated* -![](phptp_nifty.png) -[i]photo[/i] +![](photo_nifty.png) +*photo* ## The week number can be turned of in settings (default is [b]"On"[/b]) ![](screenshot_settings_nifty.png) -[i]emulated[/i] +*emulated* ![](photo_settings_nifty.png) -[i]photo[/i] +*photo* From 85b4468e818620e2bd0d13aacf1d7f5c455e4b66 Mon Sep 17 00:00:00 2001 From: Danny <31635744+DDDanny@users.noreply.github.com> Date: Sun, 26 Dec 2021 02:40:32 +0100 Subject: [PATCH 035/315] Update README.md --- apps/ffcniftya/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/ffcniftya/README.md b/apps/ffcniftya/README.md index 0c5e88b3d..a4ef073dd 100644 --- a/apps/ffcniftya/README.md +++ b/apps/ffcniftya/README.md @@ -10,7 +10,7 @@ Colors are black/white - photos have non correct camera color "blue" *photo* ## The week number can be turned of in settings -(default is [b]"On"[/b]) +(default is **"On"**) ![](screenshot_settings_nifty.png) *emulated* From 12d5fb28ef2ced37f854eb4a632cf3d453bff6f9 Mon Sep 17 00:00:00 2001 From: Danny <31635744+DDDanny@users.noreply.github.com> Date: Sun, 26 Dec 2021 02:47:01 +0100 Subject: [PATCH 036/315] Update screenshot_nifty.png --- apps/ffcniftya/screenshot_nifty.png | Bin 2379 -> 2159 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/apps/ffcniftya/screenshot_nifty.png b/apps/ffcniftya/screenshot_nifty.png index de6ba651d3a25034c1fc4006efb5e3ca4dfdc860..bbee9e27cc3554f596fd9478068376001cc1740e 100644 GIT binary patch literal 2159 zcmcJRdpHyNAIC={VN54oFdCJ_{7Q4%a+ym+NUk$t$1t~Y*EZxDr!r1GE=Mlw2=AWJqfPp zWB@?z*^iLZJnoha04M>^IiY;7URs<|@tLwxy^dYj*%`&0=Y`!$)_-w3gS9nWJ#IAe z+;bHTZQyV0*!IaKtO<8^HaL{NYh91P1+P zq4XQIjpF?}N*^cfUdHcH$)0vS9wgAm#lN?68Jmt9dCsklU2Uwju#0~BuDD@xBL>5= zKu>oI`wSBn@e?;2#+R3d2v(U{bZ#%5Hxumy@kqV{yKKKqpbO6=X3cfLhHjiPg^Y-Y z)^%NeI#@g=+)e61tpukYZ7B&rW@ZKEMZ2t=sHznZ+cuj<)w9S~`_)^>6gfF1E!zf{ zSKEY!$)(Gf3YfJ}#W(9>Bmp$2uLCSL5XY-$6 zr@Dd&wimA!3tmgg7%MuKxCOjDAXgE1_#blJO9YFMJkXy~v(tdXcb)!fzI~RhYr6aB zcQi(dizvF!zgJAL35HbNm#&rdQB$@I4e;OQ{0iNk1Y{j{WPf%%qO#*`Ih)A?7BM_tqhdS!zt|u5k1;2WeDYNd%p5IwXN}=C%+ce-sba`hc?wdBZ z@MQ_Ps~m<1^3qsZSe2l_aO%?GH>Ba|H(RR`ENC7w(s|HEneM=m1mvgA!GO8jYAW z%HeM$8Z>(EZcs9qM*l4QN8$f%!{3z6uT$l07jfde?e?5Xitl4Ey{@+uP>cdE{Y33> z%S*GYAco4f4AzGi`r^u=?q|rNh>FCvBFY}8d~Djx#q^lW&NJO#V@nP2{~10m9nT>Z zl!`QH*EMfs`VUa&J()vbT7h$6D|}_rP#<5`v_DW<+wv(me?$$1sZQ_U&AN$0!*x)` z?YV<0D1Nq3zLXrISEsm5bgUM8MUf=F8GigSw*HO{ zkBj27T$!?sd|P~T`Y&)>#GwT|*+l-VC2~*$h3N=qKfjZuE^$+FE%i(qs*baU(2V8Bn|#G zZskbN6-WRldGJgV4sGQv=u`1{HPN_6YL)P|+`0)`8$D#hXw6bCxgbDs`9#L;_*&T& zKx?{%WFy^p4n&);8R>N^$8*!_oBmk(Mg$EmLAw&n(^%Ew_*&i0d@?sogEn44uijN) zs|RT{)9Unnz0V>BI0BX%)XeoiD2mKirS|ST*?_Go+9TEC+5W0%>k3WA2D}H-Dm+%4 zl5d=^YIyQm3QhH{O9H37Eme{O`|*FRF8(xyjzlY?dySyXRdrEH+Ov?2B#hy#!AhOO!+oz#}Z7!j`j4A4WQ64 zs}YNxWZl(SP9p5bP+eb8n$bq>k_W>Fruh8Oc5pSfu7uGk`y>F)IeR*_IfUi@7n-mH AkpKVy literal 2379 zcmds(c~lbU7QnG`Dod+zQZvX(6C0Pt9Z)gN#L^&jGM6+7l@wQy+_lou!f=Ul($XfE za>HD(QA{*b5ETX;#l$sKEHm82{n0<~yno(*@2_{x@7{avIrpA>zVF`qo$tYABtl+J zRSp0E$X~Ftagy2rsci1qA=Ov^)>1>%y!7xSIcEXKsLW zLC}YRrJ9h4g+X%&(w@9J3s;-0qHWs*|DB78Kb$=j`skRN$p2uTdZ*eK8cp;|a8IUC zbZRP`_vGgzSk*TEkg%`Df5khioSuBTbX`jksgs*?W~HTG?YH{RZ~x3Rr{Im~Ue-D~9)nmvZ0dDLD1)o0n1^)mfEJF?v!b1H zIj{JV64z zO5ZaWAKUy?LRd1iUT43o#rmY}5wOm{RpwR{%;Ijx2SYaGkXAe|(KkcdoBX8NTWUe? zwnGHVwL`|I@v&aes-eC*k_I!mwSf%REi8A87g1PqQN`7$sC!mp8HD4^EEq#0AG#t_&j7kR5Vm((sylDTC;%HY={&uU&Qv+I}RU?T{h<{)T z*2@H*a_wt<*+ASeE-}ZDw0|6f2ALCt+mL^?4ycR728Ppdcg|CQy)&P4*5zL?$;)EkmiEcxf;jxuy85S$*23#i)a9D4%)@^@8Cx zl5j|n8%7Cx)ilN>-&S@eN9gUe;2N_bVM)?SFM|$Ot1Mb}XbC@F73Gyh=&b>!;mt7N z_+y$Uk(?p)xemJ^C)7aD+kp9;_Qs&-To4#KK%7u9c34(dT=)ml&f}b5vLK(*Q0<%2 zIJ0-auq5D&WcZLZ>%X9oppDt^9q5fsclj8hSi=45q3@xDhBvt+1&>-JsW}ije7W;5 zGp&VOOCNq3pg&5=RifXF^^6V;bDn^Fw`ts}ktl`ed1#bk)GKbx%O!4zWV;><+2XJs zZ(^Wme#f5O?P)@MXBchU#rA7ZE1cAZK6>CL)E!3Ibb5_ACV%ehXES#kv4;CoVlNO={kw$S@ihwmL5qgb-uK35t0fft&qS_E2d zX>$$@bbayc9;o%dNfCf?9m;ymDS3LjuiL;lWrb4AUxQEgl1h%1H5s_W7P_Bc2p(N# z!+|MQoB|8xR&lgxvDrvlWu*};dMiKGk8<~%`yDnISFAOoj`m+H%)}I2F5r~juyTjO zsU_#1+D71^a2n*EDDG=<##>mUQ4*^=QnnQs;#KJS3o&wQ9fVTezpgKKi^)D$rs@@~ zr1Xz-FjTdIhRj&0QK1kvfNi~CYNx1cAYS%7mFPi2&zhz(R*42O$v_;IC6SQ)P62CY zSXuWa>^IMc>3+AJcV96Oynn_g ziG%1CMSCsTHJ93n{1cBvTKO}tJHKbFV&rn}PIEpVt1c%8=$c4?4(Q0$BA&;7KM&AR ze8ZYt!HG-h9lb^FAe_hkxbzfCJ7enfaT}|JaaWpA_p731hPdA{|LN^-+#B4vNu{2q zNcrb5=}K34_698aXDB%qPIuMUu{acwqMlvV5Us$8{PbSI*!+Z-gir^vAqcHf2C zG0~lr2W@c4LeWY+rxp(j;90sC7z9j`8R{;EAOFcZA$LM#)%_ V>F&$)YUu|EaN#`ChHCA7_g`( Date: Sun, 26 Dec 2021 02:56:59 +0100 Subject: [PATCH 037/315] Update README.md --- apps/ffcniftya/README.md | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/apps/ffcniftya/README.md b/apps/ffcniftya/README.md index a4ef073dd..769cbcb74 100644 --- a/apps/ffcniftya/README.md +++ b/apps/ffcniftya/README.md @@ -3,19 +3,16 @@ Colors are black/white - photos have non correct camera color "blue" ## This is the clock -![](screenshot_nifty.png) -*emulated* +![](screenshot_nifty.png) (*emulated*) -![](photo_nifty.png) -*photo* + +![](photo_nifty.png) (*photo*) ## The week number can be turned of in settings (default is **"On"**) -![](screenshot_settings_nifty.png) -*emulated* +![](screenshot_settings_nifty.png) (*emulated*) -![](photo_settings_nifty.png) -*photo* +![](photo_settings_nifty.png) (*photo*) From f9c3827596c8b9a2e380009990a9a8dd8b71777e Mon Sep 17 00:00:00 2001 From: Danny <31635744+DDDanny@users.noreply.github.com> Date: Sun, 26 Dec 2021 03:17:48 +0100 Subject: [PATCH 038/315] Update app.js --- apps/ffcniftya/app.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/ffcniftya/app.js b/apps/ffcniftya/app.js index 33722b3a3..5f23599a0 100644 --- a/apps/ffcniftya/app.js +++ b/apps/ffcniftya/app.js @@ -1,6 +1,6 @@ const locale = require("locale"); const is12Hour = (require("Storage").readJSON("setting.json", 1) || {})["12hour"]; -const CFG = require('Storage').readJSON("ffcniftya.json", true) || {showWeek: true}; +const CFG = require('Storage').readJSON("ffcniftya.json", 1) || {showWeek: true}; /* Clock *********************************************/ const scale = g.getWidth() / 176; @@ -43,6 +43,7 @@ function draw() { const day = d02(now.getDate()); const month = d02(now.getMonth() + 1); const year = now.getFullYear(now); + const weekNum = d02(ISO8601_week_no(now)); const monthName = locale.month(now, 3); const dayName = locale.dow(now, 3); From 8d6a16dc7446671b5ca201234eaf2f23b544253c Mon Sep 17 00:00:00 2001 From: Danny <31635744+DDDanny@users.noreply.github.com> Date: Sun, 26 Dec 2021 03:30:19 +0100 Subject: [PATCH 039/315] settings showWeekNum --- apps/ffcniftya/app.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/ffcniftya/app.js b/apps/ffcniftya/app.js index 5f23599a0..5da1ec48e 100644 --- a/apps/ffcniftya/app.js +++ b/apps/ffcniftya/app.js @@ -1,6 +1,6 @@ const locale = require("locale"); const is12Hour = (require("Storage").readJSON("setting.json", 1) || {})["12hour"]; -const CFG = require('Storage').readJSON("ffcniftya.json", 1) || {showWeek: true}; +const CFG = require('Storage').readJSON("ffcniftya.json", 1) || {showWeekNum: true}; /* Clock *********************************************/ const scale = g.getWidth() / 176; @@ -59,7 +59,7 @@ function draw() { g.drawString(year, centerDatesScaleX, center.y - 62 * scale); g.drawString(month, centerDatesScaleX, center.y - 44 * scale); g.drawString(day, centerDatesScaleX, center.y - 26 * scale); - if (CFG.showWeek) g.drawString(d02(ISO8601_week_no(now)), centerDatesScaleX, center.y + 15 * scale); + if (CFG.showWeekNum) g.drawString(d02(ISO8601_week_no(now)), centerDatesScaleX, center.y + 15 * scale); g.drawString(monthName, centerDatesScaleX, center.y + 48 * scale); g.drawString(dayName, centerDatesScaleX, center.y + 66 * scale); } From 13483ee80cc5d6a09dd89f9f5373d8b59df289c4 Mon Sep 17 00:00:00 2001 From: Danny <31635744+DDDanny@users.noreply.github.com> Date: Sun, 26 Dec 2021 03:38:26 +0100 Subject: [PATCH 040/315] Update settings.js --- apps/ffcniftya/settings.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/ffcniftya/settings.js b/apps/ffcniftya/settings.js index d9a1c9fca..3e69f08dc 100644 --- a/apps/ffcniftya/settings.js +++ b/apps/ffcniftya/settings.js @@ -3,7 +3,7 @@ // Load settings var cfg = Object.assign({ showWeekNum: true, - }, require('Storage').readJSON(FILE, true) || {}); + }, require('Storage').readJSON(FILE, 1) || {}); function writeSettings() { require('Storage').writeJSON(FILE, cfg); From 69276a06babd56e57cd82454ad652f9c4ba9a07e Mon Sep 17 00:00:00 2001 From: Danny <31635744+DDDanny@users.noreply.github.com> Date: Sun, 26 Dec 2021 16:04:51 +0100 Subject: [PATCH 041/315] Update settings.js --- apps/ffcniftya/settings.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/ffcniftya/settings.js b/apps/ffcniftya/settings.js index 3e69f08dc..65b6486b1 100644 --- a/apps/ffcniftya/settings.js +++ b/apps/ffcniftya/settings.js @@ -1,5 +1,5 @@ (function(back) { - var FILE = "\ffcniftya.json"; + var FILE = "ffcniftya.json"; // Load settings var cfg = Object.assign({ showWeekNum: true, From 9d30fe8139aff7613ffcfad17b75f1ef2a52cf5d Mon Sep 17 00:00:00 2001 From: Danny <31635744+DDDanny@users.noreply.github.com> Date: Sun, 26 Dec 2021 16:17:42 +0100 Subject: [PATCH 042/315] settings name typo --- apps/ffcniftya/settings.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/apps/ffcniftya/settings.js b/apps/ffcniftya/settings.js index 65b6486b1..46e4ef5aa 100644 --- a/apps/ffcniftya/settings.js +++ b/apps/ffcniftya/settings.js @@ -1,9 +1,7 @@ (function(back) { var FILE = "ffcniftya.json"; // Load settings - var cfg = Object.assign({ - showWeekNum: true, - }, require('Storage').readJSON(FILE, 1) || {}); + var cfg = require('Storage').readJSON(FILE, 1) || { showWeekNum: true }; function writeSettings() { require('Storage').writeJSON(FILE, cfg); From 604f6f6c476c3bf2cc963a75bfdff1bf9c2b1cb1 Mon Sep 17 00:00:00 2001 From: phil Date: Mon, 27 Dec 2021 14:33:53 -0500 Subject: [PATCH 043/315] Add time and life app --- apps.json | 17 +++ apps/timeandlife/ChangeLog | 1 + apps/timeandlife/README.md | 7 + apps/timeandlife/app-icon.js | 1 + apps/timeandlife/app.js | 278 +++++++++++++++++++++++++++++++++++ apps/timeandlife/app.png | Bin 0 -> 605 bytes 6 files changed, 304 insertions(+) create mode 100644 apps/timeandlife/ChangeLog create mode 100644 apps/timeandlife/README.md create mode 100644 apps/timeandlife/app-icon.js create mode 100644 apps/timeandlife/app.js create mode 100644 apps/timeandlife/app.png diff --git a/apps.json b/apps.json index e5e9f8f02..02ee3d469 100644 --- a/apps.json +++ b/apps.json @@ -5062,5 +5062,22 @@ {"name":"ltherm.app.js","url":"app.js"}, {"name":"ltherm.img","url":"icon.js","evaluate":true} ] + }, + { + "id": "timeandlife", + "name": "Time and Life", + "shortName":"Time and Lfie", + "icon": "app.png", + "version":"0.0.1", + "description": "A simple watchface which displays the time when the screen is tapped and decay according to the rules of Conway's game of life.", + "type": "clock", + "tags": "clock", + "supports": ["BANGLEJS2"], + "allow_emulator":true, + "readme": "README.md", + "storage": [ + {"name":"timeandlife.app.js","url":"app.js"}, + {"name":"timeandlife.img","url":"app-icon.js","evaluate":true} + ] } ] diff --git a/apps/timeandlife/ChangeLog b/apps/timeandlife/ChangeLog new file mode 100644 index 000000000..115067b80 --- /dev/null +++ b/apps/timeandlife/ChangeLog @@ -0,0 +1 @@ +0.01: New app diff --git a/apps/timeandlife/README.md b/apps/timeandlife/README.md new file mode 100644 index 000000000..af92d8cb8 --- /dev/null +++ b/apps/timeandlife/README.md @@ -0,0 +1,7 @@ +# Time and Life + +A simple watchface which displays the time when the screen is tapped and decay according to the rules of [Conway's game of life](https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life). + +![](screenshot1.png) +![](screenshot2.png) +![](screenshot3.png) diff --git a/apps/timeandlife/app-icon.js b/apps/timeandlife/app-icon.js new file mode 100644 index 000000000..d7608fca4 --- /dev/null +++ b/apps/timeandlife/app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwwkB/4AGCY4PHC/4X/C/4X/C/4XvJ/4X/C/4X/C/4X3AH4A/AH4A/AH4A/")) diff --git a/apps/timeandlife/app.js b/apps/timeandlife/app.js new file mode 100644 index 000000000..905ec3031 --- /dev/null +++ b/apps/timeandlife/app.js @@ -0,0 +1,278 @@ +// Globals +const X = 176, + Y = 176; // screen resolution of bangle 2 +const STEP_TIMEOUT = 1000; +const PAUSE_TIME = 3000; + +// Each of my pixels is an 8x8 square. +const ON = { + width: 8, + height: 8, + bpp: 1, + transparent: 0, + buffer: new Uint8Array([ + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + ]).buffer, + state: 1, +}; +const OFF = { + width: 8, + height: 8, + bpp: 1, + transparent: 1, + buffer: new Uint8Array([ + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + ]).buffer, + state: 0, +}; + +const ONE = [ + [0, 1, 0], + [1, 1, 0], + [0, 1, 0], + [0, 1, 0], + [0, 1, 0], + [0, 1, 0], + [1, 1, 1], +]; +const TWO = [ + [0, 1, 0], + [1, 0, 1], + [0, 0, 1], + [0, 1, 0], + [1, 0, 0], + [1, 0, 0], + [1, 1, 1], +]; +const THREE = [ + [0, 1, 0], + [1, 0, 1], + [0, 0, 1], + [0, 1, 0], + [0, 0, 1], + [1, 0, 1], + [0, 1, 0], +]; +const FOUR = [ + [0, 0, 1], + [1, 0, 1], + [1, 0, 1], + [1, 1, 1], + [0, 0, 1], + [0, 0, 1], + [0, 0, 1], +]; +const FIVE = [ + [1, 1, 1], + [1, 0, 0], + [1, 0, 0], + [0, 1, 0], + [0, 0, 1], + [1, 0, 1], + [0, 1, 0], +]; +const SIX = [ + [0, 1, 0], + [1, 0, 1], + [1, 0, 0], + [1, 1, 0], + [1, 0, 1], + [1, 0, 1], + [0, 1, 0], +]; +const SEVEN = [ + [1, 1, 1], + [1, 0, 1], + [0, 0, 1], + [0, 1, 0], + [0, 1, 0], + [0, 1, 0], + [0, 1, 0], +]; +const EIGHT = [ + [0, 1, 0], + [1, 0, 1], + [1, 0, 1], + [0, 1, 0], + [1, 0, 1], + [1, 0, 1], + [0, 1, 0], +]; +const NINE = [ + [0, 1, 0], + [1, 0, 1], + [1, 0, 1], + [0, 1, 1], + [0, 0, 1], + [1, 0, 1], + [0, 1, 0], +]; +const ZERO = [ + [0, 1, 0], + [1, 0, 1], + [1, 0, 1], + [1, 0, 1], + [1, 0, 1], + [1, 0, 1], + [0, 1, 0], +]; +const NUMBERS = [ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE]; + +// Arraybuffers to store game state +// 484 8 bit integers that are either 1 or 0 form the 22 x 22 grid +let emptySeed = []; +for (i = 0; i < 484; i++) { + emptySeed.push(0); +} +let data = E.toUint8Array(emptySeed); +let nextData = E.toUint8Array(emptySeed); +const dataAddr = E.getAddressOf(data, true); +const nextDataAddr = E.getAddressOf(nextData, true); + +let lastPaused = new Date(); + +const forAllElements = fn => { + let numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21]; + numbers.forEach(i => { + numbers.forEach(j => { + fn(i, j); + }); + }); +}; + +// Conway's game of life +// if < 2 neighbours, set off +// if 2 or 3 neighbours, set on +// if > 3 neighbours, set off +const updateStateC = E.compiledC(` +// void run(int, int) +void run(char* n, char* m){ + // n is a pointer to the first byte in data, m is for nextdata + int count = 0; + for (int i=0;i<484;i++) { + // Add 8 neighbours, wrapping around + count = + *(n+(i+484-23)%484) + + *(n+(i+484-22)%484) + + *(n+(i+484-21)%484) + + *(n+(i+484-1)%484) + + *(n+(i+484+1)%484) + + *(n+(i+484+21)%484) + + *(n+(i+484+22)%484) + + *(n+(i+484+23)%484); + if (count < 2 || count > 3) { + *(m+i) = 0; + } else { + *(m+i) = 1; + } + } +} +`); +const copyStateC = E.compiledC(` +// void run(int, int) +void run(char* n, char* m){ + // n is a pointer to the first byte in data, m is for nextdata + for (int i=0;i<484;i++) { + *(n+i) = *(m+i); + } +} +`); + +const step = () => { + if (new Date() - lastPaused < PAUSE_TIME) { + return; + } + let startTime = new Date(); + updateStateC.run(dataAddr, nextDataAddr); + nextData.forEach((e, i) => { + if (e && !data[i]) { + g.drawImage(ON, Math.floor(i / 22) * 8, i % 22 * 8); + } else if (data[i]) { + g.drawImage(OFF, Math.floor(i / 22) * 8, i % 22 * 8); + } + }); + copyStateC.run(dataAddr, nextDataAddr); +}; + +const drawPixel = (i, j, value) => { + g.drawImage(value, j * 8, i * 8); + data[j * 22 + i] = value.state; + nextData[j * 22 + i] = value.state; +}; + +const drawNum = (character, i, j) => { + const startJ = j; + character.forEach(row => { + j = startJ; + row.forEach(pixel => { + if (pixel) { + drawPixel(i, j, ON); + } + j++; + }); + i++; + }); +}; + +const drawDots = () => { + drawPixel(10, 10, ON); + drawPixel(12, 10, ON); +}; + +const drawTime = () => { + lastPaused = new Date(); + g.clear(); + data.forEach((el, i) => { + data[i] = 0; + }); + const d = new Date(); + const hourTens = Math.floor(d.getHours() / 10); + const hourOnes = d.getHours() % 10; + const minuteTens = Math.floor(d.getMinutes() / 10); + const minuteOnes = d.getMinutes() % 10; + drawNum(NUMBERS[hourTens], 8, 1); + drawNum(NUMBERS[hourOnes], 8, 6); + drawDots(); + drawNum(NUMBERS[minuteTens], 8, 13); + drawNum(NUMBERS[minuteOnes], 8, 18); +}; + +const start = () => { + Bangle.setUI("clock"); // Show launcher when middle button pressed + g.clear(); + Bangle.setLCDTimeout(20); // backlight/lock timeout in seconds + let stepInterval = setInterval(step, STEP_TIMEOUT); + + // Handlers + Bangle.on('touch', drawTime); + + // Sleep mode + Bangle.on('lock', isLocked => { + if (stepInterval) { + clearInterval(stepInterval); + } + stepInterval = undefined; + if (!isLocked) { + drawTime(); + stepInterval = setInterval(step, STEP_TIMEOUT); + } + }); + + drawTime(); +}; + +start(); diff --git a/apps/timeandlife/app.png b/apps/timeandlife/app.png new file mode 100644 index 0000000000000000000000000000000000000000..b1e837d258215458c7427ee87669e9bbac4a6cff GIT binary patch literal 605 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA1SD@Hc}*5j~)%+dI0Z`UZ9TaH&0ol7?IxJKYaYEcX0Eb^M5Usybh)`_$$my-IXYqFW{daW%a!F zk%YE4*GJ2bGaSWL>YnU+^GW*oq{DUdB#k%Ctb8P~G2m6w&hE&Y0iDY`9(Sz@+-LuM z)1k`l%~5MNf3y9`eV8>jb>?f6_KAm-rYSfz^jK-FIONn6)+-_`dCR}*2fOTk551W& zq6S4e3)n;_J!b#keE;sOqbE7dHRrH2>2LdM$kbBS7$1N0nDxpV8r5TsRNT2Pd=c+H@LRGrSgzw9Q*Cx${@dC)b_|iP zv}&1UWSADKo{IZkQJ!C(|9@WQ_wUTwQbk=Q7Cfhb(ZX5a5n0T@pr;JNj1^1m%YcIH zC7!;n>`!^5g?X8JOXb~wLXst}5hc#~xw)x%B@E6*sfi`2DGKG8B^e6tp1uL$jeO!j zMed$1jv*0;-(EY&$)Lc);&}dFb)V@ScbByLLhPSB)6z^;SKizH`FoX)0vIf~@0j_1 o>aXTcb(@SJA_|_9RAS#UOgP19!;<*A7ic7dr>mdKI;Vst02rI_VgLXD literal 0 HcmV?d00001 From fb14142593aff4a48411251d593cf26a386a60da Mon Sep 17 00:00:00 2001 From: phil Date: Mon, 27 Dec 2021 14:38:57 -0500 Subject: [PATCH 044/315] fix screenshot --- apps/timeandlife/README.md | 4 +--- apps/timeandlife/screenshot.png | Bin 0 -> 811 bytes 2 files changed, 1 insertion(+), 3 deletions(-) create mode 100644 apps/timeandlife/screenshot.png diff --git a/apps/timeandlife/README.md b/apps/timeandlife/README.md index af92d8cb8..b03cbf2fb 100644 --- a/apps/timeandlife/README.md +++ b/apps/timeandlife/README.md @@ -2,6 +2,4 @@ A simple watchface which displays the time when the screen is tapped and decay according to the rules of [Conway's game of life](https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life). -![](screenshot1.png) -![](screenshot2.png) -![](screenshot3.png) +![](screenshot.png) diff --git a/apps/timeandlife/screenshot.png b/apps/timeandlife/screenshot.png new file mode 100644 index 0000000000000000000000000000000000000000..5ffda5bf052b411fab011024b6e8cf9a6b4aedb0 GIT binary patch literal 811 zcmeAS@N?(olHy`uVBq!ia0vp^`+;~L2OE$~*>-O+kYXuz@(kesf*OvL4j^B$#5JNM zI6tkVJh3R1Aw4fYH&wSdxhOR?uQ(&WkRs=z)Wnj^{5*w_%-mE4Um(NC zT)`zZS;5G_$WXz+$jaEl%D_?~z*qO>a-g+L9iA?ZAr*7p-gV46Y#`upan+Z9(?1=& zBE6;C@x+t;+j&*Iew;~4dh^xh{J*9JTfd9hd*0v9&#=8?zRt(Vs&$)=_)q(BQpi5? zk-GPvl+M8`Sm(FzXVmNS*T3IWx34?%^L*XED_{PoVYvHR#`*fHe(Tce^R>6W{J#6I zcG>gUMn5q;=vMvjcJ;08)_dLSfBzTBx1WC!BN$4*?6b}P{_XcEpS%0w{@ZUqpZ*CW zylTJ9tKX$Q?;n3bb^qUQzrWo{!>Z>0w%g}-{{3S6cM2A3zFO}2cExzz_4$UF&b+ox jzxpH==MTb2t79xWAF@BqJ@q&+Av1Wo`njxgN@xNAJLr-e literal 0 HcmV?d00001 From 27be246c82c14f31943567875392469b548cbb2d Mon Sep 17 00:00:00 2001 From: phil Date: Mon, 27 Dec 2021 14:43:37 -0500 Subject: [PATCH 045/315] fix screenshot and description --- apps.json | 2 +- apps/timeandlife/README.md | 2 +- apps/timeandlife/screenshot.png | Bin 811 -> 1634 bytes 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps.json b/apps.json index 02ee3d469..62e78b8da 100644 --- a/apps.json +++ b/apps.json @@ -5069,7 +5069,7 @@ "shortName":"Time and Lfie", "icon": "app.png", "version":"0.0.1", - "description": "A simple watchface which displays the time when the screen is tapped and decay according to the rules of Conway's game of life.", + "description": "A simple watchface which displays the time when the screen is tapped and decays according to the rules of Conway's game of life.", "type": "clock", "tags": "clock", "supports": ["BANGLEJS2"], diff --git a/apps/timeandlife/README.md b/apps/timeandlife/README.md index b03cbf2fb..4a638c952 100644 --- a/apps/timeandlife/README.md +++ b/apps/timeandlife/README.md @@ -1,5 +1,5 @@ # Time and Life -A simple watchface which displays the time when the screen is tapped and decay according to the rules of [Conway's game of life](https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life). +A simple watchface which displays the time when the screen is tapped and decays according to the rules of [Conway's game of life](https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life). ![](screenshot.png) diff --git a/apps/timeandlife/screenshot.png b/apps/timeandlife/screenshot.png index 5ffda5bf052b411fab011024b6e8cf9a6b4aedb0..3058c9346bbcb23f5348729b81179b6d6b80f37a 100644 GIT binary patch literal 1634 zcmeHIZA@Bc6utsQvBj^}W}*_hR!C)GC#$-1|oh&)E>oL(CuCH=%fOR`#=Rksa|_HeHk9@bbzPZ ze?c(;KS|^x#fxruwmzncRwO-;Pi*%aVP>N^>K0v8ZTW+Js@i*`@P<0;(kb&;PzY=F zTHJw6Q{}*2qH13eHsIHx)_?;II@%Kg9mZ$IF2CU`k3$Z5!8X;DjYckQL6nQe%idiFjU{bm(i(t*KC~zu+1)Tf2 z%XoRakyjPm#s4I8>5RXWc1On@73BAZVGqxLu^S<}&uDP=!laTfO?aHFL}y~#{W?sC zHsqL%{*e&-jX`R4eDt(~EFNS1G;j6OZ6);C3}{->aD!TpiHG!4YE_1-d3pi(Ah*1o))?Yv+!?^jBo{$GA>%jwMfJYA zoX)s@n1tssu=oYouVV^2n9wR@b2_%pU`HfP6Vy7Q^4fz;PX1tk_Txm;GD9F429sWS z93tc`gO2G{;YFp5Qdi<=$YRpBfkW9WZlI@+Sz~k7O17Y{<$%%-#xhWZ+wi+=J1jTC zdnv&poFHE!LIrZBcvbi5sbFtYg$vnVVnMJmVS+$*V){-{V zZ2A1rJ?$#6zH8eH~hTgZsal^9Z5qyfHj{ z#TlB|PpmHvst(?plyxH=S0arH(X)GXxhbixLk;+~(s5!lkQkGDQZ0ZIP^UD-!-t%AJ2YtW;C(BEA(jq N#RVlCRUZGde*iBqFmwO_ literal 811 zcmeAS@N?(olHy`uVBq!ia0vp^`+;~L2OE$~*>-O+kYXuz@(kesf*OvL4j^B$#5JNM zI6tkVJh3R1Aw4fYH&wSdxhOR?uQ(&WkRs=z)Wnj^{5*w_%-mE4Um(NC zT)`zZS;5G_$WXz+$jaEl%D_?~z*qO>a-g+L9iA?ZAr*7p-gV46Y#`upan+Z9(?1=& zBE6;C@x+t;+j&*Iew;~4dh^xh{J*9JTfd9hd*0v9&#=8?zRt(Vs&$)=_)q(BQpi5? zk-GPvl+M8`Sm(FzXVmNS*T3IWx34?%^L*XED_{PoVYvHR#`*fHe(Tce^R>6W{J#6I zcG>gUMn5q;=vMvjcJ;08)_dLSfBzTBx1WC!BN$4*?6b}P{_XcEpS%0w{@ZUqpZ*CW zylTJ9tKX$Q?;n3bb^qUQzrWo{!>Z>0w%g}-{{3S6cM2A3zFO}2cExzz_4$UF&b+ox jzxpH==MTb2t79xWAF@BqJ@q&+Av1Wo`njxgN@xNAJLr-e From b9cda9b829e29a7075d49eaf56e3d8110ae19f9f Mon Sep 17 00:00:00 2001 From: phil Date: Mon, 27 Dec 2021 14:55:22 -0500 Subject: [PATCH 046/315] version number --- apps.json | 2 +- apps/timeandlife/ChangeLog | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps.json b/apps.json index 62e78b8da..15d3005c6 100644 --- a/apps.json +++ b/apps.json @@ -5068,7 +5068,7 @@ "name": "Time and Life", "shortName":"Time and Lfie", "icon": "app.png", - "version":"0.0.1", + "version":"0.1", "description": "A simple watchface which displays the time when the screen is tapped and decays according to the rules of Conway's game of life.", "type": "clock", "tags": "clock", diff --git a/apps/timeandlife/ChangeLog b/apps/timeandlife/ChangeLog index 115067b80..c7b309a74 100644 --- a/apps/timeandlife/ChangeLog +++ b/apps/timeandlife/ChangeLog @@ -1 +1 @@ -0.01: New app +0.1: New app From 77d785bb68d3fdc1380110d58a8e6dec9ff0831c Mon Sep 17 00:00:00 2001 From: phil Date: Wed, 29 Dec 2021 22:31:58 -0500 Subject: [PATCH 047/315] remove unused code --- apps/timeandlife/app.js | 9 --------- 1 file changed, 9 deletions(-) diff --git a/apps/timeandlife/app.js b/apps/timeandlife/app.js index 905ec3031..7532f9bc8 100644 --- a/apps/timeandlife/app.js +++ b/apps/timeandlife/app.js @@ -145,15 +145,6 @@ const nextDataAddr = E.getAddressOf(nextData, true); let lastPaused = new Date(); -const forAllElements = fn => { - let numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21]; - numbers.forEach(i => { - numbers.forEach(j => { - fn(i, j); - }); - }); -}; - // Conway's game of life // if < 2 neighbours, set off // if 2 or 3 neighbours, set on From ee3a1ced6283778950d3aa748537d76bbe780b86 Mon Sep 17 00:00:00 2001 From: Peter Slendebroek Date: Sun, 2 Jan 2022 17:38:24 +0100 Subject: [PATCH 048/315] create app.js create app.js --- mmind/app.js | 198 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 198 insertions(+) create mode 100644 mmind/app.js diff --git a/mmind/app.js b/mmind/app.js new file mode 100644 index 000000000..e7def025d --- /dev/null +++ b/mmind/app.js @@ -0,0 +1,198 @@ +//MMind + +//set vars +const H = g.getWidth(); +const W = g.getHeight(); +var touch_actions = []; +var cols = ["#FF0000","#00FF00","#0000FF", "#FF00FF", "#FFFF00", "#00FFFF", "#000000","#FFFFFF"]; +var turn = 0; +var col_menu = false; +//pinsRow = 6; +//pinsThick = 10; +//pinsRow = 5; +//pinsThick = 10; +var pinsRow = 4; +var pinsThick = 10; +var play = [-1, -1, -1, -1]; + +var pinsCol = 5; +var playx = -1; +var sx = (W - 30 )/pinsRow; +var sy = (H - 20 )/7; +var touch_actions = []; +var secret = []; +var secret_no_dub = true; +var endgame = false; + +g.clear(); +g.setColor("#FFFFFF"); +g.fillRect(0, 0, H, W); +g.setFont("Vector12",45); + +function draw() { + touch_actions = []; + g.clear(); + g.setColor("#FFFFFF"); + g.fillRect(0, 0, H, W); + g.setColor("#000000"); + //draw scores + for (y=0;y= 0) s = Math.round(Math.random()*pinsCol); + secret[i]= s; + } + } + +function score() { + bScore = 0; + wScore = 0; + for (i=0; i touch_actions[i][0][0] && e.x < touch_actions[i][0][2] && + e.y > touch_actions[i][0][1] && e.y < touch_actions[i][0][3]) { + // a action is hit, add acctions here, todo: start, stop, new, etc. + switch (touch_actions[i][1][0]) { + case 1: + //get pins col menu + col_menu = 1; + playx = touch_actions[i][1][1]; + break; + case 2: + //copy choice col to play + play[playx] = touch_actions[i][1][1]; + col_menu = 0; + break; + case 3: + //score play + var sc; + sc = score(); + game.push([play, sc]); + play = [-1,-1,-1,-1]; + turn+=1; + if (turn==6 || sc[0]==pinsRow) { + play = secret; + col_menu = 0; + endgame = true; + } + break; + case 4: + //new game + play = [-1,-1,-1,-1]; + game = []; + endgame=false; + break; + } + } + } + //console.log(touch_actions[i][1][0], touch_actions[i][1][1]); + + draw(); + } +); + + +game = []; +get_secret(); +draw(); +//Bangle.loadWidgets(); +//Bangle.drawWidgets(); + + + + + From c8f914359e8acd92373763f2be76f2ecaa50ce9a Mon Sep 17 00:00:00 2001 From: Peter Slendebroek Date: Sun, 2 Jan 2022 17:57:26 +0100 Subject: [PATCH 049/315] add icon file --- mmind/app.png | Bin 0 -> 1339 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 mmind/app.png diff --git a/mmind/app.png b/mmind/app.png new file mode 100644 index 0000000000000000000000000000000000000000..bb2a27ae5c614707bb35d6400f75e54514db68f5 GIT binary patch literal 1339 zcmWksdsLDK6u&Bc8AzQnW~4PLALTKIS<=?yL>fMGil(EZsY6p+Ddraun#DXU*>}En zENaEf9LG?zAR~69ma$sSLu6rV_&jP4W=qXXQ&eJ~f82Y|@7{Co{oUWW^7yz2DtS2> z0H{%s;XER;=FHuV@EJV|^h9te;zjHPO`Fdf0+4bzyEy=jKT&2g=K;7D#m6S?ayp$u zLqn%dokCI6Xf*cq^+_a>&dyGo%_fyf&1SRRZZ{YV0|Nu448{)`#BooBC)npO zRY}$Av=)nnPL~6W5h(;wS5>KXTAh-rbb`|kc7>EO&SJ@$qpUk4LA|RVtM@ zI(h~`MIud3PWqPk(qy!ek&%!P5r6|ha2ZWj;#+e6{(Y;}%49M}M@Q@H>oE*Ny}T>{ zgM)*B5zWM9D1bo)Dhx1`&2A(}jE&KxGzv~(Fo=>8r{GeW)NC>-C=`NnCqS7%;BYvq z)zyd|0SAzbBut6v^#*tM8h{yBSF=cjD>0>!WORT-kLcCa>cGIj($Z3eLb1uylL?TM zo?cZ|g|HA{0*>Qat(Hm+0bq(m5+*QN2&{3UN4ybqGx+ z^DQY!PEMA|WCDSJ&1QRhdwZc?U;z{bgMpAm1sIl=mX@EN&qmqMNaPvBcnXfwq*9aF zL{U%(Ap~UtgF#kpgWoKv0<#Olbq|;()X=(BD@~W(?6bglT zd3jEo&55EHSCc~tT^0x<`9%N=AIzD{Uj=np#7`zfg>#Z3V}{TDd(Z!B8KWQtuad}i)RH=J% z@$RJI-Q9bg#g`Wqy-BZ&O2nQEL+|*t2~Y3;tajizK zG7#9eo=$~h(#z7qmjUjc0lW9Jv;W&zIPDR-vFM+J$J$bxW?fS<6M_@2Zut6r;2-v> zFW!DH!&nhXH^ot{!kC}er)M@jHSO{1Ij2dsD)RPr?TyRpl@vbUn)!)m(xT+TcJ<@w z^VfylrU%_eh0*PCeH!u^(Tx1#(CbU@!lLON1z+*HPVBHwltsRYzi^}@?9&?b)`m|V zg-Bd~T|fnI;mLzF=#SR7wH57j$f1p;yiYu&{kGrd4FbFvB(X zz$=dwjeogSv*yYR)y@>ocJJGTAI_J~EbQqm9++9Qa>+KywcO|VlV@vF8;*UPoo6dQ zkluVXB=zB2b^$eIa^(2>qg5M*-6EzN|E_CUniw1GI5C}6VDfSDCYov)9tUmLAEod9 zpn2W>QJ2@sFAF6 Date: Sun, 2 Jan 2022 18:03:21 +0100 Subject: [PATCH 050/315] Delete mmind directory --- mmind/app.js | 198 -------------------------------------------------- mmind/app.png | Bin 1339 -> 0 bytes 2 files changed, 198 deletions(-) delete mode 100644 mmind/app.js delete mode 100644 mmind/app.png diff --git a/mmind/app.js b/mmind/app.js deleted file mode 100644 index e7def025d..000000000 --- a/mmind/app.js +++ /dev/null @@ -1,198 +0,0 @@ -//MMind - -//set vars -const H = g.getWidth(); -const W = g.getHeight(); -var touch_actions = []; -var cols = ["#FF0000","#00FF00","#0000FF", "#FF00FF", "#FFFF00", "#00FFFF", "#000000","#FFFFFF"]; -var turn = 0; -var col_menu = false; -//pinsRow = 6; -//pinsThick = 10; -//pinsRow = 5; -//pinsThick = 10; -var pinsRow = 4; -var pinsThick = 10; -var play = [-1, -1, -1, -1]; - -var pinsCol = 5; -var playx = -1; -var sx = (W - 30 )/pinsRow; -var sy = (H - 20 )/7; -var touch_actions = []; -var secret = []; -var secret_no_dub = true; -var endgame = false; - -g.clear(); -g.setColor("#FFFFFF"); -g.fillRect(0, 0, H, W); -g.setFont("Vector12",45); - -function draw() { - touch_actions = []; - g.clear(); - g.setColor("#FFFFFF"); - g.fillRect(0, 0, H, W); - g.setColor("#000000"); - //draw scores - for (y=0;y= 0) s = Math.round(Math.random()*pinsCol); - secret[i]= s; - } - } - -function score() { - bScore = 0; - wScore = 0; - for (i=0; i touch_actions[i][0][0] && e.x < touch_actions[i][0][2] && - e.y > touch_actions[i][0][1] && e.y < touch_actions[i][0][3]) { - // a action is hit, add acctions here, todo: start, stop, new, etc. - switch (touch_actions[i][1][0]) { - case 1: - //get pins col menu - col_menu = 1; - playx = touch_actions[i][1][1]; - break; - case 2: - //copy choice col to play - play[playx] = touch_actions[i][1][1]; - col_menu = 0; - break; - case 3: - //score play - var sc; - sc = score(); - game.push([play, sc]); - play = [-1,-1,-1,-1]; - turn+=1; - if (turn==6 || sc[0]==pinsRow) { - play = secret; - col_menu = 0; - endgame = true; - } - break; - case 4: - //new game - play = [-1,-1,-1,-1]; - game = []; - endgame=false; - break; - } - } - } - //console.log(touch_actions[i][1][0], touch_actions[i][1][1]); - - draw(); - } -); - - -game = []; -get_secret(); -draw(); -//Bangle.loadWidgets(); -//Bangle.drawWidgets(); - - - - - diff --git a/mmind/app.png b/mmind/app.png deleted file mode 100644 index bb2a27ae5c614707bb35d6400f75e54514db68f5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1339 zcmWksdsLDK6u&Bc8AzQnW~4PLALTKIS<=?yL>fMGil(EZsY6p+Ddraun#DXU*>}En zENaEf9LG?zAR~69ma$sSLu6rV_&jP4W=qXXQ&eJ~f82Y|@7{Co{oUWW^7yz2DtS2> z0H{%s;XER;=FHuV@EJV|^h9te;zjHPO`Fdf0+4bzyEy=jKT&2g=K;7D#m6S?ayp$u zLqn%dokCI6Xf*cq^+_a>&dyGo%_fyf&1SRRZZ{YV0|Nu448{)`#BooBC)npO zRY}$Av=)nnPL~6W5h(;wS5>KXTAh-rbb`|kc7>EO&SJ@$qpUk4LA|RVtM@ zI(h~`MIud3PWqPk(qy!ek&%!P5r6|ha2ZWj;#+e6{(Y;}%49M}M@Q@H>oE*Ny}T>{ zgM)*B5zWM9D1bo)Dhx1`&2A(}jE&KxGzv~(Fo=>8r{GeW)NC>-C=`NnCqS7%;BYvq z)zyd|0SAzbBut6v^#*tM8h{yBSF=cjD>0>!WORT-kLcCa>cGIj($Z3eLb1uylL?TM zo?cZ|g|HA{0*>Qat(Hm+0bq(m5+*QN2&{3UN4ybqGx+ z^DQY!PEMA|WCDSJ&1QRhdwZc?U;z{bgMpAm1sIl=mX@EN&qmqMNaPvBcnXfwq*9aF zL{U%(Ap~UtgF#kpgWoKv0<#Olbq|;()X=(BD@~W(?6bglT zd3jEo&55EHSCc~tT^0x<`9%N=AIzD{Uj=np#7`zfg>#Z3V}{TDd(Z!B8KWQtuad}i)RH=J% z@$RJI-Q9bg#g`Wqy-BZ&O2nQEL+|*t2~Y3;tajizK zG7#9eo=$~h(#z7qmjUjc0lW9Jv;W&zIPDR-vFM+J$J$bxW?fS<6M_@2Zut6r;2-v> zFW!DH!&nhXH^ot{!kC}er)M@jHSO{1Ij2dsD)RPr?TyRpl@vbUn)!)m(xT+TcJ<@w z^VfylrU%_eh0*PCeH!u^(Tx1#(CbU@!lLON1z+*HPVBHwltsRYzi^}@?9&?b)`m|V zg-Bd~T|fnI;mLzF=#SR7wH57j$f1p;yiYu&{kGrd4FbFvB(X zz$=dwjeogSv*yYR)y@>ocJJGTAI_J~EbQqm9++9Qa>+KywcO|VlV@vF8;*UPoo6dQ zkluVXB=zB2b^$eIa^(2>qg5M*-6EzN|E_CUniw1GI5C}6VDfSDCYov)9tUmLAEod9 zpn2W>QJ2@sFAF6 Date: Sun, 2 Jan 2022 18:04:12 +0100 Subject: [PATCH 051/315] Create app.js --- apps/mmind/app.js | 198 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 198 insertions(+) create mode 100644 apps/mmind/app.js diff --git a/apps/mmind/app.js b/apps/mmind/app.js new file mode 100644 index 000000000..e7def025d --- /dev/null +++ b/apps/mmind/app.js @@ -0,0 +1,198 @@ +//MMind + +//set vars +const H = g.getWidth(); +const W = g.getHeight(); +var touch_actions = []; +var cols = ["#FF0000","#00FF00","#0000FF", "#FF00FF", "#FFFF00", "#00FFFF", "#000000","#FFFFFF"]; +var turn = 0; +var col_menu = false; +//pinsRow = 6; +//pinsThick = 10; +//pinsRow = 5; +//pinsThick = 10; +var pinsRow = 4; +var pinsThick = 10; +var play = [-1, -1, -1, -1]; + +var pinsCol = 5; +var playx = -1; +var sx = (W - 30 )/pinsRow; +var sy = (H - 20 )/7; +var touch_actions = []; +var secret = []; +var secret_no_dub = true; +var endgame = false; + +g.clear(); +g.setColor("#FFFFFF"); +g.fillRect(0, 0, H, W); +g.setFont("Vector12",45); + +function draw() { + touch_actions = []; + g.clear(); + g.setColor("#FFFFFF"); + g.fillRect(0, 0, H, W); + g.setColor("#000000"); + //draw scores + for (y=0;y= 0) s = Math.round(Math.random()*pinsCol); + secret[i]= s; + } + } + +function score() { + bScore = 0; + wScore = 0; + for (i=0; i touch_actions[i][0][0] && e.x < touch_actions[i][0][2] && + e.y > touch_actions[i][0][1] && e.y < touch_actions[i][0][3]) { + // a action is hit, add acctions here, todo: start, stop, new, etc. + switch (touch_actions[i][1][0]) { + case 1: + //get pins col menu + col_menu = 1; + playx = touch_actions[i][1][1]; + break; + case 2: + //copy choice col to play + play[playx] = touch_actions[i][1][1]; + col_menu = 0; + break; + case 3: + //score play + var sc; + sc = score(); + game.push([play, sc]); + play = [-1,-1,-1,-1]; + turn+=1; + if (turn==6 || sc[0]==pinsRow) { + play = secret; + col_menu = 0; + endgame = true; + } + break; + case 4: + //new game + play = [-1,-1,-1,-1]; + game = []; + endgame=false; + break; + } + } + } + //console.log(touch_actions[i][1][0], touch_actions[i][1][1]); + + draw(); + } +); + + +game = []; +get_secret(); +draw(); +//Bangle.loadWidgets(); +//Bangle.drawWidgets(); + + + + + From fd7264a31d97c02bfb64504881fc4cfd22809e2c Mon Sep 17 00:00:00 2001 From: Peter Slendebroek Date: Sun, 2 Jan 2022 18:04:39 +0100 Subject: [PATCH 052/315] Add files via upload --- apps/mmind/app.png | Bin 0 -> 1339 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 apps/mmind/app.png diff --git a/apps/mmind/app.png b/apps/mmind/app.png new file mode 100644 index 0000000000000000000000000000000000000000..bb2a27ae5c614707bb35d6400f75e54514db68f5 GIT binary patch literal 1339 zcmWksdsLDK6u&Bc8AzQnW~4PLALTKIS<=?yL>fMGil(EZsY6p+Ddraun#DXU*>}En zENaEf9LG?zAR~69ma$sSLu6rV_&jP4W=qXXQ&eJ~f82Y|@7{Co{oUWW^7yz2DtS2> z0H{%s;XER;=FHuV@EJV|^h9te;zjHPO`Fdf0+4bzyEy=jKT&2g=K;7D#m6S?ayp$u zLqn%dokCI6Xf*cq^+_a>&dyGo%_fyf&1SRRZZ{YV0|Nu448{)`#BooBC)npO zRY}$Av=)nnPL~6W5h(;wS5>KXTAh-rbb`|kc7>EO&SJ@$qpUk4LA|RVtM@ zI(h~`MIud3PWqPk(qy!ek&%!P5r6|ha2ZWj;#+e6{(Y;}%49M}M@Q@H>oE*Ny}T>{ zgM)*B5zWM9D1bo)Dhx1`&2A(}jE&KxGzv~(Fo=>8r{GeW)NC>-C=`NnCqS7%;BYvq z)zyd|0SAzbBut6v^#*tM8h{yBSF=cjD>0>!WORT-kLcCa>cGIj($Z3eLb1uylL?TM zo?cZ|g|HA{0*>Qat(Hm+0bq(m5+*QN2&{3UN4ybqGx+ z^DQY!PEMA|WCDSJ&1QRhdwZc?U;z{bgMpAm1sIl=mX@EN&qmqMNaPvBcnXfwq*9aF zL{U%(Ap~UtgF#kpgWoKv0<#Olbq|;()X=(BD@~W(?6bglT zd3jEo&55EHSCc~tT^0x<`9%N=AIzD{Uj=np#7`zfg>#Z3V}{TDd(Z!B8KWQtuad}i)RH=J% z@$RJI-Q9bg#g`Wqy-BZ&O2nQEL+|*t2~Y3;tajizK zG7#9eo=$~h(#z7qmjUjc0lW9Jv;W&zIPDR-vFM+J$J$bxW?fS<6M_@2Zut6r;2-v> zFW!DH!&nhXH^ot{!kC}er)M@jHSO{1Ij2dsD)RPr?TyRpl@vbUn)!)m(xT+TcJ<@w z^VfylrU%_eh0*PCeH!u^(Tx1#(CbU@!lLON1z+*HPVBHwltsRYzi^}@?9&?b)`m|V zg-Bd~T|fnI;mLzF=#SR7wH57j$f1p;yiYu&{kGrd4FbFvB(X zz$=dwjeogSv*yYR)y@>ocJJGTAI_J~EbQqm9++9Qa>+KywcO|VlV@vF8;*UPoo6dQ zkluVXB=zB2b^$eIa^(2>qg5M*-6EzN|E_CUniw1GI5C}6VDfSDCYov)9tUmLAEod9 zpn2W>QJ2@sFAF6 Date: Sun, 2 Jan 2022 18:09:55 +0100 Subject: [PATCH 053/315] Create app-icon.js --- apps/mmind/app-icon.js | 1 + 1 file changed, 1 insertion(+) create mode 100644 apps/mmind/app-icon.js diff --git a/apps/mmind/app-icon.js b/apps/mmind/app-icon.js new file mode 100644 index 000000000..9bcedc5f3 --- /dev/null +++ b/apps/mmind/app-icon.js @@ -0,0 +1 @@ +E.toArrayBuffer(atob("mEwgn/AF/ykYEMmUvAYPzAIX/rnMBIPzu93n4EB1OZBIW73U/+cQ/8Qn/05nM4f/+wXBt//+OZzOv//63e7j/zmI1Bn/1C4f3C4NzCQIXByf/nYXBDgPxKQM/+IvGv4XFF4QXF+ZfGAgQXBAgPyC4JpBC4QJBmEBQoUggQECmAEDBIR3BgURCgNnFQerEoXzp3kAgWIxBCBgMD+cC+JyD+JVD+nu91PBIIXBj/yj8h+MCOQSKCC4OzC4fj/84C4OPC4UiiQvEQogXCof//AvFgMBRQoXBAgVO9yPCL4cfiUziP/mMSQoUyiYECmguBAAMxkYDBkMf/4FCAH4A/AH4A/AH4A/AH4A/AH4Ap5gACAoM/BIXzAhgXE+MDBoXwh4EC+IEDBIYXE+UfBoXyl4ELI4pfXACPdAASrv")) From 3ba5066073c151800c01f7867232e15e435f3831 Mon Sep 17 00:00:00 2001 From: Peter Slendebroek Date: Sun, 2 Jan 2022 18:16:01 +0100 Subject: [PATCH 054/315] added mmind app --- apps.json | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/apps.json b/apps.json index e5e9f8f02..5bbde6af5 100644 --- a/apps.json +++ b/apps.json @@ -5062,5 +5062,20 @@ {"name":"ltherm.app.js","url":"app.js"}, {"name":"ltherm.img","url":"icon.js","evaluate":true} ] - } + }, + + { "id": "mmind", + "name": "Clasic Mind Game", + "shortName":"Master Mind", + "icon": "app.png", + "version":"0.01", + "description": "This is a classic mind game for bangles 2", + "tags": "masterminf, game", + "storage": [ + {"name":"timer.app.js","url":"app.js"}, + {"name":"mmind.img","url":"app-icon.js","evaluate":true} + ] +} +] + ] From 8a75baae96d0c913e93c6e091033d6449e8a81fc Mon Sep 17 00:00:00 2001 From: Peter Slendebroek Date: Sun, 2 Jan 2022 18:17:15 +0100 Subject: [PATCH 055/315] Update apps.json --- apps.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps.json b/apps.json index 5bbde6af5..09c171616 100644 --- a/apps.json +++ b/apps.json @@ -5065,7 +5065,7 @@ }, { "id": "mmind", - "name": "Clasic Mind Game", + "name": "Classic Mind Game", "shortName":"Master Mind", "icon": "app.png", "version":"0.01", From f6e71200c177f17968798cae63100b43cbb7f39a Mon Sep 17 00:00:00 2001 From: Peter Slendebroek Date: Sun, 2 Jan 2022 18:18:23 +0100 Subject: [PATCH 056/315] Update apps.json --- apps.json | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/apps.json b/apps.json index 09c171616..74b5b49b5 100644 --- a/apps.json +++ b/apps.json @@ -5063,7 +5063,6 @@ {"name":"ltherm.img","url":"icon.js","evaluate":true} ] }, - { "id": "mmind", "name": "Classic Mind Game", "shortName":"Master Mind", @@ -5074,8 +5073,7 @@ "storage": [ {"name":"timer.app.js","url":"app.js"}, {"name":"mmind.img","url":"app-icon.js","evaluate":true} - ] -} -] - + ] + } ] + From f93c785d1959ac2e4a19e73dafed443bb2c6bab6 Mon Sep 17 00:00:00 2001 From: Peter Slendebroek Date: Sun, 2 Jan 2022 21:23:43 +0100 Subject: [PATCH 057/315] Update apps.json --- apps.json | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/apps.json b/apps.json index 74b5b49b5..28dcf6912 100644 --- a/apps.json +++ b/apps.json @@ -5063,17 +5063,19 @@ {"name":"ltherm.img","url":"icon.js","evaluate":true} ] }, - { "id": "mmind", - "name": "Classic Mind Game", - "shortName":"Master Mind", - "icon": "app.png", - "version":"0.01", - "description": "This is a classic mind game for bangles 2", - "tags": "masterminf, game", - "storage": [ - {"name":"timer.app.js","url":"app.js"}, - {"name":"mmind.img","url":"app-icon.js","evaluate":true} + { + "id": "mmind", + "name": "Classic Mind Game", + "shortName":"Master Mind", + "icon": "app.png", + "version":"0.01", + "description": "This is a classic mind game", + "type": "game", + "tags": "mastermind, game, bangle 2", + "supports": ["BANGLEJS2"], + "storage": [ + {"name":"mmind.app.js","url":"app.js"}, + {"name":"mmind.img","url":"app-icon.js","evaluate":true} ] } ] - From ac6140704d5afb068009a4bfbdf49218101a507e Mon Sep 17 00:00:00 2001 From: Peter Slendebroek Date: Mon, 3 Jan 2022 15:13:07 +0100 Subject: [PATCH 058/315] Delete app.js --- apps/mmind/app.js | 198 ---------------------------------------------- 1 file changed, 198 deletions(-) delete mode 100644 apps/mmind/app.js diff --git a/apps/mmind/app.js b/apps/mmind/app.js deleted file mode 100644 index e7def025d..000000000 --- a/apps/mmind/app.js +++ /dev/null @@ -1,198 +0,0 @@ -//MMind - -//set vars -const H = g.getWidth(); -const W = g.getHeight(); -var touch_actions = []; -var cols = ["#FF0000","#00FF00","#0000FF", "#FF00FF", "#FFFF00", "#00FFFF", "#000000","#FFFFFF"]; -var turn = 0; -var col_menu = false; -//pinsRow = 6; -//pinsThick = 10; -//pinsRow = 5; -//pinsThick = 10; -var pinsRow = 4; -var pinsThick = 10; -var play = [-1, -1, -1, -1]; - -var pinsCol = 5; -var playx = -1; -var sx = (W - 30 )/pinsRow; -var sy = (H - 20 )/7; -var touch_actions = []; -var secret = []; -var secret_no_dub = true; -var endgame = false; - -g.clear(); -g.setColor("#FFFFFF"); -g.fillRect(0, 0, H, W); -g.setFont("Vector12",45); - -function draw() { - touch_actions = []; - g.clear(); - g.setColor("#FFFFFF"); - g.fillRect(0, 0, H, W); - g.setColor("#000000"); - //draw scores - for (y=0;y= 0) s = Math.round(Math.random()*pinsCol); - secret[i]= s; - } - } - -function score() { - bScore = 0; - wScore = 0; - for (i=0; i touch_actions[i][0][0] && e.x < touch_actions[i][0][2] && - e.y > touch_actions[i][0][1] && e.y < touch_actions[i][0][3]) { - // a action is hit, add acctions here, todo: start, stop, new, etc. - switch (touch_actions[i][1][0]) { - case 1: - //get pins col menu - col_menu = 1; - playx = touch_actions[i][1][1]; - break; - case 2: - //copy choice col to play - play[playx] = touch_actions[i][1][1]; - col_menu = 0; - break; - case 3: - //score play - var sc; - sc = score(); - game.push([play, sc]); - play = [-1,-1,-1,-1]; - turn+=1; - if (turn==6 || sc[0]==pinsRow) { - play = secret; - col_menu = 0; - endgame = true; - } - break; - case 4: - //new game - play = [-1,-1,-1,-1]; - game = []; - endgame=false; - break; - } - } - } - //console.log(touch_actions[i][1][0], touch_actions[i][1][1]); - - draw(); - } -); - - -game = []; -get_secret(); -draw(); -//Bangle.loadWidgets(); -//Bangle.drawWidgets(); - - - - - From 377099b81af2f457c8fa5d1ca87c737b95f4ca46 Mon Sep 17 00:00:00 2001 From: Peter Slendebroek Date: Mon, 3 Jan 2022 15:19:55 +0100 Subject: [PATCH 059/315] Delete app.png --- apps/mmind/app.png | Bin 1339 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 apps/mmind/app.png diff --git a/apps/mmind/app.png b/apps/mmind/app.png deleted file mode 100644 index bb2a27ae5c614707bb35d6400f75e54514db68f5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1339 zcmWksdsLDK6u&Bc8AzQnW~4PLALTKIS<=?yL>fMGil(EZsY6p+Ddraun#DXU*>}En zENaEf9LG?zAR~69ma$sSLu6rV_&jP4W=qXXQ&eJ~f82Y|@7{Co{oUWW^7yz2DtS2> z0H{%s;XER;=FHuV@EJV|^h9te;zjHPO`Fdf0+4bzyEy=jKT&2g=K;7D#m6S?ayp$u zLqn%dokCI6Xf*cq^+_a>&dyGo%_fyf&1SRRZZ{YV0|Nu448{)`#BooBC)npO zRY}$Av=)nnPL~6W5h(;wS5>KXTAh-rbb`|kc7>EO&SJ@$qpUk4LA|RVtM@ zI(h~`MIud3PWqPk(qy!ek&%!P5r6|ha2ZWj;#+e6{(Y;}%49M}M@Q@H>oE*Ny}T>{ zgM)*B5zWM9D1bo)Dhx1`&2A(}jE&KxGzv~(Fo=>8r{GeW)NC>-C=`NnCqS7%;BYvq z)zyd|0SAzbBut6v^#*tM8h{yBSF=cjD>0>!WORT-kLcCa>cGIj($Z3eLb1uylL?TM zo?cZ|g|HA{0*>Qat(Hm+0bq(m5+*QN2&{3UN4ybqGx+ z^DQY!PEMA|WCDSJ&1QRhdwZc?U;z{bgMpAm1sIl=mX@EN&qmqMNaPvBcnXfwq*9aF zL{U%(Ap~UtgF#kpgWoKv0<#Olbq|;()X=(BD@~W(?6bglT zd3jEo&55EHSCc~tT^0x<`9%N=AIzD{Uj=np#7`zfg>#Z3V}{TDd(Z!B8KWQtuad}i)RH=J% z@$RJI-Q9bg#g`Wqy-BZ&O2nQEL+|*t2~Y3;tajizK zG7#9eo=$~h(#z7qmjUjc0lW9Jv;W&zIPDR-vFM+J$J$bxW?fS<6M_@2Zut6r;2-v> zFW!DH!&nhXH^ot{!kC}er)M@jHSO{1Ij2dsD)RPr?TyRpl@vbUn)!)m(xT+TcJ<@w z^VfylrU%_eh0*PCeH!u^(Tx1#(CbU@!lLON1z+*HPVBHwltsRYzi^}@?9&?b)`m|V zg-Bd~T|fnI;mLzF=#SR7wH57j$f1p;yiYu&{kGrd4FbFvB(X zz$=dwjeogSv*yYR)y@>ocJJGTAI_J~EbQqm9++9Qa>+KywcO|VlV@vF8;*UPoo6dQ zkluVXB=zB2b^$eIa^(2>qg5M*-6EzN|E_CUniw1GI5C}6VDfSDCYov)9tUmLAEod9 zpn2W>QJ2@sFAF6 Date: Mon, 3 Jan 2022 15:20:30 +0100 Subject: [PATCH 060/315] Add files via upload --- apps/mmind/mmind.app.js | 3395 +++++++++++++++++++++++++++++++++++++++ apps/mmind/mmind.png | Bin 0 -> 1546 bytes 2 files changed, 3395 insertions(+) create mode 100644 apps/mmind/mmind.app.js create mode 100644 apps/mmind/mmind.png diff --git a/apps/mmind/mmind.app.js b/apps/mmind/mmind.app.js new file mode 100644 index 000000000..52a566ca9 --- /dev/null +++ b/apps/mmind/mmind.app.js @@ -0,0 +1,3395 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + BangleApps/app.js at master · psbest/BangleApps + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + +
+ + + +
+ + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + psbest  /   + BangleApps  /   + +
+ + + + Type # for issues and pull requests, > for commands, and ? for help + + + Type # for issues, pull requests, and projects, > for commands, and ? for help + + + Type # for issues, pull requests, and projects, / for files, and > for commands + + +
+ +
+
+ We’ve encountered an error and some results aren't available at this time. Type a new search or try again later. +
+
+ + No results matched your search + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + Search for issues and pull requests + + # + + + + Search for issues, pull requests, discussions, and projects + + # + + + + Search for organizations, repositories, and users + + @ + + + + Search for projects + + ! + + + + Search for files + + / + + + + Activate command mode + + > + + + + Search your issues, pull requests, and discussions + + # author:@me + + + + Search your issues, pull requests, and discussions + + # author:@me + + + + Filter to pull requests + + # is:pr + + + + Filter to issues + + # is:issue + + + + Filter to discussions + + # is:discussion + + + + Filter to projects + + # is:project + + + + Filter to open issues, pull requests, and discussions + + # is:open + + + + + + + + + + + + + + + + +
+
+
+ +
+ + + + + + + + + + +
+ + + + +
+
+
+ + + + + + + + + + +
+ +
+ +
+

+ + + / + + BangleApps + + + Public +

+ + forked from espruino/BangleApps + + +
+ +
    + +
  • + +
    + + + + + + + Watch + + + 0 + + + +
    +
    +

    Notifications

    + +
    + +
    +
    + + + + + + + + +
    + + +
    + + + + + Get push notifications on iOS or Android. + +
    +
    +
    +
    + + +
    +
    +
    + + + +
  • + + +
  • + + +
  • + +
  • + +
    +
    + +
    +
    + +
    +
    + + + + + +
    + +
    +
    + + + + + + + +
    + +
    +
    +
    +
    +
    +
  • + + +
  • + + +
  • +
+ +
+ +
+
+ + + + +
+ + + +
+
+ + Open in github.dev + Open in a new github.dev tab + + + + + + + +
+ + + + + Permalink + + +
+ +
+
+ + + master + + + + +
+
+
+ Switch branches/tags + +
+ + + +
+ +
+ +
+ + +
+ +
+ + + + + + + + + + + + + + + + +
+ + +
+
+
+
+ +
+ +
+ + + + Go to file + + +
+ + + + +
+
+
+ + + + +
+ +
+
+
 
+
+ +
+
 
+ Cannot retrieve contributors at this time +
+
+ + + + + + + + + + + +
+ +
+ + +
+ + 198 lines (178 sloc) + + 4.59 KB +
+ +
+ + + + +
+ + + + + + + + + + + + + + + +
+ +
+
+ +
+
+ +
+ +
+
+ + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
//MMind
+
//set vars
const H = g.getWidth();
const W = g.getHeight();
var touch_actions = [];
var cols = ["#FF0000","#00FF00","#0000FF", "#FF00FF", "#FFFF00", "#00FFFF", "#000000","#FFFFFF"];
var turn = 0;
var col_menu = false;
//pinsRow = 6;
//pinsThick = 10;
//pinsRow = 5;
//pinsThick = 10;
var pinsRow = 4;
var pinsThick = 10;
var play = [-1, -1, -1, -1];
+
var pinsCol = 5;
var playx = -1;
var sx = (W - 30 )/pinsRow;
var sy = (H - 20 )/7;
var touch_actions = [];
var secret = [];
var secret_no_dub = true;
var endgame = false;
+
g.clear();
g.setColor("#FFFFFF");
g.fillRect(0, 0, H, W);
g.setFont("Vector12",45);
+
function draw() {
touch_actions = [];
g.clear();
g.setColor("#FFFFFF");
g.fillRect(0, 0, H, W);
g.setColor("#000000");
//draw scores
for (y=0;y<game.length;y+=1) {
pp = game[y][0];
ps = game[y][1];
g.setColor("#000000");
//g.fillRect(W-30,10, W-30, 15);
g.setColor("#000000");
g.setFont("Vector30",10);
g.drawString(ps[0],W-31,y*sy+8);
g.setColor("#000000");
g.drawString(ps[1],W-15,y*sy+8);
g.setColor("#000000");
for (x=0;x<pinsRow;x+=1) {
xx = sx*x + pinsThick + 5;
yy = sy*y+20;
xc = pp[x];
g.setColor(cols[xc]);
g.fillCircle(xx,yy , pinsThick );
g.setColor("#000000");
g.drawCircle(xx,yy,pinsThick+1);
g.drawCircle(xx,yy,pinsThick);
}
}
//draw play input
for (k=0; k<pinsRow; k+=1){
xx = sx*k + pinsThick + 5;
yy = sy*7;
touch_actions.push([[xx-pinsThick-5, yy-pinsThick-10, xx+pinsThick+5, yy+pinsThick+20],[1,k]]);
if (play[k] < 0) {
//col not choisen, draw small dot
g.setColor("#000000");
g.fillCircle(xx,yy , 3 );
} else {
g.setColor(cols[play[k]]);
g.fillCircle(xx,yy , pinsThick );
+
}
}
// draw action button
// score, men
if (!endgame) {
if (col_menu) {
draw_col_choice();
} else {
// check if all pins are set yet
if (Math.min.apply(null,play) < 0) {
g.setColor("#FF0000");
} else {
g.setColor("#00FF00");
touch_actions.push([[W-30, H-30,192, 190], [3,1]]);
}
g.fillRect(W-30, H-30, W-1, H-10);
}
} else {
g.setColor("#0000FF");
touch_actions.push([[W-30, H-30,192, 190], [4,1]]);
g.fillRect(W-30, H-30, W-1, H-10);
}
}
+
function get_secret() {
//secret=[];
for (i=0; i<pinsRow; i+=1) {
s = Math.round(Math.random()*pinsCol);
if (secret_no_dub)
while(secret.indexOf(s) >= 0) s = Math.round(Math.random()*pinsCol);
secret[i]= s;
}
}
+
function score() {
bScore = 0;
wScore = 0;
for (i=0; i<pinsRow; i+=1) {
if (secret[i] == play[i]) {
bScore +=1;
}
else {
for (s=0; s<pinsRow; s+=1) {
if (secret[i] == play[s]) {
wScore +=1;
break;
}
}
}
}
+
return([bScore, wScore]);
}
+
function draw_col_choice(){
var cc = g.getColor();
var boxw = 30;
var boxh = H/pinsRow-20;
for (i=0; i<=pinsCol; i+=1) {
g.setColor(cols[i]);
g.fillRect(W-boxw, i*boxh, W-1, i*boxh+boxh);
touch_actions.push([[150, i*boxh, 191, i*boxh+boxh], [2,i]]);
g.setColor(cc);
}
+
}
+
Bangle.on('touch', function(zone,e) {
//console.log(e.x, e.y);
// check touch actions array to see what to do
for(i=0; i<touch_actions.length; i+=1) {
if (e.x > touch_actions[i][0][0] && e.x < touch_actions[i][0][2] &&
e.y > touch_actions[i][0][1] && e.y < touch_actions[i][0][3]) {
// a action is hit, add acctions here, todo: start, stop, new, etc.
switch (touch_actions[i][1][0]) {
case 1:
//get pins col menu
col_menu = 1;
playx = touch_actions[i][1][1];
break;
case 2:
//copy choice col to play
play[playx] = touch_actions[i][1][1];
col_menu = 0;
break;
case 3:
//score play
var sc;
sc = score();
game.push([play, sc]);
play = [-1,-1,-1,-1];
turn+=1;
if (turn==6 || sc[0]==pinsRow) {
play = secret;
col_menu = 0;
endgame = true;
}
break;
case 4:
//new game
play = [-1,-1,-1,-1];
game = [];
endgame=false;
break;
}
}
}
//console.log(touch_actions[i][1][0], touch_actions[i][1][1]);
draw();
}
);
+
+
game = [];
get_secret();
draw();
//Bangle.loadWidgets();
//Bangle.drawWidgets();
+
+
+
+
+
+ + + +
+ +
+ + + + +
+ + +
+ + +
+
+ + + + +
+ + + +
+
+ +
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + diff --git a/apps/mmind/mmind.png b/apps/mmind/mmind.png new file mode 100644 index 0000000000000000000000000000000000000000..8afcc26974bc8eaa2239927b33b4d566e8df42ba GIT binary patch literal 1546 zcmV+l2KD)gP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D1)oVoK~z{r?U-F? z6Im3;PqV{V8ipugkQ7?8+6Es=Ed5|9Qi@bXs_cUgVqsSiDSZ$>=tC$=D3KD;4QZii z_aQWYinyuOH0vSU0pqX{J70#8yOkFCQYcjt?fT08+MKe z0zQWJBjn4MFIDcULX3dyl@}KmSrn((t?0hSQ0pGoMbj5EvIon-q-?~(8)kx$ZXCk?HItTvuF43->3XPinTZhcM)>?_U)RQ8q5r*v%9`hzx>~6b==u?AkS3Dn*NSbW|K2Ej$$og~L)XNMo6db+Di^>}58av8Zvv z9zTBE)YPn+3xsd96bp{B5q(eQe`XU?3NpP$cUGVk8K!~AFsMRQS5$t<@|qcY2^Mr9RAjmkDQ zqNak#pr$6PR#~z_qq12GR~drez<9-F!b;k?bLZIDSZizRsZ*!uV0Jvz#5F2Qt2Biq z%^H=_-YOD_LSMYioYbgHPH(BQmX;PQrhE79(S!mg1Lh$!*{`MZ~vWp^Wbk>AQBNxrmiDL4jeeZoa^iBmoHy_@#4j0uoc;GuF z*ksVWJ5$z`jU(h|e3?}YHTd58<_$IQO@7A?#ihskI>gwB-+&1%k)>AB%62y-B85p9 zody0O#F5{>s3e5%i{zP~Cyk9tS0J)Xrlz?6`%F*sF5jFqAvbZWeKL_#B*i*Xe$8jY z&R@8j)6t>o3dC;beihH3KcAVI;SI*t3DFu#;GrT3$uy*S1BvrbPEj+V=?n3qFr}fP z;o!l8yrBn8NW?>h0D?(f>~tSTMNw1K^et{GT)K3rv$K;obiw(1NnT>16ZD z`CGeWe{nbG!2=?Sn-flYdbt1lY`tV$Wig0dhwErKz|jF6N~$U%0ON|$0#LjgL-&Q? w=1pqU)j@l^;?iSo4*L4It;N`m`91*u1O9JFJ2Em3SpWb407*qoM6N<$g6%QmuK)l5 literal 0 HcmV?d00001 From ff363e10955cb4b82ecd53b10d697f30b8b4c39b Mon Sep 17 00:00:00 2001 From: Peter Slendebroek Date: Mon, 3 Jan 2022 15:27:45 +0100 Subject: [PATCH 061/315] Update apps.json --- apps.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps.json b/apps.json index 28dcf6912..6f435fb82 100644 --- a/apps.json +++ b/apps.json @@ -5067,15 +5067,15 @@ "id": "mmind", "name": "Classic Mind Game", "shortName":"Master Mind", - "icon": "app.png", + "icon": "mmind.png", "version":"0.01", "description": "This is a classic mind game", "type": "game", - "tags": "mastermind, game, bangle 2", + "tags": "master mind, game, classic", "supports": ["BANGLEJS2"], "storage": [ - {"name":"mmind.app.js","url":"app.js"}, - {"name":"mmind.img","url":"app-icon.js","evaluate":true} + {"name":"mmind.app.js","url":"mmind.app.js"}, + {"name":"mmind.img","url":"mmind.icon.js","evaluate":true} ] } ] From 4e40afbc87ef1c616c80e49d6cf0220b63310341 Mon Sep 17 00:00:00 2001 From: Peter Slendebroek Date: Mon, 3 Jan 2022 15:44:09 +0100 Subject: [PATCH 062/315] Update apps.json --- apps.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps.json b/apps.json index 6f435fb82..50b2f3752 100644 --- a/apps.json +++ b/apps.json @@ -5069,9 +5069,9 @@ "shortName":"Master Mind", "icon": "mmind.png", "version":"0.01", - "description": "This is a classic mind game", + "description": "This is the classic game for masterminds", "type": "game", - "tags": "master mind, game, classic", + "tags": "mastermind, game, classic", "supports": ["BANGLEJS2"], "storage": [ {"name":"mmind.app.js","url":"mmind.app.js"}, From a6e7011b0d74fbbeb6b96f4c20dd3f43b60e7248 Mon Sep 17 00:00:00 2001 From: Peter Slendebroek Date: Mon, 3 Jan 2022 15:58:29 +0100 Subject: [PATCH 063/315] create changelog --- apps/mmind/ChangeLog | 1 + 1 file changed, 1 insertion(+) create mode 100644 apps/mmind/ChangeLog diff --git a/apps/mmind/ChangeLog b/apps/mmind/ChangeLog new file mode 100644 index 000000000..939ac3b5d --- /dev/null +++ b/apps/mmind/ChangeLog @@ -0,0 +1 @@ +0.01: First release From d12c58a6c6f07b1c8b47ebda14eadaf690510815 Mon Sep 17 00:00:00 2001 From: Peter Slendebroek Date: Mon, 3 Jan 2022 17:07:29 +0100 Subject: [PATCH 064/315] Delete app-icon.js --- apps/mmind/app-icon.js | 1 - 1 file changed, 1 deletion(-) delete mode 100644 apps/mmind/app-icon.js diff --git a/apps/mmind/app-icon.js b/apps/mmind/app-icon.js deleted file mode 100644 index 9bcedc5f3..000000000 --- a/apps/mmind/app-icon.js +++ /dev/null @@ -1 +0,0 @@ -E.toArrayBuffer(atob("mEwgn/AF/ykYEMmUvAYPzAIX/rnMBIPzu93n4EB1OZBIW73U/+cQ/8Qn/05nM4f/+wXBt//+OZzOv//63e7j/zmI1Bn/1C4f3C4NzCQIXByf/nYXBDgPxKQM/+IvGv4XFF4QXF+ZfGAgQXBAgPyC4JpBC4QJBmEBQoUggQECmAEDBIR3BgURCgNnFQerEoXzp3kAgWIxBCBgMD+cC+JyD+JVD+nu91PBIIXBj/yj8h+MCOQSKCC4OzC4fj/84C4OPC4UiiQvEQogXCof//AvFgMBRQoXBAgVO9yPCL4cfiUziP/mMSQoUyiYECmguBAAMxkYDBkMf/4FCAH4A/AH4A/AH4A/AH4A/AH4Ap5gACAoM/BIXzAhgXE+MDBoXwh4EC+IEDBIYXE+UfBoXyl4ELI4pfXACPdAASrv")) From b33d629065fc0a57bbe3787ea2a61c2f29b1d667 Mon Sep 17 00:00:00 2001 From: Peter Slendebroek Date: Mon, 3 Jan 2022 17:07:53 +0100 Subject: [PATCH 065/315] Add files via upload --- apps/mmind/mmind.icon.js | 1 + 1 file changed, 1 insertion(+) create mode 100644 apps/mmind/mmind.icon.js diff --git a/apps/mmind/mmind.icon.js b/apps/mmind/mmind.icon.js new file mode 100644 index 000000000..c6f72ca38 --- /dev/null +++ b/apps/mmind/mmind.icon.js @@ -0,0 +1 @@ +E.toArrayBuffer(atob("2GwxH+64A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A6gAAFEf5I/VtpEcEcZI/Dw4PbCQu0AApnZDIUeAAqLaDQUFAApIc3IAFEabHPa6StJWLKtJWLStJWLKtJWKieFChIPPCYquKWAZmUVxSwDV6quKWAYjUVxSwDVqQUIB56uTWCiuOWCquOWCiuOWByaFV5oPLVyiwSVyCwTVyCwSVyCwNTIqvMB5iv/V/6vQUpQPTVyqwQVySwRVySwQVySwNT6Kv/V/6v/V/6v/V/6v/V/6v/V/6v/V/6v/V/6v/V/6vvWCZBSV0CwUJCSuhV/6v/V/4PPWCBBRWCIjSWCJIUV0CvfWB6KTWB4jUWB5IWVz6viWBYdPEZCuMV6ywLJDCuMV+SxLRKyxMEbKxKJDitXCAQALB6AoTRS4jkJHyvoFRCJZEcxI8V9DyZEdpI/ZaQpTB4W0AApnZDIUFAAqLaDQXSAApIckYAFEaTLPbaatJWLKtJWLStJWLKtJWKaeKDAgPPEgyuKWAZmUVxSwDV6quKWAYjUVxSwDV7AZDB56uSWCiuOWCquOWCiuOWByWJBAoPPVyiwSVyCwTVyCwSVyCwNSpIKLB5qv/V/6vuVySwQVySwRVySwQVySwMV/6v/V/6uRV/6v/V8wNDV/6v/V9SuJV/6v/V8atEV/6v/V9KtLV/6v/V8SuNWCiKPWCYjQWCZISVzavSVopGLV/6v/V8RDPVz6wSEaSwRJCiuaV6KuSWCCKTWB4jUWB5IWVzKvKVAyuTCgauMMyqwLEaokDVxhIWVxgjNT46uKIiytcWJojZWJRIcVqygGAA4OOFhYUUJbIjYJH4bOV7AaIRLIjmJH4bMV7QA/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A+goAHEbUeAA5s/ADO0ADitRWLStIWP6v/VxywWVxiw/V/quOWCiuOWH6v7VyCwSVyCw/V/6v/AH6vpVySwQVySw/V/6v/ABMAAAaXeEa6v/V+SKEWDwjYV/6v/V/6v/V/6v/V/6v/V/6v/V/6v/V+SMFVzgjZV/6vzAHaviWCZHQV36v/V/6v/V/awRJCSu/V/6vLWB5JUV36v/V5awNJSyu/V/6vLWJRMaVv6v/V5YA/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4AkA=")) \ No newline at end of file From 503b64e817b3c98a5dcea565888db4d0e26a99b3 Mon Sep 17 00:00:00 2001 From: Peter Slendebroek Date: Mon, 3 Jan 2022 17:10:50 +0100 Subject: [PATCH 066/315] Update mmind.icon.js --- apps/mmind/mmind.icon.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/mmind/mmind.icon.js b/apps/mmind/mmind.icon.js index c6f72ca38..976243b48 100644 --- a/apps/mmind/mmind.icon.js +++ b/apps/mmind/mmind.icon.js @@ -1 +1 @@ -E.toArrayBuffer(atob("2GwxH+64A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A6gAAFEf5I/VtpEcEcZI/Dw4PbCQu0AApnZDIUeAAqLaDQUFAApIc3IAFEabHPa6StJWLKtJWLStJWLKtJWKieFChIPPCYquKWAZmUVxSwDV6quKWAYjUVxSwDVqQUIB56uTWCiuOWCquOWCiuOWByaFV5oPLVyiwSVyCwTVyCwSVyCwNTIqvMB5iv/V/6vQUpQPTVyqwQVySwRVySwQVySwNT6Kv/V/6v/V/6v/V/6v/V/6v/V/6v/V/6v/V/6v/V/6vvWCZBSV0CwUJCSuhV/6v/V/4PPWCBBRWCIjSWCJIUV0CvfWB6KTWB4jUWB5IWVz6viWBYdPEZCuMV6ywLJDCuMV+SxLRKyxMEbKxKJDitXCAQALB6AoTRS4jkJHyvoFRCJZEcxI8V9DyZEdpI/ZaQpTB4W0AApnZDIUFAAqLaDQXSAApIckYAFEaTLPbaatJWLKtJWLStJWLKtJWKaeKDAgPPEgyuKWAZmUVxSwDV6quKWAYjUVxSwDV7AZDB56uSWCiuOWCquOWCiuOWByWJBAoPPVyiwSVyCwTVyCwSVyCwNSpIKLB5qv/V/6vuVySwQVySwRVySwQVySwMV/6v/V/6uRV/6v/V8wNDV/6v/V9SuJV/6v/V8atEV/6v/V9KtLV/6v/V8SuNWCiKPWCYjQWCZISVzavSVopGLV/6v/V8RDPVz6wSEaSwRJCiuaV6KuSWCCKTWB4jUWB5IWVzKvKVAyuTCgauMMyqwLEaokDVxhIWVxgjNT46uKIiytcWJojZWJRIcVqygGAA4OOFhYUUJbIjYJH4bOV7AaIRLIjmJH4bMV7QA/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A+goAHEbUeAA5s/ADO0ADitRWLStIWP6v/VxywWVxiw/V/quOWCiuOWH6v7VyCwSVyCw/V/6v/AH6vpVySwQVySw/V/6v/ABMAAAaXeEa6v/V+SKEWDwjYV/6v/V/6v/V/6v/V/6v/V/6v/V/6v/V+SMFVzgjZV/6vzAHaviWCZHQV36v/V/6v/V/awRJCSu/V/6vLWB5JUV36v/V5awNJSyu/V/6vLWJRMaVv6v/V5YA/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4AkA=")) \ No newline at end of file +require("heatshrink").decompress(atob("2GwxH+64A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A6gAAFEf5I/VtpEcEcZI/Dw4PbCQu0AApnZDIUeAAqLaDQUFAApIc3IAFEabHPa6StJWLKtJWLStJWLKtJWKieFChIPPCYquKWAZmUVxSwDV6quKWAYjUVxSwDVqQUIB56uTWCiuOWCquOWCiuOWByaFV5oPLVyiwSVyCwTVyCwSVyCwNTIqvMB5iv/V/6vQUpQPTVyqwQVySwRVySwQVySwNT6Kv/V/6v/V/6v/V/6v/V/6v/V/6v/V/6v/V/6v/V/6vvWCZBSV0CwUJCSuhV/6v/V/4PPWCBBRWCIjSWCJIUV0CvfWB6KTWB4jUWB5IWVz6viWBYdPEZCuMV6ywLJDCuMV+SxLRKyxMEbKxKJDitXCAQALB6AoTRS4jkJHyvoFRCJZEcxI8V9DyZEdpI/ZaQpTB4W0AApnZDIUFAAqLaDQXSAApIckYAFEaTLPbaatJWLKtJWLStJWLKtJWKaeKDAgPPEgyuKWAZmUVxSwDV6quKWAYjUVxSwDV7AZDB56uSWCiuOWCquOWCiuOWByWJBAoPPVyiwSVyCwTVyCwSVyCwNSpIKLB5qv/V/6vuVySwQVySwRVySwQVySwMV/6v/V/6uRV/6v/V8wNDV/6v/V9SuJV/6v/V8atEV/6v/V9KtLV/6v/V8SuNWCiKPWCYjQWCZISVzavSVopGLV/6v/V8RDPVz6wSEaSwRJCiuaV6KuSWCCKTWB4jUWB5IWVzKvKVAyuTCgauMMyqwLEaokDVxhIWVxgjNT46uKIiytcWJojZWJRIcVqygGAA4OOFhYUUJbIjYJH4bOV7AaIRLIjmJH4bMV7QA/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A+goAHEbUeAA5s/ADO0ADitRWLStIWP6v/VxywWVxiw/V/quOWCiuOWH6v7VyCwSVyCw/V/6v/AH6vpVySwQVySw/V/6v/ABMAAAaXeEa6v/V+SKEWDwjYV/6v/V/6v/V/6v/V/6v/V/6v/V/6v/V+SMFVzgjZV/6vzAHaviWCZHQV36v/V/6v/V/awRJCSu/V/6vLWB5JUV36v/V5awNJSyu/V/6vLWJRMaVv6v/V5YA/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4AkA=")) From d0583def6bcfb19282b827ae1deae61e84b9f5c7 Mon Sep 17 00:00:00 2001 From: Peter Slendebroek Date: Mon, 3 Jan 2022 17:16:27 +0100 Subject: [PATCH 067/315] Delete mmind.app.js --- apps/mmind/mmind.app.js | 3395 --------------------------------------- 1 file changed, 3395 deletions(-) delete mode 100644 apps/mmind/mmind.app.js diff --git a/apps/mmind/mmind.app.js b/apps/mmind/mmind.app.js deleted file mode 100644 index 52a566ca9..000000000 --- a/apps/mmind/mmind.app.js +++ /dev/null @@ -1,3395 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - BangleApps/app.js at master · psbest/BangleApps - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - -
- - - -
- - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - -
- -
- - - psbest  /   - BangleApps  /   - -
- - - - Type # for issues and pull requests, > for commands, and ? for help - - - Type # for issues, pull requests, and projects, > for commands, and ? for help - - - Type # for issues, pull requests, and projects, / for files, and > for commands - - -
- -
-
- We’ve encountered an error and some results aren't available at this time. Type a new search or try again later. -
-
- - No results matched your search - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - Search for issues and pull requests - - # - - - - Search for issues, pull requests, discussions, and projects - - # - - - - Search for organizations, repositories, and users - - @ - - - - Search for projects - - ! - - - - Search for files - - / - - - - Activate command mode - - > - - - - Search your issues, pull requests, and discussions - - # author:@me - - - - Search your issues, pull requests, and discussions - - # author:@me - - - - Filter to pull requests - - # is:pr - - - - Filter to issues - - # is:issue - - - - Filter to discussions - - # is:discussion - - - - Filter to projects - - # is:project - - - - Filter to open issues, pull requests, and discussions - - # is:open - - - - - - - - - - - - - - - - -
-
-
- -
- - - - - - - - - - -
- - - - -
-
-
- - - - - - - - - - -
- -
- -
-

- - - / - - BangleApps - - - Public -

- - forked from espruino/BangleApps - - -
- -
    - -
  • - -
    - - - - - - - Watch - - - 0 - - - -
    -
    -

    Notifications

    - -
    - -
    -
    - - - - - - - - -
    - - -
    - - - - - Get push notifications on iOS or Android. - -
    -
    -
    -
    - - -
    -
    -
    - - - -
  • - - -
  • - - -
  • - -
  • - -
    -
    - -
    -
    - -
    -
    - - - - - -
    - -
    -
    - - - - - - - -
    - -
    -
    -
    -
    -
    -
  • - - -
  • - - -
  • -
- -
- -
-
- - - - -
- - - -
-
- - Open in github.dev - Open in a new github.dev tab - - - - - - - -
- - - - - Permalink - - -
- -
-
- - - master - - - - -
-
-
- Switch branches/tags - -
- - - -
- -
- -
- - -
- -
- - - - - - - - - - - - - - - - -
- - -
-
-
-
- -
- -
- - - - Go to file - - -
- - - - -
-
-
- - - - -
- -
-
-
 
-
- -
-
 
- Cannot retrieve contributors at this time -
-
- - - - - - - - - - - -
- -
- - -
- - 198 lines (178 sloc) - - 4.59 KB -
- -
- - - - -
- - - - - - - - - - - - - - - -
- -
-
- -
-
- -
- -
-
- - - -
- - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
//MMind
-
//set vars
const H = g.getWidth();
const W = g.getHeight();
var touch_actions = [];
var cols = ["#FF0000","#00FF00","#0000FF", "#FF00FF", "#FFFF00", "#00FFFF", "#000000","#FFFFFF"];
var turn = 0;
var col_menu = false;
//pinsRow = 6;
//pinsThick = 10;
//pinsRow = 5;
//pinsThick = 10;
var pinsRow = 4;
var pinsThick = 10;
var play = [-1, -1, -1, -1];
-
var pinsCol = 5;
var playx = -1;
var sx = (W - 30 )/pinsRow;
var sy = (H - 20 )/7;
var touch_actions = [];
var secret = [];
var secret_no_dub = true;
var endgame = false;
-
g.clear();
g.setColor("#FFFFFF");
g.fillRect(0, 0, H, W);
g.setFont("Vector12",45);
-
function draw() {
touch_actions = [];
g.clear();
g.setColor("#FFFFFF");
g.fillRect(0, 0, H, W);
g.setColor("#000000");
//draw scores
for (y=0;y<game.length;y+=1) {
pp = game[y][0];
ps = game[y][1];
g.setColor("#000000");
//g.fillRect(W-30,10, W-30, 15);
g.setColor("#000000");
g.setFont("Vector30",10);
g.drawString(ps[0],W-31,y*sy+8);
g.setColor("#000000");
g.drawString(ps[1],W-15,y*sy+8);
g.setColor("#000000");
for (x=0;x<pinsRow;x+=1) {
xx = sx*x + pinsThick + 5;
yy = sy*y+20;
xc = pp[x];
g.setColor(cols[xc]);
g.fillCircle(xx,yy , pinsThick );
g.setColor("#000000");
g.drawCircle(xx,yy,pinsThick+1);
g.drawCircle(xx,yy,pinsThick);
}
}
//draw play input
for (k=0; k<pinsRow; k+=1){
xx = sx*k + pinsThick + 5;
yy = sy*7;
touch_actions.push([[xx-pinsThick-5, yy-pinsThick-10, xx+pinsThick+5, yy+pinsThick+20],[1,k]]);
if (play[k] < 0) {
//col not choisen, draw small dot
g.setColor("#000000");
g.fillCircle(xx,yy , 3 );
} else {
g.setColor(cols[play[k]]);
g.fillCircle(xx,yy , pinsThick );
-
}
}
// draw action button
// score, men
if (!endgame) {
if (col_menu) {
draw_col_choice();
} else {
// check if all pins are set yet
if (Math.min.apply(null,play) < 0) {
g.setColor("#FF0000");
} else {
g.setColor("#00FF00");
touch_actions.push([[W-30, H-30,192, 190], [3,1]]);
}
g.fillRect(W-30, H-30, W-1, H-10);
}
} else {
g.setColor("#0000FF");
touch_actions.push([[W-30, H-30,192, 190], [4,1]]);
g.fillRect(W-30, H-30, W-1, H-10);
}
}
-
function get_secret() {
//secret=[];
for (i=0; i<pinsRow; i+=1) {
s = Math.round(Math.random()*pinsCol);
if (secret_no_dub)
while(secret.indexOf(s) >= 0) s = Math.round(Math.random()*pinsCol);
secret[i]= s;
}
}
-
function score() {
bScore = 0;
wScore = 0;
for (i=0; i<pinsRow; i+=1) {
if (secret[i] == play[i]) {
bScore +=1;
}
else {
for (s=0; s<pinsRow; s+=1) {
if (secret[i] == play[s]) {
wScore +=1;
break;
}
}
}
}
-
return([bScore, wScore]);
}
-
function draw_col_choice(){
var cc = g.getColor();
var boxw = 30;
var boxh = H/pinsRow-20;
for (i=0; i<=pinsCol; i+=1) {
g.setColor(cols[i]);
g.fillRect(W-boxw, i*boxh, W-1, i*boxh+boxh);
touch_actions.push([[150, i*boxh, 191, i*boxh+boxh], [2,i]]);
g.setColor(cc);
}
-
}
-
Bangle.on('touch', function(zone,e) {
//console.log(e.x, e.y);
// check touch actions array to see what to do
for(i=0; i<touch_actions.length; i+=1) {
if (e.x > touch_actions[i][0][0] && e.x < touch_actions[i][0][2] &&
e.y > touch_actions[i][0][1] && e.y < touch_actions[i][0][3]) {
// a action is hit, add acctions here, todo: start, stop, new, etc.
switch (touch_actions[i][1][0]) {
case 1:
//get pins col menu
col_menu = 1;
playx = touch_actions[i][1][1];
break;
case 2:
//copy choice col to play
play[playx] = touch_actions[i][1][1];
col_menu = 0;
break;
case 3:
//score play
var sc;
sc = score();
game.push([play, sc]);
play = [-1,-1,-1,-1];
turn+=1;
if (turn==6 || sc[0]==pinsRow) {
play = secret;
col_menu = 0;
endgame = true;
}
break;
case 4:
//new game
play = [-1,-1,-1,-1];
game = [];
endgame=false;
break;
}
}
}
//console.log(touch_actions[i][1][0], touch_actions[i][1][1]);
draw();
}
);
-
-
game = [];
get_secret();
draw();
//Bangle.loadWidgets();
//Bangle.drawWidgets();
-
-
-
-
-
- - - -
- -
- - - - -
- - -
- - -
-
- - - - -
- - - -
-
- -
-
- -
- - - - - - - - - - - - - - - - - - - - - - From ade75a3e7ce323cad8f862213fe1d68ec20aafce Mon Sep 17 00:00:00 2001 From: Peter Slendebroek Date: Mon, 3 Jan 2022 17:18:11 +0100 Subject: [PATCH 068/315] Add files via upload --- apps/mmind/mmind.app.js | 198 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 198 insertions(+) create mode 100644 apps/mmind/mmind.app.js diff --git a/apps/mmind/mmind.app.js b/apps/mmind/mmind.app.js new file mode 100644 index 000000000..e7def025d --- /dev/null +++ b/apps/mmind/mmind.app.js @@ -0,0 +1,198 @@ +//MMind + +//set vars +const H = g.getWidth(); +const W = g.getHeight(); +var touch_actions = []; +var cols = ["#FF0000","#00FF00","#0000FF", "#FF00FF", "#FFFF00", "#00FFFF", "#000000","#FFFFFF"]; +var turn = 0; +var col_menu = false; +//pinsRow = 6; +//pinsThick = 10; +//pinsRow = 5; +//pinsThick = 10; +var pinsRow = 4; +var pinsThick = 10; +var play = [-1, -1, -1, -1]; + +var pinsCol = 5; +var playx = -1; +var sx = (W - 30 )/pinsRow; +var sy = (H - 20 )/7; +var touch_actions = []; +var secret = []; +var secret_no_dub = true; +var endgame = false; + +g.clear(); +g.setColor("#FFFFFF"); +g.fillRect(0, 0, H, W); +g.setFont("Vector12",45); + +function draw() { + touch_actions = []; + g.clear(); + g.setColor("#FFFFFF"); + g.fillRect(0, 0, H, W); + g.setColor("#000000"); + //draw scores + for (y=0;y= 0) s = Math.round(Math.random()*pinsCol); + secret[i]= s; + } + } + +function score() { + bScore = 0; + wScore = 0; + for (i=0; i touch_actions[i][0][0] && e.x < touch_actions[i][0][2] && + e.y > touch_actions[i][0][1] && e.y < touch_actions[i][0][3]) { + // a action is hit, add acctions here, todo: start, stop, new, etc. + switch (touch_actions[i][1][0]) { + case 1: + //get pins col menu + col_menu = 1; + playx = touch_actions[i][1][1]; + break; + case 2: + //copy choice col to play + play[playx] = touch_actions[i][1][1]; + col_menu = 0; + break; + case 3: + //score play + var sc; + sc = score(); + game.push([play, sc]); + play = [-1,-1,-1,-1]; + turn+=1; + if (turn==6 || sc[0]==pinsRow) { + play = secret; + col_menu = 0; + endgame = true; + } + break; + case 4: + //new game + play = [-1,-1,-1,-1]; + game = []; + endgame=false; + break; + } + } + } + //console.log(touch_actions[i][1][0], touch_actions[i][1][1]); + + draw(); + } +); + + +game = []; +get_secret(); +draw(); +//Bangle.loadWidgets(); +//Bangle.drawWidgets(); + + + + + From 383d183fa8fa302b8ac1db20b5f1b80935978806 Mon Sep 17 00:00:00 2001 From: Peter Slendebroek Date: Mon, 3 Jan 2022 17:33:12 +0100 Subject: [PATCH 069/315] Update apps.json --- apps.json | 1 + 1 file changed, 1 insertion(+) diff --git a/apps.json b/apps.json index 50b2f3752..b195a5ee3 100644 --- a/apps.json +++ b/apps.json @@ -5073,6 +5073,7 @@ "type": "game", "tags": "mastermind, game, classic", "supports": ["BANGLEJS2"], + "allow_emulator": true, "storage": [ {"name":"mmind.app.js","url":"mmind.app.js"}, {"name":"mmind.img","url":"mmind.icon.js","evaluate":true} From 1241dba5e4833d57b72d5fcdec13218213a7cc44 Mon Sep 17 00:00:00 2001 From: Peter Slendebroek Date: Mon, 3 Jan 2022 17:51:01 +0100 Subject: [PATCH 070/315] Update apps.json --- apps.json | 1 + 1 file changed, 1 insertion(+) diff --git a/apps.json b/apps.json index b195a5ee3..eaab9e297 100644 --- a/apps.json +++ b/apps.json @@ -5072,6 +5072,7 @@ "description": "This is the classic game for masterminds", "type": "game", "tags": "mastermind, game, classic", + "readme":"README.md", "supports": ["BANGLEJS2"], "allow_emulator": true, "storage": [ From b4809c9cdd81b1f358697e10f9e8d805db10bfc9 Mon Sep 17 00:00:00 2001 From: Peter Slendebroek Date: Tue, 4 Jan 2022 21:32:54 +0100 Subject: [PATCH 071/315] Add files via upload --- apps/mmind/mmind.png | Bin 1546 -> 712 bytes apps/mmind/screenshot_mmind.png | Bin 0 -> 2577 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 apps/mmind/screenshot_mmind.png diff --git a/apps/mmind/mmind.png b/apps/mmind/mmind.png index 8afcc26974bc8eaa2239927b33b4d566e8df42ba..14a3ef7c647be749a768209a9dfaea0a09ab960f 100644 GIT binary patch delta 674 zcmeC;Il-#f8Q|y6%O%Cdz`(%k>ERLtq&I*t3p0?6o%u6&qN0MLM1W6->;M1%fkJTn zp8+iJ|9^zugt-&##Os+XJzX3_GVZ;dh9r6B4J?RMuJ;D?~a9lms4|@hr&o{8I0!Jl|U;hi%dQ8^(G6 z_$;&7>u-B@EPwyI`M`|lk3VY6OO0zw?3nst!ViPfqA91Rrhv%aCll(qPrKVk6&yd{ zFLtMR!&ABYk~fOl&$sPpTlkP?&@;u zUFtV}pd@_ctY-3|SNc0^pFOQV$hxe=^!U$((^Y0ITX*KQMW4~*?U}QDia$ww+fl;5 zXZO$%B z(=)p5(zmpO50o%u)+fz~teY_ZWBoy}E05?rl6`A?;LjXy&kYuA%pZ0gxLVd4z!i62 sJ9ho<(AUSms(Eak$?h27=k=E%;69JIf)@8nU>alaboFyt=akR{0Iy3qcK`qY delta 1534 zcmVVGd00o~(L_t(oN9~whXcJi!$4|4vSQ>^XVUQGBv)Tq9N-X_g zDN>45MXKzB4`N|g5h;BTKj=d!ODK^N(G6*#Y4;&Q9}2dLEKyQQLHtPZ#g8bpq7Vz4 zpx8>bwN2aDWMl81JNKrUiPU-Ze_?(zOwK)L?w!NE=bvP52_Xc2BuxDChv6rW$AcdW z3kw4S19$J<-L`F;-EL>GP2%ym&*z(*oWzjTYUSQMb8~b3{r%(P;}|M0FX!Gou~_Wt z)vJ+6WY3;G+qZA$UVv;id;k7@bh2hN8Z9X)kt7Ll$r6b~kKO(+04`n_e<0}hqjQr- zj~-bEt&pK%DJX@)As$eeo}RYZt^uSlEQ+JU!=pT)5DtZdQjh@2KxWW7h(j^|)2B~s zYimnOOVM6kT|IvMxXor885zMQO{lxA?LQ?Oc8&-FK8E%qYRqm=njDYNw7Z(>< z6sfOw0esyIi=zMI$B!(8f46yMFMUG(bXU1?KnzVyO}%~l*6DPjy|lD+>((t?0hSQ0 zp;~i?t#+!LO}%Mko}Lq9$slYByaMp^o zI0$zUa{Kn}nwlES45zcZyZi9r!)S}5NDU05%IrOM$ji(hELPc|)vAaLf|3*t6|3yp zHCrl0i*|HW933q@6$ypIQZPtknT&O?pfc=bHk+}ial#%ye}3H5)UKqWI_M58iyRaHJhPp_;|nafrG^(%cMJN?zrY5UaS+YW-vRMmP z8G_%yc*SMHe@fc9bLZIDSZizRsZ*!uV0Jvz#5F2Qt2Biq%^H=_-YOD_LSMYioYbgH zPH(BQmX;PQrhE79(S!mg1Lh$!9T(^jDjq(3IN8^?kz6NIe(~bPu3fu&dwZWfdlm=;aQV8rx{SXcdKd}mVI-u7 zk&qrne?oc~3F%=Zq=%7^9!5fX7zycNB&3ItkRFBivR8QEJ0;j;(7ZcS)|HJT zR1;2mdbt1lY`tV$Wig0dhwErKz|jF6N~$U%0ON|$0#LjgL-&Q?=1pqU)j@l^;?iSo k4*L4It;N`m`91*u1O9JFJ2Em3SpWb407*qoM6N<$f?a&%7XSbN diff --git a/apps/mmind/screenshot_mmind.png b/apps/mmind/screenshot_mmind.png new file mode 100644 index 0000000000000000000000000000000000000000..5c886e7e82c0a3a78ed1344837f32e33ecd639eb GIT binary patch literal 2577 zcmeHJ`#Td18=f`iPi93)YNl+N>Ez6E$T2ldFO$PqCE*pr*hVq0_hp+y)X2GnksJ!m zhs{2(P?Qg`G-ggEVHsW&msfwl_sjS5`@?hJ*Kc5!Ft)_Nzs zh6Qu>o%dc^tzxUmkj;{-P+aRHnceBu;ARBP66hcO3Gu@PKvSC>1c5gOhn$ub()Q%) zCGvBN&oP_=4mTUgfOxB`SS#Q(zg*EsIlg^@dGrI(ZDwemf-guO2xh_zz73Q;t45!n zajRzQE$wvOLR;5h?7LGy#qyRd5-Z8u8d;9P=&KZE4Wk#uHEqvJ9Y-1q8zRx`LZeUy z^+NjbL#?E($9ybNAWesu8!Xw{V($&eHi1M^FS=(Tj*BI7Ql)D*I2iQwc_8Ovuhz_j z|AUS;>wr>dAiDRR(Eq`UiUUu&Yq-TY)7v%h7e$tgJWc=oWT4ujgK!!j+M?cr?|RTy z?NMF{KPh>EaJZyNVTareswpoXyh~aRi}?26>o>P*`AQU4kr%AaYf6zC$3~*oG=fch z65EkS(M6obqSTQqkR~TF2zJ-Dhh5liSl2ageNz8UZd)#= z$mDK8SvO)^8_BAMo)6r|bRC_1lzwl{`b=?k{hnfbGk%U$x)$ ztRsI2l#v?sM{~+JdF{Lt+Bi$wSX;58@-qa;*?4gv^hPp zY^~2SoQWLT>@;({B&}7N&uj3M5!_zQsN=E5B2Ey6cau$3E8@174RQ0G=zWd3YkpVy z8Q+yRLgE?uBFO5qisa5X>9B}cpj@b#u;Ctb0Z)K?_O$B5$LZ=)eaq+eA`D#sJc8=V zxt^Kd)%u>hGZUCJFtI4omGwJF`?`|Im((@p5=plvbs-SstOtn@xb6{6sA|*pYc8*T zd0041D<8+zr`w3B1snb#(f#%fclM1PCZF^J1dp1~k63)uxni);x$rfDxc(U>I6LnOlcyh`Z~SRxYm`5viE)1x1B`F=~GD$S10%0+T3YaSfVA! zxg5v%+7;B!ZE>krVymgi^B(Y76PT_fA1gr3bc8TO+IxZTcb+xDKHbGM_YL#k&zoS%KL*uPFkYpn{xDdC5; z7Wr`k(mMWxJ}QyB{Ji@_0-`B8&sH_8-`Xa~{7VWs17qO*XM&oa$I0079)2RBlFhxZzLp<#1v=KhJ6N{6O9RU4|MAIZ;B zsUCQ@dQogjA6wa!wZq9SWvzP%!1TD8A|(h^sF;=47M^AHC-gKj1sF7=4I?^=un?r) zlGZWLh&k}T5%qTXs!k=!Fa!x-oQEK<8l|T3Rq9Pr^x-PB)|=OG0fFnR=$|KuL?~~Q zT}`iju{Y`y3IYq+(iO4g^8 T#S9|s{&)Zv2aJ8KT|m;`rbCOu literal 0 HcmV?d00001 From 786b13925cf1a3097706ec11a5c10565431e8fa9 Mon Sep 17 00:00:00 2001 From: Peter Slendebroek Date: Tue, 4 Jan 2022 22:32:36 +0100 Subject: [PATCH 072/315] Add files via upload --- apps/mmind/README.md | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 apps/mmind/README.md diff --git a/apps/mmind/README.md b/apps/mmind/README.md new file mode 100644 index 000000000..508a158dd --- /dev/null +++ b/apps/mmind/README.md @@ -0,0 +1,34 @@ +# Mastermind + +Play the classic mind game mastermind on your Bangles 2. + +![](screenshot_mmind.png) + + +## Game +The game will start when run. +Four colors pins are randomly choosen and kept secret. +You need to find the secret by scoring your choise within 6 turns. +The game makes use of touch features. + + +## Play +Select one of the dots, the color menu will show, select a colour for the pin. +If all pins are choosen with a color the red button will turn green. +Hit the green button and your play will be scored and listed from the top. +The first digit shows the number of pins with the correct color and in the right place. +The second digit gives the number of pins with the correct color but in the wrong place. +There are six turns to get the correct secret. +The blue button will start a new game. + + +## Requests + +This is the first version, things to add: +Add menu to change game options number of colors, 5 pins per row. +Add feature to drag screen up and down to see more scores + + +## Creator + +This game is created by Peter Slendebroek. \ No newline at end of file From 1fdf05958dbd13af0e65ff30d0c044208a8c737f Mon Sep 17 00:00:00 2001 From: Peter Slendebroek Date: Tue, 4 Jan 2022 22:36:51 +0100 Subject: [PATCH 073/315] Update README.md --- apps/mmind/README.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/apps/mmind/README.md b/apps/mmind/README.md index 508a158dd..e09b5b966 100644 --- a/apps/mmind/README.md +++ b/apps/mmind/README.md @@ -13,6 +13,7 @@ The game makes use of touch features. ## Play +The screen needs to be unlocked. Select one of the dots, the color menu will show, select a colour for the pin. If all pins are choosen with a color the red button will turn green. Hit the green button and your play will be scored and listed from the top. @@ -25,10 +26,11 @@ The blue button will start a new game. ## Requests This is the first version, things to add: -Add menu to change game options number of colors, 5 pins per row. -Add feature to drag screen up and down to see more scores - +... +Add a menu to change game options like the number of colors, allow double colors, 5 pins per row. +Add feature to drag screen up and down to see more scores. +Times and high score ## Creator -This game is created by Peter Slendebroek. \ No newline at end of file +This game is created by Peter Slendebroek. From ed9b7f2e6b148f10a8a2b7f07bd4c12ea8622b02 Mon Sep 17 00:00:00 2001 From: Peter Slendebroek Date: Tue, 4 Jan 2022 22:44:04 +0100 Subject: [PATCH 074/315] Update README.md --- apps/mmind/README.md | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/apps/mmind/README.md b/apps/mmind/README.md index e09b5b966..0623459f7 100644 --- a/apps/mmind/README.md +++ b/apps/mmind/README.md @@ -25,11 +25,10 @@ The blue button will start a new game. ## Requests -This is the first version, things to add: -... -Add a menu to change game options like the number of colors, allow double colors, 5 pins per row. -Add feature to drag screen up and down to see more scores. -Times and high score +This is the first version, things to add are:/ +Add a menu to change game options like the number of colors, allow double colors, 5 pins per row./ +Add feature to drag screen up and down to see more scores./ +Timer and high score./ ## Creator From 8931817a2b23ec5740346ab4c571de520153a189 Mon Sep 17 00:00:00 2001 From: Peter Slendebroek Date: Tue, 4 Jan 2022 23:00:36 +0100 Subject: [PATCH 075/315] Add files via upload --- apps/mmind/mmind.info | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 apps/mmind/mmind.info diff --git a/apps/mmind/mmind.info b/apps/mmind/mmind.info new file mode 100644 index 000000000..a6dccde65 --- /dev/null +++ b/apps/mmind/mmind.info @@ -0,0 +1,5 @@ +require("Storage").write("mmind.info",{ + "id":"mmind", + "name":"Master Mindr", + "src":"mmind.app.js" +}); \ No newline at end of file From cd71d7937d636d2b3ba77b62b6edec5ecda3f0d7 Mon Sep 17 00:00:00 2001 From: Peter Slendebroek Date: Tue, 4 Jan 2022 23:02:47 +0100 Subject: [PATCH 076/315] Update mmind.info --- apps/mmind/mmind.info | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/apps/mmind/mmind.info b/apps/mmind/mmind.info index a6dccde65..2e79822b1 100644 --- a/apps/mmind/mmind.info +++ b/apps/mmind/mmind.info @@ -1,5 +1,17 @@ -require("Storage").write("mmind.info",{ - "id":"mmind", - "name":"Master Mindr", - "src":"mmind.app.js" -}); \ No newline at end of file + { + "id": "mmind", + "name": "Classic Mind Game", + "shortName":"Master Mind", + "icon": "mmind.png", + "version":"0.01", + "description": "This is the classic game for masterminds", + "type": "game", + "tags": "mastermind, game, classic", + "readme":"README.md", + "supports": ["BANGLEJS2"], + "allow_emulator": true, + "storage": [ + {"name":"mmind.app.js","url":"mmind.app.js"}, + {"name":"mmind.img","url":"mmind.icon.js","evaluate":true} + ] + } From 1ef8a0bfb0b52107cac461c7f009a7e74a6efa36 Mon Sep 17 00:00:00 2001 From: Danny <31635744+DDDanny@users.noreply.github.com> Date: Wed, 5 Jan 2022 01:00:03 +0100 Subject: [PATCH 077/315] Update core --- core | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core b/core index 2a8e872ec..5a5957714 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit 2a8e872ecb143a10e53273b4d3473164e104e1d3 +Subproject commit 5a5957714d4aa04413329f57c03e6de0cfb74caf From 71504a7414dc35d136ae1cd45b991289fab1ec9a Mon Sep 17 00:00:00 2001 From: Marco Heiming Date: Wed, 5 Jan 2022 12:16:14 +0100 Subject: [PATCH 078/315] Setting to toggle visibility of widgets Setting to set minimal heart rate --- apps/circlesclock/app.js | 45 +++++++++++++++++++++-------------- apps/circlesclock/settings.js | 18 ++++++++++++++ 2 files changed, 45 insertions(+), 18 deletions(-) diff --git a/apps/circlesclock/app.js b/apps/circlesclock/app.js index 026b47cc6..f123e0c2a 100644 --- a/apps/circlesclock/app.js +++ b/apps/circlesclock/app.js @@ -8,12 +8,13 @@ const powerIconGreen = heatshrink.decompress(atob("h0OwYQNkAEDpAEDiQEDkmSAgUJkmA const powerIconRed = heatshrink.decompress(atob("h0OwYQNoAEDyAEDkgEDpIFDiVJBweSAgUJkmAAoYZDgQpEBwYAJA")); let settings; - function loadSettings() { settings = require("Storage").readJSON("circlesclock.json", 1) || { + 'minHR': 40, 'maxHR': 200, 'stepGoal': 10000, - 'batteryWarn': 30 + 'batteryWarn': 30, + 'showWidgets': false }; // Load step goal from pedometer widget as fallback if (settings.stepGoal == undefined) { @@ -21,18 +22,21 @@ function loadSettings() { settings.stepGoal = d != undefined && d.settings != undefined ? d.settings.goal : 10000; } } +loadSettings(); +const showWidgets = settings.showWidgets || false; +let hrtValue; + +// layout values: const colorFg = g.theme.dark ? '#fff' : '#000'; const colorBg = g.theme.dark ? '#000' : '#fff'; const colorGrey = '#808080'; const colorRed = '#ff0000'; const colorGreen = '#00ff00'; - -let hrtValue; - -const h = g.getHeight(); +const widgetOffset = showWidgets ? 12 : 0; +const h = g.getHeight() - widgetOffset; const w = g.getWidth(); -const hOffset = 30; +const hOffset = 30 - widgetOffset; const h1 = Math.round(1 * h / 5 - hOffset); const h2 = Math.round(3 * h / 5 - hOffset); const h3 = Math.round(8 * h / 8 - hOffset); @@ -102,7 +106,7 @@ function drawHeartRate() { g.fillCircle(w2, h3, radiusOuter); if (hrtValue != undefined && hrtValue > 0) { - const minHR = 40; + const minHR = settings.minHR || 40; const percent = (hrtValue - minHR) / (settings.maxHR - minHR); drawGauge(w2, h3, percent, colorRed); } @@ -233,19 +237,24 @@ Bangle.on('charging', function(charging) { }); g.clear(); + + Bangle.loadWidgets(); -/* - * we are not drawing the widgets as we are taking over the whole screen - * so we will blank out the draw() functions of each widget and change the - * area to the top bar doesn't get cleared. - */ -if (typeof WIDGETS === "object") { - for (let wd of WIDGETS) { - wd.draw = () => {}; - wd.area = ""; +if (!showWidgets) { + /* + * we are not drawing the widgets as we are taking over the whole screen + * so we will blank out the draw() functions of each widget and change the + * area to the top bar doesn't get cleared. + */ + if (WIDGETS && typeof WIDGETS === "object") { + for (let wd of WIDGETS) { + wd.draw = () => {}; + wd.area = ""; + } } } -loadSettings(); + + setInterval(draw, 60000); draw(); Bangle.setUI("clock"); diff --git a/apps/circlesclock/settings.js b/apps/circlesclock/settings.js index ffda51538..15596ff18 100644 --- a/apps/circlesclock/settings.js +++ b/apps/circlesclock/settings.js @@ -8,6 +8,16 @@ } E.showMenu({ '': { 'title': 'circlesclock' }, + 'min heartrate': { + value: "minHR" in settings ? settings.minHR : 40, + min: 0, + max : 250, + step: 10, + format: x => { + return x; + }, + onchange: x => save('minHR', x), + }, 'max heartrate': { value: "maxHR" in settings ? settings.maxHR : 200, min: 20, @@ -38,6 +48,14 @@ }, onchange: x => save('batteryWarn', x), }, + 'show widgets': { + value: "showWidgets" in settings ? settings.showWidgets : false, + format: () => (settings.showWidgets ? 'Yes' : 'No'), + onchange: () => { + settings.showWidgets = !settings.showWidgets; + save('showWidgets', settings.showWidgets); + }, + }, '< Back': back, }); }); From c41bae14c9e6c5a0dc8d33163415a03787baa632 Mon Sep 17 00:00:00 2001 From: Marco Heiming Date: Wed, 5 Jan 2022 12:16:38 +0100 Subject: [PATCH 079/315] Update README --- apps/circlesclock/README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/apps/circlesclock/README.md b/apps/circlesclock/README.md index 66d9afe08..df47c369b 100644 --- a/apps/circlesclock/README.md +++ b/apps/circlesclock/README.md @@ -8,13 +8,11 @@ It shows besides time, date and day of week the following information: * Battery (including charging and battery low) ## Screenshot - ![Screenshot](screenshot.png) ## TODO * Show weather information * Configure which information to show in each circle -* Configure visibility of widgets ## Creator Marco ([myxor](https://github.com/myxor)) From fea7c2dcf817fbb9e6fe402fae1d79bf8089cab2 Mon Sep 17 00:00:00 2001 From: The Dod Date: Wed, 5 Jan 2022 13:49:02 +0200 Subject: [PATCH 080/315] typo fix MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 😖 --- apps.json | 1 + 1 file changed, 1 insertion(+) diff --git a/apps.json b/apps.json index 04cc12a37..b0ebce263 100644 --- a/apps.json +++ b/apps.json @@ -5139,6 +5139,7 @@ {"name":"fourTwenty","url":"fourTwenty.js"}, {"name":"fourTwentyTz","url":"fourTwentyTz.js"}, {"name":"ftclock.img","url":"app-icon.js","evaluate":true} + ] }, { "id": "slash", From 766d3cc1892874b5a8be3f611c3e4335da236c80 Mon Sep 17 00:00:00 2001 From: Marco Heiming Date: Wed, 5 Jan 2022 13:27:50 +0100 Subject: [PATCH 081/315] Make the types of the circles configurable --- apps/circlesclock/app.js | 163 ++++++++++++++++++++++++---------- apps/circlesclock/settings.js | 29 ++++++ 2 files changed, 144 insertions(+), 48 deletions(-) diff --git a/apps/circlesclock/app.js b/apps/circlesclock/app.js index f123e0c2a..58055e96e 100644 --- a/apps/circlesclock/app.js +++ b/apps/circlesclock/app.js @@ -14,7 +14,10 @@ function loadSettings() { 'maxHR': 200, 'stepGoal': 10000, 'batteryWarn': 30, - 'showWidgets': false + 'showWidgets': false, + 'circle1': 'hr', + 'circle2': 'steps', + 'circle3': 'battery' }; // Load step goal from pedometer widget as fallback if (settings.stepGoal == undefined) { @@ -32,7 +35,9 @@ const colorFg = g.theme.dark ? '#fff' : '#000'; const colorBg = g.theme.dark ? '#000' : '#fff'; const colorGrey = '#808080'; const colorRed = '#ff0000'; -const colorGreen = '#00ff00'; +const colorGreen = '#008000'; +const colorBlue = '#0000ff'; +const colorYellow = '#ffff00'; const widgetOffset = showWidgets ? 12 : 0; const h = g.getHeight() - widgetOffset; const w = g.getWidth(); @@ -63,82 +68,137 @@ function draw() { g.drawString(locale.date(new Date()), w / 10, h2); g.drawString(locale.dow(new Date()), w / 10, h2 + 22); - // Steps circle - drawSteps(); - - // Heart circle - drawHeartRate(); - - // Battery circle - drawBattery(); + drawCircle(1, "steps"); + drawCircle(2, "hr"); + drawCircle(3, "battery"); } +function drawCircle(index, defaultType) { + const type = settings['circle' + index] || defaultType; + const w = index == 1 ? w1: index == 2 ? w2 : w3; -function drawSteps() { + switch (type) { + case "steps": + drawSteps(w); + break; + case "stepsDist": + drawStepsDistance(w); + break; + case "hr": + drawHeartRate(w); + break; + case "battery": + drawBattery(w); + break; + } +} +function getCirclePosition(type, defaultPos) { + for (let i = 1; i <= 3; i++) { + const setting = settings['circle' + i]; + if (setting == type) return i; + } + return defaultPos; +} + +function isCircleEnabled(type) { + return getCirclePosition(type) != undefined; +} + +function drawSteps(w) { + if (!w) w = getCirclePosition("steps", w1); const steps = getSteps(); - const blue = '#0000ff'; g.setColor(colorGrey); - g.fillCircle(w1, h3, radiusOuter); + g.fillCircle(w, h3, radiusOuter); const stepGoal = settings.stepGoal || 10000; if (stepGoal > 0) { let percent = steps / stepGoal; if (stepGoal < steps) percent = 1; - drawGauge(w1, h3, percent, blue); + drawGauge(w, h3, percent, colorBlue); } g.setColor(colorBg); - g.fillCircle(w1, h3, radiusInner); + g.fillCircle(w, h3, radiusInner); - g.fillPoly([w1, h3, w1 - 15, h3 + radiusOuter + 5, w1 + 15, h3 + radiusOuter + 5]); + g.fillPoly([w, h3, w - 15, h3 + radiusOuter + 5, w + 15, h3 + radiusOuter + 5]); g.setFont("Vector:12"); g.setFontAlign(0, 0); g.setColor(colorFg); - g.drawString(shortValue(steps), w1 + 2, h3); + g.drawString(shortValue(steps), w + 2, h3); - g.drawImage(shoesIcon, w1 - 6, h3 + radiusOuter - 6); + g.drawImage(shoesIcon, w - 6, h3 + radiusOuter - 6); } -function drawHeartRate() { +function drawStepsDistance(w) { + if (!w) w = getCirclePosition("steps", w1); + const steps = getSteps(); + const stepDistance = 0.8; // TODO make configurable + const stepsDistance = steps * stepDistance; + g.setColor(colorGrey); - g.fillCircle(w2, h3, radiusOuter); + g.fillCircle(w, h3, radiusOuter); + + const stepDistanceGoal = settings.stepDistanceGoal || 5; + if (stepDistanceGoal > 0) { + let percent = stepsDistance / stepDistanceGoal; + if (stepDistanceGoal < stepsDistance) percent = 1; + drawGauge(w, h3, percent, colorGreen); + } + + g.setColor(colorBg); + g.fillCircle(w, h3, radiusInner); + + g.fillPoly([w, h3, w - 15, h3 + radiusOuter + 5, w + 15, h3 + radiusOuter + 5]); + + g.setFont("Vector:12"); + g.setFontAlign(0, 0); + g.setColor(colorFg); + g.drawString(shortValue(stepsDistance), w + 2, h3); + + g.drawImage(shoesIcon, w - 6, h3 + radiusOuter - 6); +} + +function drawHeartRate(w) { + if (!w) w = getCirclePosition("hr", w2); + g.setColor(colorGrey); + g.fillCircle(w, h3, radiusOuter); if (hrtValue != undefined && hrtValue > 0) { const minHR = settings.minHR || 40; const percent = (hrtValue - minHR) / (settings.maxHR - minHR); - drawGauge(w2, h3, percent, colorRed); + drawGauge(w, h3, percent, colorRed); } g.setColor(colorBg); - g.fillCircle(w2, h3, radiusInner); + g.fillCircle(w, h3, radiusInner); - g.fillPoly([w2, h3, w2 - 15, h3 + radiusOuter + 5, w2 + 15, h3 + radiusOuter + 5]); + g.fillPoly([w, h3, w - 15, h3 + radiusOuter + 5, w + 15, h3 + radiusOuter + 5]); g.setFont("Vector:12"); g.setFontAlign(0, 0); g.setColor(colorFg); - g.drawString(hrtValue != undefined ? hrtValue : "-", w2, h3); + g.drawString(hrtValue != undefined ? hrtValue : "-", w, h3); - g.drawImage(heartIcon, w2 - 6, h3 + radiusOuter - 6); + g.drawImage(heartIcon, w - 6, h3 + radiusOuter - 6); } -function drawBattery() { +function drawBattery(w) { + if (!w) w = getCirclePosition("battery", w3); const battery = E.getBattery(); - const yellow = '#ffff00'; g.setColor(colorGrey); - g.fillCircle(w3, h3, radiusOuter); + g.fillCircle(w, h3, radiusOuter); if (battery > 0) { const percent = battery / 100; - drawGauge(w3, h3, percent, yellow); + drawGauge(w, h3, percent, colorYellow); } g.setColor(colorBg); - g.fillCircle(w3, h3, radiusInner); + g.fillCircle(w, h3, radiusInner); - g.fillPoly([w3, h3, w3 - 15, h3 + radiusOuter + 5, w3 + 15, h3 + radiusOuter + 5]); + g.fillPoly([w, h3, w - 15, h3 + radiusOuter + 5, w + 15, h3 + radiusOuter + 5]); g.setFont("Vector:12"); g.setFontAlign(0, 0); @@ -156,9 +216,9 @@ function drawBattery() { } } g.setColor(color); - g.drawString(battery + '%', w3, h3); + g.drawString(battery + '%', w, h3); - g.drawImage(icon, w3 - 6, h3 + radiusOuter - 6); + g.drawImage(icon, w - 6, h3 + radiusOuter - 6); } function radians(a) { @@ -210,30 +270,37 @@ function getSteps() { Bangle.on('lock', function(isLocked) { if (!isLocked) { - Bangle.setHRMPower(1, "watch"); - if (hrtValue == undefined) { - hrtValue = '...'; - drawHeartRate(); + if (isCircleEnabled("hr")) { + Bangle.setHRMPower(1, "watch"); + if (hrtValue == undefined) { + hrtValue = '...'; + drawHeartRate(); + } } } else { - Bangle.setHRMPower(0, "watch"); + if (isCircleEnabled("hr")) { + Bangle.setHRMPower(0, "watch"); + } } - drawHeartRate(); - drawSteps(); + if (isCircleEnabled("hr")) drawHeartRate(); + if (isCircleEnabled("steps")) drawSteps(); + if (isCircleEnabled("stepsDistance")) drawStepsDistance(); }); Bangle.on('HRM', function(hrm) { - //if(hrm.confidence > 90){ - hrtValue = hrm.bpm; - if (Bangle.isLCDOn()) - drawHeartRate(); - //} else { - // hrtValue = undefined; - //} + if (isCircleEnabled("hr")) { + //if(hrm.confidence > 90){ + hrtValue = hrm.bpm; + if (Bangle.isLCDOn()) + drawHeartRate(); + //} else { + // hrtValue = undefined; + //} + } }); Bangle.on('charging', function(charging) { - drawBattery(); + if (isCircleEnabled("battery")) drawBattery(); }); g.clear(); diff --git a/apps/circlesclock/settings.js b/apps/circlesclock/settings.js index 15596ff18..754fa0c69 100644 --- a/apps/circlesclock/settings.js +++ b/apps/circlesclock/settings.js @@ -6,6 +6,8 @@ settings[key] = value; storage.write(SETTINGS_FILE, settings); } + var valuesCircleTypes = ["steps", "stepsDist", "hr", "battery"]; + var namesCircleTypes = ["steps", "step distance", "heart", "battery"]; E.showMenu({ '': { 'title': 'circlesclock' }, 'min heartrate': { @@ -56,6 +58,33 @@ save('showWidgets', settings.showWidgets); }, }, + 'Left circle': { + value: Math.max(0,0 | valuesCircleTypes.indexOf(settings.circle1)), + min: 0, max: 3, + format: v => namesCircleTypes[v], + onchange: v => { + settings.circle1 = valuesCircleTypes[v]; + save('circle1', settings.circle1); + } + }, + 'Middle circle': { + value: Math.max(0,0 | valuesCircleTypes.indexOf(settings.circle2)), + min: 0, max: 3, + format: v => namesCircleTypes[v], + onchange: v => { + settings.circle2 = valuesCircleTypes[v]; + save('circle2', settings.circle2); + } + }, + 'Right circle': { + value: Math.max(0,0 | valuesCircleTypes.indexOf(settings.circle3)), + min: 0, max: 3, + format: v => namesCircleTypes[v], + onchange: v => { + settings.circle3 = valuesCircleTypes[v]; + save('circle3', settings.circle3); + } + }, '< Back': back, }); }); From ee252a3a97fc3880c7744ed79966e6f25bb6e8da Mon Sep 17 00:00:00 2001 From: Marco Heiming Date: Wed, 5 Jan 2022 14:04:04 +0100 Subject: [PATCH 082/315] Fix position, default settings and add green step distance icon --- apps/circlesclock/app.js | 5 +++-- apps/circlesclock/settings.js | 14 +++++++------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/apps/circlesclock/app.js b/apps/circlesclock/app.js index 58055e96e..686de735b 100644 --- a/apps/circlesclock/app.js +++ b/apps/circlesclock/app.js @@ -2,6 +2,7 @@ const locale = require("locale"); const heatshrink = require("heatshrink"); const shoesIcon = heatshrink.decompress(atob("h0OwYJGgmAAgUBkgECgVJB4cSoAUDyEBkARDpADBhMAyQRBgVAkgmDhIUDAAuQAgY1DAAYA=")); +const shoesIconGreen = heatshrink.decompress(atob("h0OwYJGhIEDgVIAgUEyQKDkmACgcggVACIeQAYMSgIRCgmApIbDiQUDAAkBkAFDGoYAD")); const heartIcon = heatshrink.decompress(atob("h0OwYOLkmQhMkgACByVJgESpIFBpEEBAIFBCgIFCCgsABwcAgQOCAAMSpAwDyBNM")); const powerIcon = heatshrink.decompress(atob("h0OwYQNsAED7AEDmwEDtu2AgUbtuABwXbBIUN23AAoYOCgEDFIgODABI")); const powerIconGreen = heatshrink.decompress(atob("h0OwYQNkAEDpAEDiQEDkmSAgUJkmABwVJBIUEyVAAoYOCgEBFIgODABI")); @@ -96,7 +97,7 @@ function drawCircle(index, defaultType) { function getCirclePosition(type, defaultPos) { for (let i = 1; i <= 3; i++) { const setting = settings['circle' + i]; - if (setting == type) return i; + if (setting == type) return i == 1 ? w1: i == 2 ? w2 : w3; } return defaultPos; } @@ -157,7 +158,7 @@ function drawStepsDistance(w) { g.setColor(colorFg); g.drawString(shortValue(stepsDistance), w + 2, h3); - g.drawImage(shoesIcon, w - 6, h3 + radiusOuter - 6); + g.drawImage(shoesIconGreen, w - 6, h3 + radiusOuter - 6); } function drawHeartRate(w) { diff --git a/apps/circlesclock/settings.js b/apps/circlesclock/settings.js index 754fa0c69..3ddacd29c 100644 --- a/apps/circlesclock/settings.js +++ b/apps/circlesclock/settings.js @@ -7,7 +7,7 @@ storage.write(SETTINGS_FILE, settings); } var valuesCircleTypes = ["steps", "stepsDist", "hr", "battery"]; - var namesCircleTypes = ["steps", "step distance", "heart", "battery"]; + var namesCircleTypes = ["steps", "distance", "heart", "battery"]; E.showMenu({ '': { 'title': 'circlesclock' }, 'min heartrate': { @@ -40,7 +40,7 @@ }, onchange: x => save('stepGoal', x), }, - 'battery warn lvl': { + 'battery warn': { value: "batteryWarn" in settings ? settings.batteryWarn : 30, min: 10, max : 100, @@ -58,7 +58,7 @@ save('showWidgets', settings.showWidgets); }, }, - 'Left circle': { + 'left': { value: Math.max(0,0 | valuesCircleTypes.indexOf(settings.circle1)), min: 0, max: 3, format: v => namesCircleTypes[v], @@ -67,8 +67,8 @@ save('circle1', settings.circle1); } }, - 'Middle circle': { - value: Math.max(0,0 | valuesCircleTypes.indexOf(settings.circle2)), + 'middle': { + value: Math.max(0,2 | valuesCircleTypes.indexOf(settings.circle2)), min: 0, max: 3, format: v => namesCircleTypes[v], onchange: v => { @@ -76,8 +76,8 @@ save('circle2', settings.circle2); } }, - 'Right circle': { - value: Math.max(0,0 | valuesCircleTypes.indexOf(settings.circle3)), + 'right': { + value: Math.max(0,3 | valuesCircleTypes.indexOf(settings.circle3)), min: 0, max: 3, format: v => namesCircleTypes[v], onchange: v => { From 3538c6024fe36715a82d0d2018862cab2992f944 Mon Sep 17 00:00:00 2001 From: Marco Heiming Date: Wed, 5 Jan 2022 14:14:47 +0100 Subject: [PATCH 083/315] Configuration of stepDistanceGoal and stepLength --- apps/circlesclock/app.js | 6 ++++-- apps/circlesclock/settings.js | 40 +++++++++++++++++++++-------------- 2 files changed, 28 insertions(+), 18 deletions(-) diff --git a/apps/circlesclock/app.js b/apps/circlesclock/app.js index 686de735b..3099b02ea 100644 --- a/apps/circlesclock/app.js +++ b/apps/circlesclock/app.js @@ -14,6 +14,8 @@ function loadSettings() { 'minHR': 40, 'maxHR': 200, 'stepGoal': 10000, + 'stepDistanceGoal': 8000, + 'stepLength': 0.8, 'batteryWarn': 30, 'showWidgets': false, 'circle1': 'hr', @@ -135,13 +137,13 @@ function drawSteps(w) { function drawStepsDistance(w) { if (!w) w = getCirclePosition("steps", w1); const steps = getSteps(); - const stepDistance = 0.8; // TODO make configurable + const stepDistance = settings.stepLength || 0.8; const stepsDistance = steps * stepDistance; g.setColor(colorGrey); g.fillCircle(w, h3, radiusOuter); - const stepDistanceGoal = settings.stepDistanceGoal || 5; + const stepDistanceGoal = settings.stepDistanceGoal || 8000; if (stepDistanceGoal > 0) { let percent = stepsDistance / stepDistanceGoal; if (stepDistanceGoal < stepsDistance) percent = 1; diff --git a/apps/circlesclock/settings.js b/apps/circlesclock/settings.js index 3ddacd29c..dc75f54af 100644 --- a/apps/circlesclock/settings.js +++ b/apps/circlesclock/settings.js @@ -40,6 +40,26 @@ }, onchange: x => save('stepGoal', x), }, + 'step length': { + value: "stepLength" in settings ? settings.stepLength : 0.8, + min: 0.1, + max : 1.5, + step: 0.01, + format: x => { + return x; + }, + onchange: x => save('stepLength', x), + }, + 'step dist goal': { + value: "stepDistanceGoal" in settings ? settings.stepDistanceGoal : 8000, + min: 2000, + max : 30000, + step: 1000, + format: x => { + return x; + }, + onchange: x => save('stepDistanceGoal', x), + }, 'battery warn': { value: "batteryWarn" in settings ? settings.batteryWarn : 30, min: 10, @@ -53,37 +73,25 @@ 'show widgets': { value: "showWidgets" in settings ? settings.showWidgets : false, format: () => (settings.showWidgets ? 'Yes' : 'No'), - onchange: () => { - settings.showWidgets = !settings.showWidgets; - save('showWidgets', settings.showWidgets); - }, + onchange: x => save('showWidgets', x), }, 'left': { value: Math.max(0,0 | valuesCircleTypes.indexOf(settings.circle1)), min: 0, max: 3, format: v => namesCircleTypes[v], - onchange: v => { - settings.circle1 = valuesCircleTypes[v]; - save('circle1', settings.circle1); - } + onchange: x => save('circle1', x), }, 'middle': { value: Math.max(0,2 | valuesCircleTypes.indexOf(settings.circle2)), min: 0, max: 3, format: v => namesCircleTypes[v], - onchange: v => { - settings.circle2 = valuesCircleTypes[v]; - save('circle2', settings.circle2); - } + onchange: x => save('circle2', x), }, 'right': { value: Math.max(0,3 | valuesCircleTypes.indexOf(settings.circle3)), min: 0, max: 3, format: v => namesCircleTypes[v], - onchange: v => { - settings.circle3 = valuesCircleTypes[v]; - save('circle3', settings.circle3); - } + onchange: x => save('circle3', x), }, '< Back': back, }); From f174cb56fbd586f7e6a357a73129f9d5d6ab244d Mon Sep 17 00:00:00 2001 From: Marco Heiming Date: Wed, 5 Jan 2022 14:14:56 +0100 Subject: [PATCH 084/315] Update README --- apps/circlesclock/README.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/apps/circlesclock/README.md b/apps/circlesclock/README.md index df47c369b..86c388440 100644 --- a/apps/circlesclock/README.md +++ b/apps/circlesclock/README.md @@ -2,17 +2,19 @@ A clock with circles for different data at the bottom in a probably familiar style -It shows besides time, date and day of week the following information: +By default the time, date and day of week is shown. + +It can show the following information (this can be configured): * Steps (requires [pedometer widget](https://banglejs.com/apps/#pedometer)) - * Heart rate (when screen is on and unlocked) - * Battery (including charging and battery low) + * Steps distance (depending on steps) + * Heart rate (automatically updates when screen is on and unlocked) + * Battery (including charging status and battery low warning) ## Screenshot ![Screenshot](screenshot.png) ## TODO * Show weather information -* Configure which information to show in each circle ## Creator Marco ([myxor](https://github.com/myxor)) From ad371e9678cb380ea064ed01cbe6b7df385b4d56 Mon Sep 17 00:00:00 2001 From: Marco Heiming Date: Wed, 5 Jan 2022 14:21:01 +0100 Subject: [PATCH 085/315] Update changelog and bump version --- apps.json | 2 +- apps/circlesclock/ChangeLog | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/apps.json b/apps.json index f116049dc..c6600ada0 100644 --- a/apps.json +++ b/apps.json @@ -5071,7 +5071,7 @@ { "id": "circlesclock", "name": "Circles clock", "shortName":"Circles clock", - "version":"0.03", + "version":"0.04", "description": "A clock with circles for different data at the bottom in a probably familiar style", "icon": "app.png", "screenshots": [{"url":"screenshot.png"}], diff --git a/apps/circlesclock/ChangeLog b/apps/circlesclock/ChangeLog index c0aa4e2f8..f416929ac 100644 --- a/apps/circlesclock/ChangeLog +++ b/apps/circlesclock/ChangeLog @@ -1,3 +1,4 @@ 0.01: New clock 0.02: Fix icon & add battery warn functionality 0.03: Theming support & minor fixes +0.04: Make configurable what to show in each circle; add step distance circle; allow switching visibility of widgets From 3ba696ed0e29c6916726412d35895c48d74d8560 Mon Sep 17 00:00:00 2001 From: Marco Heiming Date: Wed, 5 Jan 2022 14:30:02 +0100 Subject: [PATCH 086/315] Fix settings --- apps/circlesclock/settings.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/circlesclock/settings.js b/apps/circlesclock/settings.js index dc75f54af..0c42319f5 100644 --- a/apps/circlesclock/settings.js +++ b/apps/circlesclock/settings.js @@ -79,19 +79,19 @@ value: Math.max(0,0 | valuesCircleTypes.indexOf(settings.circle1)), min: 0, max: 3, format: v => namesCircleTypes[v], - onchange: x => save('circle1', x), + onchange: x => save('circle1', valuesCircleTypes[x]), }, 'middle': { value: Math.max(0,2 | valuesCircleTypes.indexOf(settings.circle2)), min: 0, max: 3, format: v => namesCircleTypes[v], - onchange: x => save('circle2', x), + onchange: x => save('circle2', valuesCircleTypes[x]), }, 'right': { value: Math.max(0,3 | valuesCircleTypes.indexOf(settings.circle3)), min: 0, max: 3, format: v => namesCircleTypes[v], - onchange: x => save('circle3', x), + onchange: x => save('circle3', valuesCircleTypes[x]), }, '< Back': back, }); From 639bc1962eee45c31b4cf0d50f5edf782ac94e1c Mon Sep 17 00:00:00 2001 From: Marco Heiming Date: Wed, 5 Jan 2022 15:28:18 +0100 Subject: [PATCH 087/315] Allow widgets to detect this is a clock --- apps/circlesclock/app.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/apps/circlesclock/app.js b/apps/circlesclock/app.js index 3099b02ea..2d6c132bb 100644 --- a/apps/circlesclock/app.js +++ b/apps/circlesclock/app.js @@ -308,7 +308,7 @@ Bangle.on('charging', function(charging) { g.clear(); - +Bangle.setUI("clock"); Bangle.loadWidgets(); if (!showWidgets) { /* @@ -324,7 +324,5 @@ if (!showWidgets) { } } - -setInterval(draw, 60000); draw(); -Bangle.setUI("clock"); +setInterval(draw, 60000); From 801237b2cfad1caf17a0d4bb496527bd4a217e8a Mon Sep 17 00:00:00 2001 From: Marco Heiming Date: Wed, 5 Jan 2022 15:35:01 +0100 Subject: [PATCH 088/315] Let's only register HRM and battery events when respective circle is visible --- apps/circlesclock/app.js | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/apps/circlesclock/app.js b/apps/circlesclock/app.js index 2d6c132bb..e10d55f17 100644 --- a/apps/circlesclock/app.js +++ b/apps/circlesclock/app.js @@ -280,31 +280,32 @@ Bangle.on('lock', function(isLocked) { drawHeartRate(); } } + if (isCircleEnabled("steps")) drawSteps(); + if (isCircleEnabled("stepsDistance")) drawStepsDistance(); } else { if (isCircleEnabled("hr")) { Bangle.setHRMPower(0, "watch"); } } - if (isCircleEnabled("hr")) drawHeartRate(); - if (isCircleEnabled("steps")) drawSteps(); - if (isCircleEnabled("stepsDistance")) drawStepsDistance(); }); -Bangle.on('HRM', function(hrm) { - if (isCircleEnabled("hr")) { - //if(hrm.confidence > 90){ - hrtValue = hrm.bpm; - if (Bangle.isLCDOn()) - drawHeartRate(); - //} else { - // hrtValue = undefined; - //} - } -}); +if (isCircleEnabled("hr")) { + Bangle.on('HRM', function(hrm) { + //if(hrm.confidence > 90){ + hrtValue = hrm.bpm; + if (Bangle.isLCDOn()) + drawHeartRate(); + //} else { + // hrtValue = undefined; + //} + }); +} -Bangle.on('charging', function(charging) { - if (isCircleEnabled("battery")) drawBattery(); -}); +if (isCircleEnabled("battery")) { + Bangle.on('charging', function(charging) { + drawBattery(); + }); +} g.clear(); From 6cd9167565238518a35fc345b17a64c0980c72e0 Mon Sep 17 00:00:00 2001 From: David Peer Date: Wed, 5 Jan 2022 17:49:05 +0100 Subject: [PATCH 089/315] Fixed 100% battery level. --- apps/lcars/lcars.app.js | 6 +++--- apps/lcars/screenshot.png | Bin 5527 -> 5259 bytes 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/lcars/lcars.app.js b/apps/lcars/lcars.app.js index 167adad2d..8f06abc29 100644 --- a/apps/lcars/lcars.app.js +++ b/apps/lcars/lcars.app.js @@ -148,10 +148,10 @@ function printData(key, y, c){ } g.setColor(c); - g.fillRect(79, y-2, 87 ,y+18); + g.fillRect(79, y-2, 85 ,y+18); - g.setFontAlign(1,-1,0); - g.drawString(value, 131, y); + g.setFontAlign(0,-1,0); + g.drawString(value, 110, y); g.setColor(c); g.setFontAlign(-1,-1,0); diff --git a/apps/lcars/screenshot.png b/apps/lcars/screenshot.png index fba55a9f71739c35e4497386a75c51ea4e1eee3d..5d7603b45e6c7aadcc01aa0afdf13ff4d579eb93 100644 GIT binary patch literal 5259 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 Z{Rc&E;;+Q Date: Wed, 5 Jan 2022 19:28:32 +0100 Subject: [PATCH 090/315] Fix settings default values --- apps/circlesclock/settings.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/circlesclock/settings.js b/apps/circlesclock/settings.js index 0c42319f5..95ebc17db 100644 --- a/apps/circlesclock/settings.js +++ b/apps/circlesclock/settings.js @@ -10,6 +10,7 @@ var namesCircleTypes = ["steps", "distance", "heart", "battery"]; E.showMenu({ '': { 'title': 'circlesclock' }, + '< Back': back, 'min heartrate': { value: "minHR" in settings ? settings.minHR : 40, min: 0, @@ -76,23 +77,22 @@ onchange: x => save('showWidgets', x), }, 'left': { - value: Math.max(0,0 | valuesCircleTypes.indexOf(settings.circle1)), + value: settings.circle1 ? valuesCircleTypes.indexOf(settings.circle1) : 0, min: 0, max: 3, format: v => namesCircleTypes[v], onchange: x => save('circle1', valuesCircleTypes[x]), }, 'middle': { - value: Math.max(0,2 | valuesCircleTypes.indexOf(settings.circle2)), + value: settings.circle2 ? valuesCircleTypes.indexOf(settings.circle2) : 2, min: 0, max: 3, format: v => namesCircleTypes[v], onchange: x => save('circle2', valuesCircleTypes[x]), }, 'right': { - value: Math.max(0,3 | valuesCircleTypes.indexOf(settings.circle3)), + value: settings.circle3 ? valuesCircleTypes.indexOf(settings.circle3) : 3, min: 0, max: 3, format: v => namesCircleTypes[v], onchange: x => save('circle3', valuesCircleTypes[x]), - }, - '< Back': back, + } }); }); From 9a5937a3eb3535636e74f926d83dd41ebdd8c407 Mon Sep 17 00:00:00 2001 From: Marco Heiming Date: Wed, 5 Jan 2022 19:38:18 +0100 Subject: [PATCH 091/315] Improve widget visibility --- apps/circlesclock/app.js | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/apps/circlesclock/app.js b/apps/circlesclock/app.js index e10d55f17..a256c93ce 100644 --- a/apps/circlesclock/app.js +++ b/apps/circlesclock/app.js @@ -41,7 +41,7 @@ const colorRed = '#ff0000'; const colorGreen = '#008000'; const colorBlue = '#0000ff'; const colorYellow = '#ffff00'; -const widgetOffset = showWidgets ? 12 : 0; +const widgetOffset = showWidgets ? 14 : 0; const h = g.getHeight() - widgetOffset; const w = g.getWidth(); const hOffset = 30 - widgetOffset; @@ -55,9 +55,9 @@ const radiusOuter = 22; const radiusInner = 16; function draw() { - g.reset(); + g.clear(true); g.setColor(colorBg); - g.fillRect(0, 0, w, h); + g.fillRect(0, widgetOffset, w, h); // time g.setFont("Vector:50"); @@ -265,7 +265,7 @@ function shortValue(v) { } function getSteps() { - if (WIDGETS.wpedom !== undefined) { + if (WIDGETS && WIDGETS.wpedom !== undefined) { return WIDGETS.wpedom.getSteps(); } return 0; @@ -307,8 +307,6 @@ if (isCircleEnabled("battery")) { }); } -g.clear(); - Bangle.setUI("clock"); Bangle.loadWidgets(); if (!showWidgets) { From c15b700ef6fde7bdad924150d25504e51660e358 Mon Sep 17 00:00:00 2001 From: Marco Heiming Date: Wed, 5 Jan 2022 19:50:07 +0100 Subject: [PATCH 092/315] Fix widget drawing --- apps/circlesclock/app.js | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/apps/circlesclock/app.js b/apps/circlesclock/app.js index a256c93ce..fb4635424 100644 --- a/apps/circlesclock/app.js +++ b/apps/circlesclock/app.js @@ -56,6 +56,23 @@ const radiusInner = 16; function draw() { g.clear(true); + + if (!showWidgets) { + /* + * we are not drawing the widgets as we are taking over the whole screen + * so we will blank out the draw() functions of each widget and change the + * area to the top bar doesn't get cleared. + */ + if (WIDGETS && typeof WIDGETS === "object") { + for (let wd of WIDGETS) { + wd.draw = () => {}; + wd.area = ""; + } + } + } else { + Bangle.drawWidgets(); + } + g.setColor(colorBg); g.fillRect(0, widgetOffset, w, h); @@ -280,8 +297,7 @@ Bangle.on('lock', function(isLocked) { drawHeartRate(); } } - if (isCircleEnabled("steps")) drawSteps(); - if (isCircleEnabled("stepsDistance")) drawStepsDistance(); + draw(); } else { if (isCircleEnabled("hr")) { Bangle.setHRMPower(0, "watch"); @@ -309,19 +325,6 @@ if (isCircleEnabled("battery")) { Bangle.setUI("clock"); Bangle.loadWidgets(); -if (!showWidgets) { - /* - * we are not drawing the widgets as we are taking over the whole screen - * so we will blank out the draw() functions of each widget and change the - * area to the top bar doesn't get cleared. - */ - if (WIDGETS && typeof WIDGETS === "object") { - for (let wd of WIDGETS) { - wd.draw = () => {}; - wd.area = ""; - } - } -} draw(); setInterval(draw, 60000); From 670c232f28e0c746ae8f356c81a8f65e4fef340f Mon Sep 17 00:00:00 2001 From: Andreas Rozek Date: Thu, 6 Jan 2022 06:33:01 +0100 Subject: [PATCH 093/315] Create LICENSE --- apps/colorful_clock/LICENSE | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 apps/colorful_clock/LICENSE diff --git a/apps/colorful_clock/LICENSE b/apps/colorful_clock/LICENSE new file mode 100644 index 000000000..7487dd5da --- /dev/null +++ b/apps/colorful_clock/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 Andreas Rozek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. From 49bee5390bff6e8c03710fb094227b0f5b45f5e9 Mon Sep 17 00:00:00 2001 From: Andreas Rozek Date: Thu, 6 Jan 2022 06:33:06 +0100 Subject: [PATCH 094/315] Create LICENSE --- apps/themesetter/LICENSE | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 apps/themesetter/LICENSE diff --git a/apps/themesetter/LICENSE b/apps/themesetter/LICENSE new file mode 100644 index 000000000..7487dd5da --- /dev/null +++ b/apps/themesetter/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 Andreas Rozek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. From 754e752a8bd292bdcccf73f3eb8a7ef172cd99cb Mon Sep 17 00:00:00 2001 From: Andreas Rozek Date: Thu, 6 Jan 2022 06:33:09 +0100 Subject: [PATCH 095/315] Create LICENSE --- apps/simple_clock/LICENSE | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 apps/simple_clock/LICENSE diff --git a/apps/simple_clock/LICENSE b/apps/simple_clock/LICENSE new file mode 100644 index 000000000..7487dd5da --- /dev/null +++ b/apps/simple_clock/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 Andreas Rozek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. From 117348cb16f74003180f4474c125efca0523e98e Mon Sep 17 00:00:00 2001 From: Andreas Rozek Date: Thu, 6 Jan 2022 06:33:17 +0100 Subject: [PATCH 096/315] Create app.js --- apps/configurable_clock/app.js | 1336 ++++++++++++++++++++++++++++++++ 1 file changed, 1336 insertions(+) create mode 100644 apps/configurable_clock/app.js diff --git a/apps/configurable_clock/app.js b/apps/configurable_clock/app.js new file mode 100644 index 000000000..19dc363e4 --- /dev/null +++ b/apps/configurable_clock/app.js @@ -0,0 +1,1336 @@ + let Layout = require('Layout'); + + let Caret = require("heatshrink").decompress(atob("hEUgMAsFgmEwjEYhkMg0GAYIHBBYIPBgAA==")); + + let ScreenWidth = g.getWidth(), CenterX; + let ScreenHeight = g.getHeight(), CenterY, outerRadius; + + Bangle.loadWidgets(); + +/**** updateClockFaceSize ****/ + + function updateClockFaceSize () { + CenterX = ScreenWidth/2; + CenterY = ScreenHeight/2; + + outerRadius = Math.min(CenterX,CenterY) * 0.9; + + if (global.WIDGETS == null) { return; } + + let WidgetLayouts = { + tl:{ x:0, y:0, Direction:0 }, + tr:{ x:ScreenWidth-1, y:0, Direction:1 }, + bl:{ x:0, y:ScreenHeight-24, Direction:0 }, + br:{ x:ScreenWidth-1, y:ScreenHeight-24, Direction:1 } + }; + + for (let Widget of WIDGETS) { + let WidgetLayout = WidgetLayouts[Widget.area]; // reference, not copy! + if (WidgetLayout == null) { continue; } + + Widget.x = WidgetLayout.x - WidgetLayout.Direction * Widget.width; + Widget.y = WidgetLayout.y; + + WidgetLayout.x += Widget.width * (1-2*WidgetLayout.Direction); + } + + let x,y, dx,dy; + let cx = CenterX, cy = CenterY, r = outerRadius, r2 = r*r; + + x = WidgetLayouts.tl.x; y = WidgetLayouts.tl.y+24; dx = x - cx; dy = y - cy; + if (dx*dx + dy*dy < r2) { + cy = CenterY + 12; dy = y - cy; r2 = dx*dx + dy*dy; r = Math.sqrt(r2); + } + + x = WidgetLayouts.tr.x; y = WidgetLayouts.tr.y+24; dx = x - cx; dy = y - cy; + if (dx*dx + dy*dy < r2) { + cy = CenterY + 12; dy = y - cy; r2 = dx*dx + dy*dy; r = Math.sqrt(r2); + } + + x = WidgetLayouts.bl.x; y = WidgetLayouts.bl.y; dx = x - cx; dy = y - cy; + if (dx*dx + dy*dy < r2) { + cy = CenterY - 12; dy = y - cy; r2 = dx*dx + dy*dy; r = Math.sqrt(r2); + } + + x = WidgetLayouts.br.x; y = WidgetLayouts.br.y; dx = x - cx; dy = y - cy; + if (dx*dx + dy*dy < r2) { + cy = CenterY - 12; dy = y - cy; r2 = dx*dx + dy*dy; r = Math.sqrt(r2); + } + + CenterX = cx; CenterY = cy; outerRadius = r * 0.9; + } + + updateClockFaceSize(); + +/**** custom version of Bangle.drawWidgets (does not clear the widget areas) ****/ + + Bangle.drawWidgets = function () { + var w = g.getWidth(), h = g.getHeight(); + + var pos = { + tl:{x:0, y:0, r:0, c:0}, // if r==1, we're right->left + tr:{x:w-1, y:0, r:1, c:0}, + bl:{x:0, y:h-24, r:0, c:0}, + br:{x:w-1, y:h-24, r:1, c:0} + }; + + if (global.WIDGETS) { + for (var wd of WIDGETS) { + var p = pos[wd.area]; + if (!p) continue; + + wd.x = p.x - p.r*wd.width; + wd.y = p.y; + + p.x += wd.width*(1-2*p.r); + p.c++; + } + + g.reset(); // also loads the current theme + + if (pos.tl.c || pos.tr.c) { + g.setClipRect(0,h-24,w-1,h-1); + g.reset(); // also (re)loads the current theme + } + + if (pos.bl.c || pos.br.c) { + g.setClipRect(0,h-24,w-1,h-1); + g.reset(); // also (re)loads the current theme + } + + try { + for (wd of WIDGETS) { + g.clearRect(wd.x,wd.y, wd.x+wd.width-1,23); + wd.draw(wd); + } + } catch (e) { print(e); } + } + }; + +/**** EventConsumerAtPoint ****/ + + let activeLayout; + + function EventConsumerAtPoint (HandlerName, x,y) { + let Layout = (activeLayout || {}).l; + if (Layout == null) { return; } + + function ConsumerIn (Control) { + if ( + (x < Control.x) || (x >= Control.x + Control.w) || + (y < Control.y) || (y >= Control.y + Control.h) + ) { return undefined; } + + if (typeof Control[HandlerName] === 'function') { return Control; } + + if (Control.c != null) { + let ControlList = Control.c; + for (let i = 0, l = ControlList.length; i < l; i++) { + let Consumer = ConsumerIn(ControlList[i]); + if (Consumer != null) { return Consumer; } + } + } + + return undefined; + } + + return ConsumerIn(Layout); + } + +/**** dispatchTouchEvent ****/ + + function dispatchTouchEvent (DefaultHandler) { + function handleTouchEvent (Button, xy) { + if (activeLayout == null) { + if (typeof DefaultHandler === 'function') { + DefaultHandler(); + } + } else { + let Control = EventConsumerAtPoint('onTouch', xy.x,xy.y); + if (Control != null) { + Control.onTouch(Control, Button, xy); + } + } + } + Bangle.on('touch',handleTouchEvent); + } + dispatchTouchEvent(); + +/**** dispatchStrokeEvent ****/ + + function dispatchStrokeEvent (DefaultHandler) { + function handleStrokeEvent (Coordinates) { + if (activeLayout == null) { + if (typeof DefaultHandler === 'function') { + DefaultHandler(); + } + } else { + let Control = EventConsumerAtPoint('onStroke', Coordinates.xy[0],Coordinates.xy[1]); + if (Control != null) { + Control.onStroke(Control, Coordinates); + } + } + } + Bangle.on('stroke',handleStrokeEvent); + } + dispatchStrokeEvent(); +/**** Label ****/ + + function Label (Text, Options) { + function renderLabel (Details) { + let x = Details.x, xAlignment = Details.halign || 0; + let y = Details.y, yAlignment = Details.valign || 0; + + let Width = Details.w, halfWidth = Width/2; + let Height = Details.h, halfHeight = Height/2; + + let Border = Details.border || 0, BorderColor = Details.BorderColor; + let Padding = Details.pad || 0; + let Hilite = Details.hilite || false; + let bold = Details.bold ? 1 : 0; + + if (Hilite || (Details.bgCol != null)) { + g.setBgColor(Hilite ? g.theme.bgH : Details.bgCol); + g.clearRect(x,y, x + Width-1,y + Height-1); + } + + if ((Border > 0) && (BorderColor !== null)) {// draw border of layout cell + g.setColor(BorderColor || Details.col || g.theme.fg); + + switch (Border) { + case 2: g.drawRect(x+1,y+1, x+Width-2,y+Height-2);// no break here! + case 1: g.drawRect(x,y, x+Width-1,y+Height-1); break; + default: g.fillPoly([ + x,y, x+Width,y, x+Width,y+Height, x,y+Height, x,y, + x+Border,y+Border, x+Border,y+Height-Border, + x+Width-Border,y+Height-Border, x+Width-Border,y+Border, + x+Border,y+Border + ]); + } + } + + g.setClipRect( + x+Border+Padding,y+Border+Padding, + x + Width-Border-Padding-1,y + Height-Border-Padding-1 + ); + + x += halfWidth + xAlignment*(halfWidth - Border - Padding); + y += halfHeight + yAlignment*(halfHeight - Border - Padding); + + g.setColor (Hilite ? g.theme.fgH : Details.col || g.theme.fg); + g.setBgColor(Hilite ? g.theme.bgH : Details.bgCol || g.theme.bg); + + if (Details.font != null) { g.setFont(Details.font); } + g.setFontAlign(xAlignment,yAlignment); + + g.drawString(Details.label, x,y); + if (bold !== 0) { + g.drawString(Details.label, x+1,y); + g.drawString(Details.label, x,y+1); + g.drawString(Details.label, x+1,y+1); + } + } + + let Result = Object.assign(( + Options == null ? {} : Object.assign({}, Options.common || {}, Options) + ), { + type:'custom', render:renderLabel, label:Text || '' + }); + let Border = Result.border || 0; + let Padding = Result.pad || 0; + + let TextMetrics; + if (! Result.width || ! Result.height) { + if (Result.font == null) { + Result.font = g.getFont(); + } else { + g.setFont(Result.font); + } + TextMetrics = g.stringMetrics(Result.label); + } + + if (Result.col == null) { Result.col = g.getColor(); } + if (Result.bgCol == null) { Result.bgCol = g.getBgColor(); } + + Result.width = Result.width || TextMetrics.width + 2*Border + 2*Padding; + Result.height = Result.height || TextMetrics.height + 2*Border + 2*Padding; + return Result; + } + +/**** Image ****/ + + function Image (Image, Options) { + function renderImage (Details) { + let x = Details.x, xAlignment = Details.halign || 0; + let y = Details.y, yAlignment = Details.valign || 0; + + let Width = Details.w, halfWidth = Width/2 - Details.ImageWidth/2; + let Height = Details.h, halfHeight = Height/2 - Details.ImageHeight/2; + + let Border = Details.border || 0, BorderColor = Details.BorderColor; + let Padding = Details.pad || 0; + let Hilite = Details.hilite || false; + + if (Hilite || (Details.bgCol != null)) { + g.setBgColor(Hilite ? g.theme.bgH : Details.bgCol); + g.clearRect(x,y, x + Width-1,y + Height-1); + } + + if ((Border > 0) && (BorderColor !== null)) {// draw border of layout cell + g.setColor(BorderColor || Details.col || g.theme.fg); + + switch (Border) { + case 2: g.drawRect(x+1,y+1, x+Width-2,y+Height-2);// no break here! + case 1: g.drawRect(x,y, x+Width-1,y+Height-1); break; + default: g.fillPoly([ + x,y, x+Width,y, x+Width,y+Height, x,y+Height, x,y, + x+Border,y+Border, x+Border,y+Height-Border, + x+Width-Border,y+Height-Border, x+Width-Border,y+Border, + x+Border,y+Border + ]); + } + } + + g.setClipRect( + x+Border+Padding,y+Border+Padding, + x + Width-Border-Padding-1,y + Height-Border-Padding-1 + ); + + x += halfWidth + xAlignment*(halfWidth - Border - Padding); + y += halfHeight + yAlignment*(halfHeight - Border - Padding); + + if ('rotate' in Details) { // "rotate" centers image at x,y! + x += Details.ImageWidth/2; + y += Details.ImageHeight/2; + } + + g.setColor (Hilite ? g.theme.fgH : Details.col || g.theme.fg); + g.setBgColor(Hilite ? g.theme.bgH : Details.bgCol || g.theme.bg); + + g.drawImage(Image, x,y, Details.ImageOptions); + } + + let Result = Object.assign(( + Options == null ? {} : Object.assign({}, Options.common || {}, Options) + ), { + type:'custom', render:renderImage, Image:Image + }); + let ImageMetrics = g.imageMetrics(Image); + let Scale = Result.scale || 1; + let Border = Result.border || 0; + let Padding = Result.pad || 0; + + Result.ImageWidth = Scale * ImageMetrics.width; + Result.ImageHeight = Scale * ImageMetrics.height; + + if (('rotate' in Result) || ('scale' in Result) || ('frame' in Result)) { + Result.ImageOptions = {}; + if ('rotate' in Result) { Result.ImageOptions.rotate = Result.rotate; } + if ('scale' in Result) { Result.ImageOptions.scale = Result.scale; } + if ('frame' in Result) { Result.ImageOptions.frame = Result.frame; } + } + + Result.width = Result.width || Result.ImageWidth + 2*Border + 2*Padding; + Result.height = Result.height || Result.ImageHeight + 2*Border + 2*Padding; + return Result; + } + +/**** Drawable ****/ + + function Drawable (Callback, Options) { + function renderDrawable (Details) { + let x = Details.x, xAlignment = Details.halign || 0; + let y = Details.y, yAlignment = Details.valign || 0; + + let Width = Details.w, DrawableWidth = Details.DrawableWidth || Width; + let Height = Details.h, DrawableHeight = Details.DrawableHeight || Height; + + let halfWidth = Width/2 - DrawableWidth/2; + let halfHeight = Height/2 - DrawableHeight/2; + + let Border = Details.border || 0, BorderColor = Details.BorderColor; + let Padding = Details.pad || 0; + let Hilite = Details.hilite || false; + + if (Hilite || (Details.bgCol != null)) { + g.setBgColor(Hilite ? g.theme.bgH : Details.bgCol); + g.clearRect(x,y, x + Width-1,y + Height-1); + } + + if ((Border > 0) && (BorderColor !== null)) {// draw border of layout cell + g.setColor(BorderColor || Details.col || g.theme.fg); + + switch (Border) { + case 2: g.drawRect(x+1,y+1, x+Width-2,y+Height-2);// no break here! + case 1: g.drawRect(x,y, x+Width-1,y+Height-1); break; + default: g.fillPoly([ + x,y, x+Width,y, x+Width,y+Height, x,y+Height, x,y, + x+Border,y+Border, x+Border,y+Height-Border, + x+Width-Border,y+Height-Border, x+Width-Border,y+Border, + x+Border,y+Border + ]); + } + } + + let DrawableX = x + halfWidth + xAlignment*(halfWidth - Border - Padding); + let DrawableY = y + halfHeight + yAlignment*(halfHeight - Border - Padding); + + g.setClipRect( + Math.max(x+Border+Padding,DrawableX), + Math.max(y+Border+Padding,DrawableY), + Math.min(x+Width -Border-Padding,DrawableX+DrawableWidth)-1, + Math.min(y+Height-Border-Padding,DrawableY+DrawableHeight)-1 + ); + + g.setColor (Hilite ? g.theme.fgH : Details.col || g.theme.fg); + g.setBgColor(Hilite ? g.theme.bgH : Details.bgCol || g.theme.bg); + + Callback(DrawableX,DrawableY, DrawableWidth,DrawableHeight, Details); + } + + let Result = Object.assign(( + Options == null ? {} : Object.assign({}, Options.common || {}, Options) + ), { + type:'custom', render:renderDrawable, cb:Callback + }); + let DrawableWidth = Result.DrawableWidth || 10; + let DrawableHeight = Result.DrawableHeight || 10; + + let Border = Result.border || 0; + let Padding = Result.pad || 0; + + Result.width = Result.width || DrawableWidth + 2*Border + 2*Padding; + Result.height = Result.height || DrawableHeight + 2*Border + 2*Padding; + return Result; + } + + if (g.drawRoundedRect == null) { + g.drawRoundedRect = function drawRoundedRect (x1,y1, x2,y2, r) { + let x,y; + if (x1 > x2) { x = x1; x1 = x2; x2 = x; } + if (y1 > y2) { y = y1; y1 = y2; y2 = y; } + + r = Math.min(r || 0, (x2-x1)/2, (y2-y1)/2); + + let cx1 = x1+r, cx2 = x2-r; + let cy1 = y1+r, cy2 = y2-r; + + this.drawLine(cx1,y1, cx2,y1); + this.drawLine(cx1,y2, cx2,y2); + this.drawLine(x1,cy1, x1,cy2); + this.drawLine(x2,cy1, x2,cy2); + + x = r; y = 0; + + let dx,dy, Error = 0; + while (y <= x) { + dy = 1 + 2*y; y++; Error -= dy; + if (Error < 0) { + dx = 1 - 2*x; x--; Error -= dx; + } + + this.setPixel(cx1 - x, cy1 - y); this.setPixel(cx1 - y, cy1 - x); + this.setPixel(cx2 + x, cy1 - y); this.setPixel(cx2 + y, cy1 - x); + this.setPixel(cx2 + x, cy2 + y); this.setPixel(cx2 + y, cy2 + x); + this.setPixel(cx1 - x, cy2 + y); this.setPixel(cx1 - y, cy2 + x); + } + }; + } + + if (g.fillRoundedRect == null) { + g.fillRoundedRect = function fillRoundedRect (x1,y1, x2,y2, r) { + let x,y; + if (x1 > x2) { x = x1; x1 = x2; x2 = x; } + if (y1 > y2) { y = y1; y1 = y2; y2 = y; } + + r = Math.min(r || 0, (x2-x1)/2, (y2-y1)/2); + + let cx1 = x1+r, cx2 = x2-r; + let cy1 = y1+r, cy2 = y2-r; + + this.fillRect(x1,cy1, x2,cy2); + + x = r; y = 0; + + let dx,dy, Error = 0; + while (y <= x) { + dy = 1 + 2*y; y++; Error -= dy; + if (Error < 0) { + dx = 1 - 2*x; x--; Error -= dx; + } + + this.drawLine(cx1 - x, cy1 - y, cx2 + x, cy1 - y); + this.drawLine(cx1 - y, cy1 - x, cx2 + y, cy1 - x); + this.drawLine(cx1 - x, cy2 + y, cx2 + x, cy2 + y); + this.drawLine(cx1 - y, cy2 + x, cx2 + y, cy2 + x); + } + }; + } + + +/**** Button ****/ + + function Button (Text, Options) { + function renderButton (Details) { + let x = Details.x, Width = Details.w, halfWidth = Width/2; + let y = Details.y, Height = Details.h, halfHeight = Height/2; + + let Padding = Details.pad || 0; + let Hilite = Details.hilite || false; + + if (Details.bgCol != null) { + g.setBgColor(Details.bgCol); + g.clearRect(x,y, x + Width-1,y + Height-1); + } + + if (Hilite) { + g.setColor(g.theme.bgH); // no typo! + g.fillRoundedRect(x+Padding,y+Padding, x+Width-Padding-1,y+Height-Padding-1,8); + } + + g.setColor (Hilite ? g.theme.fgH : Details.col || g.theme.fg); + g.setBgColor(Hilite ? g.theme.bgH : Details.bgCol || g.theme.bg); + + if (Details.font != null) { g.setFont(Details.font); } + g.setFontAlign(0,0); + + g.drawRoundedRect(x+Padding,y+Padding, x+Width-Padding-1,y+Height-Padding-1,8); + + g.setClipRect(x+Padding,y+Padding, x+Width-Padding-1,y+Height-Padding-1); + + g.drawString(Details.label, x+halfWidth,y+halfHeight); + g.drawString(Details.label, x+halfWidth+1,y+halfHeight); + g.drawString(Details.label, x+halfWidth,y+halfHeight+1); + g.drawString(Details.label, x+halfWidth+1,y+halfHeight+1); + } + + let Result = Object.assign(( + Options == null ? {} : Object.assign({}, Options.common || {}, Options) + ), { + type:'custom', render:renderButton, label:Text || 'Tap' + }); + let Padding = Result.pad || 0; + + let TextMetrics; + if (! Result.width || ! Result.height) { + if (Result.font == null) { + Result.font = g.getFont(); + } else { + g.setFont(Result.font); + } + TextMetrics = g.stringMetrics(Result.label); + } + + Result.width = Result.width || TextMetrics.width + 2*10 + 2*Padding; + Result.height = Result.height || TextMetrics.height + 2*5 + 2*Padding; + return Result; + } + + const Checkbox_checked = require("heatshrink").decompress(atob("ikUgMf/+GgEGoEAlEAgOAgEYsFhw8OjE54OB/EYh4OB+EYj+BwecjFw8OGg0YDocUgECsEAsP//A")); + const Checkbox_unchecked = require("heatshrink").decompress(atob("ikUgMf/+GgEGoEAlEAgOAgEYAjkUgECsEAsP//A=")); + +/**** Checkbox ****/ + + function Checkbox (Options) { + function renderCheckbox (Details) { + let x = Details.x, xAlignment = Details.halign || 0; + let y = Details.y, yAlignment = Details.valign || 0; + + let Width = Details.w, halfWidth = Width/2 - 10; + let Height = Details.h, halfHeight = Height/2 - 10; + + let Padding = Details.pad || 0; + + if (Details.bgCol != null) { + g.setBgColor(Details.bgCol); + g.clearRect(x,y, x + Width-1,y + Height-1); + } + + x += halfWidth + xAlignment*(halfWidth - Padding); + y += halfHeight + yAlignment*(halfHeight - Padding); + + g.setColor (Details.col || g.theme.fg); + g.setBgColor(Details.bgCol || g.theme.bg); + + g.drawImage( + Details.checked ? Checkbox_checked : Checkbox_unchecked, x,y + ); + } + + let Result = Object.assign(( + Options == null ? {} : Object.assign({}, Options.common || {}, Options) + ), { + type:'custom', render:renderCheckbox, onTouch:toggleCheckbox + }); + let Padding = Result.pad || 0; + + Result.width = Result.width || 20 + 2*Padding; + Result.height = Result.height || 20 + 2*Padding; + + if (Result.checked == null) { Result.checked = false; } + return Result; + } + + /* private */ function toggleCheckbox (Control) { + g.reset(); + + Control.checked = ! Control.checked; + Control.render(Control); + + if (typeof Control.onChange === 'function') { + Control.onChange(Control); + } + } + +/**** toggleInnerCheckbox ****/ + + /* export */ function toggleInnerCheckbox (Control) { + if (Control.c == null) { + if (('checked' in Control) && ! ('GroupName' in Control)) { + toggleCheckbox(Control); + return true; + } + } else { + let ControlList = Control.c; + for (let i = 0, l = ControlList.length; i < l; i++) { + let done = toggleInnerCheckbox(ControlList[i]); + if (done) { return true; } + } + } + } + + const Radiobutton_checked = require("heatshrink").decompress(atob("ikUgMB/EAsFgjEBwUAgkggFEgECoEAlEPgOB/EYj+BAgmA+EUCYciDodBwEYg0GgEfwA")); + const Radiobutton_unchecked = require("heatshrink").decompress(atob("ikUgMB/EAsFgjEBwUAgkggFEgECoEAlEAgOAgEYAhEUCYciDodBwEYg0GgEfwAA=")); + +/**** Radiobutton ****/ + + function Radiobutton (Options) { + function renderRadiobutton (Details) { + let x = Details.x, xAlignment = Details.halign || 0; + let y = Details.y, yAlignment = Details.valign || 0; + + let Width = Details.w, halfWidth = Width/2 - 10; + let Height = Details.h, halfHeight = Height/2 - 10; + + let Padding = Details.pad || 0; + + if (Details.bgCol != null) { + g.setBgColor(Details.bgCol); + g.clearRect(x,y, x + Width-1,y + Height-1); + } + + x += halfWidth + xAlignment*(halfWidth - Padding); + y += halfHeight + yAlignment*(halfHeight - Padding); + + g.setColor (Details.col || g.theme.fg); + g.setBgColor(Details.bgCol || g.theme.bg); + + g.drawImage( + Details.checked ? Radiobutton_checked : Radiobutton_unchecked, x,y + ); + } + + let Result = Object.assign(( + Options == null ? {} : Object.assign({}, Options.common || {}, Options) + ), { + type:'custom', render:renderRadiobutton, onTouch:checkRadiobutton + }); + let Padding = Result.pad || 0; + + Result.width = Result.width || 20 + 2*Padding; + Result.height = Result.height || 20 + 2*Padding; + + if (Result.checked == null) { Result.checked = false; } + return Result; + } + + /* private */ function checkRadiobutton (Control) { + if (! Control.checked) { + uncheckRadiobuttonsIn((activeLayout || {}).l,Control.GroupName); + toggleRadiobutton(Control); + + if (typeof Control.onChange === 'function') { + Control.onChange(Control); + } + } + } + + /* private */ function toggleRadiobutton (Control) { + g.reset(); + + Control.checked = ! Control.checked; + Control.render(Control); + } + + /* private */ function uncheckRadiobuttonsIn (Control,GroupName) { + if ((Control == null) || (GroupName == null)) { return; } + + if (Control.c == null) { + if (('checked' in Control) && (Control.GroupName === GroupName)) { + if (Control.checked) { toggleRadiobutton(Control); } + } + } else { + let ControlList = Control.c; + for (let i = 0, l = ControlList.length; i < l; i++) { + uncheckRadiobuttonsIn(ControlList[i],GroupName); + } + } + } + +/**** checkInnerRadiobutton ****/ + + /* export */ function checkInnerRadiobutton (Control) { + if (Control.c == null) { + if (('checked' in Control) && ('GroupName' in Control)) { + checkRadiobutton(Control); + return true; + } + } else { + let ControlList = Control.c; + for (let i = 0, l = ControlList.length; i < l; i++) { + let done = checkInnerRadiobutton(ControlList[i]); + if (done) { return true; } + } + } + } + + + let Theme = g.theme; + g.clear(true); + +/**** Settings ****/ + + let Settings; + + function readSettings () { + Settings = Object.assign({}, + { + Face:'1-12', colored:true, + Hands:'rounded', withSeconds:true, + Foreground:'Theme', Background:'Theme', Seconds:'#FF0000' + }, + require('Storage').readJSON('configurable_clock.json', true) || {} + ); + + prepareTransformedPolygon(); + } + + function saveSettings () { + require('Storage').writeJSON('configurable_clock.json', Settings); + prepareTransformedPolygon(); + } + + function prepareTransformedPolygon () { + switch (Settings.Hands) { + case 'simple': transformedPolygon = new Array(simpleHourHandPolygon.length); break; + case 'rounded': transformedPolygon = new Array(roundedHandPolygon.length); break; + case 'hollow': transformedPolygon = new Array(hollowHandPolygon.length); + } + } + +//readSettings(); // not yet + + +/**** Hands ****/ + + let HourHandLength = outerRadius * 0.5; + let HourHandWidth = 2*3, halfHourHandWidth = HourHandWidth/2; + + let MinuteHandLength = outerRadius * 0.8; + let MinuteHandWidth = 2*2, halfMinuteHandWidth = MinuteHandWidth/2; + + let SecondHandLength = outerRadius * 0.9; + let SecondHandOffset = 10; + + let twoPi = 2*Math.PI, deg2rad = Math.PI/180; + let Pi = Math.PI; + let halfPi = Math.PI/2; + + let sin = Math.sin, cos = Math.cos; + +/**** simple Hands ****/ + + let simpleHourHandPolygon = [ + -halfHourHandWidth,halfHourHandWidth, + -halfHourHandWidth,halfHourHandWidth-HourHandLength, + halfHourHandWidth,halfHourHandWidth-HourHandLength, + halfHourHandWidth,halfHourHandWidth, + ]; + + let simpleMinuteHandPolygon = [ + -halfMinuteHandWidth,halfMinuteHandWidth, + -halfMinuteHandWidth,halfMinuteHandWidth-MinuteHandLength, + halfMinuteHandWidth,halfMinuteHandWidth-MinuteHandLength, + halfMinuteHandWidth,halfMinuteHandWidth, + ]; + + +/**** rounded Hands ****/ + + let outerBoltRadius = halfHourHandWidth + 2; + let innerBoltRadius = outerBoltRadius - 4; + let roundedHandOffset = outerBoltRadius + 4; + + let sine = [0, sin(30*deg2rad), sin(60*deg2rad), 1]; + + let roundedHandPolygon = [ + -sine[3],-sine[0], -sine[2],-sine[1], -sine[1],-sine[2], -sine[0],-sine[3], + sine[0],-sine[3], sine[1],-sine[2], sine[2],-sine[1], sine[3],-sine[0], + sine[3], sine[0], sine[2], sine[1], sine[1], sine[2], sine[0], sine[3], + -sine[0], sine[3], -sine[1], sine[2], -sine[2], sine[1], -sine[3], sine[0], + ]; + + let roundedHourHandPolygon = new Array(roundedHandPolygon.length); + for (let i = 0, l = roundedHandPolygon.length; i < l; i+=2) { + roundedHourHandPolygon[i] = halfHourHandWidth*roundedHandPolygon[i]; + roundedHourHandPolygon[i+1] = halfHourHandWidth*roundedHandPolygon[i+1]; + if (i < l/2) { roundedHourHandPolygon[i+1] -= HourHandLength; } + if (i > l/2) { roundedHourHandPolygon[i+1] += roundedHandOffset; } + } + let roundedMinuteHandPolygon = new Array(roundedHandPolygon.length); + for (let i = 0, l = roundedHandPolygon.length; i < l; i+=2) { + roundedMinuteHandPolygon[i] = halfMinuteHandWidth*roundedHandPolygon[i]; + roundedMinuteHandPolygon[i+1] = halfMinuteHandWidth*roundedHandPolygon[i+1]; + if (i < l/2) { roundedMinuteHandPolygon[i+1] -= MinuteHandLength; } + if (i > l/2) { roundedMinuteHandPolygon[i+1] += roundedHandOffset; } + } + + +/**** hollow Hands ****/ + + let BoltRadius = 3; + let hollowHandOffset = BoltRadius + 15; + + let hollowHandPolygon = [ + -sine[3],-sine[0], -sine[2],-sine[1], -sine[1],-sine[2], -sine[0],-sine[3], + sine[0],-sine[3], sine[1],-sine[2], sine[2],-sine[1], sine[3],-sine[0], + sine[3], sine[0], sine[2], sine[1], sine[1], sine[2], sine[0], sine[3], + 0,0, + -sine[0], sine[3], -sine[1], sine[2], -sine[2], sine[1], -sine[3], sine[0] + ]; + + let hollowHourHandPolygon = new Array(hollowHandPolygon.length); + for (let i = 0, l = hollowHandPolygon.length; i < l; i+=2) { + hollowHourHandPolygon[i] = halfHourHandWidth*hollowHandPolygon[i]; + hollowHourHandPolygon[i+1] = halfHourHandWidth*hollowHandPolygon[i+1]; + if (i < l/2) { hollowHourHandPolygon[i+1] -= HourHandLength; } + if (i > l/2) { hollowHourHandPolygon[i+1] -= hollowHandOffset; } + } + hollowHourHandPolygon[25] = -BoltRadius; + + let hollowMinuteHandPolygon = new Array(hollowHandPolygon.length); + for (let i = 0, l = hollowHandPolygon.length; i < l; i+=2) { + hollowMinuteHandPolygon[i] = halfMinuteHandWidth*hollowHandPolygon[i]; + hollowMinuteHandPolygon[i+1] = halfMinuteHandWidth*hollowHandPolygon[i+1]; + if (i < l/2) { hollowMinuteHandPolygon[i+1] -= MinuteHandLength; } + if (i > l/2) { hollowMinuteHandPolygon[i+1] -= hollowHandOffset; } + } + hollowMinuteHandPolygon[25] = -BoltRadius; + + + +/**** transform polygon ****/ + + let transformedPolygon; + + function transformPolygon (originalPolygon, OriginX,OriginY, Phi) { + let sPhi = sin(Phi), cPhi = cos(Phi), x,y; + + for (let i = 0, l = originalPolygon.length; i < l; i+=2) { + x = originalPolygon[i]; + y = originalPolygon[i+1]; + + transformedPolygon[i] = OriginX + x*cPhi + y*sPhi; + transformedPolygon[i+1] = OriginY + x*sPhi - y*cPhi; + } + } + +/**** refreshClock ****/ + + let Timer; + function refreshClock () { + activeLayout = null; + + g.setTheme({ + fg:(Settings.Foreground === 'Theme' ? Theme.fg : Settings.Foreground || '#000000'), + bg:(Settings.Background === 'Theme' ? Theme.bg : Settings.Background || '#FFFFFF') + }); + g.clear(true); // also installs the current theme + + Bangle.drawWidgets(); + renderClock(); + + let Period = (Settings.withSeconds ? 1000 : 60000); + + let Pause = Period - (Date.now() % Period); + Timer = setTimeout(refreshClock,Pause); + } + +/**** renderClock ****/ + + function renderClock () { + g.setColor (Settings.Foreground === 'Theme' ? Theme.fg : Settings.Foreground || '#000000'); + g.setBgColor(Settings.Background === 'Theme' ? Theme.bg : Settings.Background || '#FFFFFF'); + + switch (Settings.Face) { + case 'none': + break; + case '3,6,9,12': + g.setFont('Vector', 22); + + g.setFontAlign(0,-1); + g.drawString('12', CenterX,CenterY-outerRadius); + + g.setFontAlign(1,0); + g.drawString('3', CenterX+outerRadius,CenterY); + + g.setFontAlign(0,1); + g.drawString('6', CenterX,CenterY+outerRadius); + + g.setFontAlign(-1,0); + g.drawString('9', CenterX-outerRadius,CenterY); + break; + case '1-12': + let innerRadius = outerRadius * 0.9 - 10; + + for (let i = 0; i < 60; i++) { + let Phi = i * twoPi/60; + + let x = CenterX + outerRadius * sin(Phi); + let y = CenterY - outerRadius * cos(Phi); + + if (Settings.colored) { + let Color = E.HSBtoRGB(i/60,1,1, true); + g.setColor(Color[0]/255,Color[1]/255,Color[2]/255); + } + + g.fillCircle(x,y, 1); + } + + g.setFont('Vector', 20); + g.setFontAlign(0,0); + + for (let i = 0; i < 12; i++) { + let Phi = i * twoPi/12; + + let Radius = innerRadius; + if (i >= 10) { Radius -= 4; } + + let x = CenterX + Radius * sin(Phi); + let y = CenterY - Radius * cos(Phi); + + if (Settings.colored) { + let Color = E.HSBtoRGB(i/12,1,1, true); + g.setColor(Color[0]/255,Color[1]/255,Color[2]/255); + } + + g.drawString(i == 0 ? '12' : '' + i, x,y); + } + } + + let now = new Date(); + + let Hours = now.getHours() % 12; + let Minutes = now.getMinutes(); + + let HoursAngle = (Hours+(Minutes/60))/12 * twoPi - Pi; + let MinutesAngle = (Minutes/60) * twoPi - Pi; + + g.setColor(Settings.Foreground === 'Theme' ? Theme.fg : Settings.Foreground || '#000000'); + + switch (Settings.Hands) { + case 'simple': + transformPolygon(simpleHourHandPolygon, CenterX,CenterY, HoursAngle); + g.fillPoly(transformedPolygon); + + transformPolygon(simpleMinuteHandPolygon, CenterX,CenterY, MinutesAngle); + g.fillPoly(transformedPolygon); + break; + case 'rounded': + transformPolygon(roundedHourHandPolygon, CenterX,CenterY, HoursAngle); + g.fillPoly(transformedPolygon); + + transformPolygon(roundedMinuteHandPolygon, CenterX,CenterY, MinutesAngle); + g.fillPoly(transformedPolygon); + +// g.setColor(Settings.Foreground === 'Theme' ? Theme.fg || '#000000'); + g.fillCircle(CenterX,CenterY, outerBoltRadius); + + g.setColor(Settings.Background === 'Theme' ? Theme.bg : Settings.Background || '#FFFFFF'); + g.drawCircle(CenterX,CenterY, outerBoltRadius); + g.fillCircle(CenterX,CenterY, innerBoltRadius); + break; + case 'hollow': + transformPolygon(hollowHourHandPolygon, CenterX,CenterY, HoursAngle); + g.drawPoly(transformedPolygon,true); + + transformPolygon(hollowMinuteHandPolygon, CenterX,CenterY, MinutesAngle); + g.drawPoly(transformedPolygon,true); + + g.drawCircle(CenterX,CenterY, BoltRadius); + } + + if (Settings.withSeconds) { + g.setColor(Settings.Seconds === 'Theme' ? Theme.fgH : Settings.Seconds || '#FF0000'); + + let Seconds = now.getSeconds(); + let SecondsAngle = (Seconds/60) * twoPi - Pi; + + let sPhi = Math.sin(SecondsAngle), cPhi = Math.cos(SecondsAngle); + + g.drawLine( + CenterX + SecondHandOffset*sPhi, + CenterY - SecondHandOffset*cPhi, + CenterX - SecondHandLength*sPhi, + CenterY + SecondHandLength*cPhi + ); + } + } + + +/**** MainScreen Logic ****/ + + let Changes = {}, KeysToChange; + + let fullScreen = { + x:0,y:0, w:ScreenWidth,h:ScreenHeight, x2:ScreenWidth-1,y2:ScreenHeight-1 + }; + let AppRect; + + function openMainScreen () { + if (Timer != null) { clearTimeout(Timer); Timer = undefined; } + if (AppRect == null) { AppRect = Bangle.appRect; Bangle.appRect = fullScreen; } + + KeysToChange = 'Face colored Hands withSeconds Foreground Background Seconds'; + + g.setTheme({ fg:'#000000', bg:'#FFFFFF' }); + g.clear(true); // also installs the current theme + + (activeLayout = MainScreen).render(); + } + + function applySettings () { saveSettings(); Bangle.appRect = AppRect; refreshClock(); } + function withdrawSettings () { readSettings(); Bangle.appRect = AppRect; refreshClock(); } + +/**** FacesScreen Logic ****/ + + function openFacesScreen () { + KeysToChange = 'Face colored'; + Bangle.appRect = fullScreen; + refreshFacesScreen(); + } + + function refreshFacesScreen () { + activeLayout = FacesScreen; + activeLayout['none'].checked = ((Changes.Face || Settings.Face) === 'none'); + activeLayout['3,6,9,12'].checked = ((Changes.Face || Settings.Face) === '3,6,9,12'); + activeLayout['1-12'].checked = ((Changes.Face || Settings.Face) === '1-12'); + activeLayout['colored'].checked = (Changes.colored == null ? Settings.colored : Changes.colored); + activeLayout.render(); + } + + function chooseFace (Control) { Changes.Face = Control.id; refreshFacesScreen(); } + function toggleColored () { Changes.colored = ! Changes.colored; refreshFacesScreen(); } + +/**** HandsScreen Logic ****/ + + function openHandsScreen () { + KeysToChange = 'Hands withSeconds'; + Bangle.appRect = fullScreen; + refreshHandsScreen(); + } + + function refreshHandsScreen () { + activeLayout = HandsScreen; + activeLayout['simple'].checked = ((Changes.Hands || Settings.Hands) === 'simple'); + activeLayout['rounded'].checked = ((Changes.Hands || Settings.Hands) === 'rounded'); + activeLayout['hollow'].checked = ((Changes.Hands || Settings.Hands) === 'hollow'); + activeLayout['withSeconds'].checked = (Changes.withSeconds == null ? Settings.withSeconds : Changes.withSeconds); + activeLayout.render(); + } + + function chooseHand (Control) { Changes.Hands = Control.id; refreshHandsScreen(); } + function toggleSeconds () { Changes.withSeconds = ! Changes.withSeconds; refreshHandsScreen(); } + +/**** ColorsScreen Logic ****/ + + function openColorsScreen () { + KeysToChange = 'Foreground Background Seconds'; + Bangle.appRect = fullScreen; + refreshColorsScreen(); + } + + function refreshColorsScreen () { + let Foreground = (Changes.Foreground == null ? Settings.Foreground : Changes.Foreground); + let Background = (Changes.Background == null ? Settings.Background : Changes.Background); + let Seconds = (Changes.Seconds == null ? Settings.Seconds : Changes.Seconds); + + activeLayout = ColorsScreen; + activeLayout['Foreground'].bgCol = (Foreground === 'Theme' ? Theme.fg : Foreground); + activeLayout['Background'].bgCol = (Background === 'Theme' ? Theme.bg : Background); + activeLayout['Seconds'].bgCol = (Seconds === 'Theme' ? Theme.fgH : Seconds); + activeLayout.render(); + } + + function selectForegroundColor () { ColorToChange = 'Foreground'; openColorChoiceScreen(); } + function selectBackgroundColor () { ColorToChange = 'Background'; openColorChoiceScreen(); } + function selectSecondsColor () { ColorToChange = 'Seconds'; openColorChoiceScreen(); } + +/**** ColorChoiceScreen Logic ****/ + + let ColorToChange, chosenColor; + + function openColorChoiceScreen () { + chosenColor = ( + Changes[ColorToChange] == null ? Settings[ColorToChange] : Changes[ColorToChange] + ); + Bangle.appRect = fullScreen; + refreshColorChoiceScreen(); + } + + function refreshColorChoiceScreen () { + activeLayout = ColorChoiceScreen; + activeLayout['#000000'].selected = (chosenColor === '#000000'); + activeLayout['#FF0000'].selected = (chosenColor === '#FF0000'); + activeLayout['#00FF00'].selected = (chosenColor === '#00FF00'); + activeLayout['#0000FF'].selected = (chosenColor === '#0000FF'); + activeLayout['#FFFF00'].selected = (chosenColor === '#FFFF00'); + activeLayout['#FF00FF'].selected = (chosenColor === '#FF00FF'); + activeLayout['#00FFFF'].selected = (chosenColor === '#00FFFF'); + activeLayout['#FFFFFF'].selected = (chosenColor === '#FFFFFF'); + activeLayout['Theme'].selected = (chosenColor === 'Theme'); + activeLayout.render(); + } + + function chooseColor (Control) { chosenColor = Control.id; refreshColorChoiceScreen(); } + function chooseThemeColor () { chosenColor = 'Theme'; refreshColorChoiceScreen(); } + + function applyColor () { + Changes[ColorToChange] = chosenColor; + openColorsScreen(); + } + + function withdrawColor () { + openColorsScreen(); + } + +/**** common logic for multiple screens ****/ + + function applyChanges () { + Settings = Object.assign(Settings,Changes); + Changes = {}; + openMainScreen(); + } + + function withdrawChanges () { + Changes = {}; + openMainScreen(); + } + + + g.setFont12x20(); // does not seem to be respected in layout! + + let OkCancelWidth = Math.max( + g.stringWidth('Ok'), g.stringWidth('Cancel') + ) + 2*10; + + let StdFont = { font:'12x20' }; + let legible = Object.assign({ col:'#000000', bgCol:'#FFFFFF' }, StdFont); + let leftAligned = Object.assign({ halign:-1, valign:0 }, legible); + let ColorView = Object.assign({ width:30, border:1, BorderColor:'#000000' }, StdFont); + let ColorChoice = Object.assign({ DrawableWidth:30, DrawableHeight:30, onTouch:chooseColor }, StdFont); + +/**** MainScreen ****/ + + let MainScreen = new Layout({ + type:'v', c:[ + Label('Settings', { common:legible, bold:true, filly:1 }), + { height:4 }, + { type:'h', c:[ + Label('Faces', { common:leftAligned, fillx:1 }), + Image(Caret, { common:leftAligned }), + ], filly:1, onTouch:openFacesScreen }, + { type:'h', c:[ + Label('Hands', { common:leftAligned, fillx:1 }), + Image(Caret, { common:leftAligned }), + ], filly:1, onTouch:openHandsScreen }, + { type:'h', c:[ + Label('Colors', { common:leftAligned, fillx:1 }), + Image(Caret, { common:leftAligned }), + ], filly:1, onTouch:openColorsScreen }, + { height:4 }, + { type:'h', c:[ + Button('Ok', { common:legible, width:OkCancelWidth, onTouch:applySettings }), + { width:4 }, + Button('Cancel', { common:legible, width:OkCancelWidth, onTouch:withdrawSettings }), + ], filly:1 }, + ], bgCol:'#FFFFFF' + }); + + +/**** FacesScreen ****/ + + let FacesScreen = new Layout({ + type:'v', c:[ + Label('Clock Faces', { common:legible, bold:true, filly:1 }), + { height:4 }, + { type:'h', c:[ + Radiobutton({ id:'none', GroupName:'Faces', common:legible, onChange:chooseFace }), + Label(' no Face', { common:leftAligned, pad:4, fillx:1 }), + ], filly:1, onTouch:checkInnerRadiobutton }, + { type:'h', c:[ + Radiobutton({ id:'3,6,9,12', GroupName:'Faces', common:legible, onChange:chooseFace }), + Label(' 3, 6, 9 and 12', { common:leftAligned, pad:4, fillx:1 }), + ], filly:1, onTouch:checkInnerRadiobutton }, + { type:'h', c:[ + Radiobutton({ id:'1-12', GroupName:'Faces', common:legible, onChange:chooseFace }), + Label(' numbers 1...12', { common:leftAligned, pad:4, fillx:1 }), + ], filly:1, onTouch:checkInnerRadiobutton }, + { type:'h', c:[ + { width:30 }, + Checkbox({ id:'colored', common:legible, onChange:toggleColored }), + Label(' colorful', { common:leftAligned, pad:4, fillx:1 }), + ], filly:1, onTouch:toggleInnerCheckbox }, + { height:4 }, + { type:'h', c:[ + Button('Ok', { common:legible, width:OkCancelWidth, onTouch:applyChanges }), + { width:4 }, + Button('Cancel', { common:legible, width:OkCancelWidth, onTouch:withdrawChanges }), + ], filly:1 }, + ], bgCol:'#FFFFFF' + }); + + +/**** HandsScreen ****/ + + let HandsScreen = new Layout({ + type:'v', c:[ + Label('Clock Hands', { common:legible, bold:true, filly:1 }), + { height:4 }, + { type:'h', c:[ + Radiobutton({ id:'simple', GroupName:'Faces', common:legible, onChange:chooseHand }), + Label(' simple', { common:leftAligned, pad:4, fillx:1 }), + ], filly:1, onTouch:checkInnerRadiobutton }, + { type:'h', c:[ + Radiobutton({ id:'rounded', GroupName:'Faces', common:legible, onChange:chooseHand }), + Label(' rounded + Bolt', { common:leftAligned, pad:4, fillx:1 }), + ], filly:1, onTouch:checkInnerRadiobutton }, + { type:'h', c:[ + Radiobutton({ id:'hollow', GroupName:'Faces', common:legible, onChange:chooseHand }), + Label(' hollow + Bolt', { common:leftAligned, pad:4, fillx:1 }), + ], filly:1, onTouch:checkInnerRadiobutton }, + { type:'h', c:[ + Checkbox({ id:'withSeconds', common:legible, onChange:toggleSeconds }), + Label(' show Seconds', { common:leftAligned, pad:4, fillx:1 }), + ], filly:1, onTouch:toggleInnerCheckbox }, + { height:4 }, + { type:'h', c:[ + Button('Ok', { common:legible, width:OkCancelWidth, onTouch:applyChanges }), + { width:4 }, + Button('Cancel', { common:legible, width:OkCancelWidth, onTouch:withdrawChanges }), + ], filly:1 }, + ], bgCol:'#FFFFFF' + }); + + +/**** ColorsScreen ****/ + + let ColorsScreen = new Layout({ + type:'v', c:[ + Label('Clock Colors', { common:legible, bold:true, filly:1 }), + { height:4 }, + { type:'h', c:[ + Label('Foreground', { common:leftAligned, pad:4, fillx:1 }), + Label('', { id:'Foreground', common:ColorView, bgCol:Theme.fg }), + ], filly:1, onTouch:selectForegroundColor }, + { type:'h', c:[ + Label('Background', { common:leftAligned, pad:4, fillx:1 }), + Label('', { id:'Background', common:ColorView, bgCol:Theme.bg }), + ], filly:1, onTouch:selectBackgroundColor }, + { type:'h', c:[ + Label('Seconds', { common:leftAligned, pad:4, fillx:1 }), + Label('', { id:'Seconds', common:ColorView, bgCol:Theme.fgH }), + ], filly:1, onTouch:selectSecondsColor }, + { height:4 }, + { type:'h', c:[ + Button('Ok', { common:legible, width:OkCancelWidth, onTouch:applyChanges }), + { width:4 }, + Button('Cancel', { common:legible, width:OkCancelWidth, onTouch:withdrawChanges }), + ], filly:1 }, + ], bgCol:'#FFFFFF' + }); + + +/**** ColorChoiceScreen ****/ + + function drawColorChoice (x,y, Width,Height, Details) { + let selected = Details.selected; + if (selected) { + g.setColor('#FF0000'); + g.fillPoly([ + x,y, x+Width-1,y, x+Width-1,y+Height-1, x,y+Height-1, x,y, + x+3,y+3, x+3,y+Height-4, x+Width-4,y+Height-4, x+Width-4,y+3, x+3,y+3 + ]); + } else { + g.setColor('#000000'); + g.drawRect(x+3,y+3, x+Width-4,y+Height-4); + } + + g.setColor(Details.col); + g.fillRect(x+4,y+4, x+Width-5,y+Height-5); + } + + let ColorChoiceScreen = new Layout({ + type:'v', c:[ + Label('Choose Color', { common:legible, bold:true, filly:1 }), + { height:4 }, + { type:'h', c:[ + Drawable(drawColorChoice, { id:'#000000', common:ColorChoice, col:'#000000' }), + { width:8 }, + Drawable(drawColorChoice, { id:'#FF0000', common:ColorChoice, col:'#FF0000' }), + { width:8 }, + Drawable(drawColorChoice, { id:'#00FF00', common:ColorChoice, col:'#00FF00' }), + { width:8 }, + Drawable(drawColorChoice, { id:'#0000FF', common:ColorChoice, col:'#0000FF' }), + ], filly:1 }, + { type:'h', c:[ + Drawable(drawColorChoice, { id:'#FFFFFF', common:ColorChoice, col:'#FFFFFF' }), + { width:8 }, + Drawable(drawColorChoice, { id:'#FFFF00', common:ColorChoice, col:'#FFFF00' }), + { width:8 }, + Drawable(drawColorChoice, { id:'#FF00FF', common:ColorChoice, col:'#FF00FF' }), + { width:8 }, + Drawable(drawColorChoice, { id:'#00FFFF', common:ColorChoice, col:'#00FFFF' }), + ], filly:1 }, + { type:'h', c:[ + Label('use Theme:', { id:'Theme', common:leftAligned, pad:4 }), + { width:10 }, + Drawable(drawColorChoice, { id:'Theme', common:ColorChoice, col:Theme.fg }), + ], filly:1, onTouch:chooseThemeColor }, + { height:4 }, + { type:'h', c:[ + Button('Ok', { common:legible, width:OkCancelWidth, onTouch:applyColor }), + { width:4 }, + Button('Cancel', { common:legible, width:OkCancelWidth, onTouch:withdrawColor }), + ], filly:1 }, + ], bgCol:'#FFFFFF' + }); + + + + readSettings(); + + Bangle.on('swipe', (Direction) => { + if (Direction === 0) { openMainScreen(); } + }); + + setTimeout(refreshClock, 500); // enqueue first draw request + + Bangle.on('lcdPower', (on) => { + if (on) { + if (Timer != null) { clearTimeout(Timer); Timer = undefined; } + refreshClock(); + } + }); + + Bangle.setUI('clock'); From 56a25fb3f6230e9559ef0065490c89da72045828 Mon Sep 17 00:00:00 2001 From: Andreas Rozek Date: Thu, 6 Jan 2022 06:33:20 +0100 Subject: [PATCH 097/315] Create app-screenshot.png --- apps/configurable_clock/app-screenshot.png | Bin 0 -> 3218 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 apps/configurable_clock/app-screenshot.png diff --git a/apps/configurable_clock/app-screenshot.png b/apps/configurable_clock/app-screenshot.png new file mode 100644 index 0000000000000000000000000000000000000000..5287217593fe6c4482120906e42c36c0d8860ee9 GIT binary patch literal 3218 zcmb7{*H;th7RA2=LP)4$=vr=t-aRyJ)QHgQ>-kExsW1A005WCRYRNKPWnge zY`RC4QOb2SC^=SP7-ltl1}V2o z^Ez&A^*)6D@0#H_F|`b}4_&cw@YB#xqArNJ2duAU8cp2q1I?DFO_g*nYrrV?b;WLS zVk2P|6N%fA2-?jvm`icjl!f);;SYEOra)k{$m)QEyL?C`MF;=UA-tXCyYth0sDI%) zm69p5jkvad*V#DX%5k`2hbC-Vcd889XG>EIPdB;3^1WSakq;~Dq%&&*$TZSY;c@vj%L&LY<_C_F6z#g;GrNdA59HmB=n}|0F zB4O0MuX)Q{5RAi}BJ$&^=kt3g(U_mX2}wfrOa1AON(9-XhiDGyp$P}$)jkfEsDzvd z(E;1<#h?qnAl77eTf%f5Mp@B<@CesF3!bA_w>mg}rpPyY@6PaHFzTN3HNHFkkXbDcdo&=0{Pdh}zy*3Ir$pQZC+i&FKMV#;8 z2$I#eW2Y%I;%Z5JJ-~DiiV00Luk9$`)2@Q*p}m4s1G=A^A%8qKf3Hca3s^7K-j zk8ZIL5V~gnTa%#rE)*1YeuNG~gP5%25K} z?bwXu1X%=D!tOc$|Cr!gNS(X@=SLJi*4F8L_csG~3RqmaYvY~rQ#ss2eKPT004R>n ze4qf4+OL}S=tK1&xl;<4I~(U1O%@p_{Ur>L`{Cl~>X+%?m`ddU6Gwmesy6oAO|DYG+!SHFh-lsXrEczZ56!?j?%{qyUW@ zsA;OP>LRzMa<=uOe(4uGYg0 z%E2SG41CP$q4aX@hrc#Oog`OB=UR4Kjl7!s$4?k96_iCkM;gt*W}>boFQ?Z6_*FXc zRU#CA)$El|ShC~dA6BJLhxy8f)z*;P(XU&|p?ck-?Xm1nMS2r)S%jg5cZi@~hea+= z7X4s}r%RiTrl;*>D=U?ZgjdoQK=4KNze<;`r#>8ikY^QlFc(vU>}HD6wFI-i$dpak zEuOd%v*Z2;GQP6P!>FcuhM;93eDYkVW5PL^)q{&OkRFqjj7f9WVtbgv7dxb)(XG3# zvt(Sh-F2GvpIv{o&ipdvHT6G@Rtj5ke!;8SMYf>|6{E+hkph+jgHw<#lM0auYOlD~G z9GdZ}XTD>nTj$Dv_WnJ~5TUY+pbA1+afP2>1QLE(G^f{=-~Jzpx#O5Xd=#KGlI9+JccpsX$Y`xo( znU$eav)!^dmh<^2cVPEL{*G~X;KpH)lJ(8FvWE%3G}BE6HY<>U{A6MW8XSe(@=jxL zS7=chB9u_%Po7x-ygXy=aIc;AFjrwG@hv73m$e%Ez2gzBn%0)+vx|t#XQeV zrslnj+#g!y)BM`V3g!pi4#;Joae*hP`4{xslU{=GNCH!n;#MvRnsI5}Px4XICi-P7 zv>M2!m@lYi4bbKUF_9$({cr+=R12rxz&f9Obfu~z^8oKZc10>!w%QJ^D~{j@-?tCY ze>{++@~xC2LA7IYOg6{Pi^DLPW%zC0wxrmA+R;cwjZbcJDh2mrwtov`yzI6^~gNi)oL2Abz1G2hd>Q+k-*0Rj3n&PANUi6y| z#17#;cTPN7=y)|`wz@0AI+(W5cJ5|+(N+;kA6rkZqVFuSKCw#pTGP8kZsH;dQ}V~* z6Cw`JD3#;=xFGPu5QJSVubxO6S6(@%phHNV;Mh=kW{^zQ(&nL1%jDO8=s7YC*xP_u zncyt_ri++U@TZMc$n>{K`LhE;tDW_SjiHc!{;=ckef zYB$OvNd4LtFNEnVN3Ey_#Egi_so6MXM5&PiU5&vIv&(eEb{f(gUFJhdZ|QW=2C^n9i)f;h-+s5Wf~c(4QhU?X{kg zQ|9I%_*vI$t@^132I$<6<|b4@qOEANb_+-}s#zrS9RL~5nLgeyQg8X_Arw1Im;x<% zks0-nZK*hykf$Jg@=aia0%$iWvUipOE~*W=)f^y*@2hP#f?)sPyVN?AlFJ$~=?SIT iO1v6u1OIaE7d%+S$$YPr_s8#&0Zfc63~TkV_x=x}ck>Yd literal 0 HcmV?d00001 From 9eaf501ce7b91ba1b171360bb775097d0cba9c4c Mon Sep 17 00:00:00 2001 From: Andreas Rozek Date: Thu, 6 Jan 2022 06:33:24 +0100 Subject: [PATCH 098/315] Create app-icon.png --- apps/configurable_clock/app-icon.png | Bin 0 -> 4369 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 apps/configurable_clock/app-icon.png diff --git a/apps/configurable_clock/app-icon.png b/apps/configurable_clock/app-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..58f50365d4ed18b6b1f5e006a3e2a4398452cbbb GIT binary patch literal 4369 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 D06kr; literal 0 HcmV?d00001 From a499ad279a3c95a54fbde1736f46399594907ed4 Mon Sep 17 00:00:00 2001 From: Andreas Rozek Date: Thu, 6 Jan 2022 06:33:27 +0100 Subject: [PATCH 099/315] Create app-icon.js --- apps/configurable_clock/app-icon.js | 1 + 1 file changed, 1 insertion(+) create mode 100644 apps/configurable_clock/app-icon.js diff --git a/apps/configurable_clock/app-icon.js b/apps/configurable_clock/app-icon.js new file mode 100644 index 000000000..b0cf74241 --- /dev/null +++ b/apps/configurable_clock/app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwgZC/AB1RgkQsAQMyUKAYMIkAPJgNFiEBgACBg0YCRMogEJkGSAwMSEZNAAQMAEAMGgBKHgXAlECwMgzcAmkAhgRGilRssUgMEEYcBwARFiBHBgQKB7AjCawIQEgoCCigDBjEBwwEBEwIAGlmSEYYABI4PAEYhEBNYIjCAYVtwCSElG2xdoAwQjDhpZEEAMUqAHDCIaPBEYlAiwjItkAgYjFqJHDCIdhI4j1CAAhlEZoTUEAAcGEYZKEEYWgCIgjEWYkBoqwCCITLBgcMmPXhgjCgUB2iFDm3pw0YLAMygEgc4QjF49cmA3BbQQjDgGkI5OwNZZ9FEYoRLEYxmBCI5jBEYQACyQRHgmAEYsEEZEka4kAhEEEY8BCIMJCIYjKgGChAFDCwKzDNYyKEJgUDlgRBAoPDRQQjEZQZzEjScIhgjBEwQjEH4aXEgIjBjYCBjQCBMYYADmAjDFIjcGKocAjBKCgJRCAAwaCEARQBmARIhBrEgSMEAApEBmHAAQJrCABUCjFhwwQMI4oA7")) \ No newline at end of file From db5cb644fd36460d61d76ce9014bd5a6a542c118 Mon Sep 17 00:00:00 2001 From: Andreas Rozek Date: Thu, 6 Jan 2022 06:33:32 +0100 Subject: [PATCH 100/315] Create LICENSE --- apps/configurable_clock/LICENSE | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 apps/configurable_clock/LICENSE diff --git a/apps/configurable_clock/LICENSE b/apps/configurable_clock/LICENSE new file mode 100644 index 000000000..7487dd5da --- /dev/null +++ b/apps/configurable_clock/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 Andreas Rozek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. From 54ee423106d32237a7c8738d319458c3888c9730 Mon Sep 17 00:00:00 2001 From: Andreas Rozek Date: Thu, 6 Jan 2022 06:33:34 +0100 Subject: [PATCH 101/315] Create Screenshot-01.png --- apps/configurable_clock/Screenshot-01.png | Bin 0 -> 1621 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 apps/configurable_clock/Screenshot-01.png diff --git a/apps/configurable_clock/Screenshot-01.png b/apps/configurable_clock/Screenshot-01.png new file mode 100644 index 0000000000000000000000000000000000000000..b2367784c76e682019d944c899f572357ab0fded GIT binary patch literal 1621 zcmds2+f!3_5dNKn1PDh61|{ez7gLK=g^1M#L2e=enMn|^PJs|+6icN-0E4kf@B|Q| zLji?BsS1kIf^9+UfJu?dNzH(j78EO?f^Z1bl%`;Ua%ne1ATkR8*(EkAB1x1s_k5~g zY&VQPUa@#}20v{4DfSC_4fJ+Z_8I^89!R>LySlqAr(ea%z9e~q_q&7o3j+Yt zp~VS|n@osjIyu=LC>IxlLNK`99|-jNd=cuA$piR^MrQy!A9Vt(<@V4NbnLniLR0t+ z_lZA->j^;76Iy0}SvEof*;1*q3zPU?7F?-CFZGUQ2PyfKcDt_BjcS8G=^3GvjxV7; zrOHK`s5>;rcizbZH&0kL_q>V&OCM<0uIEZ=mmt`9%ba6vjDt#*-TkvUcpmCgzx$Di zbjc3R&8ki;>)navR85kZYE6`6 zD@NtJ80Ww~$#%8E4mJv@lk07Pa7h+MU1m$fHjIYb!luTPnV6SGH}rJzBy4!n9Wm~* z1LM!b+B7*dp$w3ly~!e7tM|N&j_1rfY9}k{cyVyi$|(j}gco{y%3tq`1D>#pF}+!v z0bI!TB4&~?5cMtE7vlPLrXN;)!>1mu?Lu&x%qP@!`|M`W0Ndz84H-{${L21|%q|CGoEFg@ep_^ z^-A$6)bcrK4n;(Mk+}(F$61Dj`b3fHj<8N_4Ka=VfCc46qwIGr3%iEoiqJ?g$;efO z9C$+$Xm*}<$~_rOe1(7@ zuhS7s)eSj2Qv@gC(JZl;V82Xev6_AV?egLqAWcWwsRcXdPv&Pg((?swwo^sdLLmu$ z1#2+bUdXvTh(*Cw@r(i6v~KsvI93nr`w)a=NN>K70V)Al&@2V}RK6%XV2EZH-e)i2)AmC*M zZ?+})e04!c0mb=r6(K&no}` literal 0 HcmV?d00001 From d89f1eef84e353336078f1a7243e90ec5ec38d2a Mon Sep 17 00:00:00 2001 From: Andreas Rozek Date: Thu, 6 Jan 2022 06:33:37 +0100 Subject: [PATCH 102/315] Create Screenshot-02.png --- apps/configurable_clock/Screenshot-02.png | Bin 0 -> 1959 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 apps/configurable_clock/Screenshot-02.png diff --git a/apps/configurable_clock/Screenshot-02.png b/apps/configurable_clock/Screenshot-02.png new file mode 100644 index 0000000000000000000000000000000000000000..909a2a04a3559d66b724b7c265ee61a68b4a17d2 GIT binary patch literal 1959 zcmb7FYc!kL8vcCq;iGXTg1A@2y{@H2qljxFh>mpH6iuVr6NYLSv&c~L9hWvmqpYS? zf_9G4o>Ro2bk)(%4AnC_X-S8=PTYz?C(1OYZYQ(W{5yYU_FC_L-}UV0+56qkpI2~< zPSMde(FOoOCyW{#t;&+$1J+RO%^h!NzIl3Kr=opIN*2|YgIg*K1;x8 zR4MZor#cx6Io&|uE(Slg`>1js%xnMDEv#ZhwUmbbSePa+L<1ZtWBw4^})>HZF{-jk3>ZS&v)HN7U5xr_|Q(5OKiB2EbF)S=;b?b%G|XaQ_2#u-ezpS7hR2Va{qJ*m{8rdeVc~R`vs1##2$rmopo93&t{Z4Wc)bQvlfPaqdzpMZTfktHDQGmT&rH|AhlZ7Sa(#Xw7@a zTsd2I$sg(8*L50)QyO{>lwd)tG`#s%vquR^oj5ar@d(uF3h&w(==RR9Sxv^+DRRSB zipTqYa3elIQyknEN4uZCR7oDA{}#foZn);A#GMZ!tdU@y)}^|knlV!kh0f&QT=kzvAo;?hOl{D6TlTgBCv*^{!cm${9bDd5e1C?K>>08RabG@=9Bf zKrKOUkSy2MZ9?UtrJjNg3qR_7rMs1+#U&%b>R!)x*v^ldS%D*qL6Ewwa*Y|CAZ9X;uEJ7gvWe8D9Xxz1}lULIAw zHnxuGo4lY`%3Ky>YH1>E^`?5$>RPDZjpt(o5h=|U;gARho3e{cyx;|=uM$cntR`fPr!ry_hhls+VRS7BO^5g zl+;?6i7Vtw)`vgD9u~ZvKwp$)o{`2lKAKh4d0=Wz2IQhB9LVr@1*RD3wIfhoX8D6G5OQ()WrQ- z8pp&(rWU68aH8zNamldgep^V^-rn?^)UUI?Z|5B0qu(Fcefmuoj>GdB*SSB5cW*-* zO{>Q5`5uz|YLs+X5Z>@frr#EgqzLl8U4EibZ}QYL2g5CXh%Pe@N>&=UR(YC%#o71c4 zud%mD7$jfD2;8m%U{t}2p%E>D;)|l-TT}qC`^82qa3%T=OOz{xGgF z{xDDZC}S4ix7)AVSv#8NA$_+$oi)C0+2_>GJ;W*lQnbdt-0prpER4{^zv{F} zTuuwnPEvVSx8WQRE8G`NHC1_5->emreS5M6g?b3+K&o6Zvo)P8q)L_ r5PmQp*46`Iv)s5M8IJrXp4?Vb#?4qzK6hiPCNB^cLJw{VWdGxT>q%q& literal 0 HcmV?d00001 From 350458f9e0e53bf105234238d24e0c2a29c276b1 Mon Sep 17 00:00:00 2001 From: Andreas Rozek Date: Thu, 6 Jan 2022 06:33:39 +0100 Subject: [PATCH 103/315] Create Screenshot-03.png --- apps/configurable_clock/Screenshot-03.png | Bin 0 -> 2814 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 apps/configurable_clock/Screenshot-03.png diff --git a/apps/configurable_clock/Screenshot-03.png b/apps/configurable_clock/Screenshot-03.png new file mode 100644 index 0000000000000000000000000000000000000000..80407c84f0b4d317b0fca562ff3eaec1c396d188 GIT binary patch literal 2814 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 O1&${Owh!^-wEqH%A`7|z literal 0 HcmV?d00001 From ea0104878867a101755eedd82617e1be795ec44f Mon Sep 17 00:00:00 2001 From: Andreas Rozek Date: Thu, 6 Jan 2022 06:33:42 +0100 Subject: [PATCH 104/315] Create Screenshot-04.png --- apps/configurable_clock/Screenshot-04.png | Bin 0 -> 3302 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 apps/configurable_clock/Screenshot-04.png diff --git a/apps/configurable_clock/Screenshot-04.png b/apps/configurable_clock/Screenshot-04.png new file mode 100644 index 0000000000000000000000000000000000000000..175476c81ba153ec1b69e9537484a232d1706259 GIT binary patch literal 3302 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 Date: Thu, 6 Jan 2022 06:33:46 +0100 Subject: [PATCH 105/315] Create Screenshot-11.png --- apps/configurable_clock/Screenshot-11.png | Bin 0 -> 1570 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 apps/configurable_clock/Screenshot-11.png diff --git a/apps/configurable_clock/Screenshot-11.png b/apps/configurable_clock/Screenshot-11.png new file mode 100644 index 0000000000000000000000000000000000000000..bca534613173b18345c9c900cb584f6e2bdee4fe GIT binary patch literal 1570 zcmeHH?N3v882#Or-mc{WRhTWdg2nNovDk_tSVKioUUZ1)bQ+*c9gt|CP=(8&aA^Tc z6p7PWGtgo(qBCk0U#PQ`%e=EjEGWc*Qs5Sy1ff#p)dFQK+4d*w(>^@UNltRkNuHBD z6$$atZp_6@0DxO;OjP1L-u!DmgXg!d;Z4dsK=Q=sP2ff=Zx8^QB{nK@H=1JW>DeWjm0m7#5m?#=0`J40z@x#PB+`v&RE&f1KUb=ZmCnuEn&fK%E| z1HlS~yN8fk=L(V>4xUdc9LEOwvGMQ?IC3@^$OebxDCQlM49ND*0Xqmu_yyo~x;876 zR(lk}wn?=QsZTc!Qh>%7ah!g>x-!Lj3G=LrA(>0qGigsKa=QTNVY~*e?kKz+50qRy3|KVm>0zbyXfEC4IjIUF9!v#I#=f!jGyB9;b*Yf z;M3m$m7@aUvJ3KIy?Tc$r++O=yI4q!FVN0Q?=GMYH_3tp98xzl+V|qcQN(U;j7;(n z;ga`A|9&-OluKEik%(ROK&gihU|NeOVTwlVC&bFBE;W>?_f>QKW}h#_xDPj5I4knK z@ycc>6Zye_kf%si9uc>nDND~#i&eB$babhZpgvdnK&Wsfp|S=@VEd_B)`)uD;7%;B zycA8xFH}(tA>>3D;pyjo3ZOzun`!AquX;IxUugCb(9y)lts;;I7u@6ZSBSXLkcD&g zm^X2~?(H=y8gI(l6-sC(tD1^t@(a3GPkZhJr249~Z@a~>JUn0xE=pcC(#=H+Mtcnv zjgc^KJDmHIN0P?LO3af@mX_9 z#4Wbn1{<5vi(FE}n`T>RGvkYlMVBUI<}b+)`{>oqobG&rB!XOF#%NCPw9AL>)?!4oozl1=^P>|xwS^nauuX7LU6%qZs%^74a!e3 z+A~ll@v{EfdUDUaVMdTX%^$B4`Z9DQC4tT_bMEM#1voQ~`~0zt_-Sb0xJ|r#M;8YR ztfT!~$Q>RT%NLt~#Ty}Gn*%B#G%+UYA8NQar*GqSbyygMY?cY64quzNgCTim-3m5X z;|dGUv$AC_xXNlM2`sG^Qb@*v#*)A&9uKmohGmfqYrsi>rbqQ{97gn`*;pQIh;Vw= zXDtmVQ;1-)rZtzb0>~1+J}75`nvR#jku>1WJbWY`!sP3_{jUH#@|#NYav+OOf8g>t z2n)J)E1U*e2ajlKDS%$KHuN&U!!Ott?gnJ-%|~y&K-lHm$x0^RdHvp1LjeOv?`=zf mFx9V%t9OC_!~Q#fmxh?8^Mp2eDh?qi$?URsIQ;s<7Pv literal 0 HcmV?d00001 From 9cc680155ccea5bdf513c94e11e5174ac22586e3 Mon Sep 17 00:00:00 2001 From: Andreas Rozek Date: Thu, 6 Jan 2022 06:33:48 +0100 Subject: [PATCH 106/315] Create Screenshot-12.png --- apps/configurable_clock/Screenshot-12.png | Bin 0 -> 1682 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 apps/configurable_clock/Screenshot-12.png diff --git a/apps/configurable_clock/Screenshot-12.png b/apps/configurable_clock/Screenshot-12.png new file mode 100644 index 0000000000000000000000000000000000000000..973b6da5e62b45e5d55918ed7878b65da00c10d4 GIT binary patch literal 1682 zcmd^A>r+#A5dGcUkOT-2u$4CngD+YMiP9+wrXkRYhy_F|s5EMQq!2O$`UF=ur!Uj?`LeRsCsShi!8auRV?)WaDsv&b3tt7C<)sZqYe43V;sJdN>nYsM z{?Ao1ym-FAAiOwV$PP!9cS6WUKS?d(O;80Nkb2XbVgG@YAg2FeWLUoF%bWED_lg3~ zJ`DBO2O!?8faQswBduKY6J8Jeu~fv{-hEv&b_MaKAK&nNApr{YNRDnWKezC)+Qtvv zaGvTF=PwQtk^fzH1a2p2uq}69_++zIe*=VyS?X>m&m1pR;K?5{DN(jA`V?B38$&(i z80Fxi@0CK+cEitdpzI5sGw+UVCYTe1loz37lct?kb=Czd$_$AoGSQ@?RwwM#AgSG2 zzaWKlC64MwM_9|CO5Hhg*PIad+;b}C_5E~M#S~e{+|ULDmV|nc#$?+ddxG5wMh%rt zG_z3(m1Hx@=101*wo6#@*UPdTR7;Yk8RTI4ADByX=0F|IxUAR;;Za5 zkdTy6J?Qx(GIM$Cvc168>daBHvsmN?Z2^A-8Hr_C&iDivZzPHrlu<|?2FZD*TQ5IANP6s z5d>nTmX{6<;tn9M*VHI|_-wKXpx;N*PV(N33EGjF?7b6a#qm?TzDYr)oIOc?-#@c> zvg%dcN~~ Date: Thu, 6 Jan 2022 06:33:50 +0100 Subject: [PATCH 107/315] Create Screenshot-13.png --- apps/configurable_clock/Screenshot-13.png | Bin 0 -> 1739 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 apps/configurable_clock/Screenshot-13.png diff --git a/apps/configurable_clock/Screenshot-13.png b/apps/configurable_clock/Screenshot-13.png new file mode 100644 index 0000000000000000000000000000000000000000..b87d977124e6ce8a9c16202362d61aba3cd02c4b GIT binary patch literal 1739 zcmd^=`#)597{|{XU(C_cn5kUTRC8f->$MfTu2aL9Xo#*W*X^?8GVVt$Ii?h=8)e#J zD8#lC)5V%iypC-ODWp}3I7C)0Gl(RYo!$Lu|AGBwe|VnH`}O(Zd4735uP4(-z|+++ z)`1{Mm+!&#Rjcf;B5SF8W%WRyT1aueyp2#ri|H@~X&vKpIor^{kym|*#txskg`f+^ z1qSQhQ>}xOEn6E0Uh|%Z$3-ZfRs8fr*vpCG_?fSgSIW$>FEE3V{F{}4>~*vhp`gQ4 z782Za*F^{uM-}!XkFfv9oF(wVLW?`DV_%CP47r=}qs=vjie@Y5OUP&0V$W|(@=Jjl z#4Obn^c#h7Kmtrdb^QVqlaozIcf-5#+q7xjWa^62eX}Wu7a_OO%mpkV$LcjxUta&v zP+vTJf`K959Zd>T@`K^Brg()rV5#(bN^9AehWX=ql83e%*%b07pc2t4pqIuLLhT%V zSi3&go*X`8h>38-6ja4!;~WC$rN8{rozNo~qiI!s=kVo4NH^(VnK|a*N|S3m6KsW( z(pfQVSyK$01ha(yhG@vEU$>2AwNj-e13ge=I~9(GJc)lScNwFHY@KX`*}+VeyRfO5 zd{^HbvrG33bSFqf46`)x?Q^&W9dU$g!YnXtS1Jkxw)?`1(-~uQynYav0S|(cCTd0; z$!Bm8q%EeQ6gs9&(z9l(=y-E1mF?Os*HjOz334aE36pBNdJ7OhVwomJqZ_Zzp+|LQ z;3h>*{-N0(@QYt`F$b(Ri)N4P9ohg!!IZV2pL?PHI@uH~&D6KwXkoXB;7Wkts8M$o z&hdF-m|0vB8w*C;;2hg-Ip6CpJFLJN#-n^MKZ*mxrBo%WXVAk}9f zux8F~;?9Lj4LykC>5=XIN`H!r^_%YVjUoZzn77b1oT%e+xI8Aet041+76r}j?dnj1 zIxEKbE)BBd0~>}afmP@D2+d`U|LjgdO{(8qYdBnIg%uVwmPCctnd$WIG#-(0^YI;+ z(yi`s12^??0UpDy$!V3`ar5qL=n}r!2PZX&_03WuW~1hQ?=dQ@d}t;h_yvt;q|C9> z_r0kmr|@H%btkDx?%c@4T8vH3kC}1K>!4OmP9iIADe{1%EyD=r*$nKj`vA7x^QWSQ zeXY9lb92X)L6Y^w7f&y!@9hfi9bK?xR*?Oyvu);3KhGs%4a~lLBw^L)81InhZ%*MJ zzjoH@Vl`)-f`ldb*^hE&GBx8>^-3XiTnFy`el~n+e%)DQ7K0bAerf;$ioAWeW^jH? z>cB+4z2r}kXO=H7w^Wt2Hh`#4FTA95RauJ~-@ee3GKBHYf%~L%VOQ(^(Dj&0m>T_B z6N9&7E+K!r)tMcGC-Wav-ze_i#R-NN=&Df;?>?_xokTylmCI5USuPbHc}O118X1|` zo&rXI*=)erFuYT8#HLFB0xkll0t5tU{<<=&9PMyc#dumXRj&T2_oi*r4v0&E8SX`p zP`;-+AUU{(DkqPMQU;0@OO@yKQWfpZNPe57%c=cc*IRDUOk? Date: Thu, 6 Jan 2022 06:33:53 +0100 Subject: [PATCH 108/315] Create Screenshot-21.png --- apps/configurable_clock/Screenshot-21.png | Bin 0 -> 2678 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 apps/configurable_clock/Screenshot-21.png diff --git a/apps/configurable_clock/Screenshot-21.png b/apps/configurable_clock/Screenshot-21.png new file mode 100644 index 0000000000000000000000000000000000000000..46d799e6d2aa1296d73600ee22a335ac60756964 GIT binary patch literal 2678 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 Nm>F9c(G73J{Tl;|?qmP} literal 0 HcmV?d00001 From b28719da164d9ccb2fce2e6ccb72f2b6caba1e40 Mon Sep 17 00:00:00 2001 From: Andreas Rozek Date: Thu, 6 Jan 2022 06:33:55 +0100 Subject: [PATCH 109/315] Create Screenshot-22.png --- apps/configurable_clock/Screenshot-22.png | Bin 0 -> 3508 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 apps/configurable_clock/Screenshot-22.png diff --git a/apps/configurable_clock/Screenshot-22.png b/apps/configurable_clock/Screenshot-22.png new file mode 100644 index 0000000000000000000000000000000000000000..7ee02568ea7332cdcc302903eb0e8b2e54b84ed1 GIT binary patch literal 3508 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 i4R9g@awP?Z75D>?eJSBek!TA50000 Date: Thu, 6 Jan 2022 06:33:57 +0100 Subject: [PATCH 110/315] Create Screenshot-23.png --- apps/configurable_clock/Screenshot-23.png | Bin 0 -> 3506 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 apps/configurable_clock/Screenshot-23.png diff --git a/apps/configurable_clock/Screenshot-23.png b/apps/configurable_clock/Screenshot-23.png new file mode 100644 index 0000000000000000000000000000000000000000..f3248993bafcf568d1bcc3b4b62b227fe33a8a3a GIT binary patch literal 3506 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

EGBAq8Mt^3+q)og)k|F}jMX IxQI>oKk(JLumAu6 literal 0 HcmV?d00001 From 59eb274eeb734c9178e3fea29b4aa606ed599be4 Mon Sep 17 00:00:00 2001 From: Andreas Rozek Date: Thu, 6 Jan 2022 06:34:00 +0100 Subject: [PATCH 111/315] Create Screenshot-24.png --- apps/configurable_clock/Screenshot-24.png | Bin 0 -> 3040 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 apps/configurable_clock/Screenshot-24.png diff --git a/apps/configurable_clock/Screenshot-24.png b/apps/configurable_clock/Screenshot-24.png new file mode 100644 index 0000000000000000000000000000000000000000..8a7753bfc5dd89b2dbb0ee9b034900f5b3151889 GIT binary patch literal 3040 zcmbW3*H=@)8pY2!B$Px2X^J3HR6vS|N|hodk*0!_KqwJOP^ktxA_+x^1qBtU0YOwE z5K2Om5(QDDg9H*pK}DsB(p%u3`*8n(`!F+W?KSiC+xy!?J9!+t8MOli0KjJ3W7f{_ zS@Pc{Dh%(;${#-P0fswcErH?=g)sm?r`uW|b-C&@l{Jy_U42um!SqHK?_t~0CPyLH zw~_|^>w^bG3+9w{Y(Fy>R|V@QHf*VmGFQch9S^EiHlRca)DkuXU7eU~SuOw?e3<8j zi;J!mIL=j=?wswwIoyy%1e`tnFBCI)4ya6y5c@|B!1NpeNZ-qMN8XZ^-5{~DpfGv@ z>ti4Nn#DWRjVp!pCEV9~kthD6HRYDLW-s>CMT)(c`ku4?J%1A8R`Py{ro0v;39{(B zz!D;}g%u3G<;3uF#L|Txogi}?(z9yKdv^Po{5Wizf~b=A(mp49fmbn!V~@&%neX4P zT$(>4&>X{=xL*YhpD`&v%t@&uy<$8?J(@N#-}q{mf+W~)%FjsS2Rlx9ImJ94>c|&p zmtJ>B_I()DtaiclXdZDJEn7Gwcrd!H%yW)K{EkV_-8aonx3=JyU2{NISn{Ofs$hs{FiS9M#F;CE53YvWZg|dN{faT6&?bX;r(M z)4giuqMd3rl%*X@jBevXuE$wOOTo0+HcpgG(9zMz1S!syQbB)|F=tshR~XH({%~AJ zE~353>y)5|-?D`|iBlI|kcgkmkx!d5VwC)@-o+r=p90qDit=iLIRYgmoO^sawQccG z*GOSX6W8F6om7WC8h!C@{XubZFMzQ)(86YE3`u-qkTu`^WDavfAln0hp`xV=?5pE1Fa0O{t?h(>onn=ep)@Eoh0PR;h4 z_}GW4#%&pvu{J`oUK%38@*woE`sCUqiU3YxdlB}~fEeMY*Rwo%fY1hlKi*-DC0*&bBwWe_n*5b0m*^F`ENEL+m*{nF@i{gGxk| z+Jz^aBGb$FhtliZ<}=1(-uXVC(h6f`i=+v9M{Sz0m{xt6Q?`dU`+FjEMLWTHrvfu@lKGbkkDN1LZ|<_ zO%3{|{yDUohzuEe^YfeMyAXCju{jK5b{(lVR7=|@7Q-fO>=5j8;s7Q};#Z4hl<(;af&fXJvbAR?BLCc^=Z z(O&>3&ArIKn~Ss~M&%n{23moj){zRg99L@aN+bmH)0TNx@D;i;WMAG~W5Gg+;cg;-yBN4zP>Y86_$k-!DhBT|vF$wYt zPQK{g2xSaS|9qxd3->oW9fJqfY==ZgFn3FZZwY(~pC>Jss?#xpP>|p# zvB-2)@{#km2Uk~Sp$k%DWp~LEqell6tB{^ICE5nLj63g0^+UF+dVP21L7w0HIw`!g zg6!*7&@2248U1E26Nxu#Tb#l5Ud=B8jvHI$@m0MTpg3!FxdwYr?228DsNOknU=|eQ+>d4mwbkJ^kSiw(BC>;?)W{5N9$l+ z-Bu2`EX4tH-5gMafFdNbJcpAB{Q2~Hk3u++YgAZ6gxf;7^nY#Pf%+XVU;e1SN(Yv= z$r1fi;2KGp+0kzUf|DwFciWsTfKF$h?=|X56mS1WNgl96JU#|`Z9^hT?%dVWvj@Q= z_Sf!BXKQq_40DhtMOK|sC<>H>**)9tMf3SpUI&2)?ek?24wY}$Hg(;)?_wpA*ex0xI zFl#0!J3nvt^Uf22fhYd)OjDpL_KmV>-BvZ&&W`)fzkb_fD36V}2)hTREYd1<2n>oR zi6NwdHgL8?_+|CI1*N49ZnWw$D* zE^tKm{ZJi`;?KfKpp|mUJzd#Nw*ae(lN-JC{X$_AJEl777*B>wL~JkGoK4GwmVQZl zp$H2*rcfhxqyomLbsh2-?hMUi+EwxU^ow?4gN!@>59>T%s*?;XBA%Lcy22yhU=eGr zL%DzKdw7flr?XwKH3>be+Ozaosf%i0CnwlvWaq)#3G+}?DHo=}_^=w9udQGnR{mTi zCm5ePk$5Emrkv2WW49fg|NO$qEpU~HCwatJ!}#(ZJswhquPN&VK2V3J$D^_`6Kj~V zHEFYCJ{){!x6ARc8R9<_9?g~36*@8z814kk@rhsJPM2zXZ@eV-J%$Wr`i&`jXeR9W zuBOK3z*E?5; z;?uhz*e8j)L}8rD;;%XleW$0ZShLpwj{SZ}`exnP=es6IQ7+f(0MeoD zG7tL=^HaN0CU!)~Q_?1$%|$kvy6^W9)8PFBQu~zj5=95C0J=xyEMPxvp()nd@h#z5 zi9~sg=OLVSh}+jMedW(anA!-RuZPG`v*f!zdl70)Ygd*Ee7p)jUJ z5Onf&5|B3~y!yPo$E~eQd^$KVE%rW8#YU+9t)*k3%+&;-p5xEYmpC{Tp@t2m8YvFT z3=1rDC5O3Wd_;47`SN%t-DYN=Pis8Tq4)5sU0Zz`4jc|tDUJ7OUCylxF7OLPJAHUy zBh3u9Iv;R|(?-r->0i}fnRJs9WBJa{TOsI}`y zi|7bl{wzL+#ggI3Z0hcL>z2Wjz=kMm<=C)`z_#(kna{?l>&BG&@+b|Ocq{#skTgzH z`Q;9y>SJj}I|;2#zj+3`K;4>Tjh%LG)B!Z%j&Ocm5t79n=SJL1`5LRxAQIv&_`%^a z=1~$~!GTWE19Yd^*#@s3y(N_$MR-^y|^=9WH5&??9U&-m^NJ6#u?LaQL0p~4l%`L6;5?x zSqjQ|4}G-zY~$a%X2st-zW8K{)E5gG-m93WwU;pvhRtsH%V)<{uo|z5Nfch}%Pi^b xPvO8kEo&A%1y`P}W}_+`7*!YU_S2{}aeHtxO#!#93jVSKwl>GDi!BM!{{c?Yqi6sC literal 0 HcmV?d00001 From 01d6e37f185ea9de7c22c50eb2250294c01daa04 Mon Sep 17 00:00:00 2001 From: Andreas Rozek Date: Thu, 6 Jan 2022 06:34:02 +0100 Subject: [PATCH 112/315] Create Screenshot-25.png --- apps/configurable_clock/Screenshot-25.png | Bin 0 -> 2775 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 apps/configurable_clock/Screenshot-25.png diff --git a/apps/configurable_clock/Screenshot-25.png b/apps/configurable_clock/Screenshot-25.png new file mode 100644 index 0000000000000000000000000000000000000000..c2950d7b2ab4e1a58829bc51f2d0f739f4012f5a GIT binary patch literal 2775 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 Date: Thu, 6 Jan 2022 06:34:05 +0100 Subject: [PATCH 113/315] Create BangleApps__apps__variable_clock__README.md --- ...angleApps__apps__variable_clock__README.md | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 apps/configurable_clock/BangleApps__apps__variable_clock__README.md diff --git a/apps/configurable_clock/BangleApps__apps__variable_clock__README.md b/apps/configurable_clock/BangleApps__apps__variable_clock__README.md new file mode 100644 index 000000000..da5bed56d --- /dev/null +++ b/apps/configurable_clock/BangleApps__apps__variable_clock__README.md @@ -0,0 +1,27 @@ +# Variable Analog Clock # + +This app implements an analog clock with various faces, hands and colors to +choose from. + +You have the choice between: + +* 4 different clock faces ![](Screenshot_01.png) ![](Screenshot_02.png) ![](Screenshot_03.png) ![](Screenshot_04.png) and +* 3 different clock hands (optionally with or without second hands) ![](Screenshot_11.png) ![](Screenshot_12.png) ![](Screenshot_13.png) + +Additionally, you may use the currently configured global theme or configure +your own colors for clock fore- and background and second hands. + +Just swipe up or down to switch from clock display to configuration screen + +![](Screenshot_21.png) ![](Screenshot_22.png) ![](Screenshot_23.png) +![](Screenshot_24.png) ![](Screenshot_25.png) + +Chosen settings will be written to the Bangle.js's flash memory and restored +whenever the clock is started again. + +This clock also acts as an example for the building blocks found in the author's +[GitHub repository](https://github.com/rozek/banglejs-2-activities) + +## License ## + +[MIT License](LICENSE) From 4ffee250d7c9eb258fc8651e86704e456387869b Mon Sep 17 00:00:00 2001 From: Andreas Rozek Date: Thu, 6 Jan 2022 06:36:08 +0100 Subject: [PATCH 114/315] Create README.md --- apps/configurable_clock/README.md | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 apps/configurable_clock/README.md diff --git a/apps/configurable_clock/README.md b/apps/configurable_clock/README.md new file mode 100644 index 000000000..fd7527d0b --- /dev/null +++ b/apps/configurable_clock/README.md @@ -0,0 +1,27 @@ +# Configurable Analog Clock # + +This app implements an analog clock with various faces, hands and colors to +choose from. + +You have the choice between: + +* 4 different clock faces ![](Screenshot_01.png) ![](Screenshot_02.png) ![](Screenshot_03.png) ![](Screenshot_04.png) and +* 3 different clock hands (optionally with or without second hands) ![](Screenshot_11.png) ![](Screenshot_12.png) ![](Screenshot_13.png) + +Additionally, you may use the currently configured global theme or configure +your own colors for clock fore- and background and second hands. + +Just swipe up or down to switch from clock display to configuration screen + +![](Screenshot_21.png) ![](Screenshot_22.png) ![](Screenshot_23.png) +![](Screenshot_24.png) ![](Screenshot_25.png) + +Chosen settings will be written to the Bangle.js's flash memory and restored +whenever the clock is started again. + +This clock also acts as an example for the building blocks found in the author's +[GitHub repository](https://github.com/rozek/banglejs-2-activities) + +## License ## + +[MIT License](LICENSE) From f495cddef5d30ad826f761ddf392ceb0e2c6c4a4 Mon Sep 17 00:00:00 2001 From: Andreas Rozek Date: Thu, 6 Jan 2022 06:49:46 +0100 Subject: [PATCH 115/315] Update app.js --- apps/configurable_clock/app.js | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/apps/configurable_clock/app.js b/apps/configurable_clock/app.js index 19dc363e4..5ed52b33b 100644 --- a/apps/configurable_clock/app.js +++ b/apps/configurable_clock/app.js @@ -1147,16 +1147,22 @@ Label('Settings', { common:legible, bold:true, filly:1 }), { height:4 }, { type:'h', c:[ + { width:4 }, Label('Faces', { common:leftAligned, fillx:1 }), Image(Caret, { common:leftAligned }), + { width:4 }, ], filly:1, onTouch:openFacesScreen }, { type:'h', c:[ + { width:4 }, Label('Hands', { common:leftAligned, fillx:1 }), Image(Caret, { common:leftAligned }), + { width:4 }, ], filly:1, onTouch:openHandsScreen }, { type:'h', c:[ + { width:4 }, Label('Colors', { common:leftAligned, fillx:1 }), Image(Caret, { common:leftAligned }), + { width:4 }, ], filly:1, onTouch:openColorsScreen }, { height:4 }, { type:'h', c:[ @@ -1175,14 +1181,17 @@ Label('Clock Faces', { common:legible, bold:true, filly:1 }), { height:4 }, { type:'h', c:[ + { width:4 }, Radiobutton({ id:'none', GroupName:'Faces', common:legible, onChange:chooseFace }), Label(' no Face', { common:leftAligned, pad:4, fillx:1 }), ], filly:1, onTouch:checkInnerRadiobutton }, { type:'h', c:[ + { width:4 }, Radiobutton({ id:'3,6,9,12', GroupName:'Faces', common:legible, onChange:chooseFace }), Label(' 3, 6, 9 and 12', { common:leftAligned, pad:4, fillx:1 }), ], filly:1, onTouch:checkInnerRadiobutton }, { type:'h', c:[ + { width:4 }, Radiobutton({ id:'1-12', GroupName:'Faces', common:legible, onChange:chooseFace }), Label(' numbers 1...12', { common:leftAligned, pad:4, fillx:1 }), ], filly:1, onTouch:checkInnerRadiobutton }, @@ -1208,18 +1217,22 @@ Label('Clock Hands', { common:legible, bold:true, filly:1 }), { height:4 }, { type:'h', c:[ + { width:4 }, Radiobutton({ id:'simple', GroupName:'Faces', common:legible, onChange:chooseHand }), Label(' simple', { common:leftAligned, pad:4, fillx:1 }), ], filly:1, onTouch:checkInnerRadiobutton }, { type:'h', c:[ + { width:4 }, Radiobutton({ id:'rounded', GroupName:'Faces', common:legible, onChange:chooseHand }), Label(' rounded + Bolt', { common:leftAligned, pad:4, fillx:1 }), ], filly:1, onTouch:checkInnerRadiobutton }, { type:'h', c:[ + { width:4 }, Radiobutton({ id:'hollow', GroupName:'Faces', common:legible, onChange:chooseHand }), Label(' hollow + Bolt', { common:leftAligned, pad:4, fillx:1 }), ], filly:1, onTouch:checkInnerRadiobutton }, { type:'h', c:[ + { width:4 }, Checkbox({ id:'withSeconds', common:legible, onChange:toggleSeconds }), Label(' show Seconds', { common:leftAligned, pad:4, fillx:1 }), ], filly:1, onTouch:toggleInnerCheckbox }, @@ -1240,16 +1253,22 @@ Label('Clock Colors', { common:legible, bold:true, filly:1 }), { height:4 }, { type:'h', c:[ + { width:4 }, Label('Foreground', { common:leftAligned, pad:4, fillx:1 }), Label('', { id:'Foreground', common:ColorView, bgCol:Theme.fg }), + { width:4 }, ], filly:1, onTouch:selectForegroundColor }, { type:'h', c:[ + { width:4 }, Label('Background', { common:leftAligned, pad:4, fillx:1 }), Label('', { id:'Background', common:ColorView, bgCol:Theme.bg }), + { width:4 }, ], filly:1, onTouch:selectBackgroundColor }, { type:'h', c:[ + { width:4 }, Label('Seconds', { common:leftAligned, pad:4, fillx:1 }), Label('', { id:'Seconds', common:ColorView, bgCol:Theme.fgH }), + { width:4 }, ], filly:1, onTouch:selectSecondsColor }, { height:4 }, { type:'h', c:[ From 8338c671c2d3e1572fb6192e617588eaf04019a6 Mon Sep 17 00:00:00 2001 From: Andreas Rozek Date: Thu, 6 Jan 2022 06:53:26 +0100 Subject: [PATCH 116/315] Update apps.json --- apps.json | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/apps.json b/apps.json index ebafa9c97..6021608e2 100644 --- a/apps.json +++ b/apps.json @@ -5427,5 +5427,22 @@ {"name":"puzzle15.img","url":"puzzle15.app-icon.js","evaluate":true} ], "data": [{"name":"puzzle15.json"}] + }, + { "id": "configurable_clock", + "name": "Configurable Analog Clock", + "shortName":"Configurable Clock", + "version":"0.01", + "description": "an analog clock with several kinds of faces, hands and colors to choose from", + "icon": "app-icon.png", + "type": "clock", + "tags": "clock", + "supports" : ["BANGLEJS2"], + "allow_emulator": true, + "screenshots": [{"url":"app-screenshot.png"}], + "readme": "README.md", + "storage": [ + {"name":"configurable_clock.app.js","url":"app.js"}, + {"name":"configurable_clock.img","url":"app-icon.js","evaluate":true} + ] } ] From 4d4071e1514c29db60f6506f48335d4333f133b1 Mon Sep 17 00:00:00 2001 From: Andreas Rozek Date: Thu, 6 Jan 2022 07:05:49 +0100 Subject: [PATCH 117/315] Update README.md --- apps/configurable_clock/README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/configurable_clock/README.md b/apps/configurable_clock/README.md index fd7527d0b..e1c2bb574 100644 --- a/apps/configurable_clock/README.md +++ b/apps/configurable_clock/README.md @@ -5,16 +5,16 @@ choose from. You have the choice between: -* 4 different clock faces ![](Screenshot_01.png) ![](Screenshot_02.png) ![](Screenshot_03.png) ![](Screenshot_04.png) and -* 3 different clock hands (optionally with or without second hands) ![](Screenshot_11.png) ![](Screenshot_12.png) ![](Screenshot_13.png) +* 4 different clock faces ![](Screenshot-01.png) ![](Screenshot-02.png) ![](Screenshot-03.png) ![](Screenshot-04.png) and +* 3 different clock hands (optionally with or without second hands) ![](Screenshot-11.png) ![](Screenshot-12.png) ![](Screenshot-13.png) Additionally, you may use the currently configured global theme or configure your own colors for clock fore- and background and second hands. Just swipe up or down to switch from clock display to configuration screen -![](Screenshot_21.png) ![](Screenshot_22.png) ![](Screenshot_23.png) -![](Screenshot_24.png) ![](Screenshot_25.png) +![](Screenshot-21.png) ![](Screenshot-22.png) ![](Screenshot-23.png) +![](Screenshot-24.png) ![](Screenshot-25.png) Chosen settings will be written to the Bangle.js's flash memory and restored whenever the clock is started again. From 3571435499e824ff600b6a47f1cb22672a969bad Mon Sep 17 00:00:00 2001 From: Andreas Rozek Date: Thu, 6 Jan 2022 07:19:43 +0100 Subject: [PATCH 118/315] Update README.md --- apps/configurable_clock/README.md | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/apps/configurable_clock/README.md b/apps/configurable_clock/README.md index e1c2bb574..faddd092a 100644 --- a/apps/configurable_clock/README.md +++ b/apps/configurable_clock/README.md @@ -5,16 +5,18 @@ choose from. You have the choice between: -* 4 different clock faces ![](Screenshot-01.png) ![](Screenshot-02.png) ![](Screenshot-03.png) ![](Screenshot-04.png) and -* 3 different clock hands (optionally with or without second hands) ![](Screenshot-11.png) ![](Screenshot-12.png) ![](Screenshot-13.png) +* 4 different clock faces
![](Screenshot-01.png)   ![](Screenshot-02.png)   ![](Screenshot-03.png)   ![](Screenshot-04.png) and +* 3 different clock hands (optionally with or without second hands)
![](Screenshot-11.png)   ![](Screenshot-12.png)   ![](Screenshot-13.png) Additionally, you may use the currently configured global theme or configure your own colors for clock fore- and background and second hands. -Just swipe up or down to switch from clock display to configuration screen +Just swipe up or down to switch from clock display to the first configuration +screen and continue from there -![](Screenshot-21.png) ![](Screenshot-22.png) ![](Screenshot-23.png) -![](Screenshot-24.png) ![](Screenshot-25.png) +![](Screenshot-21.png)   ![](Screenshot-22.png)   +![](Screenshot-23.png)   ![](Screenshot-24.png)   +![](Screenshot-25.png) Chosen settings will be written to the Bangle.js's flash memory and restored whenever the clock is started again. From aba0d7126b26d1c24435cb89b2bfd24f4b07e581 Mon Sep 17 00:00:00 2001 From: Marco Heiming Date: Thu, 6 Jan 2022 11:08:46 +0100 Subject: [PATCH 119/315] Fix widget height --- apps/circlesclock/app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/circlesclock/app.js b/apps/circlesclock/app.js index fb4635424..319e99809 100644 --- a/apps/circlesclock/app.js +++ b/apps/circlesclock/app.js @@ -41,7 +41,7 @@ const colorRed = '#ff0000'; const colorGreen = '#008000'; const colorBlue = '#0000ff'; const colorYellow = '#ffff00'; -const widgetOffset = showWidgets ? 14 : 0; +const widgetOffset = showWidgets ? 24 : 0; const h = g.getHeight() - widgetOffset; const w = g.getWidth(); const hOffset = 30 - widgetOffset; From 66294b3c8a7a0e5ee92c7eeab3ea346e44f314d9 Mon Sep 17 00:00:00 2001 From: Marco Heiming Date: Thu, 6 Jan 2022 11:17:27 +0100 Subject: [PATCH 120/315] Round step distance --- apps/circlesclock/app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/circlesclock/app.js b/apps/circlesclock/app.js index 319e99809..d9a8d8eae 100644 --- a/apps/circlesclock/app.js +++ b/apps/circlesclock/app.js @@ -175,7 +175,7 @@ function drawStepsDistance(w) { g.setFont("Vector:12"); g.setFontAlign(0, 0); g.setColor(colorFg); - g.drawString(shortValue(stepsDistance), w + 2, h3); + g.drawString(Math.round(shortValue(stepsDistance)), w + 2, h3); g.drawImage(shoesIconGreen, w - 6, h3 + radiusOuter - 6); } From 33deb83a675b744599090325596ee015ea98d6f9 Mon Sep 17 00:00:00 2001 From: Marco H Date: Thu, 6 Jan 2022 13:01:36 +0100 Subject: [PATCH 121/315] Fix rounding of step distance --- apps/circlesclock/app.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/circlesclock/app.js b/apps/circlesclock/app.js index d9a8d8eae..099217706 100644 --- a/apps/circlesclock/app.js +++ b/apps/circlesclock/app.js @@ -155,7 +155,7 @@ function drawStepsDistance(w) { if (!w) w = getCirclePosition("steps", w1); const steps = getSteps(); const stepDistance = settings.stepLength || 0.8; - const stepsDistance = steps * stepDistance; + const stepsDistance = Math.round(steps * stepDistance); g.setColor(colorGrey); g.fillCircle(w, h3, radiusOuter); @@ -175,7 +175,7 @@ function drawStepsDistance(w) { g.setFont("Vector:12"); g.setFontAlign(0, 0); g.setColor(colorFg); - g.drawString(Math.round(shortValue(stepsDistance)), w + 2, h3); + g.drawString(shortValue(stepsDistance), w + 2, h3); g.drawImage(shoesIconGreen, w - 6, h3 + radiusOuter - 6); } From 5e7afb28273bdf6f72ad8ffae1a484b8016f63fe Mon Sep 17 00:00:00 2001 From: Marco Heiming Date: Thu, 6 Jan 2022 15:18:45 +0100 Subject: [PATCH 122/315] Increase size of circles and fonts inside Updated screenshots --- apps.json | 2 +- apps/circlesclock/README.md | 5 +++-- apps/circlesclock/app.js | 19 ++++++++++--------- apps/circlesclock/screenshot-dark.png | Bin 0 -> 3857 bytes apps/circlesclock/screenshot-light.png | Bin 0 -> 3823 bytes apps/circlesclock/screenshot.png | Bin 3576 -> 0 bytes 6 files changed, 14 insertions(+), 12 deletions(-) create mode 100644 apps/circlesclock/screenshot-dark.png create mode 100644 apps/circlesclock/screenshot-light.png delete mode 100644 apps/circlesclock/screenshot.png diff --git a/apps.json b/apps.json index f1609bf4f..a2fd1ec9b 100644 --- a/apps.json +++ b/apps.json @@ -5078,7 +5078,7 @@ "version":"0.04", "description": "A clock with circles for different data at the bottom in a probably familiar style", "icon": "app.png", - "screenshots": [{"url":"screenshot.png"}], + "screenshots": [{"url":"screenshot-dark.png"}, {"url":"screenshot-light.png"}], "dependencies": {"widpedom":"app"}, "type": "clock", "tags": "clock", diff --git a/apps/circlesclock/README.md b/apps/circlesclock/README.md index 86c388440..9004161d6 100644 --- a/apps/circlesclock/README.md +++ b/apps/circlesclock/README.md @@ -10,8 +10,9 @@ It can show the following information (this can be configured): * Heart rate (automatically updates when screen is on and unlocked) * Battery (including charging status and battery low warning) -## Screenshot -![Screenshot](screenshot.png) +## Screenshots +![Screenshot dark theme](screenshot-dark.png) +![Screenshot light theme](screenshot-light.png) ## TODO * Show weather information diff --git a/apps/circlesclock/app.js b/apps/circlesclock/app.js index 099217706..ac7ae1b3f 100644 --- a/apps/circlesclock/app.js +++ b/apps/circlesclock/app.js @@ -47,12 +47,13 @@ const w = g.getWidth(); const hOffset = 30 - widgetOffset; const h1 = Math.round(1 * h / 5 - hOffset); const h2 = Math.round(3 * h / 5 - hOffset); -const h3 = Math.round(8 * h / 8 - hOffset); +const h3 = Math.round(8 * h / 8 - hOffset - 3); const w1 = Math.round(w / 6); const w2 = Math.round(3 * w / 6); const w3 = Math.round(5 * w / 6); -const radiusOuter = 22; -const radiusInner = 16; +const radiusOuter = 25; +const radiusInner = 18; +const circleFont = "Vector:15"; function draw() { g.clear(true); @@ -83,7 +84,7 @@ function draw() { g.drawString(locale.time(new Date(), 1), w / 10, h1 + 8); // date & dow - g.setFont("Vector:20"); + g.setFont("Vector:21"); g.setFontAlign(-1, 0); g.drawString(locale.date(new Date()), w / 10, h2); g.drawString(locale.dow(new Date()), w / 10, h2 + 22); @@ -143,7 +144,7 @@ function drawSteps(w) { g.fillPoly([w, h3, w - 15, h3 + radiusOuter + 5, w + 15, h3 + radiusOuter + 5]); - g.setFont("Vector:12"); + g.setFont(circleFont); g.setFontAlign(0, 0); g.setColor(colorFg); g.drawString(shortValue(steps), w + 2, h3); @@ -172,7 +173,7 @@ function drawStepsDistance(w) { g.fillPoly([w, h3, w - 15, h3 + radiusOuter + 5, w + 15, h3 + radiusOuter + 5]); - g.setFont("Vector:12"); + g.setFont(circleFont); g.setFontAlign(0, 0); g.setColor(colorFg); g.drawString(shortValue(stepsDistance), w + 2, h3); @@ -196,7 +197,7 @@ function drawHeartRate(w) { g.fillPoly([w, h3, w - 15, h3 + radiusOuter + 5, w + 15, h3 + radiusOuter + 5]); - g.setFont("Vector:12"); + g.setFont(circleFont); g.setFontAlign(0, 0); g.setColor(colorFg); g.drawString(hrtValue != undefined ? hrtValue : "-", w, h3); @@ -220,7 +221,7 @@ function drawBattery(w) { g.fillPoly([w, h3, w - 15, h3 + radiusOuter + 5, w + 15, h3 + radiusOuter + 5]); - g.setFont("Vector:12"); + g.setFont(circleFont); g.setFontAlign(0, 0); let icon = powerIcon; @@ -259,7 +260,7 @@ function drawGauge(cx, cy, percent, color) { g.setColor(color); - const size = 4; + const size = radiusOuter - radiusInner - 2; // draw gauge for (i = startrot; i > endrot - size; i -= size) { x = cx + r * Math.sin(radians(i)); diff --git a/apps/circlesclock/screenshot-dark.png b/apps/circlesclock/screenshot-dark.png new file mode 100644 index 0000000000000000000000000000000000000000..00c0e3399cf9a1f4fbd299e259d245e7a9519db7 GIT binary patch literal 3857 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 F{TF;GBE$dy literal 0 HcmV?d00001 diff --git a/apps/circlesclock/screenshot-light.png b/apps/circlesclock/screenshot-light.png new file mode 100644 index 0000000000000000000000000000000000000000..af47b30a40681d7515efcf0658d43784a3e87b8d GIT binary patch literal 3823 zcmai%c{CL6_s5@^VTehj)F5j@V`n6VNtTd(H)6_e?6Pk&B&zWd8X;S{(0`}KKI_UFf%;LCCCK;IBIlF&+1U? z{@*y^hrYID*5yzjp;m^vfYK-Y^Dtlw)itu=JY2Dy?x_Iq&RIQYB60%y%04`rH4p7Jc>VxvPk z8HXO5qDVSMNFvspwLV}d)s89%tG0i=b0@+(%x3+yfpE1jz*-bCkr&HgUNO%2}8!EX; z9;d-bfC1xFX}8O-c1@4_=WD8{OSo8Q`UrG%$$Oql>HKwb+`z@tmTS#go8s#w+71)M zKJ40?aRI%Go5-A#<%WoGg)|GTP3oMRe@jDBLCcRMvS}WT=8j9#(30?;bNhRtzE=J5 zy8!M>YU}arbgj-`Y~@}qCuT)<*DgjcQR|+0?dQ1&gg>pP{q*_Q%BxmJ3pz5lg0x1J zj|7&R&4*9Wj%aEJ`ZO;bP3{rr;d^I7kcPy9*|ID)r3R*!f0jT3^~Cx|dX$z~B!D@$8k1oZ? z(L-cbLMeQ;{7| zoa}=_35~Ye_n1&>fe$y=3Mu)<@Y{JH)Yh0_j*x^&FT`2H4W@6@xOd+?M(E&WR?vl{^qTWK#9=x| zCV>WMCl^&eMx>*}Uo^~-h7*3WzWby+ii=3vQby8F-7@zc<8Q8zhbRdhWfI(j^@sU? zjV6xIJea%BT4;3JMEBBzcp*VjS^L{);>6kzXQpfl8 z`)6Q(!cJ2~ng5QAxc2m|rbg&?2Ebz&sfTdTS-KM8|Q zz&`nCRFT>1Q15pxFVpXwa%$!?n*d>py`iOUWNuUmBcVZ{aWyg$`Rmt7jq6V!k`Y@z|CpTtPg2?1#B;RT<4* z`z6Ek5-Qc?L9&*H1dv=8yOgof87D`lij|}YovlRwTgpD58m{Sue>yTw2ANA&<_E_- zkK$G%d)=88u#cG0#^Ri)wanR_gKDpD>B(FDV+YapkdQhVcJ?Y*(L7GxmOa4XedIxWk(1@mHtLH)*dFco|0avwIg1%LvU-tA$HYrq#Jjzl^;X z{{7VW7YY}Hx=ruvi;k>XE<>5FWm2GtoUIm6v+`)ihj5HQ^swc3fr?E%H<9*l_Jn_I zLk~LZQ0Fo*k9f=~weq6W;?(k@H)ju4BCT*ih5BYmrfW z(~@p@W#Fe@y&lY=M19c(?HyzDdhwZx8Hc7o`6j2tq2JDV?=M2kMB|MJxh+{}WDZg% z85)(;^(?Nvn761R3*All0Spq~YM&zcy%FU|Dk^%iS2Le0zwASXmPI*C!GqC$d4MK? zUdQco0TV?8LeiI|2dNX&fUe09u+%8v*BX*j^N9oQuFi`ysCYhokpdx_tiQP2&{9UjnJ9+So z$IB5P_km_4?a}sMIO8q4AKmfy`sR@6>9NfravtBQ3B(MXrOxH&Df7BmJv3eY0w|Yy zGEDr_xG9W!-!BN#KRct{c$BbQRp-7HTZ7gs4@*{RIAp;j8&j$A1qKMa|IhF5Kd%X8 z*1Wwi^m`X?_v(vj{OEF^Zv>&1>w3N{pWx zf4GOyaeeO^7!+#0A+`t^iCbZN)lZmd{HU^vQsNBEeoMfL!L$HkbOc_-toPA!)dPPtkOSkSn zAb)BvWVMSkI%8I(|E|rx1w{BP4O8vIY@J?Mc|OmVOC8mOPPSak>_ER=1+{{f9I5sZ zwn8J{nEDZg-+7{Y>E1RRUXv4i7+T0xt4}!S+|uF|xYCnc?LSl8xO0>MAevZlFjPTW>-SxD=bSjC zbY}~EU8}h*Q}rd|z@^~VSpjPyCqVjr@7>E22YDSIZ~Xx9-W0*&GSSl?lThsSY}Xbu zJ_%kvPDk5IO7nhY}Pka!y9D&s{bkJUAQXoRzBv z@Uf_ksw)cHeeUHV1U{WX_3eIbvFK}5mf@1l3K4Djsl-y%LeoL{FLBm~bt?A>&ok6H z-96oLr7LYQ=SJy8$kX*4X`$mhNc%O_&(YW5W-Z!2y$=^AhvuKD1o^Kp`o#Sk%f1;V zCT-bs1XZ_Y`HgrdXQy0M2@K@!I}pn*ExcIUf4B& zd=5AGg=xGfII^1`3h8qrbqRlSOc|leC-HgN_0XlT zQo9-2WtuNH@x^(ltNup@Um5A{8Anv9g;r>Lf4I7ZAPGAg_ZbyuYa7}>w}ofN;@O++ ztjH=Sum(-k85JcbxUo~|OdWU@jP9qS=kZ8=Yn>7gy_m2?V@_FY326LMW2-&FV-|SK zA1I7=QS}`YFL+&zSzRt9qH}E~IBrzgAsz4)wmP4PWO?xye#=OXG}L3F>(7Sw3d8M{ zSwDuZs(Xmro4bXv3bi~A+q6e(Dw+2d8DNXe_LTwFuZAa5B(k8Zt1Apo$R&Ts=BcJ-TIa1n;a}kQCHpY%|X7t!)>Yp!nGb`4r)3$D%THg<-5=ZmMX)hBmo z>nP)Z%7U}`+^095;>~ih76}=Dr&7fu9G(erjhL%ZROo&eZ-P}<>bY2==)zfnfvK;0 zU85gt)hbD%4%kk|w~J_#1Z4s;wWef82-4#yXW@)eJT z>%#ZqUb3f1Gn^7>KNdzGlb_8gdIp=LWch24tlo3q5GW}(L^W*GHp)&p%(|W2>F4&{ zm4HJWtR?67H*q~1{s+;#+6?8t5UsY(Q3QPM=`?SXdmm1VP!$9p4n=!7do-{vM;@4+ zVRv*tJyk%_Cv4QGR`W2oWEcG}<;6*b#`Z<#M~5&}xH0m1;t6O7V>0>qXj) zyTD*B`+iR>;vSECUyr{pz~g6nRtUq7jd>Fu{((@)!cvYRKr!TYWcd>a%W8Fk=usF7bBL zu$=CCRi9{xSjV-cHk+Z{>7oP}-RInX;>Rbo6JD=LfB4>poJ{YhXEOrT7>%_9bL+K!IH$2!6v6-vJZ-}W*uZ{?1Pl-lqF&kW62DIv4*Dd z3`u-U*0Ie)Sz}};)yL-#_@3|UoY%eQb{L~x&=hr@K+cM6Jy>ftR2-YD43GO(s!!^ zYbk+50Q5OE_RC@B=foDLmy1LeU`)uxMIZf?D$vD26=kx0NvU#5%`=}EdJ!r7a?oXv z|FZZLNJqZ&agzuD_aA_SfRCG(_&rv(#LTkgzQt<6$}hyg19ui}a)*+B%!zMCxU`oR zwD*7cQ$%~8W{tMc0Ti*KkIhJMVOj!uEF#J`+K81Q$% zaRgRMb8^?8zd;*uCl8q86bIRdnlJi4kIqZBb@hkt6|$NQ$b|ZDt;-2k!Ix`=&L)L_ zP+pSrZ5d>NHX<`gAOjK8NIN*YiMPU=m5M4s)pu`Vp&L+T9tmw1wkyt(!*?3ioO%(i z3A$)9v8=`?f4fZgDvt$tzAlY^I`uC^J~tZ?th>B>u45rNrn&YX%jsvGEo^0cA=9Ty6 zWJ{bAjo&<>Y*%2*Go`7Z=NZ*;X6h8APl;$YeKpqveoIgj&Y?2ulg~F}z8*^OscWRO zv#bR)VU2ywrecvV5TLPuVU8tip@<{@^AW7?kB8Wv)i-9)mYo<*l*OaA#esvy3UOl^l6DhikKA7E`7G znti_*eoN~AG*$3WhY`>AjsDoNZOQ$6S5<{$_+8ypXlH?e#F^#7VBF9RgLCmT+6}QT zo7&Njb;7#8`%XQ*a88pIG6P%(j~A^ecCafoPNIVUGcg$s@7>4t3Vlvf8x&w_zbt1l zqo;y@#|M@-Gk9B|?Lr^wrlLEaUEpf$TPOnxAbIo5lNa88Me;& zkERbXVV~UqZzh`d>Pg#Pj5YLn=6*+q4ro*Np4FjuXHCXBIGE>j<(xasFBdK-xmz+D z8%HXNvO`mxOe2TCGW-Y0KmpnZ^mVw%$Y2-JX7{fy;9VzX?b3-JA#Tf1&63?{ez12G zKKf!KMv6;Go=QKOL{6)Sy&DH_JS;O5$R2cq8ZuBaD2C>LcF!^)DEHl=5O$?g)PWRsX5j4MSDG(j%?gTHzts6QjSpSfSa4KF<+acnW} zRhPH9{lbjPXnCi>K@s;AKoKSq?Pg#zDc(a2Cn%fqRpll~!ES-^W2`oR94}^|v~JBS>BG_^Oh-Mf(>Ol~m<331 zd^s)3&a`ItXPtqw1e)qyRDuePE$I3ybU${(L8b^s5%44P(ueF^aU247!d0bzE3}rLGi&a%vs7;jA=~?ql(q zaVT>O^91|OjCmDD4i2OT&J0LW;#K+BgQcAD2{8eWmXtuWP=V`>wl&*}q>?>|<|Wf( zNaVt!rPZI6zqS#F?R+t_NN=B`z3dxOPHOU-`rcmEk!K5d74j2^)HK14;ujF?)!qwV ziUEZ8GUh&vIdjR?EC}3LSoY?lG44TV%#|*#P4`C|QqrK=&p-azk^28kTwv7C)F1p7 zaT!Gk@lMWfA+eB&HBPeCOshXgPMbfZGdnKsNMdWw!tJ?*M{-NVeMDgiu$Q?1O#4ia z0;TzfRDYtB;k%#fjY*$R1JNI%W2$F=+Q?cqB^_HK)}ZTs$|vOoZ2+O;gX2?<5+10f zl>Zy+6od$7jozHHmH}lx+z*0w-z--uNqusQ;8|ar?80B?+i$b!^tu7eL}BOLf7>&q z#V~SrdFQMC9YvafiOCmM#)g``u+ewC#R&o_1eHE}PhZ`&5XH_uFV`lG#*N(w(XG@! z2b>T_)T-4}(qi6X5?5qAdHO;RL$h=wvS$EHqlOQ0g(~gnprHnev97dsbADX3 z%(~SRew+k0+fP0tXFl7#ke#ViX)+lRn9Yz*8g z{IJe0Ck{#;C*+`}=&S2<2^`*bwc8Qe08=(AbL-8&I{s5&lu=Ly*1K2xrUqGww-F*c zR)O12u_oDUB@Rak48tYo?zC@Q4Ug$XH26o7hjrc-23~RgmF;&mMqOy#TZzVB#rV3( zgI^y&g8~=pjjOWhK^+tzCeiBXBL`Qi-Y*9a@GD#T!G`>t{7moVh7Qaa4HNjzdAq)n zbZ$F5!1QXl!z5Cy<#+dS9!uw&slK@k+&ZzsE`gu0pMg!Lgqx+VIp|tPBm1HgLrOx2^GgKXzwcSppx3{x*^Ap;HsigCX0?U)vJI7R7 z_#Bjn2&kt7zkxzVx6XLh7-nxcx-d73*h(B!0!$0U0uckLq!zdVjv&%j>6*Bwvq9MI z8rH;-7;3XBQKB4eVZO+8FMX3WNBQ7As@}eK@0`=snDGTkSCs1;AbscYuy%8#WB6-o z^Yw;GR|X1hht6oJt$Lt56=-p|t!@(f9@JeFJQqvoPoAzR)vfAvL04~+wfoia`DFM6}411$jVuFs39P!5*Tk3KK^)RM`;;n5_ zl}vtFDDy{&=E^0;f_h0&zA5-1HhIKgRW)lj+yv*CW9?_iKGAho=;$tI=f19P2@L(f z2KpYaV6sshj>f5XbL&~Fc?WK3?B=zB#P=|wahN`aJKhhj)@{K-HmDdurgM`kFaPbt zL45Dz`d3_a(;QUe_2pQH%6G5HV{p#ng+i3{-37ujUIZ^`qLwkhuq*} z-kw~e^$#&M$b{~WczHv*{6C~?nYQk%2qgXEfeA2u!QC=P&f}f2ODj3oMfuVwxs=aT zOAtFGFYXlFotwnF-(Ux;y`NS%V!HB0Yc96>#l?F2_cjQ}1k0SF{no*2m!@;Fay>sC z&)Pm6+@)A>xg)S|x$Ykc>Pb?YBVIw51fqE7`OUoYW?T1aD0{58L9fZ8k_8$`->@|> z)lHFY!jIB!AwbD)L8ve#_8X;1H|HN6U!_K9g8Yv)wNW!cy&re!IFYxB3ZO$9ySezA zwCKZCVAHX@;&tjoR^@(s$YbuXViPM9!KaIcqK24N_%fh+*wi92&|c@E4Zg!2lJWYumOH_M2w|-W-I?ezk_T1RY7teb`+l{o4AT4Z z#d15WBo3drKN=)jEZslwcC7_)>9v+ETa$^^?&POFs2KMbw@6k`aY%YlUfdQJ9`{U@ zG%nVx8f`x>(#6^}Ky}PRx5$HMQ=D?g91hA~#C~4{*)NH-jUkCKZo6dJ@oF!o8}3Wt d08WwZ51V4}M)R57;s5=1fblI0{W>H%@xRtAyzu}4 From ba20a7b51eecc1452c7e5fb62b4964b5d7d875ad Mon Sep 17 00:00:00 2001 From: Marco Heiming Date: Thu, 6 Jan 2022 15:37:33 +0100 Subject: [PATCH 123/315] Center clock text & better placement for date texts --- apps/circlesclock/app.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/circlesclock/app.js b/apps/circlesclock/app.js index ac7ae1b3f..b5ee61c75 100644 --- a/apps/circlesclock/app.js +++ b/apps/circlesclock/app.js @@ -79,15 +79,15 @@ function draw() { // time g.setFont("Vector:50"); - g.setFontAlign(-1, -1); + g.setFontAlign(0, -1); g.setColor(colorFg); - g.drawString(locale.time(new Date(), 1), w / 10, h1 + 8); + g.drawString(locale.time(new Date(), 1), w / 2, h1 + 8); // date & dow g.setFont("Vector:21"); g.setFontAlign(-1, 0); - g.drawString(locale.date(new Date()), w / 10, h2); - g.drawString(locale.dow(new Date()), w / 10, h2 + 22); + g.drawString(locale.date(new Date()), w > 180 ? 2 * w / 10 : w / 10, h2); + g.drawString(locale.dow(new Date()), w > 180 ? 2 * w / 10 : w / 10, h2 + 22); drawCircle(1, "steps"); drawCircle(2, "hr"); From 3558049233e1ecc75b477ccc7cfef588fc9b50f8 Mon Sep 17 00:00:00 2001 From: Peter Slendebroek Date: Thu, 6 Jan 2022 20:35:28 +0100 Subject: [PATCH 124/315] Update README.md --- apps/mmind/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/mmind/README.md b/apps/mmind/README.md index 0623459f7..ea584b7e7 100644 --- a/apps/mmind/README.md +++ b/apps/mmind/README.md @@ -1,6 +1,6 @@ # Mastermind -Play the classic mind game mastermind on your Bangles 2. +Play the classic mind game mastermind on your Bangle 2. ![](screenshot_mmind.png) From 32fb5dc58e272b88810dc58236e003b9eada25d4 Mon Sep 17 00:00:00 2001 From: hughbarney Date: Thu, 6 Jan 2022 21:39:23 +0000 Subject: [PATCH 125/315] Limelight: configurable analogue clock --- apps.json | 15 ++ apps/limelight/ChangeLog | 1 + apps/limelight/README.md | 11 ++ apps/limelight/limelight.app.js | 187 ++++++++++++++++++++++++ apps/limelight/limelight.icon.js | 1 + apps/limelight/limelight.png | Bin 0 -> 929 bytes apps/limelight/limelight.settings.js | 67 +++++++++ apps/limelight/screenshot_limelight.png | Bin 0 -> 2180 bytes 8 files changed, 282 insertions(+) create mode 100644 apps/limelight/ChangeLog create mode 100644 apps/limelight/README.md create mode 100644 apps/limelight/limelight.app.js create mode 100644 apps/limelight/limelight.icon.js create mode 100644 apps/limelight/limelight.png create mode 100644 apps/limelight/limelight.settings.js create mode 100644 apps/limelight/screenshot_limelight.png diff --git a/apps.json b/apps.json index 833c3505e..c4d7624be 100644 --- a/apps.json +++ b/apps.json @@ -5448,5 +5448,20 @@ {"name":"flipper.app.js","url":"flipper.app.js"}, {"name":"flipper.img","url":"flipper.icon.js","evaluate":true} ] + }, + { + "id": "limelight", + "name": "Limelight Clock", + "version": "0.01", + "description": " Simple configurable analogue clock based on the work of @Andreas_Rozek (Simple_Clock)", + "icon": "limelight.png", + "screenshots": [{"url":"screenshot_limelight.png"}], + "type": "clock", + "tags": "clock", + "supports": ["BANGLEJS","BANGLEJS2"], + "storage": [ + {"name":"limelight.app.js","url":"app.js"}, + {"name":"limelight.img","url":"icon.js","evaluate":true} + ] } ] diff --git a/apps/limelight/ChangeLog b/apps/limelight/ChangeLog new file mode 100644 index 000000000..9db0e26c5 --- /dev/null +++ b/apps/limelight/ChangeLog @@ -0,0 +1 @@ +0.01: first release diff --git a/apps/limelight/README.md b/apps/limelight/README.md new file mode 100644 index 000000000..7d80ed985 --- /dev/null +++ b/apps/limelight/README.md @@ -0,0 +1,11 @@ +# Limelight + * Simple configurable analogie clock based on the work of @Andreas_Rozek [Simple_Clock](https://github.com/espruino/BangleApps/tree/master/apps/simple_clock)* + +![](screenshot_limelight.jpg) + +* Selection of different fonts +* 100 less lines of code, demonstrating that there is no need for a custom widget draw method + +Written by: [Hugh Barney](https://github.com/hughbarney) For support and discussion please post in the [Bangle JS +Forum](http://forum.espruino.com/microcosms/1424/) + diff --git a/apps/limelight/limelight.app.js b/apps/limelight/limelight.app.js new file mode 100644 index 000000000..a1af79466 --- /dev/null +++ b/apps/limelight/limelight.app.js @@ -0,0 +1,187 @@ +g.clear(); +Bangle.loadWidgets(); +Bangle.drawWidgets(); + +// fonts.google.com +Graphics.prototype.setFontLimelight = function(scale) { + // Actual height 28 (28 - 1) + g.setFontCustom(atob("AAAAAAAAAAAAAAAAAeAAAAAD8AAAAAf4AAAAB/gAAAAH+AAAAAf4AAAAB/gAAAAD8AAAAAHgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeAAAAAPwAAAAH8AAAAD+AAAAD+AAAAB/AAAAA/gAAAAfwAAAAD4AAAAAMAAAAAAAAAAAAAAAAAAAAA/gAAAA//wAAAP//wAAB///wAAP///gAA///+AAH///8AAf///4AD////gAP///+AA////4AD////gAMAAAGAAwAAAYADAAABgAMAAAGAAwAAAwABgAADAAHAAAYAAOAADgAAeAA8AAAfh/AAAAf/wAAAAHgAAAAAAAAAAGAAAAAAYAAAAABAAAAAAMAAAAAAwAAAAAD///+AAf///4AB////gAH///+AAf///4AD////gAP///+AA////4AH////gAf///+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgABAAAeAAOAAH4AAwAA/gAGAAP+AAYAB/4ADAAf/gAMAD/+AAwAf/4ADAH//gAMA//+AAwH//4ADB//9gAOP//GAA///wYAD//+BgAH//gGAAf/8AYAA//ABgAB/4AGAAD+AAYAADAAAAAAAAAAAAAAAAAAAAAAAAAAAABwAAAAAHAAAwAAGAAHAAAMAAYAAAwADAEABgAMAwAGAAwDAAYADAMABgAMAwAGAAwDAAYAD////gAP///+AA////4AD////gAP///8AAf///wAB/7//AAD/H/4AAP4f/AAAPA/4AAAAA+AAAAAAAAAAAAAAAAAAAGAAAAAB8AAAAAPwAAAADzAAAAAcMAAAAHgwAAAA8DAAAAHAMAAAB4AwAAAOADAAADwAMAAAcAAwAAD///+AA////4AD////gAP///+AA////4AD////gAP///+AA////4AD////gAP///+AAAAAMAAAAAAwAAAAADAAAAAAcAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAHAAAH4AOAAP/gAcAA+GAAwADAwABgAMDAAGAAwMAAYADAwABgAMDAAGAAwMAAYADA///gAMD//+AAwP//4ADA///AAMB//8AAwH//wADAP/+AAIAf/wAAAA/+AAAAB/gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABgAAAAD/8AAAA//8AAAH//4AAB///wAAH///gAA////AAH///8AAf///4AD////gAP///+AAwAAAYADAYABgAMBgAGAAwGAAYADAYABgAMBgAGAAwGAAwABgYADAAHAwAYAAMDgHAAAAHh4AAAAP/AAAAAHgAAAAAAAAAAAAAAAA+AAAAAD4AAAAAMAAAAAAwAAAAADAAAAAAMAA/+AAwB//4ADB///gAM///+AA////4AD////gAP///+AA////4AD////gAP///+AA////4AD//+AAAP/wAAAA/wAAAAD4AAAAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHwAAA/g/wAAH/GDgAA/+wGAAD//AMAAf/4AwAB//gBgAP//AGAAx/+AYADD/4BgAMH/wGAAwP/AYACA/+BgAMB/8GAAwD/wYADAP/jgAMBf/+AAYH//wABgz//AADHH/4AAH4f/gAAOA/8AAAAB/AAAAAAwAAAAAAAAAAAAAAAAAeAAAAAH/AAAAB8eAAAAGAcBgAAwAwHAAGABgMAAYAGAYADAAIBgAMAAwGAAwADAYADAAYBgAMAAgGAAwAAAYAD////gAP///+AA////wAB////AAH///4AAP///AAA///8AAA///AAAB//4AAAB/+AAAAAcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAfAeAAAD8D8AAAf4f4AAB/h/gAAH+H+AAAf4f4AAB/h/gAAD8D8AAAHgHgAAAAAAAAAAAAAAA="), 46, atob("DQ0aExgZHRkbGBsbDQ=="), 40+(scale<<8)+(1<<16)); +} + +// fonts.google.com +Graphics.prototype.setFontGochiHand = function(scale) { + // Actual height 29 (31 - 3) + g.setFontCustom(atob("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABwAAAAAB4AAAAAD4AAAAAB4AAAAAB4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPAAAAAH/gAAAD//gAAD///gAD///+AAH///AAAH//gAAAH/wAAAAHwAAAAAAAAwAAAAAP+AAAAA//gAAAB//wAAAD//4AAAD8P4AAAHwD8AAAHgB8AAAPgA8AAAPAA8AAAPAA8AAAPAA8AAAPgA8AAAPgA8AAAPgB8AAAHwB4AAAH4D4AAAD+PwAAAD//gAAAB//gAAAA/+AAAAAP8AAAAAAAAAAAAAAAAAAAcAAAAAA8AAAAAB8AAAAAD4AAAAAD4AAAAAHwAAAAAHgAAAAAPgAAAAAPgAAAAAf/AAAAAf//wAAAP//wAAAH//wAAAAf/wAAAAAPgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAA8AAAeAB8AAA+AD8AAB+AH8AAB4AP8AAD4AP8AADwAf8AADwB+8AAD4D88AAD4H48AAD//w+AAB//g+AAB//A+AAA/8A+AAAPwA+AAAAAA+AAAAAAcAAAAAAIAAAAAAAAAA8AAAAAB8AAAAAB8AAAAAB4AHgAAD4AHwAAD4AH4AADwPH8AADwfB8AADwfA8AAD4fA+AAD4fA+AAB//A+AAB//A+AAA//A8AAA//x8AAAPP/8AAAAH/4AAAAD/wAAAAB/gAAAAAOAAAAAAAAAAAAAAAAAAAAAAAAAAB4AAAAAH8AAAAAP+AAAAA/+AAAAB/+AAAAD8+AAAAP4+AAAB/weAAAD/weAAAD/8eAAAB///AAAA///AAAAH//8AAAAf//AAAAD//AAAAAf/AAAAAf+AAAAAfAAAAAAMAAAAAAAAAAAAAAAAAAPA/gAAAfh/wAAA/x/4AAA/x/4AAB/4/8AAB74B8AAB58A8AAB58A+AAB5+A+AAB4+A+AAB4+A+AAB4fA+AAB4fg+AAB4Pg8AAB4P58AAB4H/4AAB4D/4AAB4D/wAAAQA/gAAAAAAAAAAAAAAAAAAAAAAAAAf8AAAAB/+AAAAD//gAAAH//gAAAPwfwAAAPgf4AAAfAf4AAAeA/8AAAeA98AAAeA88AAAfB48AAAfB48AAAPB48AAAOB48AAAAB98AAAAB/8AAAAA/4AAAAA/wAAAAAfgAAA8AAAAAA8BAAAAA8HgAAAA8HgAAAA8HgAAAA8HgAAAA8HgAAAA+HgAAAA+HgAAAA+HgAAAAfHgAAAAf//+AAAf//+AAAP//+AAAH//8AAAAPwAAAAAHgAAAAAHwAAAAAHwAAAAAHwAAAAADwAAAAADgAAAAAAAAAAAAAAAAAAAB/AAAAP3/wAAAf//wAAA///4AAA//D8AAB9+B8AAB4+A8AAB4+A+AAB4+A+AAB4+A+AAB8+A+AAB8+A+AAA/+A8AAA//A8AAAf/x8AAAP//4AAAH//wAAAAD/gAAAAB/AAAAAAAAAAAAAAAAAAD/AAAAAD/gAAAAH/gAAAAP/wAAAAPHwAAAAPDwAAAAeDwAAAAeDwAAAAeDwAAAAeHwAAAAeHgAAAAePgAAAAefAAAAAf/AAAAAf///gAAf///wAAP///wAAP///gAAH8AAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8BwAAAA8B4AAAA+D4AAAA8B4AAAAcB4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="), 46, atob("DQoYERUWFBYVFhcVDQ=="), 42+(scale<<8)+(1<<16)); +} + +// free for commercial use +// https://www.1001fonts.com/search.html?search=Grenadier+NF +Graphics.prototype.setFontGrenadierNF = function(scale) { + // Actual height 39 (39 - 1) + g.setFontCustom(atob("AAAAAAAAAAAAB4AAAAAAPAAAAAAB4AAAAAAAAAAAAAAAAAAAAAAEAAAAAAPgAAAAA/8AAAAB//gAAAD//4AAAP//wAAAf//AAAB//+AAAD//8AAAB//wAAAAP/gAAAAB+AAAAAAMAAAAAAAAAAAAAAAAB4AAAAAD/8AAAAB//4AAAA///wAAAP8D/AAAD8AD8AAA/AAPwAAPgAAfAAD4AAB8AAeAAAHgAHwAAA+AA8AAADwAHgAAAeAB4AAAB4APAAAAPAB4AAAB4APAAAAPAB4AAAB4APAAAAPAB4AAAB4APAAAAPAB4AAAB4APgAAAfAA8AAADwAHwAAA+AAeAAAHgAD4AAB8AAPgAAfAAA+AAHwAAD8AD8AAAP8D/AAAA///wAAAD//8AAAAH/+AAAAAD8AAAAAAAAAAAAAAAAAAABAAAAAAAcAAAAAAHwAAAAAB8AAAAAAfgAAAAAH/////AB/////4AP/////AB/////4AAAAAAAAAAAAAAAAAAAAADAAAAAAA4APAAAAPAB4AAAD4APAAAA/AB4AAAP4APAAAD/AB8AAA/4AHgAAPvAA8AAD54ADwAB+PAAfAAfh4AB8AH4PAAPwD+B4AA///gPAAD//wB4AAH/4APAAAP8AAAAAAAAAAAAAAAAAAAPAAAAHAB4AAAB4APAAAAPAB4PAAB4APB4AAPAB+/gAB4AH/8AAfAAf/wADwAB/fAA+AABD8APgAAAPwH4AAAA//+AAAAD//gAAAAH/4AAAAAP8AAAAAAAAAAAAAAAAAAAAAAYAAAAAAPAAAAAAH4AAAAAD/AAAAAB/4AAAAA//AAAAAf94AAAAH+PAAAAD/B4AAAB/gPAAAA/wB4AAAf8APAAAP////4AH/////AD/////4AAAAAPAAAAAAA4AAAAAAAAAAAAAAAAAAAIAAPAAAPAAB4AAf4AAPAA//gAB4AP/8AAPAB/3gAB4APg8AAfAB4DwADwAPAfAA+AB4B8APgAPAP4H4AB4A//+AAPAB//gAB4AH/4AAAAAP8AAAAAAAAAAAAAB4AAAAAD/4AAAAA//wAAAAf//AAAAP+H8AAAH+AHwAAB/gAfAAA/4AB4AAf+AAPAAP/wAA8AH+eAAHgB/ngAA8APw8AAHgB4HgAA8AMA8AAHgAADwAA8AAAeAAPgAAD4AB4AAAPgAfAAAA+AHwAAAH4D8AAAAf//AAAAB//wAAAAD/8AAAAAH8AAAAAAAAAAAAAAAAAAAAAAAYAAAAAAfAB4AAAP4APAAAH/AB4AAH/gAPAAD/wAB4AD/wAAPAB/4AAB4A/8AAAPA/8AAAB4f+AAAAPP+AAAAB//AAAAAP/gAAAAB/gAAAAAPwAAAAAB4AAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAD/gAAAAB//AAAAAf/+AAAAH//4AAAB+AfgAA+fAB8AAP/wAHwAD/+AAeAA//gAB4APj8AAPAB4PAAB4APB4AAPAB4PAAB4APB4AAPAB8fgAB4AH/8AAPAAf/wADwAB/eAA+AADj4APgAAAPwD8AAAA///AAAAD//wAAAAP/4AAAAAf8AAAAAAAAAAAB4AAAAAB/4AAAAA//wAAAAP//AAAAD+H8AAAA/AHwAAAHgAfAAAB8AB4AAAPAAHgAADwAA8AAAeAAHgBADwAAeA4AeAADwfADwAAeP4AeAAD3+ADwAA9/gAfAAH/wAB4AB/4AAPgAf8AAA+AH+AAAD8B/gAAAP//wAAAA//4AAAAD/8AAAAAD+AAAAAAAAAAAAAAAAAAAAAAAeB4AAAADwPAAAAAeB4AAAAAAAAAAAAAAAA=="), 46, atob("Bg4kChURExEaFBoaBg=="), 45+(scale<<8)+(1<<16)); +} + +// fonts.google.com +Graphics.prototype.setFontMonoton = function(scale) { + // Actual height 38 (37 - 0) + g.setFontCustom(atob("AAAAAAAAAAEkAAAAAbYAAAABtgAAAAG2AAAAAbYAAAABtgAAAAG2AAAAASQAAAAAAAAAAAAAAAAAAAB4AAAAB/gAAAB/gAAAB/h4AAB/h/AAB/h/CAB/h/D4B/h/D/B/j/D/APj/D/AAD/D/AAB/D/AAAPD/AAAAD/AAAAB/AAAAAPAAAAAAAAAAAAAAAAAAAAAD/wAAAB//4AAAfAD4AAHj/x4AA5//5wAHfAB5gAzj/5zAHc//5mAbvDBzcDdz/zmwNu+HzZhs3ADu2G2YAHbYbbAANthtsAA2yG2wABtsbbAAG2xtsAA2yG2wADbYbZgAdthm3ADs2DZv/92wM3P/O7AbvAD3YB3P/87gDvP/HMAHPgD7gAOP/+cAAfH+HgAAfgH4AAAf/+AAAAD+AAAAAAAAAAAAAAAAbYAAAABtgAAAAG2AAAAAbYAAAABt////wG3////AbYAAAABt////wG3////AbYAAAABt////wG3////AbYAAAABt////wEn///+AAAAAAAAAAAAAADQAAAUgdoAAF7BtsAA3sG2wAOewbbAB17BtsAc3sG2wDnewbbAdx7BtsHO3sG2w7newbbPd57Btv3OXsGzc73ewZuPc57A2f3nHsDMc5wewG8POB7Ac/zgHsA4Y8AewB+fABSAB/wAAAAAAAAAAAAAAAAA0AAAAsHbAAAbYbbAANthtsAA22G2wADbYbbJJNthts22W2G2zbZpIbbNtm2xts22bbG2zbZJIbbNttthtv2322Gzfbu7YNuO3HZg3f7P5sDuf2OMwGeHPHmAO/2f8wAccOOOAA/PfvwAA/4f8AAAAAAAAAAAAAAAAABkgAAAA/bAAAAPtsAAAD52wAAA8fbAAAfH9sAAHz42wAB8+fbAAePn9sADjx82wAJ8ePbAAfPj9sADz482wAI+fDbAAfHwNsADx8A2wAM+D/b+APgP9v4D4AA2wAMAD/b+AAAP9v4AAAA2wAAAADSAAAAAAAAAAAAAAAAAAAAMAaf/8AwBt//wJgG2AAA3Abf/8JsBt//w2wG2AABtgbf/822BtgADbYG2NvNtgbY28SSBtjbxtsG2NvG2gbY28SSBtjbzbYG2Nv9tgbY23m2BtjNg2YG2Gz+bAbYZnzcBtgzg5gG2Dn/MASQHHzgAAAPg8AAAAP/gAAAAHwAAAAAAAAAAAAAAAAA//4AAAf//8AAHgAB4AA4//44AGf//5wAzgAB7AGY//52AbP//7MDZwABmwNu//zZhs3//m2G25LTbYbbN7Nthts3sSSG2zexpIbbN7G2xts3sSaG2zezbYbbN7Nthts3v22GbDbezYNsG+HbA3Qbf7sBsB3edgGQDPHuAMAGf9wAQAOOOAAAAfvwAAAAf8AAAAAAAAAAAAAABtgAAAAG2AAAAAbYAAAABtgAAAAG2AAAAAbYAAAMBtgAAPwG2AAP8AbYAf4cBtgf4fwG0f4f4Aaf4f4cAf4f4fwH4f4f4AYf4f4cA/4/w/wHw/w/wAQ/w/wAA/w/wAAHw/wAAAQ/wAAAA/wAAAAHwAAAAAAAAAAAAAAAAAAAA+AfAAAf/P/gADwPwHgA5/OfnAHP+f/OAZwO4HYDM+d/MwNn+3/bBuwZsM2G2e2+bYbb7b9thtskk2yG2zbZtobbNtm2xts22bbG2zbZtsbbNtm2xts22bbG2zbZNsbbNttshtv2322GzfZu7YNuO3HZg3f7v5sBud3OcwHfPvHmAOf3P8wAcAeAOAAf///wAA/4f8AAAAAAAAAAAAAAAAfwAAAAH/wAAAA4DwAIAGfzgAwAz/3AJgGYDsA2AzP2YDsDZz9g2wNszbDNhs3ns22G2zezbYbbN5NthtsTkSSG2xORtMbbE5G2xts3sySG2zezbYbbN7Nths2ABm2Cbf/+3YNmf/nbAzeAB7MBuf/+dgHcP/DuAO///9wAc///OAA8AADwAA///8AAA///AAAAAAAAAAAAAAAAAAAAAAA2xtgAADbG2AAANsbYAAA2xtgAADbG2AAANsbYAAAkhJAAAAAAAAAAAAAAAA"), 46, atob("ChIiERcYGRwfGSAfCw=="), 40+(scale<<8)+(1<<16)); +} + +function loadSettings() { + settings = require("Storage").readJSON(SETTINGS_FILE,1)||{}; + settings.secondhand = settings.secondhand||false; + settings.font = settings.font||"Limelight"; + settings.vector = settings.vector||false; + settings.vector_size = settings.vector_size||42; + UPDATE_PERIOD = (settings.secondhand ? 1000 : 60000); +} + +var UPDATE_PERIOD; +var drawTimeout; + +const CenterX = g.getWidth()/2; +const CenterY = (g.getHeight()/2) + (Bangle.appRect.y/2); +const outerRadius = (g.getHeight() - Bangle.appRect.y)/2; + +function debug(o) { + //console.log(o); +} + +debug("limelight.app.js"); +debug("CenterX=" + CenterX); +debug("CenterY=" + CenterY); +debug("outerRadius=" + outerRadius); +debug("y12=" + (CenterY - outerRadius)); +debug("y6=" + (CenterY + outerRadius)); + +const HourHandLength = outerRadius * 0.5; +const HourHandWidth = 2*3, halfHourHandWidth = HourHandWidth/2; +const MinuteHandLength = outerRadius * 0.7; +const MinuteHandWidth = 2*2, halfMinuteHandWidth = MinuteHandWidth/2; +const SecondHandLength = outerRadius * 0.9; +const SecondHandOffset = 6; + +const twoPi = 2*Math.PI; +const Pi = Math.PI; +const halfPi = Math.PI/2; + +let HourHandPolygon = [ + -halfHourHandWidth,halfHourHandWidth, + -halfHourHandWidth,halfHourHandWidth-HourHandLength, + halfHourHandWidth,halfHourHandWidth-HourHandLength, + halfHourHandWidth,halfHourHandWidth, +]; + +let MinuteHandPolygon = [ + -halfMinuteHandWidth,halfMinuteHandWidth, + -halfMinuteHandWidth,halfMinuteHandWidth-MinuteHandLength, + halfMinuteHandWidth,halfMinuteHandWidth-MinuteHandLength, + halfMinuteHandWidth,halfMinuteHandWidth, +]; + +let transformedPolygon = new Array(HourHandPolygon.length); + +function transformPolygon (originalPolygon, OriginX,OriginY, Phi) { + let sPhi = Math.sin(Phi), cPhi = Math.cos(Phi), x,y; + + for (let i = 0, l = originalPolygon.length; i < l; i+=2) { + x = originalPolygon[i]; + y = originalPolygon[i+1]; + + transformedPolygon[i] = OriginX + x*cPhi + y*sPhi; + transformedPolygon[i+1] = OriginY + x*sPhi - y*cPhi; + } +} + +function setHandsFont() { + if (settings.vector) { + g.setFont('Vector', settings.vector_size); + return; + } + + if (settings.font == "GochiHand") + g.setFontGochiHand(); + else if (settings.font == "Grenadier") + g.setFontCabinSketch(); + else if (settings.font == "Monoton") + g.setFontMonoton(); + else + g.setFontLimelight(); +} + +function drawNumbers() { + g.setColor(g.theme.fg); + setNumbersFont(); + + g.setFontAlign(0,-1); + g.drawString('12', CenterX, CenterY - outerRadius); + + g.setFontAlign(1,0); + g.drawString('3', CenterX + outerRadius, CenterY); + + g.setFontAlign(0,1); + g.drawString('6', CenterX, CenterY + outerRadius); + + g.setFontAlign(-1,0); + g.drawString('9', CenterX - outerRadius,CenterY); +} + +function drawHands () { + let now = new Date(); + let Hours = now.getHours() % 12; + let Minutes = now.getMinutes(); + let Seconds = now.getSeconds(); + + let HoursAngle = (Hours+(Minutes/60))/12 * twoPi - Pi; + let MinutesAngle = (Minutes/60) * twoPi - Pi; + let SecondsAngle = (Seconds/60) * twoPi - Pi; + + g.setColor(g.theme.fg); + transformPolygon(HourHandPolygon, CenterX,CenterY, HoursAngle); + g.fillPoly(transformedPolygon); + transformPolygon(MinuteHandPolygon, CenterX,CenterY, MinutesAngle); + g.fillPoly(transformedPolygon); + + if (settings.secondhand) { + let sPhi = Math.sin(SecondsAngle), cPhi = Math.cos(SecondsAngle); + g.setColor('#FF0000'); + g.drawLine( + CenterX + SecondHandOffset*sPhi, + CenterY - SecondHandOffset*cPhi, + CenterX - SecondHandLength*sPhi, + CenterY + SecondHandLength*cPhi + ); + } +} + +function draw() { + g.setColor(g.theme.bg); + g.fillRect(Bangle.appRect); + + drawHands(); + drawNumbers(); + queueDraw(); +} + +// schedule a draw for the next minute +function queueDraw() { + if (drawTimeout) clearTimeout(drawTimeout); + drawTimeout = setTimeout(function() { + drawTimeout = undefined; + draw(); + }, UPDATE_PERIOD - (Date.now() % UPDATE_PERIOD)); +} + +// Stop updates when LCD is off, restart when on +Bangle.on('lcdPower',on=>{ + if (on) { + draw(); // draw immediately, queue redraw + } else { // stop draw timer + if (drawTimeout) clearTimeout(drawTimeout); + drawTimeout = undefined; + } +}); + +loadSettings(); +Bangle.setUI('clock'); +draw(); diff --git a/apps/limelight/limelight.icon.js b/apps/limelight/limelight.icon.js new file mode 100644 index 000000000..06f93e2ef --- /dev/null +++ b/apps/limelight/limelight.icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwwIdah/wAof//4ECgYFB4AFBg4FB8AFBj/wh/4AoM/wEB/gFBvwCEBAU/AQP4gfAj8AgPwAoMPwED8AFBg/AAYIBDA4ngg4TB4EBApkPKgJSBJQIFTMgIFCJIIFDKoIFEvgFBGoMAnw7DP4IFEh+BAoItBg+DNIQwBMIaeCKoKxCPoIzCEgKVHUIqtFXIrFFaIrdFdIwAV")) diff --git a/apps/limelight/limelight.png b/apps/limelight/limelight.png new file mode 100644 index 0000000000000000000000000000000000000000..cf057046be6eca51564a213bc3e7307271464009 GIT binary patch literal 929 zcmV;S177@zP)hL^4Q9~j~`7LX9JB(!Q` zf!g{&{RcFW&Q~mny+EQd5wRkG(GU|*v#i00#krWf=gz{s+-Te{nPTqF`ObG{=bo84 z7wV|v|Hht3JPkk}FaUG|9Y7m!Ao=|p@Bx?yW`SwoCGazne{UQEt^-TJmSbB2t^w^e zR}HiRcY*JgVs~m~;0|!8R^p4mY6RiBtpaENr0^Uv>(vCT0r!Cspcg0r`;t~jo{azx zfb|`CCKF##(F8oL;_xjnl#FrV8%ADg6Xz30z8#UnEWQMc5jI;nU_9Z{{Eq{QD8L7t!&STXpy9ZFm@kj^1Fem7{l-O!eBYr8>b)d^b3W}9W~#A6U*g95Oi>^=c4 z)~Zv`8K;EXvhfK3pp)!7am&FTkR7(HNX8sFd;lS+^%_N}!U1DH{Ly|K9>B#6_hueBM`PvzgXPMrIx>vGBiU)6Z4 zEpn3sb9fkCLB-z-YcKpmwJ#|r9RWl zC5~dFfRx^~zcZo4lLpcS%$dU%U1Vo|3%C)3JcraOHF*iC9^?bK^S~v{rNu|U-T>|j zG$FN0?PUAC7)9=|wrEE3yiS#A@zILA+sGlcN|VDaIFIb+1>`8+h@2|>kwB-& z?yx%JM4NdN29eBAO@MFvNQ4*G7A;7*Pj7ZUZ3CJ0gS8T$MjKKwTeK9b&o&dl(GUSK zKeKitb( font_options[v], + onchange: v => { + s.font = font_options[v]; + save(); + }, + }, + 'Vector Font': { + value: s.vector, + format: () => (s.vector ? 'Yes' : 'No'), + onchange: () => { + s.vector = !s.vector; + save(); + }, + }, + 'Vector Size': { + value: settings.vector_size, + min: 24, + max: 56, + step: 6, + onchange: v => { + settings.vector_size = v; + save(); + } + }, + 'Second Hand': { + value: s.secondhand, + format: () => (s.secondhand ? 'Yes' : 'No'), + onchange: () => { + s.secondhand = !s.secondhand; + save(); + }, + } + }); +}) diff --git a/apps/limelight/screenshot_limelight.png b/apps/limelight/screenshot_limelight.png new file mode 100644 index 0000000000000000000000000000000000000000..9affc3d1cbb9be291270cb57cd1474e03b685ea3 GIT binary patch literal 2180 zcmeHJ`!m~#7LSNFq7QG4TD79mCYD=m?;?bf2t`|^K}kwI(xOFMA!V(vUOPogqtPx) zwBp$kY0?!DtKZ#A>(yv(SCxupNUsVNgnHLaXZH8|2i$vR&iR}<^O^a~oSE~PlXvO_ zX(z%Q0f9hv`uY$~YmoOf;oCH|S*W0DK?8cLOw|IFED~c|;Q4-U9~) zer&36Ls`wW^pT=>0|PeRk*>q{zySHX*^Cw=)L&!OKwFX}`itSpWNT98-xPg%uxZ<5 zs4MIF3-B+3s;8nnb6!6g&&Cpa+netS1h0@1+9x^o^0CFRvPq};>_>>_ZU z^1+0+VpY!T_nuaB-G<4tc0hj`xNIi=Nb0$X6B|dI`!*XiiH{KIX!W3AIF)I_YHC0? zbzFaCdNd5rTTD0tqjs>*4Q6j_N5VJGd`Wap>^nK$QqHQy7kg+re6g|DC0~!VyRF}$ zs~d`J@2uK8Z5(?}GCJSdq&tTthCA$jc@WOi#vUksati`=@H!c#qXi?MvWZ4&!Kgp6 z|3E!L|0sk!f72+0wg`jAzle+B=E23oV;>ea@8C&%B^1r0nM8 zj{NDAH%t<8(mwMdaQM{Y0)|fDd%PJ!m6*RfW70f=EWgz*_4EDvM7(22ZUfb9eyW$U z2A9r5)rc5$JIRf7+o#yyL0S+xWI+-2!RS5HBLL3q0QT~c1e>I5oBgs!cZ)U+tc$FNDaHL27xA$IjEyF>+Y?g%2qrelFW z)-KN!oDW9fX!kErM5lo?mQdZY$Crc0_b!XFyvOaOZC7HUMSr{mgLPl&o*d*@qtD*h zp|&SeM6aQwR~T{j`9lKXSbx={^{M`XH>fh9-&5}BK>!ts>t6RQ(hr-b#gvLZH$LNz z^1%@1@?ITwspu=E7(^|23ma#+j#sJZ_R$xT8^kK&-M~u%3G#-?Xy%yPt0R-FC6w=o6mQcEU8hw(~o#iq-) zJkx57KP%jg`l*f|i5M$sOGL3tkeoy^VTuV2W8b>0M{SpgGTak# zL6mh`f#X`vq!PUZKg5%iBebwuu$J-KpUWW7$9cuH{n;RS)Hq1v-A4l#8e#fx^M5%X zuQ4p!#XN#^;Ro4;+U8O|1uO zZL`7nDn*!vVe);~pBkGBV7dNZ?0;vCD`qy|{M+>()y}q>w*ulzJVD@kM&|qnB+=s~ literal 0 HcmV?d00001 From e5dad4094be9e05a723850bafdad2c19548b1623 Mon Sep 17 00:00:00 2001 From: hughbarney Date: Thu, 6 Jan 2022 21:58:44 +0000 Subject: [PATCH 126/315] fixed apps.json for limelight --- apps.json | 4 ++-- apps/limelight/README.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps.json b/apps.json index c4d7624be..98ce3e5d5 100644 --- a/apps.json +++ b/apps.json @@ -5460,8 +5460,8 @@ "tags": "clock", "supports": ["BANGLEJS","BANGLEJS2"], "storage": [ - {"name":"limelight.app.js","url":"app.js"}, - {"name":"limelight.img","url":"icon.js","evaluate":true} + {"name":"limelight.app.js","url":"limelight.app.js"}, + {"name":"limelight.img","url":"limelight.icon.js","evaluate":true} ] } ] diff --git a/apps/limelight/README.md b/apps/limelight/README.md index 7d80ed985..aa0c359b9 100644 --- a/apps/limelight/README.md +++ b/apps/limelight/README.md @@ -1,5 +1,5 @@ # Limelight - * Simple configurable analogie clock based on the work of @Andreas_Rozek [Simple_Clock](https://github.com/espruino/BangleApps/tree/master/apps/simple_clock)* + * Simple configurable analogue clock based on the work of @Andreas_Rozek [Simple_Clock](https://github.com/espruino/BangleApps/tree/master/apps/simple_clock)* ![](screenshot_limelight.jpg) From 59c7cb49d6d33cb87a95d85440105faf64532698 Mon Sep 17 00:00:00 2001 From: hughbarney Date: Thu, 6 Jan 2022 22:10:56 +0000 Subject: [PATCH 127/315] limelight fixed apps.json, added settings file --- apps.json | 1 + apps/limelight/limelight.app.js | 2 ++ 2 files changed, 3 insertions(+) diff --git a/apps.json b/apps.json index 98ce3e5d5..64b5c358e 100644 --- a/apps.json +++ b/apps.json @@ -5461,6 +5461,7 @@ "supports": ["BANGLEJS","BANGLEJS2"], "storage": [ {"name":"limelight.app.js","url":"limelight.app.js"}, + {"name":"limelight.settings.js","url":"limelight.settings.js"}, {"name":"limelight.img","url":"limelight.icon.js","evaluate":true} ] } diff --git a/apps/limelight/limelight.app.js b/apps/limelight/limelight.app.js index a1af79466..f17114f2d 100644 --- a/apps/limelight/limelight.app.js +++ b/apps/limelight/limelight.app.js @@ -27,6 +27,8 @@ Graphics.prototype.setFontMonoton = function(scale) { g.setFontCustom(atob("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"), 46, atob("ChIiERcYGRwfGSAfCw=="), 40+(scale<<8)+(1<<16)); } +const SETTINGS_FILE = "limelight.json"; + function loadSettings() { settings = require("Storage").readJSON(SETTINGS_FILE,1)||{}; settings.secondhand = settings.secondhand||false; From cc7cbd24e1a7de0115fb87bb9250cc449865109c Mon Sep 17 00:00:00 2001 From: hughbarney Date: Thu, 6 Jan 2022 22:18:46 +0000 Subject: [PATCH 128/315] limelight fixes --- apps/limelight/limelight.app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/limelight/limelight.app.js b/apps/limelight/limelight.app.js index f17114f2d..c4a599c96 100644 --- a/apps/limelight/limelight.app.js +++ b/apps/limelight/limelight.app.js @@ -95,7 +95,7 @@ function transformPolygon (originalPolygon, OriginX,OriginY, Phi) { } } -function setHandsFont() { +function setNumbersFont() { if (settings.vector) { g.setFont('Vector', settings.vector_size); return; From bce36e9afc5e8e68ac508c11436bfe7c160020dd Mon Sep 17 00:00:00 2001 From: hughbarney Date: Thu, 6 Jan 2022 23:29:38 +0000 Subject: [PATCH 129/315] limelight fixes --- apps.json | 2 +- apps/limelight/limelight.app.js | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/apps.json b/apps.json index 64b5c358e..3e63507c7 100644 --- a/apps.json +++ b/apps.json @@ -5453,7 +5453,7 @@ "id": "limelight", "name": "Limelight Clock", "version": "0.01", - "description": " Simple configurable analogue clock based on the work of @Andreas_Rozek (Simple_Clock)", + "description": "Simple configurable analogue clock based on the work of @Andreas_Rozek (Simple_Clock)", "icon": "limelight.png", "screenshots": [{"url":"screenshot_limelight.png"}], "type": "clock", diff --git a/apps/limelight/limelight.app.js b/apps/limelight/limelight.app.js index c4a599c96..af4a99a38 100644 --- a/apps/limelight/limelight.app.js +++ b/apps/limelight/limelight.app.js @@ -46,7 +46,7 @@ const CenterY = (g.getHeight()/2) + (Bangle.appRect.y/2); const outerRadius = (g.getHeight() - Bangle.appRect.y)/2; function debug(o) { - //console.log(o); + console.log(o); } debug("limelight.app.js"); @@ -55,6 +55,7 @@ debug("CenterY=" + CenterY); debug("outerRadius=" + outerRadius); debug("y12=" + (CenterY - outerRadius)); debug("y6=" + (CenterY + outerRadius)); +debug("appRect=" + Bangle.appRect); const HourHandLength = outerRadius * 0.5; const HourHandWidth = 2*3, halfHourHandWidth = HourHandWidth/2; From a31b22d3fbad98d3b325fc7f46e4a1c8bfd5f292 Mon Sep 17 00:00:00 2001 From: hughbarney Date: Fri, 7 Jan 2022 00:38:15 +0000 Subject: [PATCH 130/315] limelight sorted icon and png --- apps/limelight/limelight.app.js | 42 +++++++++++++++++---------- apps/limelight/limelight.icon.js | 2 +- apps/limelight/limelight.png | Bin 929 -> 318 bytes apps/limelight/limelight.settings.js | 6 ++-- 4 files changed, 31 insertions(+), 19 deletions(-) diff --git a/apps/limelight/limelight.app.js b/apps/limelight/limelight.app.js index af4a99a38..f41b050d1 100644 --- a/apps/limelight/limelight.app.js +++ b/apps/limelight/limelight.app.js @@ -41,6 +41,16 @@ function loadSettings() { var UPDATE_PERIOD; var drawTimeout; + +/* + * This calculation assumes that there will never be widgets on the + * bottom but it could just as easily be adjusted. If only 1 widget + * is loaded at the top Bangle.appRect changes to report as if + * widgets were loaded at the bottom as well. The other option would + * be for Bangle.appRect to adjust for different combinations EG: no + * widgets, wigets on top, widgets on bottom and widgets on top and + * bottom areas. + */ const CenterX = g.getWidth()/2; const CenterY = (g.getHeight()/2) + (Bangle.appRect.y/2); const outerRadius = (g.getHeight() - Bangle.appRect.y)/2; @@ -96,22 +106,6 @@ function transformPolygon (originalPolygon, OriginX,OriginY, Phi) { } } -function setNumbersFont() { - if (settings.vector) { - g.setFont('Vector', settings.vector_size); - return; - } - - if (settings.font == "GochiHand") - g.setFontGochiHand(); - else if (settings.font == "Grenadier") - g.setFontCabinSketch(); - else if (settings.font == "Monoton") - g.setFontMonoton(); - else - g.setFontLimelight(); -} - function drawNumbers() { g.setColor(g.theme.fg); setNumbersFont(); @@ -157,6 +151,22 @@ function drawHands () { } } +function setNumbersFont() { + if (settings.vector) { + g.setFont('Vector', settings.vector_size); + return; + } + + if (settings.font == "GochiHand") + g.setFontGochiHand(); + else if (settings.font == "Grenadier") + g.setFontGrenadierNF(); + else if (settings.font == "Monoton") + g.setFontMonoton(); + else + g.setFontLimelight(); +} + function draw() { g.setColor(g.theme.bg); g.fillRect(Bangle.appRect); diff --git a/apps/limelight/limelight.icon.js b/apps/limelight/limelight.icon.js index 06f93e2ef..9e886bbf8 100644 --- a/apps/limelight/limelight.icon.js +++ b/apps/limelight/limelight.icon.js @@ -1 +1 @@ -require("heatshrink").decompress(atob("mEwwIdah/wAof//4ECgYFB4AFBg4FB8AFBj/wh/4AoM/wEB/gFBvwCEBAU/AQP4gfAj8AgPwAoMPwED8AFBg/AAYIBDA4ngg4TB4EBApkPKgJSBJQIFTMgIFCJIIFDKoIFEvgFBGoMAnw7DP4IFEh+BAoItBg+DNIQwBMIaeCKoKxCPoIzCEgKVHUIqtFXIrFFaIrdFdIwAV")) +require("heatshrink").decompress(atob("lksgIqngf/wAFC//+AgUch/4AgMBwAQEh/8Dgf/4AKOEAQKCAYUB//gAoU/DQkPBQYVBGx5SDBQIbDBR0GEAlgFYcHGwh4B+CDHRwL04")); diff --git a/apps/limelight/limelight.png b/apps/limelight/limelight.png index cf057046be6eca51564a213bc3e7307271464009..b1744b28eab888dc537519f74401e020471b0b7e 100644 GIT binary patch literal 318 zcmV-E0m1%>P)Px#_(?=TR9Hvtn9&M=APhz4|9`Y$B#4yV%`Fpd&#{ij>(r8nWZCFR1P-1p8V(jL zG`x-Bobm3MQkhuWGaU&HXpd+Cp8{@SpFWNZNCWNyJo@0TfRPj;z@-jqdCD+>0RuGL zOF}Y?=J(8c^zrfySOe=0{06st<7ffCfOR)~x5!5W(Z*ppa2=oqeEFi&LKE21hc%Xe zV;DUE5txza445KOHv^=9qB|f`%e--H3yiF6#4u{tY`DhChL^4Q9~j~`7LX9JB(!Q` zf!g{&{RcFW&Q~mny+EQd5wRkG(GU|*v#i00#krWf=gz{s+-Te{nPTqF`ObG{=bo84 z7wV|v|Hht3JPkk}FaUG|9Y7m!Ao=|p@Bx?yW`SwoCGazne{UQEt^-TJmSbB2t^w^e zR}HiRcY*JgVs~m~;0|!8R^p4mY6RiBtpaENr0^Uv>(vCT0r!Cspcg0r`;t~jo{azx zfb|`CCKF##(F8oL;_xjnl#FrV8%ADg6Xz30z8#UnEWQMc5jI;nU_9Z{{Eq{QD8L7t!&STXpy9ZFm@kj^1Fem7{l-O!eBYr8>b)d^b3W}9W~#A6U*g95Oi>^=c4 z)~Zv`8K;EXvhfK3pp)!7am&FTkR7(HNX8sFd;lS+^%_N}!U1DH{Ly|K9>B#6_hueBM`PvzgXPMrIx>vGBiU)6Z4 zEpn3sb9fkCLB-z-YcKpmwJ#|r9RWl zC5~dFfRx^~zcZo4lLpcS%$dU%U1Vo|3%C)3JcraOHF*iC9^?bK^S~v{rNu|U-T>|j zG$FN0?PUAC7)9=|wrEE3yiS#A@zILA+sGlcN|VDaIFIb+1>`8+h@2|>kwB-& z?yx%JM4NdN29eBAO@MFvNQ4*G7A;7*Pj7ZUZ3CJ0gS8T$MjKKwTeK9b&o&dl(GUSK zKeKitb( { - settings.vector_size = v; + s.vector_size = v; save(); } }, From 32a1d048770859131aadb4b34fb58ed37ff61b89 Mon Sep 17 00:00:00 2001 From: hughbarney Date: Fri, 7 Jan 2022 01:00:22 +0000 Subject: [PATCH 131/315] Limelight - screenshots --- apps/limelight/README.md | 11 +++++++++-- apps/limelight/screenshot_gochihand.png | Bin 0 -> 2332 bytes apps/limelight/screenshot_grenadier.png | Bin 0 -> 2376 bytes apps/limelight/screenshot_limelight.png | Bin 2180 -> 2425 bytes apps/limelight/screenshot_monoton.png | Bin 0 -> 3032 bytes 5 files changed, 9 insertions(+), 2 deletions(-) create mode 100644 apps/limelight/screenshot_gochihand.png create mode 100644 apps/limelight/screenshot_grenadier.png create mode 100644 apps/limelight/screenshot_monoton.png diff --git a/apps/limelight/README.md b/apps/limelight/README.md index aa0c359b9..f1cc52092 100644 --- a/apps/limelight/README.md +++ b/apps/limelight/README.md @@ -1,11 +1,18 @@ # Limelight * Simple configurable analogue clock based on the work of @Andreas_Rozek [Simple_Clock](https://github.com/espruino/BangleApps/tree/master/apps/simple_clock)* -![](screenshot_limelight.jpg) +![](screenshot_limelight.png) * Selection of different fonts +* Settings menu where you can select font, or switch to Vector font and try a range of sizes * 100 less lines of code, demonstrating that there is no need for a custom widget draw method -Written by: [Hugh Barney](https://github.com/hughbarney) For support and discussion please post in the [Bangle JS +![](screenshot_gochihand.png) +![](screenshot_monoton.png) +![](screenshot_grenadier.png) + +Many thanks for @Andreas_Rozek for his pioneering work on building a toolkit for the Bangle 2. + +Limelight Written by: [Hugh Barney](https://github.com/hughbarney) For support and discussion please post in the [Bangle JS Forum](http://forum.espruino.com/microcosms/1424/) diff --git a/apps/limelight/screenshot_gochihand.png b/apps/limelight/screenshot_gochihand.png new file mode 100644 index 0000000000000000000000000000000000000000..af405c0f8406505893cedcbac16da25ea1e27804 GIT binary patch literal 2332 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 BY>NN@ literal 2180 zcmeHJ`!m~#7LSNFq7QG4TD79mCYD=m?;?bf2t`|^K}kwI(xOFMA!V(vUOPogqtPx) zwBp$kY0?!DtKZ#A>(yv(SCxupNUsVNgnHLaXZH8|2i$vR&iR}<^O^a~oSE~PlXvO_ zX(z%Q0f9hv`uY$~YmoOf;oCH|S*W0DK?8cLOw|IFED~c|;Q4-U9~) zer&36Ls`wW^pT=>0|PeRk*>q{zySHX*^Cw=)L&!OKwFX}`itSpWNT98-xPg%uxZ<5 zs4MIF3-B+3s;8nnb6!6g&&Cpa+netS1h0@1+9x^o^0CFRvPq};>_>>_ZU z^1+0+VpY!T_nuaB-G<4tc0hj`xNIi=Nb0$X6B|dI`!*XiiH{KIX!W3AIF)I_YHC0? zbzFaCdNd5rTTD0tqjs>*4Q6j_N5VJGd`Wap>^nK$QqHQy7kg+re6g|DC0~!VyRF}$ zs~d`J@2uK8Z5(?}GCJSdq&tTthCA$jc@WOi#vUksati`=@H!c#qXi?MvWZ4&!Kgp6 z|3E!L|0sk!f72+0wg`jAzle+B=E23oV;>ea@8C&%B^1r0nM8 zj{NDAH%t<8(mwMdaQM{Y0)|fDd%PJ!m6*RfW70f=EWgz*_4EDvM7(22ZUfb9eyW$U z2A9r5)rc5$JIRf7+o#yyL0S+xWI+-2!RS5HBLL3q0QT~c1e>I5oBgs!cZ)U+tc$FNDaHL27xA$IjEyF>+Y?g%2qrelFW z)-KN!oDW9fX!kErM5lo?mQdZY$Crc0_b!XFyvOaOZC7HUMSr{mgLPl&o*d*@qtD*h zp|&SeM6aQwR~T{j`9lKXSbx={^{M`XH>fh9-&5}BK>!ts>t6RQ(hr-b#gvLZH$LNz z^1%@1@?ITwspu=E7(^|23ma#+j#sJZ_R$xT8^kK&-M~u%3G#-?Xy%yPt0R-FC6w=o6mQcEU8hw(~o#iq-) zJkx57KP%jg`l*f|i5M$sOGL3tkeoy^VTuV2W8b>0M{SpgGTak# zL6mh`f#X`vq!PUZKg5%iBebwuu$J-KpUWW7$9cuH{n;RS)Hq1v-A4l#8e#fx^M5%X zuQ4p!#XN#^;Ro4;+U8O|1uO zZL`7nDn*!vVe);~pBkGBV7dNZ?0;vCD`qy|{M+>()y}q>w*ulzJVD@kM&|qnB+=s~ diff --git a/apps/limelight/screenshot_monoton.png b/apps/limelight/screenshot_monoton.png new file mode 100644 index 0000000000000000000000000000000000000000..d17d9bd26e9795c28c427f37ca8407db63b3f5b8 GIT binary patch literal 3032 zcmcJR`8U*y8^=GNkHMHxjJ+Dfbdhzs8d2E>Nw$!6G>v3WQ3@0Jj4n|cuRMxQ# z#pt8UO^d9PU4s-MDT9mZ>weGq{t4e7p67kev%JoE&Uwyxp2U-OmOC)JF#rJUusUw; zxUH;z4K1|os~bO1w*|cHXh{aD-s0x~0DITU-1Jlgbun-B>Vlf6dGoJd#g{V-mCVrO z5-fX%ixD!H(at?Avk`Gd}BrEcAa6w8o%K#c##rUfSuvJrQbUf;+GC&xS!^Njf= z&Kp?i-36)$C{~()O|DuT#+|5I=$i9PQx!xyf1Gs8BplSVW!glTm&zwTiZTDAE_-Rk z^4tPl5FH|*47Msf?@ZDKwdc!ja|>jk%3Q~eAV$z)#ZS^^!VvymH30sch~LkXEEA>BF zJHx=kS5|(m8YXbHOYZj)braZW=0RP#^j^eO6gd(D;h4!%XNY^H+F#eSu@4*tW(|8O&{k7TRF_+shqJ@><)?w=3eJv8$kWKHRe{{InfFup;N~Gz6 zUm9ep_R7d_SM75tPr<>Y_o#^6y^swI3g!oqVaAxhb0394dREa&zl3I0r8cQ<)>(XP zN-$#&qFMQPs3Pc~G_Thd`{mc?mrBUfV{-tZ((Fm9!|F|j&xL?(Kz$J6PN#7P*K|87 zT20QbJJ)3$R}Z6!B^fQ5MAWq8`l((YZq&{YBGPN(*1hHnKNYk0A}|#l;lUk<`jhJV zT|hHjKTu#5vRaHuRdV|nZfa>=p6jRA5rffEHMGFGn*9|lC^ zvczd7#ySWm)Q~p323d*QpoxWfvNVKb8;jXanTR2sbvuy(W0j~ZPPGgur1lN)T>1n# ziQ1y8HN`-o*>Aubj41jZjSPc0L!b^4c&_p<(_D_Xw%Ky1yI@{wFOujH6a9YItBO{i z$b}n`xXgsW_s%;)RNDW@lnw2lG-On&fBjAJl7x|6_DcYKdrI#6CG^ND4=}Id!gwyLc7TOfN%tDVDqfxZX7V z!te}*jAq&Da7VBqOOuMvD_(U)(@rbjvrs{Nd}B2~!O}y2KMc&cuA3c6E1N#vmNHr?_5-qu^}-6d_%5I;NU)-x8OL474{g z4f{Xs|$#rh%Ry`6Son2A8ZV<$RKYi-X%Mc(szg%YKo) z?^U7mjK=YRyXrNT!mt z65s1#a725nx9CO{4T}nIKakV!7&jXGXZmyiV64=1M3MrvC`1g353Rt}5w+u}u^hyO- zjeTP>W>f8p!-qzUaz&$KIN8^-i!B1|8gAr$6DcTNH>v9Q`R z(uWJ$!Cbv8-Qy8YUv;-om#57YS#O3{N_5)_a{Ttgxskfnm$yj@(R~3W7kHKwEqAEj zo(VbfgE!qifcc$vP8g)OIW+jet+xxn~Z*$>c+53Np$zg$BGyI|}<4wo0 z4h1!Yulc#=;DynfxTro~Qf)!R=|KIoQuu1WSC~Uabi6Itgu(|Xxm_Wh&;P#Wk4?>< zKLwLgN~Fx~3EftUMjFfY;@P}XKH~pM`C9ZWzW!P~|1s9gnfO4F6O!F)CzD0uAgrOcg?M=#RRGavKgJjP`Qk@i3fowI0a zeQa%X2>SglGJNOoiLdW?%Ccd>T*C~;^NXI}`aYtDvL<>*J8&US1iYj?52zwSh7J*_ zCvtw|IGD*6eqL#c><+Ns{(UpD;?|Fg-5Ak8 zKTz&TLK=I#YAarmxMFz^Ms}C))A0Gstnw_YFgGpdh@@IYE%ZrpQ9|@M@#1S9 z2~hM!OVdEYK4WHyw(%dp5y!F7fRvFNRO2zbm)-pacfT5L2OHAZuT$g`*p>>x9D~fp zE+T}tAwi0@l5Om^Of Date: Fri, 7 Jan 2022 01:02:43 +0000 Subject: [PATCH 132/315] Limelight - screenshots --- apps.json | 1 + 1 file changed, 1 insertion(+) diff --git a/apps.json b/apps.json index 3e63507c7..00a2b9860 100644 --- a/apps.json +++ b/apps.json @@ -5455,6 +5455,7 @@ "version": "0.01", "description": "Simple configurable analogue clock based on the work of @Andreas_Rozek (Simple_Clock)", "icon": "limelight.png", + "readme":"README.md", "screenshots": [{"url":"screenshot_limelight.png"}], "type": "clock", "tags": "clock", From 0dec5b608a9bb374a5be61b503e7032599cafbf2 Mon Sep 17 00:00:00 2001 From: hughbarney Date: Fri, 7 Jan 2022 01:07:20 +0000 Subject: [PATCH 133/315] Limelight - apps.json update --- apps.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps.json b/apps.json index 00a2b9860..91ef1450a 100644 --- a/apps.json +++ b/apps.json @@ -5451,9 +5451,9 @@ }, { "id": "limelight", - "name": "Limelight Clock", + "name": "Limelight", "version": "0.01", - "description": "Simple configurable analogue clock based on the work of @Andreas_Rozek (Simple_Clock)", + "description": "Simple analogue clock (with configurable fonts) based on the work of @Andreas_Rozek (Simple_Clock)", "icon": "limelight.png", "readme":"README.md", "screenshots": [{"url":"screenshot_limelight.png"}], From fe66e54b4fdfc7b9f34bb8874c57bf537287cf45 Mon Sep 17 00:00:00 2001 From: hughbarney Date: Fri, 7 Jan 2022 01:48:39 +0000 Subject: [PATCH 134/315] Limelight fix icon --- apps/limelight/limelight.icon.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/limelight/limelight.icon.js b/apps/limelight/limelight.icon.js index 9e886bbf8..f7e74db90 100644 --- a/apps/limelight/limelight.icon.js +++ b/apps/limelight/limelight.icon.js @@ -1 +1 @@ -require("heatshrink").decompress(atob("lksgIqngf/wAFC//+AgUch/4AgMBwAQEh/8Dgf/4AKOEAQKCAYUB//gAoU/DQkPBQYVBGx5SDBQIbDBR0GEAlgFYcHGwh4B+CDHRwL04")); +require("heatshrink").decompress(atob("lksgIqngf/wAFC//+AgUch/4AgMBwAQEh/8Dgf/4AKOEAQKCAYUB//gAoU/DQkPBQYVBGx5SDBQIbDBR0GEAlgFYcHGwh4B+CDHRwL04")) \ No newline at end of file From aa47b7fa99cceb520f7684a8e05bd995fd828de1 Mon Sep 17 00:00:00 2001 From: Marco Heiming Date: Fri, 7 Jan 2022 09:53:40 +0100 Subject: [PATCH 135/315] Hopefully fix bug where no HRM data is received --- apps/circlesclock/app.js | 67 +++++++++++++++++++++------------------- 1 file changed, 35 insertions(+), 32 deletions(-) diff --git a/apps/circlesclock/app.js b/apps/circlesclock/app.js index b5ee61c75..392fa4287 100644 --- a/apps/circlesclock/app.js +++ b/apps/circlesclock/app.js @@ -9,6 +9,7 @@ const powerIconGreen = heatshrink.decompress(atob("h0OwYQNkAEDpAEDiQEDkmSAgUJkmA const powerIconRed = heatshrink.decompress(atob("h0OwYQNoAEDyAEDkgEDpIFDiVJBweSAgUJkmAAoYZDgQpEBwYAJA")); let settings; + function loadSettings() { settings = require("Storage").readJSON("circlesclock.json", 1) || { 'minHR': 40, @@ -60,10 +61,10 @@ function draw() { if (!showWidgets) { /* - * we are not drawing the widgets as we are taking over the whole screen - * so we will blank out the draw() functions of each widget and change the - * area to the top bar doesn't get cleared. - */ + * we are not drawing the widgets as we are taking over the whole screen + * so we will blank out the draw() functions of each widget and change the + * area to the top bar doesn't get cleared. + */ if (WIDGETS && typeof WIDGETS === "object") { for (let wd of WIDGETS) { wd.draw = () => {}; @@ -97,7 +98,7 @@ function draw() { function drawCircle(index, defaultType) { const type = settings['circle' + index] || defaultType; - const w = index == 1 ? w1: index == 2 ? w2 : w3; + const w = index == 1 ? w1 : index == 2 ? w2 : w3; switch (type) { case "steps": @@ -114,12 +115,13 @@ function drawCircle(index, defaultType) { break; } } + function getCirclePosition(type, defaultPos) { for (let i = 1; i <= 3; i++) { const setting = settings['circle' + i]; - if (setting == type) return i == 1 ? w1: i == 2 ? w2 : w3; + if (setting == type) return i == 1 ? w1 : i == 2 ? w2 : w3; } - return defaultPos; + return defaultPos || undefined; } function isCircleEnabled(type) { @@ -229,8 +231,7 @@ function drawBattery(w) { if (Bangle.isCharging()) { color = colorGreen; icon = powerIconGreen; - } - else { + } else { if (settings.batteryWarn != undefined && battery <= settings.batteryWarn) { color = colorRed; icon = powerIconRed; @@ -289,39 +290,41 @@ function getSteps() { return 0; } +function enableHRMSensor() { + Bangle.setHRMPower(1, "circleclock"); + if (hrtValue == undefined) { + hrtValue = '...'; + drawHeartRate(); + } +} + Bangle.on('lock', function(isLocked) { if (!isLocked) { if (isCircleEnabled("hr")) { - Bangle.setHRMPower(1, "watch"); - if (hrtValue == undefined) { - hrtValue = '...'; - drawHeartRate(); - } + enableHRMSensor(); } draw(); } else { - if (isCircleEnabled("hr")) { - Bangle.setHRMPower(0, "watch"); - } + Bangle.setHRMPower(0, "circleclock"); } }); -if (isCircleEnabled("hr")) { - Bangle.on('HRM', function(hrm) { - //if(hrm.confidence > 90){ - hrtValue = hrm.bpm; - if (Bangle.isLCDOn()) - drawHeartRate(); - //} else { - // hrtValue = undefined; - //} - }); -} -if (isCircleEnabled("battery")) { - Bangle.on('charging', function(charging) { - drawBattery(); - }); +Bangle.on('HRM', function(hrm) { + if (isCircleEnabled("hr")) { + hrtValue = hrm.bpm; + if (Bangle.isLCDOn()) + drawHeartRate(); + } +}); + + +Bangle.on('charging', function(charging) { + if (isCircleEnabled("battery")) drawBattery(); +}); + +if (isCircleEnabled("hr")) { + enableHRMSensor(); } Bangle.setUI("clock"); From 2f16365e6cf6b4ad9717770e4103b6d52a4f6fe2 Mon Sep 17 00:00:00 2001 From: Marco Heiming Date: Fri, 7 Jan 2022 10:26:45 +0100 Subject: [PATCH 136/315] Redraw background rectangle before drawing circles (fixes graphical glitch) --- apps/circlesclock/app.js | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/apps/circlesclock/app.js b/apps/circlesclock/app.js index 392fa4287..4f2fea4ab 100644 --- a/apps/circlesclock/app.js +++ b/apps/circlesclock/app.js @@ -131,6 +131,11 @@ function isCircleEnabled(type) { function drawSteps(w) { if (!w) w = getCirclePosition("steps", w1); const steps = getSteps(); + + // Draw rectangle background: + g.setColor(colorBg); + g.fillRect(w - radiusOuter - 3, h3 - radiusOuter - 3, w + radiusOuter + 3, h3 + radiusOuter + 3); + g.setColor(colorGrey); g.fillCircle(w, h3, radiusOuter); @@ -160,6 +165,10 @@ function drawStepsDistance(w) { const stepDistance = settings.stepLength || 0.8; const stepsDistance = Math.round(steps * stepDistance); + // Draw rectangle background: + g.setColor(colorBg); + g.fillRect(w - radiusOuter - 3, h3 - radiusOuter - 3, w + radiusOuter + 3, h3 + radiusOuter + 3); + g.setColor(colorGrey); g.fillCircle(w, h3, radiusOuter); @@ -185,6 +194,11 @@ function drawStepsDistance(w) { function drawHeartRate(w) { if (!w) w = getCirclePosition("hr", w2); + + // Draw rectangle background: + g.setColor(colorBg); + g.fillRect(w - radiusOuter - 3, h3 - radiusOuter - 3, w + radiusOuter + 3, h3 + radiusOuter + 3); + g.setColor(colorGrey); g.fillCircle(w, h3, radiusOuter); @@ -210,6 +224,11 @@ function drawHeartRate(w) { function drawBattery(w) { if (!w) w = getCirclePosition("battery", w3); const battery = E.getBattery(); + + // Draw rectangle background: + g.setColor(colorBg); + g.fillRect(w - radiusOuter - 3, h3 - radiusOuter - 3, w + radiusOuter + 3, h3 + radiusOuter + 3); + g.setColor(colorGrey); g.fillCircle(w, h3, radiusOuter); @@ -319,6 +338,12 @@ Bangle.on('HRM', function(hrm) { }); +Bangle.setUI("clock"); +Bangle.loadWidgets(); + +draw(); +setInterval(draw, 60000); + Bangle.on('charging', function(charging) { if (isCircleEnabled("battery")) drawBattery(); }); @@ -326,9 +351,3 @@ Bangle.on('charging', function(charging) { if (isCircleEnabled("hr")) { enableHRMSensor(); } - -Bangle.setUI("clock"); -Bangle.loadWidgets(); - -draw(); -setInterval(draw, 60000); From 96802b0bd48e50ba721b157590d23e3fad8963dd Mon Sep 17 00:00:00 2001 From: Marco Heiming Date: Fri, 7 Jan 2022 10:32:39 +0100 Subject: [PATCH 137/315] Make min- & maxHR settings more granular --- apps/circlesclock/settings.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/circlesclock/settings.js b/apps/circlesclock/settings.js index 95ebc17db..a16bb99a8 100644 --- a/apps/circlesclock/settings.js +++ b/apps/circlesclock/settings.js @@ -15,7 +15,7 @@ value: "minHR" in settings ? settings.minHR : 40, min: 0, max : 250, - step: 10, + step: 5, format: x => { return x; }, @@ -25,7 +25,7 @@ value: "maxHR" in settings ? settings.maxHR : 200, min: 20, max : 250, - step: 10, + step: 5, format: x => { return x; }, From c47cabe156e3e03756492be8ed34b8bc31854d98 Mon Sep 17 00:00:00 2001 From: Marco Heiming Date: Fri, 7 Jan 2022 10:43:06 +0100 Subject: [PATCH 138/315] Update ChangeLog --- apps/circlesclock/ChangeLog | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/circlesclock/ChangeLog b/apps/circlesclock/ChangeLog index f416929ac..4230c1468 100644 --- a/apps/circlesclock/ChangeLog +++ b/apps/circlesclock/ChangeLog @@ -1,4 +1,7 @@ 0.01: New clock 0.02: Fix icon & add battery warn functionality 0.03: Theming support & minor fixes -0.04: Make configurable what to show in each circle; add step distance circle; allow switching visibility of widgets +0.04: Make configurable what to show in each circle + Add step distance circle + Allow switching visibility of widgets + Make circles and text slightly bigger From b0238957b6be2c3ec4b41bcd214c1b25919ff39c Mon Sep 17 00:00:00 2001 From: Peter Slendebroek Date: Fri, 7 Jan 2022 12:56:53 +0100 Subject: [PATCH 139/315] fix update mmind.icon,js from 176px to 48px --- apps/mmind/mmind.icon.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/mmind/mmind.icon.js b/apps/mmind/mmind.icon.js index 976243b48..17c28ba0f 100644 --- a/apps/mmind/mmind.icon.js +++ b/apps/mmind/mmind.icon.js @@ -1 +1 @@ -require("heatshrink").decompress(atob("2GwxH+64A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A6gAAFEf5I/VtpEcEcZI/Dw4PbCQu0AApnZDIUeAAqLaDQUFAApIc3IAFEabHPa6StJWLKtJWLStJWLKtJWKieFChIPPCYquKWAZmUVxSwDV6quKWAYjUVxSwDVqQUIB56uTWCiuOWCquOWCiuOWByaFV5oPLVyiwSVyCwTVyCwSVyCwNTIqvMB5iv/V/6vQUpQPTVyqwQVySwRVySwQVySwNT6Kv/V/6v/V/6v/V/6v/V/6v/V/6v/V/6v/V/6v/V/6vvWCZBSV0CwUJCSuhV/6v/V/4PPWCBBRWCIjSWCJIUV0CvfWB6KTWB4jUWB5IWVz6viWBYdPEZCuMV6ywLJDCuMV+SxLRKyxMEbKxKJDitXCAQALB6AoTRS4jkJHyvoFRCJZEcxI8V9DyZEdpI/ZaQpTB4W0AApnZDIUFAAqLaDQXSAApIckYAFEaTLPbaatJWLKtJWLStJWLKtJWKaeKDAgPPEgyuKWAZmUVxSwDV6quKWAYjUVxSwDV7AZDB56uSWCiuOWCquOWCiuOWByWJBAoPPVyiwSVyCwTVyCwSVyCwNSpIKLB5qv/V/6vuVySwQVySwRVySwQVySwMV/6v/V/6uRV/6v/V8wNDV/6v/V9SuJV/6v/V8atEV/6v/V9KtLV/6v/V8SuNWCiKPWCYjQWCZISVzavSVopGLV/6v/V8RDPVz6wSEaSwRJCiuaV6KuSWCCKTWB4jUWB5IWVzKvKVAyuTCgauMMyqwLEaokDVxhIWVxgjNT46uKIiytcWJojZWJRIcVqygGAA4OOFhYUUJbIjYJH4bOV7AaIRLIjmJH4bMV7QA/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A+goAHEbUeAA5s/ADO0ADitRWLStIWP6v/VxywWVxiw/V/quOWCiuOWH6v7VyCwSVyCw/V/6v/AH6vpVySwQVySw/V/6v/ABMAAAaXeEa6v/V+SKEWDwjYV/6v/V/6v/V/6v/V/6v/V/6v/V/6v/V+SMFVzgjZV/6vzAHaviWCZHQV36v/V/6v/V/awRJCSu/V/6vLWB5JUV36v/V5awNJSyu/V/6vLWJRMaVv6v/V5YA/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4AkA=")) +require("heatshrink").decompress(atob("mEwxH+64A/AEOBq2sBAusqwJHCaQFDAYlP2m0yGBCIkSj0eiWHBIkDgsFgYTE01v3O5t4mC1krgAEBq0ACYQuCAANsHIcxFwIwCEocsFwIwCBIYuCAANQF4QwBOgQABAgNIF4ZgELwQvCHIcCF4cEKwYvEt45DF4QwCL5YvFL5ITDF6OstheCvTjEjAuBjDJFX4UEq4TEyguBygTEF4dWBIeskkkqwQDDgUGgwaEBIUBgITHkslCYeBd4MrqwDBAgIuBcwRVGNIVs0oJEv3S6V+CYmIisjkcVZAYpBgDyBAAJFBFwTlGZIolDqouBGAQJDFwQABmRfCFAICCGwXXhgvDMAheCfI1UF4eoKwYvEiovHSoJfLF4pfJCYYvN1gwBAYMSLwVcbQmQFwOQZIq/C1GACYkcFwMcCYQoCLYNWF4KPBDgNWmIkEBIVPp5TDBIdWqoTHmUyCYlWRQTwCD4wA/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AHmy2QJH6PRBI/Q6AkOCAIAFBINDjwABGInR3+53O/GIu72gABGJnQCAQAE69oFwQABCYfFFwIwCBIfCDIe7FIus1gvXLwQACLw4aCAAkAgAvcL4gvLq1WF5uyFwdoCYfLF4fLDpHCX6owBtFoxoUF6PF4ruFDwPC4XJFxbSCAAwVNAH4ARA")) From 2fe1ea524d2d6c0882edcd04ed96c39772aa30df Mon Sep 17 00:00:00 2001 From: Peter Slendebroek Date: Fri, 7 Jan 2022 13:15:54 +0100 Subject: [PATCH 140/315] correct some typo's --- apps/mmind/README.md | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/apps/mmind/README.md b/apps/mmind/README.md index ea584b7e7..8060b95f6 100644 --- a/apps/mmind/README.md +++ b/apps/mmind/README.md @@ -7,15 +7,14 @@ Play the classic mind game mastermind on your Bangle 2. ## Game The game will start when run. -Four colors pins are randomly choosen and kept secret. -You need to find the secret by scoring your choise within 6 turns. +Four colors pins are randomly chosen and kept secret. +You need to find the secret by scoring your choice within 6 turns. The game makes use of touch features. ## Play -The screen needs to be unlocked. Select one of the dots, the color menu will show, select a colour for the pin. -If all pins are choosen with a color the red button will turn green. +If all pins are chosen with a color the red button will turn green. Hit the green button and your play will be scored and listed from the top. The first digit shows the number of pins with the correct color and in the right place. The second digit gives the number of pins with the correct color but in the wrong place. @@ -24,12 +23,9 @@ The blue button will start a new game. ## Requests - -This is the first version, things to add are:/ -Add a menu to change game options like the number of colors, allow double colors, 5 pins per row./ -Add feature to drag screen up and down to see more scores./ -Timer and high score./ +This is the first version, things to add are: +Add a menu to change game options like the number of colors, allow double colors, 5 pins per row. Add feature to drag screen up and down to see more scores. Timer and high score. +Any other fearures or remarks, let me know @psbest. ## Creator - This game is created by Peter Slendebroek. From 2397f5957acc41e9eb91c4da6e65d50901debcca Mon Sep 17 00:00:00 2001 From: Marco Heiming Date: Fri, 7 Jan 2022 13:30:09 +0100 Subject: [PATCH 141/315] Add weather functionality Improve circle position finding --- apps/circlesclock/ChangeLog | 2 +- apps/circlesclock/README.md | 4 +- apps/circlesclock/app.js | 138 +++++++++++++++++++++++++++++----- apps/circlesclock/settings.js | 10 +-- 4 files changed, 126 insertions(+), 28 deletions(-) diff --git a/apps/circlesclock/ChangeLog b/apps/circlesclock/ChangeLog index 4230c1468..ca1da6e21 100644 --- a/apps/circlesclock/ChangeLog +++ b/apps/circlesclock/ChangeLog @@ -2,6 +2,6 @@ 0.02: Fix icon & add battery warn functionality 0.03: Theming support & minor fixes 0.04: Make configurable what to show in each circle - Add step distance circle + Add step distance and weather Allow switching visibility of widgets Make circles and text slightly bigger diff --git a/apps/circlesclock/README.md b/apps/circlesclock/README.md index 9004161d6..a071efcf5 100644 --- a/apps/circlesclock/README.md +++ b/apps/circlesclock/README.md @@ -9,14 +9,12 @@ It can show the following information (this can be configured): * Steps distance (depending on steps) * Heart rate (automatically updates when screen is on and unlocked) * Battery (including charging status and battery low warning) + * Weather (requires [weather app](https://banglejs.com/apps/#weather)) ## Screenshots ![Screenshot dark theme](screenshot-dark.png) ![Screenshot light theme](screenshot-light.png) -## TODO -* Show weather information - ## Creator Marco ([myxor](https://github.com/myxor)) diff --git a/apps/circlesclock/app.js b/apps/circlesclock/app.js index 4f2fea4ab..23be307b9 100644 --- a/apps/circlesclock/app.js +++ b/apps/circlesclock/app.js @@ -1,5 +1,6 @@ const locale = require("locale"); const heatshrink = require("heatshrink"); +const storage = require("Storage"); const shoesIcon = heatshrink.decompress(atob("h0OwYJGgmAAgUBkgECgVJB4cSoAUDyEBkARDpADBhMAyQRBgVAkgmDhIUDAAuQAgY1DAAYA=")); const shoesIconGreen = heatshrink.decompress(atob("h0OwYJGhIEDgVIAgUEyQKDkmACgcggVACIeQAYMSgIRCgmApIbDiQUDAAkBkAFDGoYAD")); @@ -8,10 +9,19 @@ const powerIcon = heatshrink.decompress(atob("h0OwYQNsAED7AEDmwEDtu2AgUbtuABwXbB const powerIconGreen = heatshrink.decompress(atob("h0OwYQNkAEDpAEDiQEDkmSAgUJkmABwVJBIUEyVAAoYOCgEBFIgODABI")); const powerIconRed = heatshrink.decompress(atob("h0OwYQNoAEDyAEDkgEDpIFDiVJBweSAgUJkmAAoYZDgQpEBwYAJA")); +const weatherCloudy = heatshrink.decompress(atob("h0OwYPMgfwAgU//4FCv///+Ag4DB//gh4EC//jAgYAK+IED8EBAgXAHpQA==")); +const weatherSunny = heatshrink.decompress(atob("h0OwYKHhuAAYM2AQkA7AOD2wFCgdt20AgOA7dtwHAC4PbsAUGgFt2ApIAAgIIA==")); +const weatherPartlyCloudy = heatshrink.decompress(atob("h0OwYOLg4FEn/8AgV+g/gAgMcgE48EB48f/wJBgP/gfwgEDBAIRBC4UH/kB4AmC8F+C4X4gf/AAIaBAAgA==")); +const weatherRainy = heatshrink.decompress(atob("h0OwYKHh/AAgX8AoUB/EAuEAj/wgEDwEHCIX/wIXD8ARB/kAnED+P/8f+BgNwnARCjkOAgUH/+AAoU/IQ4A=")); +const weatherPartlyRainy = heatshrink.decompress(atob("h0OwYJGjkAnAFCj+AAgU//4FCuEA8EAg8ch/4gEB4////AAoIIBCIMD/wgCg4bBg/8BwMD+AgBh4ZBDQf/FIIABh4IBgAA==")); +const weatherSnowy = heatshrink.decompress(atob("h0OwYKHh/AAgUD+AKD/gIDn4LC/4ABBYX8DQYODgYPCAoIOCEAgpGDQRCHA=")); +const weatherFoggy = heatshrink.decompress(atob("h0OwYPMj/+AgU4gFwgED+ACBwEH8AMB/kB4AEBBAYAHg////H/+ABQl+n4LB/A9K")); +const weatherStormy = heatshrink.decompress(atob("h0OwYKHh/AAgX8AoUB/EAuEAj/wgEDwEHCIX/wIRBBwPgAQMcgE4gfwn8D/wpGCgQAQA")); + let settings; function loadSettings() { - settings = require("Storage").readJSON("circlesclock.json", 1) || { + settings = storage.readJSON("circlesclock.json", 1) || { 'minHR': 40, 'maxHR': 200, 'stepGoal': 10000, @@ -48,13 +58,12 @@ const w = g.getWidth(); const hOffset = 30 - widgetOffset; const h1 = Math.round(1 * h / 5 - hOffset); const h2 = Math.round(3 * h / 5 - hOffset); -const h3 = Math.round(8 * h / 8 - hOffset - 3); -const w1 = Math.round(w / 6); -const w2 = Math.round(3 * w / 6); -const w3 = Math.round(5 * w / 6); +const h3 = Math.round(8 * h / 8 - hOffset - 3); // circle y position +const circlePosX = [Math.round(w / 6), Math.round(3 * w / 6), Math.round(5 * w / 6)]; // cirle x positions const radiusOuter = 25; const radiusInner = 18; const circleFont = "Vector:15"; +const circleFontSmall = "Vector:13"; function draw() { g.clear(true); @@ -90,16 +99,17 @@ function draw() { g.drawString(locale.date(new Date()), w > 180 ? 2 * w / 10 : w / 10, h2); g.drawString(locale.dow(new Date()), w > 180 ? 2 * w / 10 : w / 10, h2 + 22); - drawCircle(1, "steps"); - drawCircle(2, "hr"); - drawCircle(3, "battery"); + drawCircle(1); + drawCircle(2); + drawCircle(3); } +const defaultCircleTypes = ["steps", "hr", "battery"]; -function drawCircle(index, defaultType) { - const type = settings['circle' + index] || defaultType; - const w = index == 1 ? w1 : index == 2 ? w2 : w3; - +function drawCircle(index) { + let type = settings['circle' + index]; + if (!type) type = defaultCircleTypes[index - 1]; + const w = getCirclePosition(type); switch (type) { case "steps": drawSteps(w); @@ -113,15 +123,21 @@ function drawCircle(index, defaultType) { case "battery": drawBattery(w); break; + case "weather": + drawWeather(w); + break; } } -function getCirclePosition(type, defaultPos) { +function getCirclePosition(type) { for (let i = 1; i <= 3; i++) { const setting = settings['circle' + i]; - if (setting == type) return i == 1 ? w1 : i == 2 ? w2 : w3; + if (setting == type) return circlePosX[i - 1]; } - return defaultPos || undefined; + for (let i = 0; i < defaultCircleTypes.length; i++) { + if (type == defaultCircleTypes[i]) return circlePosX[i]; + } + return undefined; } function isCircleEnabled(type) { @@ -129,7 +145,7 @@ function isCircleEnabled(type) { } function drawSteps(w) { - if (!w) w = getCirclePosition("steps", w1); + if (!w) w = getCirclePosition("steps"); const steps = getSteps(); // Draw rectangle background: @@ -160,7 +176,7 @@ function drawSteps(w) { } function drawStepsDistance(w) { - if (!w) w = getCirclePosition("steps", w1); + if (!w) w = getCirclePosition("steps"); const steps = getSteps(); const stepDistance = settings.stepLength || 0.8; const stepsDistance = Math.round(steps * stepDistance); @@ -193,7 +209,7 @@ function drawStepsDistance(w) { } function drawHeartRate(w) { - if (!w) w = getCirclePosition("hr", w2); + if (!w) w = getCirclePosition("hr"); // Draw rectangle background: g.setColor(colorBg); @@ -222,7 +238,7 @@ function drawHeartRate(w) { } function drawBattery(w) { - if (!w) w = getCirclePosition("battery", w3); + if (!w) w = getCirclePosition("battery"); const battery = E.getBattery(); // Draw rectangle background: @@ -262,6 +278,85 @@ function drawBattery(w) { g.drawImage(icon, w - 6, h3 + radiusOuter - 6); } +function drawWeather(w) { + if (!w) w = getCirclePosition("weather"); + const weather = getWeather(); + const tempString = weather ? locale.temp(weather.temp - 273.15) : undefined; + const code = weather ? weather.code : -1; + + // Draw rectangle background: + g.setColor(colorBg); + g.fillRect(w - radiusOuter - 3, h3 - radiusOuter - 3, w + radiusOuter + 3, h3 + radiusOuter + 3); + + g.setColor(colorGrey); + g.fillCircle(w, h3, radiusOuter); + + g.setColor(colorBg); + g.fillCircle(w, h3, radiusInner); + + g.fillPoly([w, h3, w - 15, h3 + radiusOuter + 5, w + 15, h3 + radiusOuter + 5]); + + const content = tempString ? tempString : "?"; + g.setFont(content.length < 4 ? circleFont : circleFontSmall); + g.setFontAlign(0, 0); + g.setColor(colorFg); + g.drawString(content, w, h3); + + if (code > 0) { + const icon = getWeatherIconByCode(code); + if (icon) g.drawImage(icon, w - 6, h3 + radiusOuter - 6); + } +} + +/* + * Choose weather icon to display based on weather conditition code + * https://openweathermap.org/weather-conditions#Weather-Condition-Codes-2 + */ +function getWeatherIconByCode(code) { + const codeGroup = Math.round(code / 100); + switch (codeGroup) { + case 2: + return weatherStormy; + case 3: + return weatherCloudy; + case 5: + switch (code) { + case 511: + return weatherSnowy; + case 520: + return weatherPartlyRainy; + case 521: + return weatherPartlyRainy; + case 522: + return weatherPartlyRainy; + case 531: + return weatherPartlyRainy; + default: + return weatherRainy; + } + break; + case 6: + return weatherSnowy; + case 7: + return weatherFoggy; + case 8: + switch (code) { + case 800: + return weatherSunny; + case 801: + return weatherPartlyCloudy; + case 802: + return weatherPartlyCloudy; + default: + return weatherCloudy; + } + break; + default: + return undefined; + } + return undefined; +} + function radians(a) { return a * Math.PI / 180; } @@ -309,6 +404,11 @@ function getSteps() { return 0; } +function getWeather() { + const jsonWeather = storage.readJSON('weather.json'); + return jsonWeather && jsonWeather.weather ? jsonWeather.weather : undefined; +} + function enableHRMSensor() { Bangle.setHRMPower(1, "circleclock"); if (hrtValue == undefined) { diff --git a/apps/circlesclock/settings.js b/apps/circlesclock/settings.js index a16bb99a8..ac4215a8a 100644 --- a/apps/circlesclock/settings.js +++ b/apps/circlesclock/settings.js @@ -6,8 +6,8 @@ settings[key] = value; storage.write(SETTINGS_FILE, settings); } - var valuesCircleTypes = ["steps", "stepsDist", "hr", "battery"]; - var namesCircleTypes = ["steps", "distance", "heart", "battery"]; + var valuesCircleTypes = ["steps", "stepsDist", "hr", "battery", "weather"]; + var namesCircleTypes = ["steps", "distance", "heart", "battery", "weather"]; E.showMenu({ '': { 'title': 'circlesclock' }, '< Back': back, @@ -78,19 +78,19 @@ }, 'left': { value: settings.circle1 ? valuesCircleTypes.indexOf(settings.circle1) : 0, - min: 0, max: 3, + min: 0, max: 4, format: v => namesCircleTypes[v], onchange: x => save('circle1', valuesCircleTypes[x]), }, 'middle': { value: settings.circle2 ? valuesCircleTypes.indexOf(settings.circle2) : 2, - min: 0, max: 3, + min: 0, max: 4, format: v => namesCircleTypes[v], onchange: x => save('circle2', valuesCircleTypes[x]), }, 'right': { value: settings.circle3 ? valuesCircleTypes.indexOf(settings.circle3) : 3, - min: 0, max: 3, + min: 0, max: 4, format: v => namesCircleTypes[v], onchange: x => save('circle3', valuesCircleTypes[x]), } From 209d05e6d68c5748f80b98298aaba1cacc68292a Mon Sep 17 00:00:00 2001 From: Qucchia <45072410+qucchia@users.noreply.github.com> Date: Fri, 7 Jan 2022 16:24:36 +0100 Subject: [PATCH 142/315] Fix alarm not activating --- apps/qalarm/qalarm.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/qalarm/qalarm.js b/apps/qalarm/qalarm.js index 6b31ba645..8e82be186 100644 --- a/apps/qalarm/qalarm.js +++ b/apps/qalarm/qalarm.js @@ -143,7 +143,7 @@ let alarms = require("Storage").readJSON("qalarm.json", 1) || []; let active = alarms.filter( (alarm) => alarm.on && - alarm.t < t && + alarm.t <= t && alarm.last != time.getDate() && (alarm.timer || alarm.daysOfWeek[time.getDay()]) ); From 426ba76ad4012f14072d1694d36510977346665d Mon Sep 17 00:00:00 2001 From: Qucchia <45072410+qucchia@users.noreply.github.com> Date: Fri, 7 Jan 2022 16:25:15 +0100 Subject: [PATCH 143/315] Update ChangeLog --- apps/qalarm/ChangeLog | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/qalarm/ChangeLog b/apps/qalarm/ChangeLog index fb6c751bb..b9be6039d 100644 --- a/apps/qalarm/ChangeLog +++ b/apps/qalarm/ChangeLog @@ -3,3 +3,4 @@ 0.03: Fix unfreed memory, and clearInterval that disabled all clocks at midnight Fix app icon Change menu order so 'back' is at the top +0.04: Fix alarm not activating sometimes. From ab00b477fd39f0304c12cdf407fcbd2d9fa42c16 Mon Sep 17 00:00:00 2001 From: Qucchia <45072410+qucchia@users.noreply.github.com> Date: Fri, 7 Jan 2022 16:25:55 +0100 Subject: [PATCH 144/315] Update apps.json --- apps.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps.json b/apps.json index 3fc0616da..e0c85c2f3 100644 --- a/apps.json +++ b/apps.json @@ -4422,7 +4422,7 @@ "name": "Q Alarm and Timer", "shortName": "Q Alarm", "icon": "app.png", - "version": "0.03", + "version": "0.04", "description": "Alarm and timer app with days of week and 'hard' option.", "tags": "tool,alarm,widget", "supports": ["BANGLEJS", "BANGLEJS2"], From ea71f6a0ead902813e91d065363bcf6b288b7b70 Mon Sep 17 00:00:00 2001 From: Didgeridoohan Date: Fri, 7 Jan 2022 16:39:45 +0100 Subject: [PATCH 145/315] Swedish localisation with English text (en_SE) --- apps/locale/locales.js | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/apps/locale/locales.js b/apps/locale/locales.js index cf511c54f..fea217efe 100644 --- a/apps/locale/locales.js +++ b/apps/locale/locales.js @@ -283,6 +283,24 @@ var locales = { day: "söndag,måndag,tisdag,onsdag,torsdag,fredag,lördag", trans: { yes: "ja", Yes: "Ja", no: "nej", No: "Nej", ok: "ok", on: "on", off: "off" } }, + "en_SE": { // Swedish localisation with English text + lang: "en_SE", + decimal_point: ",", + thousands_sep: ".", + currency_symbol: "kr", + int_curr_symbol: "SKR", + speed: 'kmh', + distance: { "0": "m", "1": "km" }, + temperature: '°C', + ampm: { 0: "", 1: "" }, + timePattern: { 0: "%HH:%MM:%SS ", 1: "%HH:%MM" }, + datePattern: { 0: "%A %B %d %Y", "1": "%Y-%m-%d" }, // Sunday 1 March 2020 // 2020-03-01 + abmonth: "Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec", + month: "January,February,March,April,May,June,July,August,September,October,November,December", + abday: "Sun,Mon,Tue,Wed,Thu,Fri,Sat", + day: "Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday", + // No translation for english... + }, "en_NZ": { lang: "en_NZ", decimal_point: ".", From efc8845c13434357cb7b1afd0d3d1058e572ebce Mon Sep 17 00:00:00 2001 From: Didgeridoohan Date: Fri, 7 Jan 2022 16:42:29 +0100 Subject: [PATCH 146/315] Update ChangeLog --- apps/locale/ChangeLog | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/locale/ChangeLog b/apps/locale/ChangeLog index 448f8119a..1b6f82671 100644 --- a/apps/locale/ChangeLog +++ b/apps/locale/ChangeLog @@ -14,3 +14,4 @@ 0.12: Fixed nl_NL formatting, because the full months won't fit on the Bangle.js2's screen 0.13: Now use shorter de_DE date format to more closely match other languages for size 0.14: Added some first translations for Messages in nl_NL +0.15: Added Swedish localisation with English text From 0a4f2dd5b928528d97194bdcee601c380b881b87 Mon Sep 17 00:00:00 2001 From: Didgeridoohan Date: Fri, 7 Jan 2022 16:43:12 +0100 Subject: [PATCH 147/315] Update apps.json --- apps.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps.json b/apps.json index 3fc0616da..f5a17c37d 100644 --- a/apps.json +++ b/apps.json @@ -218,7 +218,7 @@ { "id": "locale", "name": "Languages", - "version": "0.14", + "version": "0.15", "description": "Translations for different countries", "icon": "locale.png", "type": "locale", From 9e0bef98ae313ccabc7117545f56d302953f7ec9 Mon Sep 17 00:00:00 2001 From: 7kasper <7kasper@users.noreply.github.com> Date: Fri, 7 Jan 2022 16:44:54 +0100 Subject: [PATCH 148/315] Add combination HID to bootupdate. --- apps/boot/bootupdate.js | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/boot/bootupdate.js b/apps/boot/bootupdate.js index 664d64ee7..1b826de5a 100644 --- a/apps/boot/bootupdate.js +++ b/apps/boot/bootupdate.js @@ -18,6 +18,7 @@ boot += `var bleServices = {}, bleServiceOptions = { uart : true};\n`; if (s.ble!==false) { if (s.HID) { // Human interface device if (s.HID=="joy") boot += `Bangle.HID = E.toUint8Array(atob("BQEJBKEBCQGhAAUJGQEpBRUAJQGVBXUBgQKVA3UBgQMFAQkwCTEVgSV/dQiVAoECwMA="));`; + else if (s.HID=="com") boot += `Bangle.HID = E.toUint8Array(atob("BQEJAqEBhQEJAaEABQkZASkFFQAlAZUFdQGBApUBdQOBAwUBCTAJMQk4FYElf3UIlQOBBgUMCjgCFYElf3UIlQGBBsDABQEJBqEBhQIFBxngKecVACUBdQGVCIECdQiVAYEBGQApcxUAJXOVBXUIgQDA"));` else if (s.HID=="kb") boot += `Bangle.HID = E.toUint8Array(atob("BQEJBqEBBQcZ4CnnFQAlAXUBlQiBApUBdQiBAZUFdQEFCBkBKQWRApUBdQORAZUGdQgVACVzBQcZAClzgQAJBRUAJv8AdQiVArECwA=="));` else /*kbmedia*/boot += `Bangle.HID = E.toUint8Array(atob("BQEJBqEBhQIFBxngKecVACUBdQGVCIEClQF1CIEBlQV1AQUIGQEpBZEClQF1A5EBlQZ1CBUAJXMFBxkAKXOBAAkFFQAm/wB1CJUCsQLABQwJAaEBhQEVACUBdQGVAQm1gQIJtoECCbeBAgm4gQIJzYECCeKBAgnpgQIJ6oECwA=="));`; boot += `bleServiceOptions.hid=Bangle.HID;\n`; From 47da82a547e82e29228c3d0a86c2992e71fafb90 Mon Sep 17 00:00:00 2001 From: 7kasper <7kasper@users.noreply.github.com> Date: Fri, 7 Jan 2022 16:48:15 +0100 Subject: [PATCH 149/315] Add HID option to settings. --- apps/setting/settings.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/setting/settings.js b/apps/setting/settings.js index 4bdf7f304..27ce24e50 100644 --- a/apps/setting/settings.js +++ b/apps/setting/settings.js @@ -154,8 +154,8 @@ function showAlertsMenu() { function showBLEMenu() { - var hidV = [false, "kbmedia", "kb", "joy"]; - var hidN = ["Off", "Kbrd & Media", "Kbrd","Joystick"]; + var hidV = [false, "kbmedia", "kb", "com", "joy"]; + var hidN = ["Off", "Kbrd & Media", "Kbrd", "Kbrd & Mouse" ,"Joystick"]; E.showMenu({ '': { 'title': 'Bluetooth' }, '< Back': ()=>showMainMenu(), From 677cd16f8b081c8954bd8242d1a9328e5b3d5778 Mon Sep 17 00:00:00 2001 From: David Peer Date: Fri, 7 Jan 2022 17:26:34 +0100 Subject: [PATCH 150/315] Fixed bug that clock is unresponsive --- apps.json | 2 +- apps/lcars/ChangeLog | 3 ++- apps/lcars/lcars.app.js | 26 ++++++++++---------------- 3 files changed, 13 insertions(+), 18 deletions(-) diff --git a/apps.json b/apps.json index 0f200d53a..20ac0afce 100644 --- a/apps.json +++ b/apps.json @@ -4488,7 +4488,7 @@ "name": "LCARS Clock", "shortName":"LCARS", "icon": "lcars.png", - "version":"0.09", + "version":"0.10", "readme": "README.md", "supports": ["BANGLEJS2"], "description": "Library Computer Access Retrieval System (LCARS) clock.", diff --git a/apps/lcars/ChangeLog b/apps/lcars/ChangeLog index f5d8346da..26aa605e6 100644 --- a/apps/lcars/ChangeLog +++ b/apps/lcars/ChangeLog @@ -6,4 +6,5 @@ 0.06: Fix - Alarm disabled, if clock was closed. 0.07: Added settings to adjust data that is shown for each row. 0.08: Support for multiple screens. 24h graph for steps + HRM. Fullscreen Mode. -0.09: Tab anywhere to open the launcher. \ No newline at end of file +0.09: Tab anywhere to open the launcher. +0.10: Fix - Clock is unresponsive, if gadgetbridge connects. \ No newline at end of file diff --git a/apps/lcars/lcars.app.js b/apps/lcars/lcars.app.js index 8f06abc29..3535f57d5 100644 --- a/apps/lcars/lcars.app.js +++ b/apps/lcars/lcars.app.js @@ -32,8 +32,8 @@ let cGrey = "#9E9E9E"; let lcarsViewPos = 0; let drag; let hrmValue = 0; -var connected = NRF.getSecurityStatus().connected; var plotWeek = false; +var disableInfoUpdate = true; // When gadgetbridge connects, step infos cannot be loaded /* * Requirements and globals @@ -170,7 +170,7 @@ function drawHorizontalBgLine(color, x1, x2, y, h){ } -function drawLock(){ +function drawInfo(){ if(lcarsViewPos != 0){ return; } @@ -179,7 +179,8 @@ function drawLock(){ g.setColor(cOrange); g.clearRect(120, 10, g.getWidth(), 75); g.drawString("LCARS", 128, 13); - if(connected){ + + if(NRF.getSecurityStatus().connected){ g.drawString("CONN", 128, 33); } else { g.drawString("NOCON", 128, 33); @@ -243,8 +244,8 @@ function drawPosition0(){ drawHorizontalBgLine(cOrange, 35, batX2, 171, 5); drawHorizontalBgLine(cGrey, batX2+10, 172, 171, 5); - // Draw logo - drawLock(); + // Draw Infos + drawInfo(); // Write time g.setFontAlign(-1, -1, 0); @@ -467,24 +468,17 @@ function handleAlarm(){ Bangle.on('lcdPower',on=>{ if (on) { // Whenever we connect to Gadgetbridge, reading data from - // health failed. Therefore, we update and read data from - // health iff the connection state did not change. - if(connected == NRF.getSecurityStatus().connected) { - draw(); - } else { - connected = NRF.getSecurityStatus().connected - drawLock(); - } + // health failed. Therefore, we update only partially... + drawInfo(); + drawState(); } else { // stop draw timer if (drawTimeout) clearTimeout(drawTimeout); drawTimeout = undefined; } - - connected = NRF.getSecurityStatus().connected }); Bangle.on('lock', function(isLocked) { - drawLock(); + drawInfo(); }); Bangle.on('charging',function(charging) { From 83debe93ee54ef1d01f78e572dc2c1a2d7dee66e Mon Sep 17 00:00:00 2001 From: Marco Heiming Date: Fri, 7 Jan 2022 18:21:36 +0100 Subject: [PATCH 151/315] Bigger weather icons & a bit thinner circles --- apps/circlesclock/app.js | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/apps/circlesclock/app.js b/apps/circlesclock/app.js index 23be307b9..f93a283f2 100644 --- a/apps/circlesclock/app.js +++ b/apps/circlesclock/app.js @@ -9,14 +9,14 @@ const powerIcon = heatshrink.decompress(atob("h0OwYQNsAED7AEDmwEDtu2AgUbtuABwXbB const powerIconGreen = heatshrink.decompress(atob("h0OwYQNkAEDpAEDiQEDkmSAgUJkmABwVJBIUEyVAAoYOCgEBFIgODABI")); const powerIconRed = heatshrink.decompress(atob("h0OwYQNoAEDyAEDkgEDpIFDiVJBweSAgUJkmAAoYZDgQpEBwYAJA")); -const weatherCloudy = heatshrink.decompress(atob("h0OwYPMgfwAgU//4FCv///+Ag4DB//gh4EC//jAgYAK+IED8EBAgXAHpQA==")); -const weatherSunny = heatshrink.decompress(atob("h0OwYKHhuAAYM2AQkA7AOD2wFCgdt20AgOA7dtwHAC4PbsAUGgFt2ApIAAgIIA==")); -const weatherPartlyCloudy = heatshrink.decompress(atob("h0OwYOLg4FEn/8AgV+g/gAgMcgE48EB48f/wJBgP/gfwgEDBAIRBC4UH/kB4AmC8F+C4X4gf/AAIaBAAgA==")); -const weatherRainy = heatshrink.decompress(atob("h0OwYKHh/AAgX8AoUB/EAuEAj/wgEDwEHCIX/wIXD8ARB/kAnED+P/8f+BgNwnARCjkOAgUH/+AAoU/IQ4A=")); +const weatherCloudy = heatshrink.decompress(atob("iEQwYWTgP//+AAoMPAoPwAoN/AocfAgP//0AAgQAB/AFEABgdDAAMDDohMRA")); +const weatherSunny = heatshrink.decompress(atob("iEQwYLIg3AAgVgAQMMAo8Am3YAgUB23bAoUNAoIUBjYFCsOwBYoFDDpFgHYI1JI4gFGAAYA=")); +const weatherPartlyCloudy = heatshrink.decompress(atob("iEQwYQNv0AjgGDn4EDh///gFChwREC4MfxwIBv0//+AC4X4j4FCv/AgfwgED/wIBuAaBBwgFDgP4gf/AAXABwIEBDQQAEA==")); +const weatherRainy = heatshrink.decompress(atob("iEQwYLIg/gAgUB///wAFBh/AgfwgED/wIBuEAj4OCv0AjgaCh/4AocAnAFBFIU4EAM//gRBEAIOBhw1C/AmDAosAC4JNIAAg")); const weatherPartlyRainy = heatshrink.decompress(atob("h0OwYJGjkAnAFCj+AAgU//4FCuEA8EAg8ch/4gEB4////AAoIIBCIMD/wgCg4bBg/8BwMD+AgBh4ZBDQf/FIIABh4IBgAA==")); -const weatherSnowy = heatshrink.decompress(atob("h0OwYKHh/AAgUD+AKD/gIDn4LC/4ABBYX8DQYODgYPCAoIOCEAgpGDQRCHA=")); -const weatherFoggy = heatshrink.decompress(atob("h0OwYPMj/+AgU4gFwgED+ACBwEH8AMB/kB4AEBBAYAHg////H/+ABQl+n4LB/A9K")); -const weatherStormy = heatshrink.decompress(atob("h0OwYKHh/AAgX8AoUB/EAuEAj/wgEDwEHCIX/wIRBBwPgAQMcgE4gfwn8D/wpGCgQAQA")); +const weatherSnowy = heatshrink.decompress(atob("iEQwYROn/8AocH8AECuAFBh0Agf+CIN/4EDx/4j/x4EAgIIBwAXBAogRFDoopFGoxBGABIA=")); +const weatherFoggy = heatshrink.decompress(atob("iEQwYROn/8AgUB/EfwAFBh/AgfwgED/wIBuEABwd/4EcDQgFDgE4Fosf///8f//A/Lj/xCQIRNA=")); +const weatherStormy = heatshrink.decompress(atob("iEQwYLIg/gAgUB///wAFBh/AgfwgED/wIBuEAj4OCv0AjgaCh/4AoX8gE4AoQpBnAdBF4IRBDQMH/kOHgY7DAo4AOA==")); let settings; @@ -61,7 +61,7 @@ const h2 = Math.round(3 * h / 5 - hOffset); const h3 = Math.round(8 * h / 8 - hOffset - 3); // circle y position const circlePosX = [Math.round(w / 6), Math.round(3 * w / 6), Math.round(5 * w / 6)]; // cirle x positions const radiusOuter = 25; -const radiusInner = 18; +const radiusInner = 20; const circleFont = "Vector:15"; const circleFontSmall = "Vector:13"; @@ -292,9 +292,9 @@ function drawWeather(w) { g.fillCircle(w, h3, radiusOuter); g.setColor(colorBg); - g.fillCircle(w, h3, radiusInner); + g.fillCircle(w, h3, radiusInner + 1); // the weather circle is thinner - g.fillPoly([w, h3, w - 15, h3 + radiusOuter + 5, w + 15, h3 + radiusOuter + 5]); + g.fillPoly([w, h3, w - 25, h3 + radiusOuter + 5, w + 25, h3 + radiusOuter + 5]); const content = tempString ? tempString : "?"; g.setFont(content.length < 4 ? circleFont : circleFontSmall); @@ -304,7 +304,7 @@ function drawWeather(w) { if (code > 0) { const icon = getWeatherIconByCode(code); - if (icon) g.drawImage(icon, w - 6, h3 + radiusOuter - 6); + if (icon) g.drawImage(icon, w - 6, h3 + radiusOuter - 10); } } @@ -375,7 +375,7 @@ function drawGauge(cx, cy, percent, color) { g.setColor(color); - const size = radiusOuter - radiusInner - 2; + const size = radiusOuter - radiusInner - 3; // draw gauge for (i = startrot; i > endrot - size; i -= size) { x = cx + r * Math.sin(radians(i)); From 8bbe2a43b40a2a2f6bc48b17f934ac2c413a3a86 Mon Sep 17 00:00:00 2001 From: Marco Heiming Date: Fri, 7 Jan 2022 18:33:09 +0100 Subject: [PATCH 152/315] Same size for every circle --- apps/circlesclock/app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/circlesclock/app.js b/apps/circlesclock/app.js index f93a283f2..6d408fd59 100644 --- a/apps/circlesclock/app.js +++ b/apps/circlesclock/app.js @@ -292,7 +292,7 @@ function drawWeather(w) { g.fillCircle(w, h3, radiusOuter); g.setColor(colorBg); - g.fillCircle(w, h3, radiusInner + 1); // the weather circle is thinner + g.fillCircle(w, h3, radiusInner); g.fillPoly([w, h3, w - 25, h3 + radiusOuter + 5, w + 25, h3 + radiusOuter + 5]); From 6a72aafc1919f4440051a20424c13dd12953e635 Mon Sep 17 00:00:00 2001 From: Richard de Boer Date: Fri, 7 Jan 2022 20:18:17 +0100 Subject: [PATCH 153/315] layout: use 'col' for btn label/image --- modules/Layout.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/Layout.js b/modules/Layout.js index 65e9a8dc8..cb64183ea 100644 --- a/modules/Layout.js +++ b/modules/Layout.js @@ -34,7 +34,7 @@ layoutObject has: optional `scale` specifies if image should be scaled up or not * `"custom"` - a custom block where `render(layoutObj)` is called to render * `"h"` - Horizontal layout, `c` is an array of more `layoutObject` - * `"v"` - Veritical layout, `c` is an array of more `layoutObject` + * `"v"` - Vertical layout, `c` is an array of more `layoutObject` * A `id` field. If specified the object is added with this name to the returned `layout` object, so can be referenced as `layout.foo` * A `font` field, eg `6x8` or `30%` to use a percentage of screen height @@ -261,6 +261,7 @@ Layout.prototype.render = function (l) { x,y+4 ], bg = l.selected?g.theme.bgH:g.theme.bg2; g.setColor(bg).fillPoly(poly).setColor(l.selected ? g.theme.fgH : g.theme.fg2).drawPoly(poly); + if (l.col) g.setColor(l.col); if (l.src) g.setBgColor(bg).drawImage("function"==typeof l.src?l.src():l.src, l.x + 10 + (0|l.pad), l.y + 8 + (0|l.pad)); else g.setFont("6x8",2).setFontAlign(0,0,l.r).drawString(l.label,l.x+l.w/2,l.y+l.h/2); }, "img":function(l){ From 436aecbca3f6fc772c83205daa4ae9ce1baea7c0 Mon Sep 17 00:00:00 2001 From: Danny <31635744+DDDanny@users.noreply.github.com> Date: Fri, 7 Jan 2022 20:28:00 +0100 Subject: [PATCH 154/315] ISO8601 added in changelog and readme --- apps/ffcniftya/ChangeLog | 2 +- apps/ffcniftya/README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/ffcniftya/ChangeLog b/apps/ffcniftya/ChangeLog index bf70a213b..420c553f5 100644 --- a/apps/ffcniftya/ChangeLog +++ b/apps/ffcniftya/ChangeLog @@ -1,2 +1,2 @@ 0.01: New Clock Nifty A -0.02: Shows the current week number, can be disabled via settings "" +0.02: Shows the current week number (ISO8601), can be disabled via settings "" diff --git a/apps/ffcniftya/README.md b/apps/ffcniftya/README.md index 769cbcb74..66acd1421 100644 --- a/apps/ffcniftya/README.md +++ b/apps/ffcniftya/README.md @@ -8,7 +8,7 @@ Colors are black/white - photos have non correct camera color "blue" ![](photo_nifty.png) (*photo*) -## The week number can be turned of in settings +## The week number (ISO8601) can be turned of in settings (default is **"On"**) ![](screenshot_settings_nifty.png) (*emulated*) From a3d1494318039c39d464204cc654e76cf321dc53 Mon Sep 17 00:00:00 2001 From: Peter Slendebroek Date: Fri, 7 Jan 2022 20:34:23 +0100 Subject: [PATCH 155/315] update tags mmind , remove spaces. --- apps.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps.json b/apps.json index 663cb1ae3..5dd4331f9 100644 --- a/apps.json +++ b/apps.json @@ -5134,7 +5134,7 @@ "version":"0.01", "description": "This is the classic game for masterminds", "type": "game", - "tags": "mastermind, game, classic", + "tags": "game,app", "readme":"README.md", "supports": ["BANGLEJS2"], "allow_emulator": true, From 0ee13c2fffc9902cb9d9351004491fe7da7ee768 Mon Sep 17 00:00:00 2001 From: Peter Slendebroek Date: Fri, 7 Jan 2022 21:05:46 +0100 Subject: [PATCH 156/315] added screenshot to mmind app --- apps.json | 1 + 1 file changed, 1 insertion(+) diff --git a/apps.json b/apps.json index 5dd4331f9..3321f822f 100644 --- a/apps.json +++ b/apps.json @@ -5133,6 +5133,7 @@ "icon": "mmind.png", "version":"0.01", "description": "This is the classic game for masterminds", + "screenshots": [{"url":"screenshot_mmind.png"}], "type": "game", "tags": "game,app", "readme":"README.md", From c8ea4c55b3e743ceee9350a091fcd80d63023826 Mon Sep 17 00:00:00 2001 From: hughbarney Date: Fri, 7 Jan 2022 22:43:49 +0000 Subject: [PATCH 157/315] Limelight, switched to bolted hands, redid screenshots --- apps/limelight/README.md | 1 + apps/limelight/limelight.app.js | 98 +++++++++++++++++------- apps/limelight/screenshot_gochihand.png | Bin 2332 -> 2452 bytes apps/limelight/screenshot_grenadier.png | Bin 2376 -> 2646 bytes apps/limelight/screenshot_limelight.png | Bin 2425 -> 2573 bytes apps/limelight/screenshot_monoton.png | Bin 3032 -> 2993 bytes 6 files changed, 71 insertions(+), 28 deletions(-) diff --git a/apps/limelight/README.md b/apps/limelight/README.md index f1cc52092..e84714403 100644 --- a/apps/limelight/README.md +++ b/apps/limelight/README.md @@ -6,6 +6,7 @@ * Selection of different fonts * Settings menu where you can select font, or switch to Vector font and try a range of sizes * 100 less lines of code, demonstrating that there is no need for a custom widget draw method +* Full screen options (widgets loaded but not displayed) ![](screenshot_gochihand.png) ![](screenshot_monoton.png) diff --git a/apps/limelight/limelight.app.js b/apps/limelight/limelight.app.js index 2d4ce5a43..20d79deeb 100644 --- a/apps/limelight/limelight.app.js +++ b/apps/limelight/limelight.app.js @@ -1,3 +1,14 @@ +/* + * Limelight analoguce clock with bolted hands + * Based on the work of @Andreas_Rozek + * [Simple_Clock](https://github.com/espruino/BangleApps/tree/master/apps/simple_clock) + * + * . Demonstrates simpler approach to establishing the available size of the appRect in relation + * to widgets, avoids having to take on the responsibility for managing the widget draw. + * . Demonstrates a settings menu and various configuration options + * . Demonstrates fullscreen verses, widgets and app area. + * + */ g.clear(); @@ -78,7 +89,7 @@ if (settings.fullscreen) { } function debug(o) { - console.log(o); + //console.log(o); } debug("limelight.app.js"); @@ -88,35 +99,54 @@ debug("outerRadius=" + outerRadius); debug("y12=" + (CenterY - outerRadius)); debug("y6=" + (CenterY + outerRadius)); -const HourHandLength = outerRadius * 0.5; -const HourHandWidth = 2*3, halfHourHandWidth = HourHandWidth/2; -const MinuteHandLength = outerRadius * 0.7; -const MinuteHandWidth = 2*2, halfMinuteHandWidth = MinuteHandWidth/2; -const SecondHandLength = outerRadius * 0.9; -const SecondHandOffset = 6; +let HourHandLength = outerRadius * 0.5; +let HourHandWidth = 2*5, halfHourHandWidth = HourHandWidth/2; -const twoPi = 2*Math.PI; -const Pi = Math.PI; -const halfPi = Math.PI/2; +let MinuteHandLength = outerRadius * 0.7; +let MinuteHandWidth = 2*3, halfMinuteHandWidth = MinuteHandWidth/2; -let HourHandPolygon = [ - -halfHourHandWidth,halfHourHandWidth, - -halfHourHandWidth,halfHourHandWidth-HourHandLength, - halfHourHandWidth,halfHourHandWidth-HourHandLength, - halfHourHandWidth,halfHourHandWidth, +let SecondHandLength = outerRadius * 0.9; +let SecondHandOffset = halfHourHandWidth + 10; + +let outerBoltRadius = halfHourHandWidth + 2, innerBoltRadius = outerBoltRadius - 4; +let HandOffset = outerBoltRadius + 4; + +let twoPi = 2*Math.PI, deg2rad = Math.PI/180; +let Pi = Math.PI; +let halfPi = Math.PI/2; + +let sin = Math.sin, cos = Math.cos; + +let sine = [0, sin(30*deg2rad), sin(60*deg2rad), 1]; + +let HandPolygon = [ + -sine[3],-sine[0], -sine[2],-sine[1], -sine[1],-sine[2], -sine[0],-sine[3], + sine[0],-sine[3], sine[1],-sine[2], sine[2],-sine[1], sine[3],-sine[0], + sine[3], sine[0], sine[2], sine[1], sine[1], sine[2], sine[0], sine[3], + -sine[0], sine[3], -sine[1], sine[2], -sine[2], sine[1], -sine[3], sine[0], ]; -let MinuteHandPolygon = [ - -halfMinuteHandWidth,halfMinuteHandWidth, - -halfMinuteHandWidth,halfMinuteHandWidth-MinuteHandLength, - halfMinuteHandWidth,halfMinuteHandWidth-MinuteHandLength, - halfMinuteHandWidth,halfMinuteHandWidth, -]; +let HourHandPolygon = new Array(HandPolygon.length); +for (let i = 0, l = HandPolygon.length; i < l; i+=2) { + HourHandPolygon[i] = halfHourHandWidth*HandPolygon[i]; + HourHandPolygon[i+1] = halfHourHandWidth*HandPolygon[i+1]; + if (i < l/2) { HourHandPolygon[i+1] -= HourHandLength; } + if (i > l/2) { HourHandPolygon[i+1] += HandOffset; } +} +let MinuteHandPolygon = new Array(HandPolygon.length); +for (let i = 0, l = HandPolygon.length; i < l; i+=2) { + MinuteHandPolygon[i] = halfMinuteHandWidth*HandPolygon[i]; + MinuteHandPolygon[i+1] = halfMinuteHandWidth*HandPolygon[i+1]; + if (i < l/2) { MinuteHandPolygon[i+1] -= MinuteHandLength; } + if (i > l/2) { MinuteHandPolygon[i+1] += HandOffset; } +} -let transformedPolygon = new Array(HourHandPolygon.length); +/**** transforme polygon ****/ + +let transformedPolygon = new Array(HandPolygon.length); function transformPolygon (originalPolygon, OriginX,OriginY, Phi) { - let sPhi = Math.sin(Phi), cPhi = Math.cos(Phi), x,y; + let sPhi = sin(Phi), cPhi = cos(Phi), x,y; for (let i = 0, l = originalPolygon.length; i < l; i+=2) { x = originalPolygon[i]; @@ -127,8 +157,11 @@ function transformPolygon (originalPolygon, OriginX,OriginY, Phi) { } } -function drawHands () { +/**** draw clock hands ****/ + +function drawClockHands () { let now = new Date(); + let Hours = now.getHours() % 12; let Minutes = now.getMinutes(); let Seconds = now.getSeconds(); @@ -138,14 +171,17 @@ function drawHands () { let SecondsAngle = (Seconds/60) * twoPi - Pi; g.setColor(g.theme.fg); + transformPolygon(HourHandPolygon, CenterX,CenterY, HoursAngle); g.fillPoly(transformedPolygon); + transformPolygon(MinuteHandPolygon, CenterX,CenterY, MinutesAngle); g.fillPoly(transformedPolygon); + let sPhi = Math.sin(SecondsAngle), cPhi = Math.cos(SecondsAngle); + if (settings.secondhand) { - let sPhi = Math.sin(SecondsAngle), cPhi = Math.cos(SecondsAngle); - g.setColor('#FF0000'); + g.setColor(g.theme.fg2); g.drawLine( CenterX + SecondHandOffset*sPhi, CenterY - SecondHandOffset*cPhi, @@ -153,6 +189,13 @@ function drawHands () { CenterY + SecondHandLength*cPhi ); } + + g.setColor(g.theme.fg); + g.fillCircle(CenterX,CenterY, outerBoltRadius); + + g.setColor(g.theme.bg); + g.drawCircle(CenterX,CenterY, outerBoltRadius); + g.fillCircle(CenterX,CenterY, innerBoltRadius); } function setNumbersFont() { @@ -192,7 +235,7 @@ function draw() { g.setColor(g.theme.bg); g.fillRect(Bangle.appRect); - drawHands(); + drawClockHands(); drawNumbers(); queueDraw(); } @@ -216,6 +259,5 @@ Bangle.on('lcdPower',on=>{ } }); -loadSettings(); Bangle.setUI('clock'); draw(); diff --git a/apps/limelight/screenshot_gochihand.png b/apps/limelight/screenshot_gochihand.png index af405c0f8406505893cedcbac16da25ea1e27804..244b008dc2f56804bcb252a7f89dd49339c6e0f7 100644 GIT binary patch literal 2452 zcmai$dpOkDAIHyk#tdc{lnK#QDKkdol1pO|hLsV9M3~s*+UQ5iPcC2ki>5>utyL)3 z+!_ql$GPLsv$!~pz8^_h9I z>z3pIk(M#^OkwYux6@Ax`c;1q(Z-1cYhn~6%ofG!_hn|v>buO*6ddHuNaABm|k+I;ryvGF9)Jww~I}JZ) zVnF;AIV8AM+8-4|xmfDL4#q6FzM1MuU_7ld^!iZoVWjrE@foymUAMOm6}(yaDTgyd ze+d>Ut~$T?JjN@lb(WJEtuvS8zse2;m6+mteO*vGDYx#u9kqO=(OO3{edH5aXFGE! z+Xy^l{h4-}y`v!A@NqbEPQ59T9!yOfxX8GX<{f`ji@5&yV^>;J3CbQH;3%C(^g=PB zy~ZW0K9Pi%;EEy%TFjA4!ROP5pS50G>gHS>eM!If8i{ z2)lf(n^g<|x|@dsLf+b)dCOxUP(5Oa3U<#HBpyQ>k~oCXU_}raQG?(SvyG!RP}m9U zxwf*A?KJJiV#F*9a+l`Jh}15i)b78!*7hJDxPy(wR<|STw;fxex2fEtqA!0ZEhzy zLSSvKvv|L_LkjA)?L`1=M))xlFrb00P%!NR;MhjpQZ@>l?U3RLH34EasqAV60c~H2 zzzs#fe01?9DGvZ8-Cy)$aDd}@%!cR$;ACZson{y?TBMqP<1l9z@}LSLeo4|-#D!pV zqd9y9`H`e3Rk+1J~ zf2b@J!urZ-uXcvW>d23vc@GBH0J@rZ|L3jQtk@Y%0*K$7emYpasgUVfqp}w*EXi?~ zHBRc+(J0dH&wNqlx|V4s%Unz<&8(R0BBso5zO)%DbJ2v$Lh^1HQ`wI;3^e-cJwMMT zPZEt#OSnBPQ{TPz4R58NT~igNe(m49YZmJt#KevUhd43c`mLKZ>I-ho> z*>CY6*qsp7MeEU0&y)XMpEdlj=2LcwMFT3BG&}FwjsJ4vk;#~l+dpQ|8?c-~5WXB* z*YefqxQ`7=Y1O0iNZ}$Es5M+YQu)B*r>qmN3jAUoCqynxJV|oP*OF}m_5G`#r>m^ zWPyzxo*~Hr&);;8xrsvbLA;yj-cTLW?2Bc;vlFFyr(eK6eUh~9INn%LVr>~zfASo4 zvqj^D^;?QzPqO>XkZe`j&3iSOs^`WwjnifymLPVm+|n@C{Gh|F;#|9lOAdaCMt)Ub z;YlfVHs(sy8-bn81?9{J%4-I1Dz)dyniQgO2Kl|K9<1+$HvDhQ0h>72lN{+}(SmklJm!Um>H%J`E^zST6vna~B#D20d?>jj~W+ zv(CPxb)`)g4a65_QJrKbrNM1qtf zhQ4iSHHfZg>`|n|{r3qBcW(7`g#V^Fd0G!8CPm@yTrZa#oWKEMwz!F`oDcq>35XLzY2km50D_wt^M&{Y94CSIsg~JS{!_A)q0hUQ2`({O; zPb`b#-zB^6*?``24H!&?v1e$TUtRG>fU5PLt7wjsJ-#5nq=J}{Y)s-P45c!&@eOVf zOGTLDLX-}8hvO(YYuZIm+uL`=&)m8Fb-9rnn}Ipvy5Unbo3Oe?5MA%l?K>HD%b>We zD9;izyuDnE*YXiP^}D!`Q`Ijp;U{j-Ixx|^^sU6 zFwEJcq)*F?9yhN4je6H9fl_*gRC?aKltZJCI6if+Z7FXm_Lw$n@Qt63w)~nSNk`nH zEi39fE~|lwKEQ19?^AGNdw$ssNB-c9=Bt8XZ3yuwG?L_!3)ONLuj_q#x2)E**2Z8S z%t+TEcTBy+BX7GoVS%Yba2B-GAFD$gy?K5TGUY0Ov%k@fx*P@w?v7MR82}@zNxh0< zl3O0IoF@U~a?3uwL=-5Ozka(>91&iu?vuFykgfI?REjfUMD-u7&%j&3j~*P8JPq+T O3)orHttu^npGOI2g!9Am-1q0Yug`V;bYIVt?CeOCmQs>}!C=xP zJ8M^Qt^Rf3lH$9H^U+6KBqCjjCt;O5m01`J&L>%)ICI5kzHsz1>)=jU{?^vaS9NI} zGHj0Od1!E0%_CKE$obvz`1trD%eWI1XFvwrUmuyhp^?B%lC>B7U9l#;vFLtjV+#pc zjS@}3Zs-A`0#J1z&n0_L2LPUr(b0Akz5DT46p&B;4X07arO7od8~7ZB$bXZo*>l+< zQPW+517sDC)*9D!e>Tt^l+JmQsI3DjZ8%%(Fq9A144(zba-+?;hC`lZDgFM4>;;cw z<;j}iBsjQQPuUz1yJ}7DZ(1%PT~)VRx({XWaqUOfj&%-3tG9NjeX~dmX7F2k2lMcA ziD-hrxd2OdfI*&ev^Hk|u5u?UfQ?WKr+=u}YY&60E@oDkNq`p|3RX^vQEkV}Cz=Ud zc5}xZD-afIv z!+VN04}ymEjo8Y7{^mY)`NGhfU*A~?kdCe~m;isE=jO)M<>&1Rc*)X?y-=vg#@ZN? z(Pmy~<*jxVGujUxs!ho>)Jj)puK`j4Ot}0JOjZPo#(J@*qxb}0`OYv@>zm3jNnq~Y*%SiB;vC4w zm7_1Nv_$@N96J&LRu;34>kPW}ha?jy%A8l)B~|;hfYG;!HYSXDZPW6=zB#P;kvoYQVZ;9 ze8lTmK8rEmNf0QcmFb`Im9Ol%F^FspUDX$Yy?92fceWLxwQV;sr^$^qMV;`~oL3cA zzOH)%kR^s-r&*I^o<~Vl{b8aCW?f#hdikd5Gje2_$vxpQ27TrEfohxT{;Bl8YU_XY z)G|N$Ww`lSigp2E_c(apI_{nat89)G)nl}o={+ob?$IE#&UQ|oe;t$S_i$_o@ch`M z+a0UHyxK~)pS+MxH@>SM^(0C0q(D#SoS9KwFV4Z2z5IAP^Hkmbz8-93InrJ4xALjA z&qfz*&*jG=U34|Amag`UO#w_P=cz`tFcX)TS0*(kvNqN7F4Ox$UHZ}_6nO+-%s%@r zx$BHRii}3ay-DJ0O$H^^^XHY6zMp!(v~V6@6o^2LXgFIhGNY>eiUWDoj62jbFG~Yw zR$!3R(c;i9y}qf%AM&{?NQm6L6~B<-ZV(>i8{KfNB1TKMGr-dRz|y)_s!?_S=gH!t zTW|X{hylwOvn(zXfve??@>2qRtZfBV<(fI%Jo?o=&{-2zySUG@v1Z>Zyu9STF90b4 zKECI!I{DLCrWKy5<@+2nPAfoqm)67cYg(R`SBG%2;bYQ_wnQPehFTn)mUHPgLjS=> zJT-KrIm-P$d1m6)<=wB;&cyl0x~9-P6S>k#arIpqCg}AdiS{COqjWvbW#<;BV3*TE zGirYKJJQ#Ct#qMmBj=eAVbWvDv{z9#lEXu-_i3!GP#xw{@S=AvqTtkrs4}dsUX%{J zpxUBtTrgxkc1keM$$qrqr#L&0#w;r^{uOVeEN_t}1&aVJbb z9i_WbGbsFZKbA_}h5!R714QSLf*V0Ucc?(hJ$s+141UkW0z}0jo&NDsV;~xB6!F%a zoXXA6jOvXVHrNhCXIFL)MCW(Iy*i6|M}$~0hsoxPqTjlzg&W++{8-3P!i1w=2Q!VA zOl<{upRhd^Q{pBdbI6c(C>hn*V2oJmum6)ExOx4FZqTiuR4zM&)XbYfW5Qi)&N0nI zOaSuC%Zy{A#P(XbWl=FKl9(f{NNLMx*bP6H;M``f^1Il>$XwFn@VZ#~g!LD1Dqk$r z)~9fOBNdJLMgRh}%|^vSICo=;v`2|CAfxTX%*5HHa&tliTUa-sg`C2DTHv{ro+J?6 zCg0{l23ap#^k1m{ohFgaHCAcgd_dAM0CM3kjuXYn-owJKkIx%FSB7mA0?;;h+pVql z37HqN0H}~{>!U@W;Q@1rhVQg^9=dcFkwS|_jUZkrrg0q;;9tR+okWTj;W0N;OP=R? zL5%Vmd=b4ehYG^CPr~&RE=48T4h*;+Q#C~W*i?a5dN;*U^nXeF?GsLJMXKgc+dEPC zgsGe^w^3kLnnFk(EFlQ~%MU(41^!APiu2bI#1UbHDSYy1UwmVD@4F03r_d zCp`I;@h^fXer{-)59SwGyr-QNpbsg01^^@GaKh4?6#VtxRMJD7u#MX8?r@2X%hJ2t zywzUrbifr|e%#!aPNQ07aB+za@u_#s z7WY%*x?a)d?o(cO_``WM#sIHNs~^yWMJ0kk>HVXWw^$b9NW@^{sMFA{Hh$r)G}+DQ z30x4`u(~V{O$K|UsxBfO;#Pu_Qyw^Nk8teS*I&l_JVO#|UYTvtb3~!H6di-nFfhT! z8{N;{!BZdqZ1*`g-4_s$yKXwXRq`_3n&wD;>NZQj3PaIQ*p8B>uq7T%2YxrAo>@E; zaq6redyz8dw6&fb0E<3WJ3KlM1waO;7j5VSL5+Q&STbc{u>g&m><`zuaUpk})*0+8 zzgx0NyY*wy(sr%(FPt7|Ko8$L)+ONQ=={aJaw{z#?t%OV@7VlP2a>;8wk3z*S*2#> z^t8IbK$lC3^pHCs8+ae+y?_C{3nPs&S#VHVzF$Ae3y`CW$}$Zk0rx>p-<;i`ko#1e zf+fnv+!@U!7mxIBjC?RvLHF#IU?5kK&S+j!G2-+&@y&+Hv~GvB{1uOb=;IC8S3gs@ zknJG-!5C1ttfz)JZ;iizvD`V4n@raz``ET}K+|p$XxK=w9Cgz23XGEl@^5r3SN{Hm z4z(6{wT7`CO``(VY|?e10L(}sTYvBrw)gu<69qEjV3S3)zpcC|IelD!DB^!lpTK20 zou7rReGG>)is`*Lk(grM9TE_Rq^orL!pV)=Ra7(tB16J8$&`)VPY*H$xwKekCz6H| zKrk}ZVrc@UvfQ+){71yKTN{ z(H4ZHn=bdwLdU0%Hy&7GmRI6hqfa`33C{^xHA?lK`s6}18RqxmMzXUcQKaMPX#6h= z(MXi{9X&Xaz0r7!(5hs=Wk>q8)&yB@C7m;t;|eFp88H%x|A( zboQ7PliQ@-_mxVM2K{^6T=)ISi@FYH1S)`Hqa**`^vLsqvD8_yq=rnuB|qw|0g;lC zJu#g0cXh&0N_|$YK=9oG5II_xW(cMZpon*aKUKh3hxEbJcTGi+j-+H5i|+qH7&JQx zK}mye&H_dd0W?SW96^vSJ%KaaTE6>(m7)X!w8q(*73Tfo zPM@v@C1x>h|P{A)AH^r|T2U(;OpM!9Euk9V5n|Hhb4yfTMC+F{ zGvOEkj$(UlomYnGjno5+E!}ncS=mwbDOuoWS`cZ$Ud8tKGsNso*icfa3FILbu-@3< zdYDzQ@3H~pa?5$gtTTSckZi`Q7yK)n*F1?4)iN`PgO%>#9Q9dPU}Ev#N=Y_kt$nUA z9DLdtL_}FJ7kfIdr}57s(vCqleXGYQ2KR6&1>C_)y~$p%z(Qx6f%E%RO_B(=@)vO1 zJK{2rKTx!Yb=f5zY)rQ5SD)T8+um0lzK&0+b>#Z}XMM__>7M$KC-rB*X z85OowsiH-EZbI3dLz?m8u<3F#`*A_p1-J1n=TA`mV6()4eLKM~BJF}Q`^pCCNJ!B3 z>p25I`-{ZSS&N%n@}(QC%Ka^FYvp}YhBXTzvJgkLr5fklpPAZr((G{nlB=y0h1kr? zH0AsrBxN7>#UxyHS}S=2FTkbMeGQA!miqdp{QeVPx3UsE8_w7WU(ZhLQ+ORxS<0cg z9qPD0*Z->Gbd6Z&`izN;ddi`$!Sssbo!3p<-_HQM-zEYLFXk62-HKpuecl`P^LAo+ zF}(Ee#8|c4lT8Q72d|-m>qmC;lKAQ2;SWQt-S5Caqg&?UN318J%hZ$p$r2d zlhLk%w)47N+D<BAW%gUh)OoC zrzU8zd-A-JA^pjv!GR}ASUg>VDTX8+PGO(eywZ zaMh6mYC@V<5!@4847x78$pS~v!xhH6^F7@q23w*}UWmC?oC%ycYYhwc~v zoP+%-SzwHr*h{C#pk2k<#o^>D?cp;>?t^#uSLzas^>?%3MkzBL1TF+Se0ViA7?u4$ z8SWE=wx5s{)GdCv3HNy3O-({|SSU2;V^_v_U(k_sj_sU_Q8ky{^J&jTE8p7*~Xgs^D z4&)sJVF5PIFN&4SCCPaQ2T(f4%3_ZdC}W{siL>xqa{aA&?}gFCQyK>4{kdn@y%Aab z>3_&^!wNnqd_HW1BrAT(@0Pi@X1~?s1z7%suiMx@UfI#1@5Lo3h~jy!V{AwWPl5A{ z3Csvv3YWR;QludFeo#t*9RK6MBoPTn46gRAIsg{G zI53~{jRf(zzm6{q42>6^zaj;=&odeW>3m;Nr#6hz0?-xYxwb&$Kgh$e!C}`iayERU O2pnu&PtdK18UF>*lD-=N delta 2353 zcmV-13C{M`6vz^gFnS&_6$4y8iovz|!)O41sZAY66SE zTir6cv7?-H;3!q%HVM4TX6eQj(L)07O>UX+wX@NcXw7ed@PB=n-#8!PSU&*-UWtgn z{SszotQ2@z*L$=2b%d~X&b^Me7H&Pxn}0Mu1DjYq0R;YY8)gw7f%TGAW;|Ws_2xz$ zbs4`F%_`m~|L6$8*|$8;%{ zfWT6mB`|Pf7rRr8r5}O#p$ri8G&+00K*Kl7Fn500MUtXFe$b1eW3?SvLU$ zP7;6rz-RBBvFo8(|0>U}=3$#QS6x z4<`AGfxu2?M^ah@97%1-;au{qha<3~ylVNZo!qg+#|=ebW64MIzS2axr{yedT;d~# zA+V$DBY%k_0>7q5Vn-2HLlM}??j_s$`+ZA_sK8qiXL32WH1%)U@cMc_oK)PKUM^Ch-6O(+5oM0)N-B z{my*!^&;*8=iwu8p5b8zx^FGu5`jlwYJ5`XLEwo59*Mi&$`eF>n!w%rm2_aQxbGt0 zUE=P7*7mz`_Ui+%jqin$gE@U55Qz{{=9m>Zhuuq5-ApScZs{tgONIR#3)?ZTW6>PE5)naTt{(^ z=AirjrBhXBiNKkc{;G|gE$`8%a2Z}#*q3(=l{G$H;H^U6rNDIH|5d+~z!i(B$m#78 z72}^SaL4}L9k@caikuZfdUJLZ(7UG2@yho~vNv%RvQ^~lEY#jy2)uuTOMi7tqyrb3 z&Mma#M@e7U6%xAzt~iw6u>(K7`@Z*u%8MC+n>(l7`yJZ;5AeY(JR?7rLs-oF;q zZ|p(>tBw)s&6Kwg#{?DK#xeb+hbrqX6WDtwS8n2p)k5Ios;FLh!vgQUOj^!(cP#Gv z4Wn&6N|OflL)P>)ujZ^h^&O-5v^)$k=wb5@SdkU+%+B|bI_Ah~}b!nv!rwB~< zJ^%7Lt4k~8ZRx=31)pE~d#<3mOGj=kT1c07VAWa2vKhu`2}GqfeUNkJH!`f4=)P7` z^NbrEJv!wrKSI!b=YJ71y3)vlOUm~^Wk(3)jVdvBT=x@)WdhG#23D^muypB)PYn@R zSt)Y06F}g0g}fWS(cApgk##9Jw1Z5dU_q9;cjzM4%Pr9!Nq%#cy zJAv&Dr~8UPI)Bq3uoKwUaO4$045mQfAh;!L@92QkNwCIn1U7=Q9vv*{lz$)BGT)uY zAaJ6(*1tx+H3bqUz`uneaDrn-;AL7wP86W)|HS2%c+KdMylXML|8n^?sp(fm2M#ig z-uJEgcT>S_Odp28ff7dL9o@MIEamYb2<%iKD=!i|fqxH%Be0XF^8T(emvbAp8IHit zQmUm>=W}jn`r!!dETLLBbw1~IrXP;LjuKYLR*}=OrRj$vu%m<(vQ^}CY-#$T2<#|f zg=`f$9b1}yC;~f5SRq?QPREv}ABw=v5~_t$=W}jn`r!!dETK|3WiID7ZZjN#ouyPt zr_ANt#(!;wBXFRU3h`7QNe7mHs}KYZlrt+|Ha@WA+lC-;u(XlKA|o-ur%Ayu#_EBKbt9hESwTizPZazWcA|y6(U3>$#r$_xw;yT$f_Vdt`5I$qe`UlrtPw zYAR#n{A(qjYg^?=DBQztMAtrTvAr=-cwAfNxR>{;R=!+9R9PZCrut07hqn$m7F$`O zxrp>7Pg87EO#dG$aG?d2eo|nvOHS0Wnp~S z(Hy)9ja~bTaUS>2pDp(;k^jJ7M0eRqwTYZWf0Z1S_hn>WO{7-Nc3uspvBoF#XPmqdke^51z3 zgL`v1CO(umb1dtjL6>Mb0Y>>b(t!W_pN$BX3W9A|Iv7{zSx zUm7g*LQ(8<1+CT_%Aweh(Bu@WD%(uk84OZ&}xzD zNQT86VuC)M3#g)h9j!^nqze^V4xXLPlrE8n{|*blfW zmGMWKGmk0iRG!|Yz%^m!EGwb|@cnl7KP+3V`Jk1P-K7>zI04maZ{uCXWzo&Hh{sX$ zy!V||_jlkt);#2gUQXVv7|{9ZiqDP3p6B~>_Vw?|KcdF*Bb2N1se0A&EM})uLhXcI znQgVet#`9;{&Z%q1WH@a=yZ3|XSeLKe`0ZV(u380RYe;$Yp!@9QDO6pT4cKS1VWAH zUhroJ)`o@f_!rh|GJvaR?rW%%DkK>4U}5(=pL-K{6hGbnY#?T_L`+dOA*MN=kmybB)hCbz-!?n9`$-4p{J`!&UArJ@uXXmU3j@_?tG>QMJJ2?X%Jb z-$+<@w&!E^_3Cq9#lHl*61sJ>{acDz{Y!mNO6zj?DbQDVw&Bu1>6$hgxyzKN`hdSB z*S6sFW)`V<*n83kt&b{8m+>>4_WzsOaAGFRjM7xSu*6!*KKnKmX;2lv$B7PfGFd3`tUX}A?XxY_N zmgP>0DRijszMfvG6BJAkHfnv$3_8l7Oa`+?bKf>!+E^XpUpwF)GRCX=c+j15)^ZzK z-R6$EPqjycRxjjQcTUut+IC}y?(89w>$R2NuxY1ZB154`_v@=XPy1TM2*3Ddw);e@ zq)0bh*OC>@#nakb>VG|G)xR_T+B7F&vUr{7nEW}l;_r((N>PMF&p;5}efpW@-DBUG zQ{iI6SUDwu+3@+`$y<fSr6>h@V zXShM~PN3mwgBqwN(r0ecVfuI-s%hmGrTKf#Q6eUL2REqw(!L0&#DmLP#IsfFd2l7h zEz0JO(;f+q>uR7l(^oPmzU}xX$!k(KL8uj3utZt;JGtUDX>5ZYP>+4UdEm~`bhSwK zA2LB$+fMV&;>iuiy#I$65XjX^vXsFr(fZakuTT3%-?upVs`CYR<^K>6E$f8M5OLvl z-V@*3rq7oMAX0$f&~$I!2KERduAIt8B*c{$HD@$Y?xWp*O~v+`u2!+$!mt_8aPu{C zPh7KJIOe5(UVesPvA80}`#s8F{N0V>&my(8%Ro0-1Rhc0m0=~>R`3Tsjwu4{#N3ex zj;aw+I_8(M+Wh;&i^^O94LsBFL~E4`DdGd3`2YhS;xjB)v7t43v(6R=<-H0! zVpsnI%ZIyz5)n9@uj3^}1}yesz>qo~8f@*FWEdhIX>A!>FZ8GntjgZT$-3N%6Z0?n Ce0p>M literal 2425 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 BY>NN@ diff --git a/apps/limelight/screenshot_monoton.png b/apps/limelight/screenshot_monoton.png index d17d9bd26e9795c28c427f37ca8407db63b3f5b8..e75b11f5daaceca3fc7ee629ee942e822dca01bb 100644 GIT binary patch delta 2974 zcmYk4c|6p67stQ9S!nDcd-m*P$r$?*DY|6rYm=_byZ zmWpI=vQ#QtQgWlmeLeSiy`J;m`FuX_bIu=ULh!y|rUo2z%G}f;)@!ABC1yd1!(#de z{BhXIxme1ao|U=4{e73H&x=UMHqm3g?r!eaV^|^F4&4oH8%Dl;`}SQp`KRRk)ywla z;v~*4X{O=KV4ph|I#W9nav6OV(yWR&nz}W=(Q=Xd+dL=0X&~RYZf~^8-)_~!@w7S% z19=2oV?Yp*+SDM0u=<5#YpYb`t1w!5Q5H5++6(Nj)jhX?C2o8v|;B842M zSp?KqQomjFuTMGsEL(~0zB}WtGDct1kcN@$0V6(y-d*eWXoAK4-&mmXktj=d3Y6lw zB+Lf{%(~?1@jC*QF_->nX!1V)*9iK=|2$L~E&7ks#u_lNjM`em;ef&TNuwhZ>3yjD zj%|mXuG^e|op)%Me!Zu^k(Q{z#RW37t%k@lu~bo!J{~w<8zM-3lleI2=9n;-IH-(T z8bOiJ)Fxi$%Qo?mquQ10tCA@FuI0s4=-*NldQ&35@Fq71|RYJOl(_ z)J;%l@L4i?_t?7-4tG@`pl}^{P(HAEM*l%-Rpkck(H1}s$=)Zoe}|+uilEsj8JvUx z?9w$Ls#=h78VfOfOm!~i^5|pS+tAFz#NniZ!C|>j%hM4FcMv{Inb%cofoKrxW+o<9 z4S+Wo3$@zeH#7o5CIHSrMS`^04c+vq`T@6U{PSMs1e~@z_R06+UT2xg-d3rrN@f&c#YvBTvh5MMV{+JV$ac zs?KQ~;{kg)X_3;5k#}i;b^zj$7_Nv1t^0IRdsgisq_@uTt5}*U-Q==@v&83L;{dtQ zkJGEGnBK>)-rvef&j&)O#(l4(idB&6JQ96xR*Tip>O5=1qy73WTm;EI-1&|enk?O< zQyI3GAgUqj=7eak(g4wB=1YOUW_fcTUXXdRYRMrF8no8>Af?x@JQ!kgt8?5g?GU*T zyeW=DU`MgG*jalALWbNF2vxN3eD`Dy|TLV`E4j)tYxRY?~ybFZ?M0+aKF!7`!=rh~ilVx(^b8f%q z2bwpvSbJq+f?9)ruKSf~1uY6s-=t7a|9bIN2U)wG&REOi?kP@ye-B?;?3Wp&w7^>B z#!t}n-xUk0QtdAU#E8&$zj?h)H@E>25p>SecVjh6$N*Dj6HApONvg~(BtE8H(dkMEy{j3J3+HllA7RWX zn)~qiQz`n;jGkwsKwOy2huOT0&G9XjPM$X+#@4Bt3J>ys=_7(Y6XGmW*sN;(2^KQe z3p!5mI+}69$p_~hi`#ufX7i@MIHO&kb$5w+kBqpDm_6jmj#swS`%a66IXy;t=01kz zw~=kAUCG&5t9}(G9-jga%XJ#0ReC5v6HX>*`{oYOx~!kyVvlKscbP7)+@nI&f<*Vb z{KB-1y6l8J{kB=wspq3eB6>E0uWHb9sIKc(aC00E>HR}LqWLM6G_xfZi+$i0r|925 zAl;sm*7y3khFjRz0V@r7Y-TsqD18p6}D~4DmYG7w*VxUjekot818L{%i=1e{-#xRBw zR|{IPimDs@1^$AAlT%^k<5jxaMON=`6;BIWbNimQTKOBFeFDI%zT`OcmeW{p=I~TE zs!eR+z|1WbgIDt$u5QI}nDJ75qWkUompvIQ8V7$3l*A)^hc@lCS0+oF{nkk7gl%p7^o^-S2_>&UU0 zv(;}0?QQ%})Vv+%r`?7)!@}8f?^-@hzD!zC;2rXat^+LI_hk&JbO$lnpsUD%LcB;Jdt zg6#(pEKKvR`21%t@2W=#S+^mWjPRTUzQ_EYP@_VwHw*o`RT~x*-IE9M*A?3l1UrSt z9Hc{eks&a^+1Uace*0)Nz5L8|VW6zEGzG%TDWFK9@*^9`qKsb)I5`Y7Lrhu2wrg3k zcSbpZK04@DPC`y{bUQ?-B7h=Umuyime6VRpoHnF7Vj_!~2}jaT?cmL1G0V|Nx=pWw zR5r>w5=nP8+t(DAqmXo?uEOzLo>OM9-YjUeSGP))?aiJ6;pEJH(Q0P~G};~=E$j%# zNV9l?@H4a~;jOTwR8v79#?M9KOSTS&=)%(Y-*Weaq9D4)te2aenQW?1G(q-_u!IIF15yKBJeXRB+UhJTE?;#o1l9N=23J&2e<_@tJ@kF`4H?n zzHoRTxf$M)N?JgGxCvC+e`$aAjm{`>41rv3b_z0Io~ZvJjH40tgrdJH=!e1TxRJg)i_cO7=f)=+h?eP51VaT-7qk^LS>xK(Akr+p2zi|~ z0TWfug0OdO@nszNw$!6G>v3WQ3@0Jj4n|cuRMxQ# z#pt8UO^d9PU4s-MDT9mZ>weGq{t4e7p67kev%JoE&Uwyxp2U-OmOC)JF#rJUusUw; zxUH;z4K1|os~bO1w*|cHXh{aD-s0x~0DITU-1Jlgbun-B>Vlf6dGoJd#g{V-mCVrO z5-fX%ixD!H(at?Avk`Gd}BrEcAa6w8o%K#c##rUfSuvJrQbUf;+GC&xS!^Njf= z&Kp?i-36)$C{~()O|DuT#+|5I=$i9PQx!xyf1Gs8BplSVW!glTm&zwTiZTDAE_-Rk z^4tPl5FH|*47Msf?@ZDKwdc!ja|>jk%3Q~eAV$z)#ZS^^!VvymH30sch~LkXEEA>BF zJHx=kS5|(m8YXbHOYZj)braZW=0RP#^j^eO6gd(D;h4!%XNY^H+F#eSu@4*tW(|8O&{k7TRF_+shqJ@><)?w=3eJv8$kWKHRe{{InfFup;N~Gz6 zUm9ep_R7d_SM75tPr<>Y_o#^6y^swI3g!oqVaAxhb0394dREa&zl3I0r8cQ<)>(XP zN-$#&qFMQPs3Pc~G_Thd`{mc?mrBUfV{-tZ((Fm9!|F|j&xL?(Kz$J6PN#7P*K|87 zT20QbJJ)3$R}Z6!B^fQ5MAWq8`l((YZq&{YBGPN(*1hHnKNYk0A}|#l;lUk<`jhJV zT|hHjKTu#5vRaHuRdV|nZfa>=p6jRA5rffEHMGFGn*9|lC^ zvczd7#ySWm)Q~p323d*QpoxWfvNVKb8;jXanTR2sbvuy(W0j~ZPPGgur1lN)T>1n# ziQ1y8HN`-o*>Aubj41jZjSPc0L!b^4c&_p<(_D_Xw%Ky1yI@{wFOujH6a9YItBO{i z$b}n`xXgsW_s%;)RNDW@lnw2lG-On&fBjAJl7x|6_DcYKdrI#6CG^ND4=}Id!gwyLc7TOfN%tDVDqfxZX7V z!te}*jAq&Da7VBqOOuMvD_(U)(@rbjvrs{Nd}B2~!O}y2KMc&cuA3c6E1N#vmNHr?_5-qu^}-6d_%5I;NU)-x8OL474{g z4f{Xs|$#rh%Ry`6Son2A8ZV<$RKYi-X%Mc(szg%YKo) z?^U7mjK=YRyXrNT!mt z65s1#a725nx9CO{4T}nIKakV!7&jXGXZmyiV64=1M3MrvC`1g353Rt}5w+u}u^hyO- zjeTP>W>f8p!-qzUaz&$KIN8^-i!B1|8gAr$6DcTNH>v9Q`R z(uWJ$!Cbv8-Qy8YUv;-om#57YS#O3{N_5)_a{Ttgxskfnm$yj@(R~3W7kHKwEqAEj zo(VbfgE!qifcc$vP8g)OIW+jet+xxn~Z*$>c+53Np$zg$BGyI|}<4wo0 z4h1!Yulc#=;DynfxTro~Qf)!R=|KIoQuu1WSC~Uabi6Itgu(|Xxm_Wh&;P#Wk4?>< zKLwLgN~Fx~3EftUMjFfY;@P}XKH~pM`C9ZWzW!P~|1s9gnfO4F6O!F)CzD0uAgrOcg?M=#RRGavKgJjP`Qk@i3fowI0a zeQa%X2>SglGJNOoiLdW?%Ccd>T*C~;^NXI}`aYtDvL<>*J8&US1iYj?52zwSh7J*_ zCvtw|IGD*6eqL#c><+Ns{(UpD;?|Fg-5Ak8 zKTz&TLK=I#YAarmxMFz^Ms}C))A0Gstnw_YFgGpdh@@IYE%ZrpQ9|@M@#1S9 z2~hM!OVdEYK4WHyw(%dp5y!F7fRvFNRO2zbm)-pacfT5L2OHAZuT$g`*p>>x9D~fp zE+T}tAwi0@l5Om^Of Date: Fri, 7 Jan 2022 23:46:24 +0100 Subject: [PATCH 158/315] menuwheel: override Bangle.setUI to clear up touch handler Because apps/libraries expect setUI to clean up touch handlers. --- apps.json | 2 +- apps/menuwheel/ChangeLog | 1 + apps/menuwheel/boot.js | 10 ++++++---- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/apps.json b/apps.json index 3fc0616da..56691d2d4 100644 --- a/apps.json +++ b/apps.json @@ -4805,7 +4805,7 @@ { "id": "menuwheel", "name": "Wheel Menus", - "version": "0.01", + "version": "0.02", "description": "Replace Bangle.js 2's menus with a version that contains variable-size text and a back button", "readme": "README.md", "icon": "icon.png", diff --git a/apps/menuwheel/ChangeLog b/apps/menuwheel/ChangeLog index defdb5049..050cf2049 100644 --- a/apps/menuwheel/ChangeLog +++ b/apps/menuwheel/ChangeLog @@ -1 +1,2 @@ 0.01: New menu! +0.02: Clean up touch handler in setUI diff --git a/apps/menuwheel/boot.js b/apps/menuwheel/boot.js index 3e708e9a8..deb15264d 100644 --- a/apps/menuwheel/boot.js +++ b/apps/menuwheel/boot.js @@ -1,8 +1,5 @@ E.showMenu = function(items) { g.clearRect(Bangle.appRect); // clear screen if no menu supplied - // clean up back button listener - if (Bangle.backHandler) Bangle.removeListener('touch', Bangle.backHandler) - delete Bangle.backHandler; if (!items) { Bangle.setUI(); return; @@ -206,8 +203,13 @@ E.showMenu = function(items) { if (b===1) back(); } } - // note: backHandler is cleaned up at the top of this file Bangle.on('touch', Bangle.backHandler); } return l; }; +// setUI now also needs to clear up our back button touch handler +Bangle.setUI = (old => function() { + if (Bangle.backHandler) Bangle.removeListener("touch", Bangle.backHandler); + delete Bangle.backHandler; + return old.apply(this, arguments); +})(Bangle.setUI); \ No newline at end of file From ebfedfd18b1220b00cc6cf7ec64663e56d440377 Mon Sep 17 00:00:00 2001 From: hughbarney Date: Fri, 7 Jan 2022 22:55:43 +0000 Subject: [PATCH 159/315] fixed apps.json --- apps.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps.json b/apps.json index 1ddacceca..7d0789953 100644 --- a/apps.json +++ b/apps.json @@ -5483,4 +5483,4 @@ {"name":"limelight.img","url":"limelight.icon.js","evaluate":true} ] } -} +] From 2a2c26393fafe60c5509f15157fed98d575023e5 Mon Sep 17 00:00:00 2001 From: hughbarney Date: Fri, 7 Jan 2022 23:11:14 +0000 Subject: [PATCH 160/315] limelight README tweak --- apps/limelight/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/limelight/README.md b/apps/limelight/README.md index e84714403..e7c13a139 100644 --- a/apps/limelight/README.md +++ b/apps/limelight/README.md @@ -5,14 +5,14 @@ * Selection of different fonts * Settings menu where you can select font, or switch to Vector font and try a range of sizes -* 100 less lines of code, demonstrating that there is no need for a custom widget draw method -* Full screen options (widgets loaded but not displayed) +* Reduction by 100 lines of code, demonstrating that there is no need for a custom widget draw method +* Full screen option (widgets are loaded but not displayed) ![](screenshot_gochihand.png) ![](screenshot_monoton.png) ![](screenshot_grenadier.png) -Many thanks for @Andreas_Rozek for his pioneering work on building a toolkit for the Bangle 2. +Many thanks for @Andreas_Rozek for his pioneering work on building an analogue clock toolkit for the Bangle 2. Limelight Written by: [Hugh Barney](https://github.com/hughbarney) For support and discussion please post in the [Bangle JS Forum](http://forum.espruino.com/microcosms/1424/) From 597efeab00c8f9a9caf106e6c366e2c66dfefbf4 Mon Sep 17 00:00:00 2001 From: hughbarney Date: Fri, 7 Jan 2022 23:14:15 +0000 Subject: [PATCH 161/315] limelight README tweak --- apps/limelight/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/limelight/README.md b/apps/limelight/README.md index e7c13a139..49b858127 100644 --- a/apps/limelight/README.md +++ b/apps/limelight/README.md @@ -1,5 +1,5 @@ # Limelight - * Simple configurable analogue clock based on the work of @Andreas_Rozek [Simple_Clock](https://github.com/espruino/BangleApps/tree/master/apps/simple_clock)* + *Simple configurable analogue clock based on the work of @Andreas_Rozek [Simple_Clock](https://github.com/espruino/BangleApps/tree/master/apps/simple_clock)* ![](screenshot_limelight.png) From 049555a08dd3083b956c8df0e44575f9148e5add Mon Sep 17 00:00:00 2001 From: hughbarney Date: Sat, 8 Jan 2022 00:25:43 +0000 Subject: [PATCH 162/315] Simplest, switched to queueDraw() method, update once per minute --- apps.json | 2 +- apps/simplest/ChangeLog | 1 + apps/simplest/app.js | 66 ++++++++++++++++++++++++++++++----------- 3 files changed, 51 insertions(+), 18 deletions(-) diff --git a/apps.json b/apps.json index 7d0789953..1f4e983e6 100644 --- a/apps.json +++ b/apps.json @@ -3794,7 +3794,7 @@ { "id": "simplest", "name": "Simplest Clock", - "version": "0.03", + "version": "0.04", "description": "The simplest working clock, acts as a tutorial piece", "icon": "simplest.png", "screenshots": [{"url":"screenshot_simplest.png"}], diff --git a/apps/simplest/ChangeLog b/apps/simplest/ChangeLog index f37015d6a..c5ceb7a44 100644 --- a/apps/simplest/ChangeLog +++ b/apps/simplest/ChangeLog @@ -1,3 +1,4 @@ 0.01: Modified for use with new bootloader and firmware 0.02: Use Bangle.setUI for button/launcher handling 0.03: Fix display for Bangle 2 +0.04: Use queueDraw(), update every minute, respect theme, use Lato font diff --git a/apps/simplest/app.js b/apps/simplest/app.js index 68564ff33..85ccc1509 100644 --- a/apps/simplest/app.js +++ b/apps/simplest/app.js @@ -1,28 +1,60 @@ - const h = g.getHeight(); const w = g.getWidth(); -function draw() { - var d = new Date(); - var da = d.toString().split(" "); - var time = da[4].substr(0,5); - - g.reset(); - g.clearRect(0, 30, w, 99); - g.setFontAlign(0, -1); - g.setFont("Vector", w/3); - g.drawString(time, w/2, 40); +// from fonts.google.com +Graphics.prototype.setFontLato = function(scale) { + // Actual height 50 (53 - 4) + this.setFontCustom(atob("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+AAAAAAAAAP4AAAAAAAAD/gAAAAAAAAf8AAAAAAAAD/gAAAAAAAAP4AAAAAAAAB/AAAAAAAAADgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA4AAAAAAAAAfAAAAAAAAAf4AAAAAAAAP/AAAAAAAAP/wAAAAAAAH/4AAAAAAAH/8AAAAAAAH/8AAAAAAAD/+AAAAAAAD/+AAAAAAAB//AAAAAAAB//AAAAAAAA//gAAAAAAA//gAAAAAAAf/gAAAAAAAf/wAAAAAAAP/wAAAAAAAP/4AAAAAAAH/4AAAAAAAB/8AAAAAAAAf8AAAAAAAAD+AAAAAAAAAeAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAf//gAAAAAAf///gAAAAAf////gAAAAH/////AAAAD/////8AAAA//////wAAAP/4AB//AAAD/wAAA/8AAA/wAAAA/wAAH8AAAAD+AAB/AAAAAP4AAPwAAAAA/AAB8AAAAAD4AAPgAAAAAfAAD8AAAAAD8AAfgAAAAAfgAD8AAAAAD8AAfgAAAAAfgAD8AAAAAD8AAPgAAAAAfAAB+AAAAAH4AAPwAAAAA/AAA/AAAAAPwAAH+AAAAH+AAAf8AAAB/gAAD/4AAB/8AAAP//gf//AAAA//////wAAAB/////4AAAAH////+AAAAAP////AAAAAAP///AAAAAAAD/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAADgAAAAAAAAA+AAAAAAAAAPwAAAD4AAAD+AAAAfAAAA/gAAAD4AAAP4AAAAfAAAD+AAAAD4AAA/wAAAAfAAAH8AAAAD4AAB/AAAAAfAAAfwAAAAD4AAH8AAAAAfAAB///////4AAP///////AAB///////4AAP///////AAB///////4AAP///////AAAAAAAAAD4AAAAAAAAAfAAAAAAAAAD4AAAAAAAAAfAAAAAAAAAD4AAAAAAAAAfAAAAAAAAAD4AAAAAAAAAfAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPAAAAHAAAAD4AAAH4AAAA/AAAB/AAAAP4AAA/4AAAD/AAAP/AAAA/4AAD/4AAAP/AAAf4AAAD/4AAH8AAAA//AAA/AAAAP74AAPwAAAD+fAAB+AAAA/n4AAPgAAAP4/AAD8AAAD+H4AAfgAAA/g/AAD8AAAP4H4AAfgAAD+A/AAD8AAA/gH4AAfgAAP4A/AAB8AAH+AH4AAPwAB/gA/AAB/AA/4AH4AAH8Af+AA/AAA////gAH4AAD///wAA/AAAP//8AAH4AAA///AAA/AAAD//gAAH4AAAH/wAAA/AAAAHwAAAD4AAAAAAAAAPAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAA8AAAAAPAAAP4AAAAP4AAB/gAAAD/AAAP/AAAA/4AAB/4AAAP/AAAD/gAAD/wAAAH+AAA/wAAAAfwAAH8AAAAB/AAB/AAAAAH4AAPwAAAAAfAAB8AAAAAD8AAPgADwAAfgAD8AAeAAD8AAfgADwAAfgAD8AAfAAD8AAfgAH4AAfgAD8AA/AAD8AAPgAH4AAfAAB+AB/gAH4AAPwAP8AA/AAB/AD/wAPwAAH+B+/AH+AAA///3+D/gAAD//8f//8AAAP//D///AAAA//wP//wAAAB/8A//8AAAAD8AB/+AAAAAAAAD+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAcAAAAAAAAAH4AAAAAAAAD/AAAAAAAAA/4AAAAAAAAP/AAAAAAAAH/4AAAAAAAB//AAAAAAAAf74AAAAAAAP+fAAAAAAAD/D4AAAAAAA/wfAAAAAAAf8D4AAAAAAH+AfAAAAAAD/gD4AAAAAA/4AfAAAAAAP8AD4AAAAAH/AAfAAAAAB/gAD4AAAAAf4AAfAAAAAP+AAD4AAAAD/AAAfAAAAA/wAAD4AAAAP///////AAB///////4AAP///////AAB///////4AAP///////AAB///////4AAAAAAAfAAAAAAAAAD4AAAAAAAAAfAAAAAAAAAD4AAAAAAAAAfAAAAAAAAAD4AAAAAAAAAOAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAA4AAAAAAAAAPgAAAAB/AAD8AAAAH/4AAfwAAA///AAB+AAB///4AAP4AAP///AAA/AAB///4AAH4AAP/gfAAAfAAB+AHwAAD8AAPwA+AAAfgAB+AHwAAD8AAPwA+AAAfgAB+AHwAAD8AAPwA+AAAfgAB+AH4AAD4AAPwA/AAAfAAB+AH4AAH4AAPwAfgAB/AAB+AD8AAfwAAPwAf4AH+AAB+AB/gD/gAAPwAP///4AAB+AA///+AAAPgAD///gAAB8AAP//4AAAPAAAf/8AAAAAAAA/+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/gAAAAAAAB//gAAAAAAA///AAAAAAAf//8AAAAAAH///4AAAAAD////AAAAAA//gf8AAAAAP/wAfwAAAAH/8AB+AAAAB//AAH4AAAA//wAA/AAAAP+8AAD4AAAD/ngAAfgAAB/58AAD8AAAf8PgAAfgAAH/B8AAD8AAD/wPgAAfgAA/8B8AAD8AAP+APgAAfAAB/gB8AAD4AAP4APwAA/AAB8AB+AAH4AAPAAH4AB+AABwAA/wA/wAAIAAD/gf8AAAAAAf///AAAAAAB///wAAAAAAH//8AAAAAAAf//AAAAAAAA//gAAAAAAAB/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB8AAAAAAAAAPgAAAAAAAAB+AAAAAAAAAPwAAAAAAAAB+AAAAAAAAAPwAAAAADAAB+AAAAAB4AAPwAAAAA/AAB+AAAAAf4AAPwAAAAP/AAB+AAAAH/4AAPwAAAD/+AAB+AAAB//AAAPwAAA//gAAB+AAAf/wAAAPwAAP/4AAAB+AAH/8AAAAPwAD/+AAAAB+AB//AAAAAPwA//gAAAAB+Af/gAAAAAPwP/wAAAAAB+H/4AAAAAAPz/8AAAAAAB//+AAAAAAAP//AAAAAAAB//gAAAAAAAP/wAAAAAAAB/4AAAAAAAAP8AAAAAAAAB+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAf8AAAAAHgAP/4AAAAH/gD//gAAAD//A///AAAA//8P//4AAAP//z///gAAD//+fwP+AAA/4f/4AfwAAH4A/+AB/AAB+AB/gAH4AAPgAH8AAfAAB8AA/AAD4AAfgAH4AAfgAD4AAfAAB8AAfAAD4AAPgAD4AAfAAB8AAfAAD4AAPgAD4AAfAAD8AAPgAH4AAfAAB8AA/gAD4AAPwAP8AA/AAA/AD/wAH4AAH8B//AB+AAAf//78A/wAAD//+f//8AAAP//h///gAAA//4P//4AAAB/+A//+AAAAD/AD//gAAAAAAAH/wAAAAAAAAHwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPAAAAAAAAAf/gAAAAAAAP/+AAAAAAAD//8AAAAAAA///wAAAAAAP///AAAAAAD///4AADAAA/wB/gAA4AAH8AD8AAPAAB/AAPwAH4AAPwAB+AB/AAB8AAHwAf4AAPgAA+AP/AAD8AAHwD/wAAfgAA+A/8AAD8AAHwf+AAAfgAA+H/gAAD8AAHx/wAAAPgAA8/8AAAB8AAPv/AAAAPwAB//gAAAB/AAf/4AAAAH8AH/8AAAAA/wD//AAAAAD////gAAAAAP///4AAAAAA///8AAAAAAD//+AAAAAAAH//AAAAAAAAP/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHgAAHwAAAAB+AAB/AAAAAf4AAP4AAAAD/AAD/gAAAAf4AAf8AAAAD/AAB/AAAAAPwAAP4AAAAA8AAA+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="), 46, atob("DRclJSUlJSUlJSUlEA=="), 63+(scale<<8)+(1<<16)); + return this; } -// handle switch display on by pressing BTN1 -Bangle.on('lcdPower', function(on) { - if (on) draw(); +function draw() { + var date = new Date(); + var timeStr = require("locale").time(date,1); + var dateStr = require("locale").date(date).toUpperCase(); + + g.reset(); + g.setColor(g.theme.bg); + g.fillRect(Bangle.appRect); + + g.setFontLato(); + g.setFontAlign(0, -1); + g.setColor(g.theme.fg); + g.drawString(timeStr, w/2, h/3); + + g.setFont("6x8",2); + g.setFontAlign(0,0) + g.drawString(dateStr, w/2, h - 24 - 24); + + queueDraw(); +} + +// timeout used to update every minute +var drawTimeout; + +// schedule a draw for the next minute +function queueDraw() { + if (drawTimeout) clearTimeout(drawTimeout); + drawTimeout = setTimeout(function() { + drawTimeout = undefined; + draw(); + }, 60000 - (Date.now() % 60000)); +} + +// Stop updates when LCD is off, restart when on +Bangle.on('lcdPower',on=>{ + if (on) { + draw(); // draw immediately, queue redraw + } else { // stop draw timer + if (drawTimeout) clearTimeout(drawTimeout); + drawTimeout = undefined; + } }); g.clear(); +// Show launcher when middle button pressed +Bangle.setUI("clock"); +// Load widgets Bangle.loadWidgets(); Bangle.drawWidgets(); -setInterval(draw, 15000); // refresh every 15s draw(); -// Show launcher when button pressed -Bangle.setUI("clock"); From 968e7b5840fdf95f1b3b5300a964b77ab788ab8a Mon Sep 17 00:00:00 2001 From: Marco Heiming Date: Sat, 8 Jan 2022 10:25:24 +0100 Subject: [PATCH 163/315] Make text size in heart rate circle slightly bigger as it does not have any units --- apps/circlesclock/app.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/circlesclock/app.js b/apps/circlesclock/app.js index 6d408fd59..3843d5dda 100644 --- a/apps/circlesclock/app.js +++ b/apps/circlesclock/app.js @@ -63,6 +63,7 @@ const circlePosX = [Math.round(w / 6), Math.round(3 * w / 6), Math.round(5 * w / const radiusOuter = 25; const radiusInner = 20; const circleFont = "Vector:15"; +const circleFontBig = "Vector:16"; const circleFontSmall = "Vector:13"; function draw() { @@ -229,7 +230,7 @@ function drawHeartRate(w) { g.fillPoly([w, h3, w - 15, h3 + radiusOuter + 5, w + 15, h3 + radiusOuter + 5]); - g.setFont(circleFont); + g.setFont(circleFontBig); g.setFontAlign(0, 0); g.setColor(colorFg); g.drawString(hrtValue != undefined ? hrtValue : "-", w, h3); From 04129c82818dbd956ed4f7b13d103b7754a02a1e Mon Sep 17 00:00:00 2001 From: Peter Slendebroek Date: Sat, 8 Jan 2022 13:58:47 +0100 Subject: [PATCH 164/315] changed type to app of mmind app --- apps.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps.json b/apps.json index 3321f822f..5153e3deb 100644 --- a/apps.json +++ b/apps.json @@ -5134,8 +5134,8 @@ "version":"0.01", "description": "This is the classic game for masterminds", "screenshots": [{"url":"screenshot_mmind.png"}], - "type": "game", - "tags": "game,app", + "type": "app", + "tags": "game", "readme":"README.md", "supports": ["BANGLEJS2"], "allow_emulator": true, From a1ebca296cf3f09ab8974610c23307ffb5cf76f9 Mon Sep 17 00:00:00 2001 From: Marcus Olsson Date: Sat, 8 Jan 2022 21:15:32 +0100 Subject: [PATCH 165/315] Fixed sv_SE formatting Long date does not work well for Bangle.js2 This aligns with default locale en_GB. --- apps.json | 2 +- apps/locale/ChangeLog | 1 + apps/locale/locales.js | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/apps.json b/apps.json index 3fc0616da..f5a17c37d 100644 --- a/apps.json +++ b/apps.json @@ -218,7 +218,7 @@ { "id": "locale", "name": "Languages", - "version": "0.14", + "version": "0.15", "description": "Translations for different countries", "icon": "locale.png", "type": "locale", diff --git a/apps/locale/ChangeLog b/apps/locale/ChangeLog index 448f8119a..198322fb2 100644 --- a/apps/locale/ChangeLog +++ b/apps/locale/ChangeLog @@ -14,3 +14,4 @@ 0.12: Fixed nl_NL formatting, because the full months won't fit on the Bangle.js2's screen 0.13: Now use shorter de_DE date format to more closely match other languages for size 0.14: Added some first translations for Messages in nl_NL +0.15: Fixed sv_SE formatting, long date does not work well for Bangle.js2 diff --git a/apps/locale/locales.js b/apps/locale/locales.js index cf511c54f..1626b744f 100644 --- a/apps/locale/locales.js +++ b/apps/locale/locales.js @@ -276,7 +276,7 @@ var locales = { temperature: "°C", ampm: { 0: "fm", 1: "em" }, timePattern: { 0: "%HH:%MM:%SS ", 1: "%HH:%MM" }, - datePattern: { 0: "%A %B %d %Y", "1": "%Y-%m-%d" }, // söndag 1 mars 2020 // 2020-03-01 + datePattern: { 0: "%b %d %Y", "1": "%Y-%m-%d" }, // feb 1 2020 // 2020-03-01 abmonth: "jan,feb,mars,apr,maj,juni,juli,aug,sep,okt,nov,dec", month: "januari,februari,mars,april,maj,juni,juli,augusti,september,oktober,november,december", abday: "sön,mån,tis,ons,tors,fre,lör", From 4341efb46a358612bce0c11ca259abd0109f374d Mon Sep 17 00:00:00 2001 From: hughbarney Date: Sat, 8 Jan 2022 20:43:06 +0000 Subject: [PATCH 166/315] Updated simplest to make it simpler, tweak to Pastel to make it cycle better --- apps.json | 4 ++-- apps/pastel/ChangeLog | 1 + apps/pastel/pastel.app.js | 2 +- apps/simplest/ChangeLog | 2 ++ apps/simplest/app.js | 27 +++++++++++---------------- 5 files changed, 17 insertions(+), 19 deletions(-) diff --git a/apps.json b/apps.json index 1f4e983e6..2d87b2f73 100644 --- a/apps.json +++ b/apps.json @@ -3794,7 +3794,7 @@ { "id": "simplest", "name": "Simplest Clock", - "version": "0.04", + "version": "0.05", "description": "The simplest working clock, acts as a tutorial piece", "icon": "simplest.png", "screenshots": [{"url":"screenshot_simplest.png"}], @@ -4215,7 +4215,7 @@ "id": "pastel", "name": "Pastel Clock", "shortName": "Pastel", - "version": "0.10", + "version": "0.11", "description": "A Configurable clock with custom fonts, background and weather display. Has a cyclic information line that includes, day, date, battery, sunrise and sunset times", "icon": "pastel.png", "dependencies": {"mylocation":"app", "widpedom":"app","weather":"app"}, diff --git a/apps/pastel/ChangeLog b/apps/pastel/ChangeLog index 627531f03..00090fcd1 100644 --- a/apps/pastel/ChangeLog +++ b/apps/pastel/ChangeLog @@ -8,3 +8,4 @@ 0.08: Added dependancy on MyLocation 0.09: Added dependancy on Pedometer Widget 0.10: Added Weather line, fixed issues on a Bangle 1, update every minute +0.11: Changed cycle on minute to prevInfo to avoid the 2nd one being the blank line diff --git a/apps/pastel/pastel.app.js b/apps/pastel/pastel.app.js index db60a2738..3e64cdd9c 100644 --- a/apps/pastel/pastel.app.js +++ b/apps/pastel/pastel.app.js @@ -255,7 +255,7 @@ function queueDraw() { if (drawTimeout) clearTimeout(drawTimeout); drawTimeout = setTimeout(function() { drawTimeout = undefined; - nextInfo(); + prevInfo(); draw(); }, 60000 - (Date.now() % 60000)); } diff --git a/apps/simplest/ChangeLog b/apps/simplest/ChangeLog index c5ceb7a44..e7ab5f2c3 100644 --- a/apps/simplest/ChangeLog +++ b/apps/simplest/ChangeLog @@ -2,3 +2,5 @@ 0.02: Use Bangle.setUI for button/launcher handling 0.03: Fix display for Bangle 2 0.04: Use queueDraw(), update every minute, respect theme, use Lato font +0.05: Decided against custom font as it inceases the code size + minimalism is useful when narrowing down issues diff --git a/apps/simplest/app.js b/apps/simplest/app.js index 85ccc1509..582c4c2d5 100644 --- a/apps/simplest/app.js +++ b/apps/simplest/app.js @@ -1,31 +1,19 @@ const h = g.getHeight(); const w = g.getWidth(); -// from fonts.google.com -Graphics.prototype.setFontLato = function(scale) { - // Actual height 50 (53 - 4) - this.setFontCustom(atob("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+AAAAAAAAAP4AAAAAAAAD/gAAAAAAAAf8AAAAAAAAD/gAAAAAAAAP4AAAAAAAAB/AAAAAAAAADgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA4AAAAAAAAAfAAAAAAAAAf4AAAAAAAAP/AAAAAAAAP/wAAAAAAAH/4AAAAAAAH/8AAAAAAAH/8AAAAAAAD/+AAAAAAAD/+AAAAAAAB//AAAAAAAB//AAAAAAAA//gAAAAAAA//gAAAAAAAf/gAAAAAAAf/wAAAAAAAP/wAAAAAAAP/4AAAAAAAH/4AAAAAAAB/8AAAAAAAAf8AAAAAAAAD+AAAAAAAAAeAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAf//gAAAAAAf///gAAAAAf////gAAAAH/////AAAAD/////8AAAA//////wAAAP/4AB//AAAD/wAAA/8AAA/wAAAA/wAAH8AAAAD+AAB/AAAAAP4AAPwAAAAA/AAB8AAAAAD4AAPgAAAAAfAAD8AAAAAD8AAfgAAAAAfgAD8AAAAAD8AAfgAAAAAfgAD8AAAAAD8AAPgAAAAAfAAB+AAAAAH4AAPwAAAAA/AAA/AAAAAPwAAH+AAAAH+AAAf8AAAB/gAAD/4AAB/8AAAP//gf//AAAA//////wAAAB/////4AAAAH////+AAAAAP////AAAAAAP///AAAAAAAD/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAADgAAAAAAAAA+AAAAAAAAAPwAAAD4AAAD+AAAAfAAAA/gAAAD4AAAP4AAAAfAAAD+AAAAD4AAA/wAAAAfAAAH8AAAAD4AAB/AAAAAfAAAfwAAAAD4AAH8AAAAAfAAB///////4AAP///////AAB///////4AAP///////AAB///////4AAP///////AAAAAAAAAD4AAAAAAAAAfAAAAAAAAAD4AAAAAAAAAfAAAAAAAAAD4AAAAAAAAAfAAAAAAAAAD4AAAAAAAAAfAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPAAAAHAAAAD4AAAH4AAAA/AAAB/AAAAP4AAA/4AAAD/AAAP/AAAA/4AAD/4AAAP/AAAf4AAAD/4AAH8AAAA//AAA/AAAAP74AAPwAAAD+fAAB+AAAA/n4AAPgAAAP4/AAD8AAAD+H4AAfgAAA/g/AAD8AAAP4H4AAfgAAD+A/AAD8AAA/gH4AAfgAAP4A/AAB8AAH+AH4AAPwAB/gA/AAB/AA/4AH4AAH8Af+AA/AAA////gAH4AAD///wAA/AAAP//8AAH4AAA///AAA/AAAD//gAAH4AAAH/wAAA/AAAAHwAAAD4AAAAAAAAAPAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAA8AAAAAPAAAP4AAAAP4AAB/gAAAD/AAAP/AAAA/4AAB/4AAAP/AAAD/gAAD/wAAAH+AAA/wAAAAfwAAH8AAAAB/AAB/AAAAAH4AAPwAAAAAfAAB8AAAAAD8AAPgADwAAfgAD8AAeAAD8AAfgADwAAfgAD8AAfAAD8AAfgAH4AAfgAD8AA/AAD8AAPgAH4AAfAAB+AB/gAH4AAPwAP8AA/AAB/AD/wAPwAAH+B+/AH+AAA///3+D/gAAD//8f//8AAAP//D///AAAA//wP//wAAAB/8A//8AAAAD8AB/+AAAAAAAAD+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAcAAAAAAAAAH4AAAAAAAAD/AAAAAAAAA/4AAAAAAAAP/AAAAAAAAH/4AAAAAAAB//AAAAAAAAf74AAAAAAAP+fAAAAAAAD/D4AAAAAAA/wfAAAAAAAf8D4AAAAAAH+AfAAAAAAD/gD4AAAAAA/4AfAAAAAAP8AD4AAAAAH/AAfAAAAAB/gAD4AAAAAf4AAfAAAAAP+AAD4AAAAD/AAAfAAAAA/wAAD4AAAAP///////AAB///////4AAP///////AAB///////4AAP///////AAB///////4AAAAAAAfAAAAAAAAAD4AAAAAAAAAfAAAAAAAAAD4AAAAAAAAAfAAAAAAAAAD4AAAAAAAAAOAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAA4AAAAAAAAAPgAAAAB/AAD8AAAAH/4AAfwAAA///AAB+AAB///4AAP4AAP///AAA/AAB///4AAH4AAP/gfAAAfAAB+AHwAAD8AAPwA+AAAfgAB+AHwAAD8AAPwA+AAAfgAB+AHwAAD8AAPwA+AAAfgAB+AH4AAD4AAPwA/AAAfAAB+AH4AAH4AAPwAfgAB/AAB+AD8AAfwAAPwAf4AH+AAB+AB/gD/gAAPwAP///4AAB+AA///+AAAPgAD///gAAB8AAP//4AAAPAAAf/8AAAAAAAA/+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/gAAAAAAAB//gAAAAAAA///AAAAAAAf//8AAAAAAH///4AAAAAD////AAAAAA//gf8AAAAAP/wAfwAAAAH/8AB+AAAAB//AAH4AAAA//wAA/AAAAP+8AAD4AAAD/ngAAfgAAB/58AAD8AAAf8PgAAfgAAH/B8AAD8AAD/wPgAAfgAA/8B8AAD8AAP+APgAAfAAB/gB8AAD4AAP4APwAA/AAB8AB+AAH4AAPAAH4AB+AABwAA/wA/wAAIAAD/gf8AAAAAAf///AAAAAAB///wAAAAAAH//8AAAAAAAf//AAAAAAAA//gAAAAAAAB/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB8AAAAAAAAAPgAAAAAAAAB+AAAAAAAAAPwAAAAAAAAB+AAAAAAAAAPwAAAAADAAB+AAAAAB4AAPwAAAAA/AAB+AAAAAf4AAPwAAAAP/AAB+AAAAH/4AAPwAAAD/+AAB+AAAB//AAAPwAAA//gAAB+AAAf/wAAAPwAAP/4AAAB+AAH/8AAAAPwAD/+AAAAB+AB//AAAAAPwA//gAAAAB+Af/gAAAAAPwP/wAAAAAB+H/4AAAAAAPz/8AAAAAAB//+AAAAAAAP//AAAAAAAB//gAAAAAAAP/wAAAAAAAB/4AAAAAAAAP8AAAAAAAAB+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAf8AAAAAHgAP/4AAAAH/gD//gAAAD//A///AAAA//8P//4AAAP//z///gAAD//+fwP+AAA/4f/4AfwAAH4A/+AB/AAB+AB/gAH4AAPgAH8AAfAAB8AA/AAD4AAfgAH4AAfgAD4AAfAAB8AAfAAD4AAPgAD4AAfAAB8AAfAAD4AAPgAD4AAfAAD8AAPgAH4AAfAAB8AA/gAD4AAPwAP8AA/AAA/AD/wAH4AAH8B//AB+AAAf//78A/wAAD//+f//8AAAP//h///gAAA//4P//4AAAB/+A//+AAAAD/AD//gAAAAAAAH/wAAAAAAAAHwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPAAAAAAAAAf/gAAAAAAAP/+AAAAAAAD//8AAAAAAA///wAAAAAAP///AAAAAAD///4AADAAA/wB/gAA4AAH8AD8AAPAAB/AAPwAH4AAPwAB+AB/AAB8AAHwAf4AAPgAA+AP/AAD8AAHwD/wAAfgAA+A/8AAD8AAHwf+AAAfgAA+H/gAAD8AAHx/wAAAPgAA8/8AAAB8AAPv/AAAAPwAB//gAAAB/AAf/4AAAAH8AH/8AAAAA/wD//AAAAAD////gAAAAAP///4AAAAAA///8AAAAAAD//+AAAAAAAH//AAAAAAAAP/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHgAAHwAAAAB+AAB/AAAAAf4AAP4AAAAD/AAD/gAAAAf4AAf8AAAAD/AAB/AAAAAPwAAP4AAAAA8AAA+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="), 46, atob("DRclJSUlJSUlJSUlEA=="), 63+(scale<<8)+(1<<16)); - return this; -} - function draw() { var date = new Date(); var timeStr = require("locale").time(date,1); - var dateStr = require("locale").date(date).toUpperCase(); g.reset(); g.setColor(g.theme.bg); g.fillRect(Bangle.appRect); - g.setFontLato(); - g.setFontAlign(0, -1); + g.setFont('Vector', w/3); + g.setFontAlign(0, 0); g.setColor(g.theme.fg); - g.drawString(timeStr, w/2, h/3); + g.drawString(timeStr, w/2, h/2); - g.setFont("6x8",2); - g.setFontAlign(0,0) - g.drawString(dateStr, w/2, h - 24 - 24); - queueDraw(); } @@ -52,8 +40,15 @@ Bangle.on('lcdPower',on=>{ }); g.clear(); + // Show launcher when middle button pressed -Bangle.setUI("clock"); +//Bangle.setUI("clock"); +// use clockupdown as it tests for issue #1249 +Bangle.setUI("clockupdown", btn=> { + draw(); +}); + + // Load widgets Bangle.loadWidgets(); Bangle.drawWidgets(); From 72eb12827255b12926d82cd825871349cdcea5b7 Mon Sep 17 00:00:00 2001 From: Didgeridoohan Date: Sun, 9 Jan 2022 07:32:57 +0100 Subject: [PATCH 167/315] Tweak long date --- apps/locale/locales.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/locale/locales.js b/apps/locale/locales.js index fea217efe..fce2b8c2a 100644 --- a/apps/locale/locales.js +++ b/apps/locale/locales.js @@ -294,7 +294,7 @@ var locales = { temperature: '°C', ampm: { 0: "", 1: "" }, timePattern: { 0: "%HH:%MM:%SS ", 1: "%HH:%MM" }, - datePattern: { 0: "%A %B %d %Y", "1": "%Y-%m-%d" }, // Sunday 1 March 2020 // 2020-03-01 + datePattern: { 0: "%B %d %Y", "1": "%Y-%m-%d" }, // March 1 2020 // 2020-03-01 abmonth: "Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec", month: "January,February,March,April,May,June,July,August,September,October,November,December", abday: "Sun,Mon,Tue,Wed,Thu,Fri,Sat", From 6896b282b2ac83fdf6c4149ff463493a5b8c07a6 Mon Sep 17 00:00:00 2001 From: The Dod Date: Sun, 9 Jan 2022 14:17:14 +0200 Subject: [PATCH 168/315] Rewrite mkFourTwentyTz in JS (instead of Python) --- apps/ftclock/.gitignore | 4 + apps/ftclock/README.md | 18 +- apps/ftclock/fourTwentyTz.js | 997 +++++++++++++++------------------ apps/ftclock/mkFourTwentyTz.js | 74 +++ apps/ftclock/mkFourTwentyTz.py | 46 -- apps/ftclock/package.json | 15 + 6 files changed, 568 insertions(+), 586 deletions(-) create mode 100644 apps/ftclock/.gitignore create mode 100644 apps/ftclock/mkFourTwentyTz.js delete mode 100644 apps/ftclock/mkFourTwentyTz.py create mode 100644 apps/ftclock/package.json diff --git a/apps/ftclock/.gitignore b/apps/ftclock/.gitignore new file mode 100644 index 000000000..b384cf1f2 --- /dev/null +++ b/apps/ftclock/.gitignore @@ -0,0 +1,4 @@ +timezonedb.csv.zip +country.csv +zone.csv +timezone.csv diff --git a/apps/ftclock/README.md b/apps/ftclock/README.md index 665a7693d..f30151552 100644 --- a/apps/ftclock/README.md +++ b/apps/ftclock/README.md @@ -4,12 +4,20 @@ A clock that tells when and where it's going to be [4:20](https://en.wikipedia.o ![screensot](screenshot.png) ![screenshot at 4:20](screenshot1.png) -## Note +## Generating `fourTwentyTz.js` -Once in a while, there'd be updates to the [timezone database](https://timezonedb.com/download) which -would require updating `fourTwentyTz.js`. I'll do my best to release a new version every time this happens, -but if you ever need to do this yourself, just run `python mkFourTwentyTz.py` (after downloading the timezone CSV files. -See comment at the top of the script). +Once in a while we need to regenerate it for 2 reasons: + +* One or more places got in or out of daylight saving time (DST) mode. +* The database saying _when_ places enter/exit DST mode got updated. + +I'll do my best to release a new version every time this happens, +but if you ever need to do this yourself, here's how: + +* `cd` to the `ftclock` folder +* If you haven't done so yet, run `npm install` there (this would create the `node_modules` folder). +* Get and unzip the latest `timezone.csv.zip` from https://timezonedb.com/download +* Run `npm run make` ## Creator diff --git a/apps/ftclock/fourTwentyTz.js b/apps/ftclock/fourTwentyTz.js index e41f3fdd0..cebab42cb 100644 --- a/apps/ftclock/fourTwentyTz.js +++ b/apps/ftclock/fourTwentyTz.js @@ -1,536 +1,463 @@ -// Generated by mk420tz.py - see https://github.com/thedod/BangleApps/420clock -// (version: Sat Dec 18 10:17:32 2021) +// Generated by mkFourTwentyTz.js // Data source: https://timezonedb.com/files/timezonedb.csv.zip -// (version: Sat Oct 16 01:48:14 2021) -exports.timezones = [ - [ - 1380, - [ - "Azores, Portugal", - "Cape Verde, Cabo Verde", - "Scoresbysund, Greenland" - ] - ], - [ - 1320, - [ - "Noronha, Brazil", - "South Georgia, South Georgia and the South Sandwich Islands" - ] - ], - [ - 1260, - [ - "Araguaina, Brazil", - "Asuncion, Paraguay", - "Bahia, Brazil", - "Belem, Brazil", - "Buenos Aires, Argentina", - "Catamarca, Argentina", - "Cayenne, French Guiana", - "Cordoba, Argentina", - "Fortaleza, Brazil", - "Jujuy, Argentina", - "La Rioja, Argentina", - "Maceio, Brazil", - "Mendoza, Argentina", - "Miquelon, Saint Pierre and Miquelon", - "Montevideo, Uruguay", - "Nuuk, Greenland", - "Palmer, Antarctica", - "Paramaribo, Suriname", - "Punta Arenas, Chile", - "Recife, Brazil", - "Rio Gallegos, Argentina", - "Rothera, Antarctica", - "Salta, Argentina", - "San Juan, Argentina", - "San Luis, Argentina", - "Santarem, Brazil", - "Santiago, Chile", - "Sao Paulo, Brazil", - "Stanley, Falkland Islands (Malvinas)", - "Tucuman, Argentina", - "Ushuaia, Argentina" - ] - ], - [ - 1200, - [ - "Anguilla, AI", - "Antigua, Antigua and Barbuda", - "Aruba, AW", - "Barbados, BB", - "Bermuda, BM", - "Blanc-Sablon, Canada", - "Boa Vista, Brazil", - "Campo Grande, Brazil", - "Caracas, Venezuela (Bolivarian Republic of)", - "Cuiaba, Brazil", - "Curacao, Cura\u00e7ao", - "Dominica, DM", - "Glace Bay, Canada", - "Goose Bay, Canada", - "Grenada, GD", - "Guadeloupe, GP", - "Guyana, GY", - "Halifax, Canada", - "Kralendijk, Bonaire, Sint Eustatius and Saba", - "La Paz, Bolivia (Plurinational State of)", - "Lower Princes, Sint Maarten (Dutch part)", - "Manaus, Brazil", - "Marigot, Saint Martin (French part)", - "Martinique, MQ", - "Moncton, Canada", - "Montserrat, MS", - "Port of Spain, Trinidad and Tobago", - "Porto Velho, Brazil", - "Puerto Rico, PR", - "Santo Domingo, Dominican Republic", - "St Barthelemy, Saint Barth\u00e9lemy", - "St Kitts, Saint Kitts and Nevis", - "St Lucia, Saint Lucia", - "St Thomas, Virgin Islands (U.S.)", - "St Vincent, Saint Vincent and the Grenadines", - "Thule, Greenland", - "Tortola, Virgin Islands (British)" - ] - ], - [ - 1140, - [ - "Atikokan, Canada", - "Bogota, Colombia", - "Cancun, Mexico", - "Cayman, Cayman Islands", - "Detroit, United States of America", - "Easter, Chile", - "Eirunepe, Brazil", - "Grand Turk, Turks and Caicos Islands", - "Guayaquil, Ecuador", - "Havana, Cuba", - "Indianapolis, Indiana", - "Iqaluit, Canada", - "Jamaica, JM", - "Lima, Peru", - "Louisville, Kentucky", - "Marengo, Indiana", - "Monticello, Kentucky", - "Nassau, Bahamas", - "New York, United States of America", - "Nipigon, Canada", - "Panama, PA", - "Pangnirtung, Canada", - "Petersburg, Indiana", - "Port-au-Prince, Haiti", - "Rio Branco, Brazil", - "Thunder Bay, Canada", - "Toronto, Canada", - "Vevay, Indiana", - "Vincennes, Indiana", - "Winamac, Indiana" - ] - ], - [ - 1080, - [ - "Bahia Banderas, Mexico", - "Belize, BZ", - "Beulah, North Dakota", - "Center, North Dakota", - "Chicago, United States of America", - "Costa Rica, CR", - "El Salvador, SV", - "Galapagos, Ecuador", - "Guatemala, GT", - "Knox, Indiana", - "Managua, Nicaragua", - "Matamoros, Mexico", - "Menominee, United States of America", - "Merida, Mexico", - "Mexico City, Mexico", - "Monterrey, Mexico", - "New Salem, North Dakota", - "Rainy River, Canada", - "Rankin Inlet, Canada", - "Regina, Canada", - "Resolute, Canada", - "Swift Current, Canada", - "Tegucigalpa, Honduras", - "Tell City, Indiana", - "Winnipeg, Canada" - ] - ], - [ - 1020, - [ - "Boise, United States of America", - "Cambridge Bay, Canada", - "Chihuahua, Mexico", - "Creston, Canada", - "Dawson Creek, Canada", - "Dawson, Canada", - "Denver, United States of America", - "Edmonton, Canada", - "Fort Nelson, Canada", - "Hermosillo, Mexico", - "Inuvik, Canada", - "Mazatlan, Mexico", - "Ojinaga, Mexico", - "Phoenix, United States of America", - "Whitehorse, Canada", - "Yellowknife, Canada" - ] - ], - [ - 960, - [ - "Los Angeles, United States of America", - "Pitcairn, PN", - "Tijuana, Mexico", - "Vancouver, Canada" - ] - ], - [ - 900, - [ - "Anchorage, United States of America", - "Gambier, French Polynesia", - "Juneau, United States of America", - "Metlakatla, United States of America", - "Nome, United States of America", - "Sitka, United States of America", - "Yakutat, United States of America" - ] - ], - [ - 840, - [ - "Adak, United States of America", - "Honolulu, United States of America", - "Kiritimati, Kiribati", - "Rarotonga, Cook Islands", - "Tahiti, French Polynesia" - ] - ], - [ - 780, - [ - "Apia, Samoa", - "Auckland, New Zealand", - "Fakaofo, Tokelau", - "Kanton, Kiribati", - "McMurdo, Antarctica", - "Midway, United States Minor Outlying Islands", - "Niue, NU", - "Pago Pago, American Samoa", - "Tongatapu, Tonga" - ] - ], - [ - 720, - [ - "Anadyr, Russian Federation", - "Fiji, FJ", - "Funafuti, Tuvalu", - "Kamchatka, Russian Federation", - "Kwajalein, Marshall Islands", - "Majuro, Marshall Islands", - "Nauru, NR", - "Norfolk, Norfolk Island", - "Tarawa, Kiribati", - "Wake, United States Minor Outlying Islands", - "Wallis, Wallis and Futuna" - ] - ], - [ - 660, - [ - "Bougainville, Papua New Guinea", - "Casey, Antarctica", - "Efate, Vanuatu", - "Guadalcanal, Solomon Islands", - "Hobart, Australia", - "Kosrae, Micronesia (Federated States of)", - "Lord Howe, Australia", - "Macquarie, Australia", - "Magadan, Russian Federation", - "Melbourne, Australia", - "Noumea, New Caledonia", - "Pohnpei, Micronesia (Federated States of)", - "Sakhalin, Russian Federation", - "Srednekolymsk, Russian Federation", - "Sydney, Australia" - ] - ], - [ - 600, - [ - "Brisbane, Australia", - "Chuuk, Micronesia (Federated States of)", - "DumontDUrville, Antarctica", - "Guam, GU", - "Lindeman, Australia", - "Port Moresby, Papua New Guinea", - "Saipan, Northern Mariana Islands", - "Ust-Nera, Russian Federation", - "Vladivostok, Russian Federation" - ] - ], - [ - 540, - [ - "Chita, Russian Federation", - "Dili, Timor-Leste", - "Jayapura, Indonesia", - "Khandyga, Russian Federation", - "Palau, PW", - "Pyongyang, Korea (Democratic People's Republic of)", - "Seoul, Korea, Republic of", - "Tokyo, Japan", - "Yakutsk, Russian Federation" - ] - ], - [ - 480, - [ - "Brunei, Brunei Darussalam", - "Choibalsan, Mongolia", - "Hong Kong, HK", - "Irkutsk, Russian Federation", - "Kuala Lumpur, Malaysia", - "Kuching, Malaysia", - "Macau, Macao", - "Makassar, Indonesia", - "Manila, Philippines", - "Perth, Australia", - "Shanghai, China", - "Singapore, SG", - "Taipei, Taiwan, Province of China", - "Ulaanbaatar, Mongolia" - ] - ], - [ - 420, - [ - "Bangkok, Thailand", - "Barnaul, Russian Federation", - "Christmas, Christmas Island", - "Davis, Antarctica", - "Ho Chi Minh, Viet Nam", - "Hovd, Mongolia", - "Jakarta, Indonesia", - "Krasnoyarsk, Russian Federation", - "Novokuznetsk, Russian Federation", - "Novosibirsk, Russian Federation", - "Phnom Penh, Cambodia", - "Pontianak, Indonesia", - "Tomsk, Russian Federation", - "Vientiane, Lao People's Democratic Republic" - ] - ], - [ - 360, - [ - "Almaty, Kazakhstan", - "Bishkek, Kyrgyzstan", - "Chagos, British Indian Ocean Territory", - "Dhaka, Bangladesh", - "Omsk, Russian Federation", - "Qostanay, Kazakhstan", - "Thimphu, Bhutan", - "Urumqi, China", - "Vostok, Antarctica" - ] - ], - [ - 300, - [ - "Aqtau, Kazakhstan", - "Aqtobe, Kazakhstan", - "Ashgabat, Turkmenistan", - "Atyrau, Kazakhstan", - "Dushanbe, Tajikistan", - "Karachi, Pakistan", - "Kerguelen, French Southern Territories", - "Maldives, MV", - "Mawson, Antarctica", - "Oral, Kazakhstan", - "Qyzylorda, Kazakhstan", - "Samarkand, Uzbekistan", - "Tashkent, Uzbekistan", - "Yekaterinburg, Russian Federation" - ] - ], - [ - 240, - [ - "Astrakhan, Russian Federation", - "Baku, Azerbaijan", - "Dubai, United Arab Emirates", - "Mahe, Seychelles", - "Mauritius, MU", - "Muscat, Oman", - "Reunion, R\u00e9union", - "Samara, Russian Federation", - "Saratov, Russian Federation", - "Tbilisi, Georgia", - "Ulyanovsk, Russian Federation", - "Yerevan, Armenia" - ] - ], - [ - 180, - [ - "Addis Ababa, Ethiopia", - "Aden, Yemen", - "Antananarivo, Madagascar", - "Asmara, Eritrea", - "Baghdad, Iraq", - "Bahrain, BH", - "Comoro, Comoros", - "Dar es Salaam, Tanzania, United Republic of", - "Djibouti, DJ", - "Istanbul, Turkey", - "Kampala, Uganda", - "Kirov, Russian Federation", - "Kuwait, KW", - "Mayotte, YT", - "Minsk, Belarus", - "Mogadishu, Somalia", - "Moscow, Russian Federation", - "Nairobi, Kenya", - "Qatar, QA", - "Riyadh, Saudi Arabia", - "Simferopol, Ukraine", - "Syowa, Antarctica", - "Volgograd, Russian Federation" - ] - ], - [ - 120, - [ - "Amman, Jordan", - "Athens, Greece", - "Beirut, Lebanon", - "Blantyre, Malawi", - "Bucharest, Romania", - "Bujumbura, Burundi", - "Cairo, Egypt", - "Chisinau, Moldova, Republic of", - "Damascus, Syrian Arab Republic", - "Famagusta, Cyprus", - "Gaborone, Botswana", - "Gaza, Palestine, State of", - "Harare, Zimbabwe", - "Hebron, Palestine, State of", - "Helsinki, Finland", - "Jerusalem, Israel", - "Johannesburg, South Africa", - "Juba, South Sudan", - "Kaliningrad, Russian Federation", - "Khartoum, Sudan", - "Kiev, Ukraine", - "Kigali, Rwanda", - "Lubumbashi, Congo, Democratic Republic of the", - "Lusaka, Zambia", - "Maputo, Mozambique", - "Mariehamn, \u00c5land Islands", - "Maseru, Lesotho", - "Mbabane, Eswatini", - "Nicosia, Cyprus", - "Riga, Latvia", - "Sofia, Bulgaria", - "Tallinn, Estonia", - "Tripoli, Libya", - "Uzhgorod, Ukraine", - "Vilnius, Lithuania", - "Windhoek, Namibia", - "Zaporozhye, Ukraine" - ] - ], - [ - 60, - [ - "Algiers, Algeria", - "Amsterdam, Netherlands", - "Andorra, AD", - "Bangui, Central African Republic", - "Belgrade, Serbia", - "Berlin, Germany", - "Bratislava, Slovakia", - "Brazzaville, Congo", - "Brussels, Belgium", - "Budapest, Hungary", - "Busingen, Germany", - "Casablanca, Morocco", - "Ceuta, Spain", - "Copenhagen, Denmark", - "Douala, Cameroon", - "El Aaiun, Western Sahara", - "Gibraltar, GI", - "Kinshasa, Congo, Democratic Republic of the", - "Lagos, Nigeria", - "Libreville, Gabon", - "Ljubljana, Slovenia", - "Longyearbyen, Svalbard and Jan Mayen", - "Luanda, Angola", - "Luxembourg, LU", - "Madrid, Spain", - "Malabo, Equatorial Guinea", - "Malta, MT", - "Monaco, MC", - "Ndjamena, Chad", - "Niamey, Niger", - "Oslo, Norway", - "Paris, France", - "Podgorica, Montenegro", - "Porto-Novo, Benin", - "Prague, Czechia", - "Rome, Italy", - "San Marino, SM", - "Sarajevo, Bosnia and Herzegovina", - "Skopje, North Macedonia", - "Stockholm, Sweden", - "Tirane, Albania", - "Tunis, Tunisia", - "Vaduz, Liechtenstein", - "Vatican, Holy See", - "Vienna, Austria", - "Warsaw, Poland", - "Zagreb, Croatia", - "Zurich, Switzerland" - ] - ], - [ - 0, - [ - "Abidjan, C\u00f4te d'Ivoire", - "Accra, Ghana", - "Bamako, Mali", - "Banjul, Gambia", - "Bissau, Guinea-Bissau", - "Canary, Spain", - "Conakry, Guinea", - "Dakar, Senegal", - "Danmarkshavn, Greenland", - "Dublin, Ireland", - "Faroe, Faroe Islands", - "Freetown, Sierra Leone", - "Guernsey, GG", - "Isle of Man, IM", - "Jersey, JE", - "Lisbon, Portugal", - "Lome, Togo", - "London, United Kingdom of Great Britain and Northern Ireland", - "Madeira, Portugal", - "Monrovia, Liberia", - "Nouakchott, Mauritania", - "Ouagadougou, Burkina Faso", - "Reykjavik, Iceland", - "Sao Tome, Sao Tome and Principe", - "St Helena, Saint Helena, Ascension and Tristan da Cunha", - "Troll, Antarctica" - ] - ] -]; +// Sun Jan 09 2022 13:21:47 GMT+0200 (Israel Standard Time) +exports.timezones = { + "0": [ + "Troll, Antarctica", + "Ouagadougou, Burkina Faso", + "Abidjan, Côte d'Ivoire", + "Canary, Spain", + "Faroe, Faroe Islands", + "London, United Kingdom of Great Britain and Northern Ireland", + "Guernsey, Guernsey", + "Accra, Ghana", + "Danmarkshavn, Greenland", + "Banjul, Gambia", + "Conakry, Guinea", + "Bissau, Guinea-Bissau", + "Dublin, Ireland", + "Isle of_Man, Isle of Man", + "Reykjavik, Iceland", + "Jersey, Jersey", + "Monrovia, Liberia", + "Bamako, Mali", + "Nouakchott, Mauritania", + "Lisbon, Portugal", + "Madeira, Portugal", + "St Helena, Saint Helena, Ascension and Tristan da Cunha", + "Freetown, Sierra Leone", + "Dakar, Senegal", + "Sao Tome, Sao Tome and Principe", + "Lome, Togo" + ], + "60": [ + "Andorra, Andorra", + "Tirane, Albania", + "Luanda, Angola", + "Vienna, Austria", + "Sarajevo, Bosnia and Herzegovina", + "Brussels, Belgium", + "Porto-Novo, Benin", + "Kinshasa, Congo, Democratic Republic of the", + "Bangui, Central African Republic", + "Brazzaville, Congo", + "Zurich, Switzerland", + "Douala, Cameroon", + "Prague, Czechia", + "Berlin, Germany", + "Busingen, Germany", + "Copenhagen, Denmark", + "Algiers, Algeria", + "El Aaiun, Western Sahara", + "Madrid, Spain", + "Ceuta, Spain", + "Paris, France", + "Libreville, Gabon", + "Gibraltar, Gibraltar", + "Malabo, Equatorial Guinea", + "Zagreb, Croatia", + "Budapest, Hungary", + "Rome, Italy", + "Vaduz, Liechtenstein", + "Luxembourg, Luxembourg", + "Casablanca, Morocco", + "Monaco, Monaco", + "Podgorica, Montenegro", + "Skopje, North Macedonia", + "Malta, Malta", + "Niamey, Niger", + "Lagos, Nigeria", + "Amsterdam, Netherlands", + "Oslo, Norway", + "Warsaw, Poland", + "Belgrade, Serbia", + "Stockholm, Sweden", + "Ljubljana, Slovenia", + "Longyearbyen, Svalbard and Jan Mayen", + "Bratislava, Slovakia", + "San Marino, San Marino", + "Ndjamena, Chad", + "Tunis, Tunisia", + "Vatican, Holy See" + ], + "120": [ + "Mariehamn, Åland Islands", + "Sofia, Bulgaria", + "Bujumbura, Burundi", + "Gaborone, Botswana", + "Lubumbashi, Congo, Democratic Republic of the", + "Nicosia, Cyprus", + "Famagusta, Cyprus", + "Tallinn, Estonia", + "Cairo, Egypt", + "Helsinki, Finland", + "Athens, Greece", + "Jerusalem, Israel", + "Amman, Jordan", + "Beirut, Lebanon", + "Maseru, Lesotho", + "Vilnius, Lithuania", + "Riga, Latvia", + "Tripoli, Libya", + "Chisinau, Moldova, Republic of", + "Blantyre, Malawi", + "Maputo, Mozambique", + "Windhoek, Namibia", + "Gaza, Palestine, State of", + "Hebron, Palestine, State of", + "Bucharest, Romania", + "Kaliningrad, Russian Federation", + "Kigali, Rwanda", + "Khartoum, Sudan", + "Juba, South Sudan", + "Damascus, Syrian Arab Republic", + "Mbabane, Eswatini", + "Kiev, Ukraine", + "Uzhgorod, Ukraine", + "Zaporozhye, Ukraine", + "Johannesburg, South Africa", + "Lusaka, Zambia", + "Harare, Zimbabwe" + ], + "180": [ + "Syowa, Antarctica", + "Bahrain, Bahrain", + "Minsk, Belarus", + "Djibouti, Djibouti", + "Asmara, Eritrea", + "Addis Ababa, Ethiopia", + "Baghdad, Iraq", + "Nairobi, Kenya", + "Comoro, Comoros", + "Kuwait, Kuwait", + "Antananarivo, Madagascar", + "Qatar, Qatar", + "Moscow, Russian Federation", + "Simferopol, Ukraine", + "Kirov, Russian Federation", + "Volgograd, Russian Federation", + "Riyadh, Saudi Arabia", + "Mogadishu, Somalia", + "Istanbul, Turkey", + "Dar es_Salaam, Tanzania, United Republic of", + "Kampala, Uganda", + "Aden, Yemen", + "Mayotte, Mayotte" + ], + "240": [ + "Dubai, United Arab Emirates", + "Yerevan, Armenia", + "Baku, Azerbaijan", + "Tbilisi, Georgia", + "Mauritius, Mauritius", + "Muscat, Oman", + "Reunion, Réunion", + "Astrakhan, Russian Federation", + "Saratov, Russian Federation", + "Ulyanovsk, Russian Federation", + "Samara, Russian Federation", + "Mahe, Seychelles" + ], + "300": [ + "Mawson, Antarctica", + "Qyzylorda, Kazakhstan", + "Aqtobe, Kazakhstan", + "Aqtau, Kazakhstan", + "Atyrau, Kazakhstan", + "Oral, Kazakhstan", + "Maldives, Maldives", + "Karachi, Pakistan", + "Yekaterinburg, Russian Federation", + "Kerguelen, French Southern Territories", + "Dushanbe, Tajikistan", + "Ashgabat, Turkmenistan", + "Samarkand, Uzbekistan", + "Tashkent, Uzbekistan" + ], + "360": [ + "Vostok, Antarctica", + "Dhaka, Bangladesh", + "Thimphu, Bhutan", + "Urumqi, China", + "Chagos, British Indian Ocean Territory", + "Bishkek, Kyrgyzstan", + "Almaty, Kazakhstan", + "Qostanay, Kazakhstan", + "Omsk, Russian Federation" + ], + "420": [ + "Davis, Antarctica", + "Christmas, Christmas Island", + "Jakarta, Indonesia", + "Pontianak, Indonesia", + "Phnom Penh, Cambodia", + "Vientiane, Lao People's Democratic Republic", + "Hovd, Mongolia", + "Novosibirsk, Russian Federation", + "Barnaul, Russian Federation", + "Tomsk, Russian Federation", + "Novokuznetsk, Russian Federation", + "Krasnoyarsk, Russian Federation", + "Bangkok, Thailand", + "Ho Chi_Minh, Viet Nam" + ], + "480": [ + "Perth, Australia", + "Brunei, Brunei Darussalam", + "Shanghai, China", + "Hong Kong, Hong Kong", + "Makassar, Indonesia", + "Ulaanbaatar, Mongolia", + "Choibalsan, Mongolia", + "Macau, Macao", + "Kuala Lumpur, Malaysia", + "Kuching, Malaysia", + "Manila, Philippines", + "Irkutsk, Russian Federation", + "Singapore, Singapore", + "Taipei, Taiwan, Province of China" + ], + "540": [ + "Jayapura, Indonesia", + "Tokyo, Japan", + "Pyongyang, Korea (Democratic People's Republic of)", + "Seoul, Korea, Republic of", + "Palau, Palau", + "Chita, Russian Federation", + "Yakutsk, Russian Federation", + "Khandyga, Russian Federation", + "Dili, Timor-Leste" + ], + "600": [ + "DumontDUrville, Antarctica", + "Brisbane, Australia", + "Lindeman, Australia", + "Chuuk, Micronesia (Federated States of)", + "Guam, Guam", + "Saipan, Northern Mariana Islands", + "Port Moresby, Papua New Guinea", + "Vladivostok, Russian Federation", + "Ust-Nera, Russian Federation" + ], + "660": [ + "Casey, Antarctica", + "Lord Howe, Australia", + "Macquarie, Australia", + "Hobart, Australia", + "Melbourne, Australia", + "Sydney, Australia", + "Pohnpei, Micronesia (Federated States of)", + "Kosrae, Micronesia (Federated States of)", + "Noumea, New Caledonia", + "Bougainville, Papua New Guinea", + "Magadan, Russian Federation", + "Sakhalin, Russian Federation", + "Srednekolymsk, Russian Federation", + "Guadalcanal, Solomon Islands", + "Efate, Vanuatu" + ], + "720": [ + "Tarawa, Kiribati", + "Majuro, Marshall Islands", + "Kwajalein, Marshall Islands", + "Norfolk, Norfolk Island", + "Nauru, Nauru", + "Kamchatka, Russian Federation", + "Anadyr, Russian Federation", + "Funafuti, Tuvalu", + "Wake, United States Minor Outlying Islands", + "Wallis, Wallis and Futuna" + ], + "780": [ + "McMurdo, Antarctica", + "Pago Pago, American Samoa", + "Fiji, Fiji", + "Kanton, Kiribati", + "Niue, Niue", + "Auckland, New Zealand", + "Fakaofo, Tokelau", + "Tongatapu, Tonga", + "Midway, United States Minor Outlying Islands", + "Apia, Samoa" + ], + "840": [ + "Rarotonga, Cook Islands", + "Kiritimati, Kiribati", + "Tahiti, French Polynesia", + "Adak, United States of America", + "Honolulu, United States of America" + ], + "900": [ + "Gambier, French Polynesia", + "Anchorage, United States of America", + "Juneau, United States of America", + "Sitka, United States of America", + "Metlakatla, United States of America", + "Yakutat, United States of America", + "Nome, United States of America" + ], + "960": [ + "Vancouver, Canada", + "Tijuana, Mexico", + "Pitcairn, Pitcairn", + "Los Angeles, United States of America" + ], + "1020": [ + "Edmonton, Canada", + "Cambridge Bay, Canada", + "Yellowknife, Canada", + "Inuvik, Canada", + "Creston, Canada", + "Dawson Creek, Canada", + "Fort Nelson, Canada", + "Whitehorse, Canada", + "Dawson, Canada", + "Mazatlan, Mexico", + "Chihuahua, Mexico", + "Ojinaga, Mexico", + "Hermosillo, Mexico", + "Denver, United States of America", + "Boise, United States of America", + "Phoenix, United States of America" + ], + "1080": [ + "Belize, Belize", + "Winnipeg, Canada", + "Rainy River, Canada", + "Resolute, Canada", + "Rankin Inlet, Canada", + "Regina, Canada", + "Swift Current, Canada", + "Costa Rica, Costa Rica", + "Galapagos, Ecuador", + "Guatemala, Guatemala", + "Tegucigalpa, Honduras", + "Mexico City, Mexico", + "Merida, Mexico", + "Monterrey, Mexico", + "Matamoros, Mexico", + "Bahia Banderas, Mexico", + "Managua, Nicaragua", + "El Salvador, El Salvador", + "Chicago, United States of America", + "Tell City, Indiana", + "Knox, Indiana", + "Menominee, United States of America", + "Center, North Dakota", + "New_Salem, North Dakota", + "Beulah, North Dakota" + ], + "1140": [ + "Eirunepe, Brazil", + "Rio Branco, Brazil", + "Nassau, Bahamas", + "Toronto, Canada", + "Nipigon, Canada", + "Thunder Bay, Canada", + "Iqaluit, Canada", + "Pangnirtung, Canada", + "Atikokan, Canada", + "Easter, Chile", + "Bogota, Colombia", + "Havana, Cuba", + "Guayaquil, Ecuador", + "Port-au-Prince, Haiti", + "Jamaica, Jamaica", + "Cayman, Cayman Islands", + "Cancun, Mexico", + "Panama, Panama", + "Lima, Peru", + "Grand Turk, Turks and Caicos Islands", + "New York, United States of America", + "Detroit, United States of America", + "Louisville, Kentucky", + "Monticello, Kentucky", + "Indianapolis, Indiana", + "Vincennes, Indiana", + "Winamac, Indiana", + "Marengo, Indiana", + "Petersburg, Indiana", + "Vevay, Indiana" + ], + "1200": [ + "Antigua, Antigua and Barbuda", + "Anguilla, Anguilla", + "Aruba, Aruba", + "Barbados, Barbados", + "St Barthelemy, Saint Barthélemy", + "Bermuda, Bermuda", + "La Paz, Bolivia (Plurinational State of)", + "Kralendijk, Bonaire, Sint Eustatius and Saba", + "Campo Grande, Brazil", + "Cuiaba, Brazil", + "Porto Velho, Brazil", + "Boa Vista, Brazil", + "Manaus, Brazil", + "Halifax, Canada", + "Glace Bay, Canada", + "Moncton, Canada", + "Goose Bay, Canada", + "Blanc-Sablon, Canada", + "Curacao, Curaçao", + "Dominica, Dominica", + "Santo Domingo, Dominican Republic", + "Grenada, Grenada", + "Thule, Greenland", + "Guadeloupe, Guadeloupe", + "Guyana, Guyana", + "St Kitts, Saint Kitts and Nevis", + "St Lucia, Saint Lucia", + "Marigot, Saint Martin (French part)", + "Martinique, Martinique", + "Montserrat, Montserrat", + "Puerto Rico, Puerto Rico", + "Lower Princes, Sint Maarten (Dutch part)", + "Port of_Spain, Trinidad and Tobago", + "St Vincent, Saint Vincent and the Grenadines", + "Caracas, Venezuela (Bolivarian Republic of)", + "Tortola, Virgin Islands (British)", + "St Thomas, Virgin Islands (U.S.)" + ], + "1260": [ + "Palmer, Antarctica", + "Rothera, Antarctica", + "Buenos Aires, Argentina", + "Cordoba, Argentina", + "Salta, Argentina", + "Jujuy, Argentina", + "Tucuman, Argentina", + "Catamarca, Argentina", + "La Rioja, Argentina", + "San Juan, Argentina", + "Mendoza, Argentina", + "San Luis, Argentina", + "Rio Gallegos, Argentina", + "Ushuaia, Argentina", + "Belem, Brazil", + "Fortaleza, Brazil", + "Recife, Brazil", + "Araguaina, Brazil", + "Maceio, Brazil", + "Bahia, Brazil", + "Sao Paulo, Brazil", + "Santarem, Brazil", + "Santiago, Chile", + "Punta Arenas, Chile", + "Stanley, Falkland Islands (Malvinas)", + "Cayenne, French Guiana", + "Nuuk, Greenland", + "Miquelon, Saint Pierre and Miquelon", + "Asuncion, Paraguay", + "Paramaribo, Suriname", + "Montevideo, Uruguay" + ], + "1320": [ + "Noronha, Brazil", + "South Georgia, South Georgia and the South Sandwich Islands" + ], + "1380": [ + "Cape Verde, Cabo Verde", + "Scoresbysund, Greenland", + "Azores, Portugal" + ] +} \ No newline at end of file diff --git a/apps/ftclock/mkFourTwentyTz.js b/apps/ftclock/mkFourTwentyTz.js new file mode 100644 index 000000000..dd199523a --- /dev/null +++ b/apps/ftclock/mkFourTwentyTz.js @@ -0,0 +1,74 @@ +let fs = require('fs'); +let csv = require('csv'); + +let countries = {}, + zones = {}, + offsdict = {}, + now = Date.now(); // we need this to find zone's current DST state + +function handleWrite(err,bytes) { + if (err) { + console.log(`Error writing to file ${err}`); + } +} + +console.log("Generating fourTwentyTz.js..."); +fs.createReadStream(__dirname+'/country.csv') + .pipe(csv.parse()) + .on('data', (r) => { + countries[r[0]] = r[1]; + }) + .on('end', () => { + fs.createReadStream(__dirname+'/zone.csv') + .pipe(csv.parse()) + .on('data', (r) => { + let parts = r[2].replace('_',' ').split('/'); + let city = parts[parts.length-1]; + let country =''; + if (parts.length>2) { // e.g. America/North_Dakota/New_Salem + country = parts[1]; // e.g. North Dakota + } else { + country = countries[r[1]]; // e.g. United States + } + zones[parseInt(r[0])] = {"name": `${city}, ${country}`}; + }) + .on('end', () => { + fs.createReadStream(__dirname+'/timezone.csv') + .pipe(csv.parse()) + .on('data', (r) => { + code = parseInt(r[0]); + if (!(code in zones)) return; + starttime = parseInt(r[2] || "0"); // Bugger. They're feeding us blanks for UTC now + offs = parseInt(r[3]); + if (offs<0) { + offs += 60*60*24; + } + zone = zones[code]; + if (starttime { + for (z in zones) { + zone = zones[z]; + if (zone.offs%60) continue; // One a dem funky timezones. Ignore. + zonelist = offsdict[zone.offs] || []; + zonelist.push(zone.name); + offsdict[zone.offs] = zonelist; + } + fs.open("fourTwentyTz.js","w", (err, fd) => { + if (err) { + console.log("Can't open output file"); + return; + } + fs.write(fd, "// Generated by mkFourTwentyTz.js\n", handleWrite); + fs.write(fd, `// ${Date()}\n`, handleWrite); + fs.write(fd, "// Data source: https://timezonedb.com/files/timezonedb.csv.zip\n", handleWrite); + fs.write(fd, "exports.timezones = ", handleWrite); + fs.write(fd, JSON.stringify(offsdict, null, 4), handleWrite); + console.log('Done.'); + }); + }) + }) + }); diff --git a/apps/ftclock/mkFourTwentyTz.py b/apps/ftclock/mkFourTwentyTz.py deleted file mode 100644 index 713b68059..000000000 --- a/apps/ftclock/mkFourTwentyTz.py +++ /dev/null @@ -1,46 +0,0 @@ -# Generates fourTwentyTz.js from time zone csv files -# get latest files from https://timezonedb.com/download -import csv,json,time,os,math -countries = {} -for r in csv.reader(open("country.csv")): - countries[r[0]] = r[1] -zones = {} -for r in csv.reader(open("zone.csv")): - parts = r[2].replace('_',' ').split('/') - city = parts[-1] - if len(parts)>2: # e.g. America/North_Dakota/New_Salem - country = parts[1] # e.g. North Dakota - else: # e.g. America/Denver - country = countries[r[1]] # e.g. United States - if country==city: # Avoid awkward searches like "Anguilla, Anguilla" - country = r[1] # Use code instead - zones[int(r[0])] = {"name":', '.join((city,country))} -now = int(time.time()) -for r in csv.reader(open("timezone.csv")): - code = int(r[0]) - if code not in zones: - continue - starttime = int(r[2] or "0") # Bugger. They're feeding us blanks for UTC now - offs = int(r[3]) - if offs < 0: - offs += 60*60*24 - d = zones[code] - if starttime Date: Sun, 9 Jan 2022 13:42:01 +0100 Subject: [PATCH 169/315] Fix drawing of full circle --- apps/circlesclock/app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/circlesclock/app.js b/apps/circlesclock/app.js index 3843d5dda..1f6cc75ab 100644 --- a/apps/circlesclock/app.js +++ b/apps/circlesclock/app.js @@ -372,7 +372,7 @@ function drawGauge(cx, cy, percent, color) { if (percent > 1) percent = 1; var startrot = -offset; - var endrot = startrot - ((end - offset) * percent) - 15; + var endrot = startrot - ((end - offset) * percent) - 35; g.setColor(color); From 05f0d3003a32df7e1e95bfd72d679d9edc333097 Mon Sep 17 00:00:00 2001 From: Marco Heiming Date: Sun, 9 Jan 2022 13:45:50 +0100 Subject: [PATCH 170/315] Fix minor glitch in circle drawing --- apps/circlesclock/app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/circlesclock/app.js b/apps/circlesclock/app.js index 1f6cc75ab..91d4937c4 100644 --- a/apps/circlesclock/app.js +++ b/apps/circlesclock/app.js @@ -376,7 +376,7 @@ function drawGauge(cx, cy, percent, color) { g.setColor(color); - const size = radiusOuter - radiusInner - 3; + const size = radiusOuter - radiusInner - 2; // draw gauge for (i = startrot; i > endrot - size; i -= size) { x = cx + r * Math.sin(radians(i)); From 6f1b1093621a20aba705cbe483222013c416f1b4 Mon Sep 17 00:00:00 2001 From: Marco Heiming Date: Sun, 9 Jan 2022 13:46:12 +0100 Subject: [PATCH 171/315] Add TODOs to README --- apps/circlesclock/README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/circlesclock/README.md b/apps/circlesclock/README.md index a071efcf5..9aaa4bc8e 100644 --- a/apps/circlesclock/README.md +++ b/apps/circlesclock/README.md @@ -15,6 +15,10 @@ It can show the following information (this can be configured): ![Screenshot dark theme](screenshot-dark.png) ![Screenshot light theme](screenshot-light.png) +# TODO +* Add sunrise and sunset +* Display moon instead of sun during night on weather circle + ## Creator Marco ([myxor](https://github.com/myxor)) From 992b1e6564777d5d4e3bb012594ee5c030953393 Mon Sep 17 00:00:00 2001 From: Adam Schmalhofer Date: Sun, 9 Jan 2022 18:55:33 +0100 Subject: [PATCH 172/315] Bumped wohrm version number --- apps.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps.json b/apps.json index ebe193f3a..c155f9262 100644 --- a/apps.json +++ b/apps.json @@ -1717,7 +1717,7 @@ { "id": "wohrm", "name": "Workout HRM", - "version": "0.09-rc10", + "version": "0.09", "description": "Workout heart rate monitor notifies you with a buzz if your heart rate goes above or below the set limits.", "icon": "app.png", "type": "app", From 707118ffbbc92dc8869b5643fce60847521ef530 Mon Sep 17 00:00:00 2001 From: Adam Schmalhofer Date: Sun, 9 Jan 2022 19:04:00 +0100 Subject: [PATCH 173/315] Bumped Hand Wash Timer version number --- apps.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps.json b/apps.json index 6fbc82e8b..b73cfe0e6 100644 --- a/apps.json +++ b/apps.json @@ -1893,7 +1893,7 @@ { "id": "widhwt", "name": "Hand Wash Timer", - "version": "0.02-rc10", + "version": "0.02", "description": "On Bangle.js 1 swipe your wrist over the watch face to start your personal Bangle.js 1 hand wash timer. On Bangle.js2 the Pattern Launcher is recommended to start the timer. Start washing after the short buzz and stop after the long buzz 35sec. later.", "icon": "widget.png", "type": "widget", From 20406ca29cadef7492c6cdc3e6a06ca134252259 Mon Sep 17 00:00:00 2001 From: Danny <31635744+DDDanny@users.noreply.github.com> Date: Mon, 10 Jan 2022 00:11:24 +0100 Subject: [PATCH 174/315] Clock can optionally show ISO-8601 calendar weeknumber --- apps.json | 2 +- apps/antonclk/ChangeLog | 3 +++ apps/antonclk/README.md | 3 +-- apps/antonclk/app.js | 38 +++++++++++++++++++++++++++++--------- apps/antonclk/settings.js | 8 ++++++++ 5 files changed, 42 insertions(+), 12 deletions(-) diff --git a/apps.json b/apps.json index 3fc0616da..c2180b91d 100644 --- a/apps.json +++ b/apps.json @@ -4242,7 +4242,7 @@ { "id": "antonclk", "name": "Anton Clock", - "version": "0.04", + "version": "0.05", "description": "A clock using the bold Anton font, optionally showing seconds and date in ISO-8601 format.", "readme":"README.md", "icon": "app.png", diff --git a/apps/antonclk/ChangeLog b/apps/antonclk/ChangeLog index 668047d7a..fdf20c175 100644 --- a/apps/antonclk/ChangeLog +++ b/apps/antonclk/ChangeLog @@ -2,3 +2,6 @@ 0.02: Load widgets after setUI so widclk knows when to hide 0.03: Clock now shows day of week under date. 0.04: Clock can optionally show seconds, date optionally in ISO-8601 format, weekdays and uppercase configurable, too. +0.05: Clock can optionally show ISO-8601 calendar weeknumber (default: Off) + when weekday name "Off": week #: + when weekday name "On": weekday name is cut at 6th position and .# is added \ No newline at end of file diff --git a/apps/antonclk/README.md b/apps/antonclk/README.md index 41d3e4559..fa4cc4919 100644 --- a/apps/antonclk/README.md +++ b/apps/antonclk/README.md @@ -40,8 +40,7 @@ The main menu contains several settings covering Anton clock in general. * **Show Weekday** - Weekday is shown in the time presentation without seconds. Weekday name depends on the current locale. If seconds are shown, the weekday is never shown as there is not enough space on the watch face. -* **Uppercase** - Weekday name and month name in the long format are converted to upper case letters. -This can improve readability. +**Show Weeknumber** - Weeknumber (ISO-8601) is shown. * **Vector font** - Use the built-in vector font for dates and weekday. This can improve readability. Otherwise, a scaled version of the built-in 6x8 pixels font is used. diff --git a/apps/antonclk/app.js b/apps/antonclk/app.js index 1f3e49792..be6c23789 100644 --- a/apps/antonclk/app.js +++ b/apps/antonclk/app.js @@ -19,6 +19,7 @@ var secondsWithColon; var dateOnMain; var dateOnSecs; var weekDay; +var calWeek; var upperCase; var vectorFont; @@ -29,22 +30,25 @@ var secondsScreen = true; var isBangle1 = (g.getWidth() == 240); -/* For development purposes +//For development purposes +/* require('Storage').writeJSON(SETTINGSFILE, { - secondsMode: "Always", // "Never", "Unlocked", "Always" + secondsMode: "Unlocked", // "Never", "Unlocked", "Always" secondsColoured: true, secondsWithColon: true, dateOnMain: "Long", // "Short", "Long", "ISO8601" dateOnSecs: "Year", // "No", "Year", "Weekday", LEGACY: true/false weekDay: true, + calWeek: true, upperCase: true, vectorFont: true, }); -/* */ +*/ -/* OR (also for development purposes) +// OR (also for development purposes) +/* require('Storage').erase(SETTINGSFILE); -/* */ +*/ // Helper method for loading the settings function def(value, def) { @@ -60,6 +64,7 @@ function loadSettings() { dateOnMain = def(settings.dateOnMain, "Long"); dateOnSecs = def(settings.dateOnSecs, "Year"); weekDay = def(settings.weekDay, true); + calWeek = def(settings.calWeek, false); upperCase = def(settings.upperCase, true); vectorFont = def(settings.vectorFont, false); @@ -99,6 +104,18 @@ function isoStr(date) { return date.getFullYear() + "-" + ("0" + (date.getMonth() + 1)).substr(-2) + "-" + ("0" + date.getDate()).substr(-2); } +function ISO8601calWeek(date) { //copied from: https://gist.github.com/IamSilviu/5899269#gistcomment-3035480 + var tdt = new Date(date.valueOf()); + var dayn = (date.getDay() + 6) % 7; + tdt.setDate(tdt.getDate() - dayn + 3); + var firstThursday = tdt.valueOf(); + tdt.setMonth(0, 1); + if (tdt.getDay() !== 4) { + tdt.setMonth(0, 1 + ((4 - tdt.getDay()) + 7) % 7); + } + return 1 + Math.ceil((firstThursday - tdt) / 604800000); +} + function doColor() { return !isBangle1 && !Bangle.isLocked() && secondsColoured; } @@ -169,11 +186,14 @@ function draw() { else g.setFont("6x8", 2); g.drawString(dateStr, x, y); - if (weekDay) { - var dowStr = require("locale").dow(date); + if (weekDay || calWeek) { + var dowwumStr = require("locale").dow(date); + dowwumStr = "thursday"; + if (calWeek) + dowwumStr = (weekDay ? dowwumStr.substr(0,Math.min(dowwumStr.length,6)) + (dowwumStr.length>=6 ? "." : "") : "week ") + "#" + ISO8601calWeek(date); if (upperCase) - dowStr = dowStr.toUpperCase(); - g.drawString(dowStr, x, y + (vectorFont ? 26 : 16)); + dowwumStr = dowwumStr.toUpperCase(); + g.drawString(dowwumStr, x, y + (vectorFont ? 26 : 16)); } } diff --git a/apps/antonclk/settings.js b/apps/antonclk/settings.js index 08fde512e..293aa0438 100644 --- a/apps/antonclk/settings.js +++ b/apps/antonclk/settings.js @@ -47,6 +47,14 @@ writeSettings(); } }, + "Show Weeknumber": { + value: (settings.weekNum !== undefined ? settings.weekNum : true), + format: v => v ? "On" : "Off", + onchange: v => { + settings.weekNum = v; + writeSettings(); + } + }, "Uppercase": { value: (settings.upperCase !== undefined ? settings.upperCase : false), format: v => v ? "On" : "Off", From d06283137995b78bb126e1861a6a2a81f0d80c1a Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Mon, 10 Jan 2022 08:47:52 +0000 Subject: [PATCH 175/315] Changelog for #1240 0.41: Add Keyboard and Mouse Bluetooth HID option --- apps.json | 2 +- apps/boot/ChangeLog | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/apps.json b/apps.json index 2493ac6cb..2a51fc0ae 100644 --- a/apps.json +++ b/apps.json @@ -16,7 +16,7 @@ { "id": "boot", "name": "Bootloader", - "version": "0.40", + "version": "0.41", "description": "This is needed by Bangle.js to automatically load the clock, menu, widgets and settings", "icon": "bootloader.png", "type": "bootloader", diff --git a/apps/boot/ChangeLog b/apps/boot/ChangeLog index d6619822b..702a8091e 100644 --- a/apps/boot/ChangeLog +++ b/apps/boot/ChangeLog @@ -44,3 +44,4 @@ 0.38: Option to log to file if settings.log==2 0.39: Fix passkey support (fix https://github.com/espruino/Espruino/issues/2035) 0.40: Bootloader now rebuilds for new firmware versions +0.41: Add Keyboard and Mouse Bluetooth HID option From eaaddae9465af1c1bcc3c409b874f4806343c498 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Mon, 10 Jan 2022 14:06:50 +0000 Subject: [PATCH 176/315] fix broken instagram icon --- apps/messages/app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/messages/app.js b/apps/messages/app.js index e36bb699e..6e51c2b33 100644 --- a/apps/messages/app.js +++ b/apps/messages/app.js @@ -83,7 +83,7 @@ function getMessageImage(msg) { if (s=="calendar") return atob("GBiBAAAAAAAAAAAAAA//8B//+BgAGBgAGBgAGB//+B//+B//+B9m2B//+B//+Btm2B//+B//+Btm+B//+B//+A//8AAAAAAAAAAAAA=="); if (s=="facebook") return getFBIcon(); if (s=="hangouts") return atob("FBaBAAH4AH/gD/8B//g//8P//H5n58Y+fGPnxj5+d+fmfj//4//8H//B//gH/4A/8AA+AAHAABgAAAA="); - if (s=="instagram") return atob("GBiBAf////////////////wAP/n/n/P/z/f/b/eB7/c87/d+7/d+7/d+7/d+7/c87/eB7/f/7/P/z/n/n/wAP////////////////w=="); + if (s=="instagram") return atob("GBiBAAAAAAAAAAAAAAAAAAP/wAYAYAwAMAgAkAh+EAjDEAiBEAiBEAiBEAiBEAjDEAh+EAgAEAwAMAYAYAP/wAAAAAAAAAAAAAAAAA=="); if (s=="gmail") return getNotificationImage(); if (s=="google home") return atob("GBiCAAAAAAAAAAAAAAAAAAAAAoAAAAAACqAAAAAAKqwAAAAAqroAAAACquqAAAAKq+qgAAAqr/qoAACqv/6qAAKq//+qgA6r///qsAqr///6sAqv///6sAqv///6sAqv///6sA6v///6sA6v///qsA6qqqqqsA6qqqqqsA6qqqqqsAP7///vwAAAAAAAAAAAAAAAAA=="); if (s=="mail") return getNotificationImage(); From b711b50f888ecfb96f5a5cf4e2340507a6087c87 Mon Sep 17 00:00:00 2001 From: Marco Heiming Date: Mon, 10 Jan 2022 16:10:42 +0100 Subject: [PATCH 177/315] Initial version of BanglExercise --- apps.json | 19 ++- apps/banglexercise/ChangeLog | 1 + apps/banglexercise/README.md | 35 ++++ apps/banglexercise/app-icon.js | 1 + apps/banglexercise/app.js | 259 ++++++++++++++++++++++++++++++ apps/banglexercise/app.png | Bin 0 -> 690 bytes apps/banglexercise/screenshot.png | Bin 0 -> 2043 bytes 7 files changed, 314 insertions(+), 1 deletion(-) create mode 100644 apps/banglexercise/ChangeLog create mode 100644 apps/banglexercise/README.md create mode 100644 apps/banglexercise/app-icon.js create mode 100644 apps/banglexercise/app.js create mode 100644 apps/banglexercise/app.png create mode 100644 apps/banglexercise/screenshot.png diff --git a/apps.json b/apps.json index 389603249..0adb4abc5 100644 --- a/apps.json +++ b/apps.json @@ -5149,7 +5149,7 @@ {"name":"mmind.app.js","url":"mmind.app.js"}, {"name":"mmind.img","url":"mmind.icon.js","evaluate":true} ] - }, + }, { "id": "presentor", "name": "Presentor", @@ -5503,5 +5503,22 @@ {"name":"limelight.settings.js","url":"limelight.settings.js"}, {"name":"limelight.img","url":"limelight.icon.js","evaluate":true} ] + }, + { "id": "banglexercise", + "name": "BanglExercise", + "shortName":"BanglExercise", + "version":"0.01", + "description": "Can automatically track exercises while wearing the Bangle.js watch.", + "icon": "app.png", + "screenshots": [{"url":"screenshot.png"}], + "type": "app", + "tags": "sport", + "supports" : ["BANGLEJS2"], + "allow_emulator":true, + "readme": "README.md", + "storage": [ + {"name":"banglexercise.app.js","url":"app.js"}, + {"name":"banglexercise.img","url":"app-icon.js","evaluate":true} + ] } ] diff --git a/apps/banglexercise/ChangeLog b/apps/banglexercise/ChangeLog new file mode 100644 index 000000000..5560f00bc --- /dev/null +++ b/apps/banglexercise/ChangeLog @@ -0,0 +1 @@ +0.01: New App! diff --git a/apps/banglexercise/README.md b/apps/banglexercise/README.md new file mode 100644 index 000000000..e7ac9573d --- /dev/null +++ b/apps/banglexercise/README.md @@ -0,0 +1,35 @@ +# Banglexercise + +Can automatically track exercises while wearing the Bangle.js watch. + +Currently only push ups are supported. + + +## Usage + +Select the exercise type you want to practive and go for it! +Press stop to end your exercise. + + +## Screenshots +![](screenshot.png) + +## TODO +* Add other exercise types: + * Rope jumps + * Curls + * Sit ups + * ... +* Save exercises to file system +* Add settings (vibration, beep, ...) +* Find a nicer icon + + +## Contribute +Feel free to send in improvements and remarks. + +## Creator +Marco ([myxor](https://github.com/myxor)) + +## Icons +Icons taken from [materialdesignicons](https://materialdesignicons.com) under Apache License 2.0 diff --git a/apps/banglexercise/app-icon.js b/apps/banglexercise/app-icon.js new file mode 100644 index 000000000..e1923bf54 --- /dev/null +++ b/apps/banglexercise/app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwwIbYh/8AYM/+EP/wFBv4FB/4FB/4FHAwIEBAv4FPAgIGCAosHAofggYFD4EABgXgOgIFLDAQWBAo0BAoOAVIV/UYQABj/4AocDCwQFTg46CEY4vFAopBBApIAVA==")) diff --git a/apps/banglexercise/app.js b/apps/banglexercise/app.js new file mode 100644 index 000000000..feb3a1127 --- /dev/null +++ b/apps/banglexercise/app.js @@ -0,0 +1,259 @@ +const Layout = require("Layout"); + +let historyY = []; +let historyZ = []; +const avgSize = 10; + +const thresholdY = 2500; +const thresholdPushUpTime = 1400; // mininmal time between two push ups +let tStart; + +let avgY; +let avgZ; +let historyAvgY = []; +let historyAvgZ = []; +let historySlopeY = []; +let historySlopeZ = []; + +let lastZeroPassType; +let lastZeroPassTime = 0; +let lastPushUpCmpltTime = 0; + +let exerciseType = ""; +let pushUpCounter = 0; + +let layout; + +let recordActive = false; + + +function showMenu() { + let menu; + if (pushUpCounter == 0) { + menu = { + "": { + title: "Banglexercise" + }, + "Start push ups": function() { + exerciseType = "push ups"; + E.showMenu(); + startRecording(); + } + }; + } else { + menu = { + "": { + title: "Banglexercise" + }, + "Last:": { + value: pushUpCounter + " push ups" + }, + "Start push ups": function() { + exerciseType = "push ups"; + E.showMenu(); + startRecording(); + } + }; + } + E.showMenu(menu); +} + +function accelHandler(accel) { + const t = Math.round(new Date().getTime()); // time in ms + const y = accel.y * 8192; + const z = accel.z * 8192; + //console.log(t, y, z); + + while (historyY.length > avgSize) + historyY.shift(); + historyY.push(y); + + if (historyY.length > avgSize / 2) + avgY = E.sum(historyY) / historyY.length; + + while (historyZ.length > avgSize) + historyZ.shift(); + historyZ.push(z); + + if (historyZ.length > avgSize / 2) + avgZ = E.sum(historyZ) / historyZ.length; + + if (avgY) { + //console.log(avgY, avgZ); + historyAvgY.push([t, avgY]); + historyAvgZ.push([t, avgZ]); + } + + let mY; + let mZ; + // slope for Y + let l = historyAvgY.length; + if (l > 1) { + const p1 = historyAvgY[l - 2]; + const p2 = historyAvgY[l - 1]; + mY = (p2[1] - p1[1]) / (p2[0] / 1000 - p1[0] / 1000); + if (Math.abs(mY) >= thresholdY) { + historyAvgY.shift(); + historySlopeY.push([t, mY]); + //console.log(t, Math.abs(mY)); + + const lMY = historySlopeY.length; + if (lMY > 1) { + const pMY1 = historySlopeY[lMY - 2][1]; + const pMY2 = historySlopeY[lMY - 1][1]; + isValidPushUp(pMY1, pMY2, t); + } + } + } + + // slope for Z + l = historyAvgZ.length; + if (l > 1) { + const p1 = historyAvgZ[l - 2]; + const p2 = historyAvgZ[l - 1]; + mZ = (p2[1] - p1[1]) / (p2[0] - p1[0]); + historyAvgZ.shift(); + historySlopeZ.push([p2[0] - p1[0], mZ]); + } +} + +function isValidPushUp(p1, p2, t) { + if (p1 > 0 && p2 < 0) { + + if (lastZeroPassType == "-+") { + console.log(t, "Push up half complete..."); + + layout.progress.label = "..."; + layout.render(layout.progress); + } + + lastZeroPassType = "+-"; + lastZeroPassTime = t; + } + if (p2 > 0 && p1 < 0) { + + if (lastZeroPassType == "+-") { + // potential complete push up. Let's check the time difference... + const tDiffLastPushUp = t - lastPushUpCmpltTime; + const tDiffStart = t - tStart; + console.log(t, "Push up maybe complete?", Math.round(tDiffLastPushUp), Math.round(tDiffStart)); + + if ((lastPushUpCmpltTime <= 0 && tDiffStart >= thresholdPushUpTime) || tDiffLastPushUp >= thresholdPushUpTime) { + console.log(t, "Push up complete!!!"); + + lastPushUpCmpltTime = t; + pushUpCounter++; + + layout.count.label = pushUpCounter; + layout.render(layout.count); + layout.progress.label = ""; + layout.render(layout.progress); + + Bangle.buzz(100, 0.3); // TODO make configurable + } else { + console.log(t, "Push up to quick for threshold!"); + } + } + + lastZeroPassType = "-+"; + lastZeroPassTime = t; + } +} + +/* + +function calcPushUps() { + const l = historySlopeY.length; + for (let i = 1; i < l; i++) { + const p1 = historySlopeY[i - 1][1]; + const p2 = historySlopeY[i][1]; + const t = historySlopeY[i][0]; + isValidPushUp(p1, p2, t); + } +} +*/ + +function reset() { + historyY = []; + historyZ = []; + historyAvgY = []; + historyAvgZ = []; + historySlopeY = []; + historySlopeZ = []; + + lastZeroPassType = ""; + lastZeroPassTime = 0; + lastPushUpCmpltTime = 0; + pushUpCounter = 0; +} + + +function startRecording() { + if (recordActive) return; + g.clear(1); + reset(); + layout = new Layout({ + type: "v", + c: [{ + type: "txt", + id: "type", + font: "6x8:2", + label: exerciseType, + pad: 5 + }, + { + type: "txt", + id: "count", + font: "6x8:9", + label: pushUpCounter, + pad: 5, + bgCol: g.theme.bg + }, + { + type: "txt", + id: "progress", + font: "6x8:2", + label: "", + pad: 5 + }, + { + type: "txt", + id: "recording", + font: "6x8:2", + label: "RECORDING", + bgCol: "#f00", + pad: 5, + fillx: 1 + }, + ] + }, { + btns: [ + { + label: "STOP", + cb: () => { + stopRecording(); + } + } + ] + }); + layout.render(); + + Bangle.setPollInterval(80); // 12.5 Hz + Bangle.on('accel', accelHandler); + Bangle.buzz(200, 1); + tStart = new Date().getTime(); + recordActive = true; +} + +function stopRecording() { + if (!recordActive) return; + g.clear(1); + Bangle.removeListener('accel', accelHandler); + showMenu(); + console.log("Found " + pushUpCounter + " push ups!"); + recordActive = false; +} + +g.clear(1); +Bangle.drawWidgets(); +showMenu(); diff --git a/apps/banglexercise/app.png b/apps/banglexercise/app.png new file mode 100644 index 0000000000000000000000000000000000000000..ee733206310029c15e866e4fc6bef39305d70668 GIT binary patch literal 690 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA1|-9oezpTCmUKs7M+SzC{oH>NS%G|oWRD45dJguM!v-tY$DUh!@P+6=(yLU`z6LcLCBs@Y8vBJ&@uo z@Q5r1(g|SvA=~LZ0|Vn0PZ!6KjC*fqZuC0rAk)5ISX|cS=uz>4qEPnOCH@cIG_P3P zFGDWi zNGnrbNL|R7G5egyoLkxdBkfxbtgvmLFk!~jikVyTJQzLaunJ`CzH(+>eiw_(tM5ID zCxaKT>-gQeKjZ#PZ`Muf7F<@rVfw%ShRjWzrNDVa4Hc#BdJrKWAyK=c`uohKOXBRS z7i6&M&E|RIp%;De^8uL)tYJyZ&wgNABYF7x`R1LH8)UCF6mu=pVXB?2D!xxh=y%`w zvwFGbP5q~azSwr`;=Yw1ZzZe9Wl8+~?RF@-QMWVkzz65fv&UH090_!2JnVKjno+s% zjis=&wZJj^z|x7+T(&#?Q18sW|I6{rTaII}*{P}%1L#X5Imj9~9Jam|MPl%6IS=VU&;E=?<Hxi+V}Sty2#I1U-4_X;bU=*PM1S-^ErIH(Bc9_KZH+1;!FW?Xq@{?d#wat2 zqSPaenYJE9vqHzCE!82k>QzeX6>8#H&He5_^T(`p*S-JUv(`C#?X~wgd+)PNP;eAqEM1m z_SP0|asJCCgE3v@PMo1! z*f|v3#LSzFzS{I!!rV21lYAG;c$8rSY` zrtv;c`F-*otRXP}(DjxKjPZJTgeC>x=>7yoFGVWJH|o)xX+XB^NKHex&wPl`a~=~X za(P8aF({q6xR8)IKj56l)xcxv656}p+2QGn?xOha*4FfUv5E=1o8>8@ke5^X-Alra z{?c-FSdtCn#41uNW-umNx0VFrlWLa)#(@Ij$rUqQ#GSv%Zi@XPBg}gPCyKWp&p8}M z6HV+)2y3H)YaQ^Mom$c5vW71elfNdWFPDfG{GjOe_VwTz(o~)T+9W+c*{D*%tK9*e zoJ~|W+Yzo%+X)vnc0{$qEqCJk=RJ4*O9-72(B~Uzi@Es|RQEyjmgu4b^j7ydTi6Z= zTKjLeV4AP--+63`7du)}g~nr62CXHl@SB==)Cgk4oJWBwo1uoLt@$Jzoe zC8XG-fYql4>_h}+N$)&!8#8LB2x!D1B(J^4SIpD$WT!%~SBvItV#w}Bu^X$Pk*we;?6cI0@-D(Q=rGO_|R9q%_clHFEW>WP@3PJ2lX6b9WH_gJ#2oO{P>u;wA8BEkN?TPq z%^@Y+O-FLEsH-w~$0{or?;P%C_!V_W>sRIRoIl=dlz?e=`(Rq?PWbD0J3{ciJg-L; zxvZ9qEgR}wlM84&H3=%LDFm|q3jH11uV|iGtX+s^Gmi0ynq5i*$3#_ zg+J!w${3g@L`bGr#cC#`$MNK5&VPC>2@A?DFMX?x#pRoMyH9t@B^7G+?s{Oh_8X0G zdxIWdXd?sP7~p>UV*XhE!$E*z;+B&8<4Q^M4d>$>b`fhPoA)+AQJd17ewQEr$U-(Z zi?LMG(ytl$U}&R@dAxoWMG>q1h-<}t6VKQVm+sCMa7sP7#%G{990ok zZaza$U~;u;dV?Im+ikXvp0`kdvfQSWgVmHyrEgp=ZF(@0w^`k28dzQ*VFU;ceDdf(o`Cg>Bmg3o{v-Hn zd2^(E?-x3$-1VX;Tbvj|TjlUy#vZ*@U9b6V39?(t1J}IJ@v@K-((+>Q%!fY+P7m~> z)!xYJRn$*Dw4B`OQ+_C%Wykju9`})?N8H^aB$=bl;ZJN}EjlY>dhI#z)la1C1rXhwz1fgbiQh50C;I)_p2 z20-=scl5QzK*vM-t?q$nFKrt?G64N@O6e*^3d{M literal 0 HcmV?d00001 From bfe2725483e55f657f0592e519e60c077abe1897 Mon Sep 17 00:00:00 2001 From: Marco Heiming Date: Mon, 10 Jan 2022 19:02:39 +0100 Subject: [PATCH 178/315] Show heart rate during training Alot of code cleanup and improvements --- apps/banglexercise/README.md | 2 +- apps/banglexercise/app.js | 269 +++++++++++++++++++---------------- 2 files changed, 151 insertions(+), 120 deletions(-) diff --git a/apps/banglexercise/README.md b/apps/banglexercise/README.md index e7ac9573d..efc87424d 100644 --- a/apps/banglexercise/README.md +++ b/apps/banglexercise/README.md @@ -1,4 +1,4 @@ -# Banglexercise +# BanglExercise Can automatically track exercises while wearing the Bangle.js watch. diff --git a/apps/banglexercise/app.js b/apps/banglexercise/app.js index feb3a1127..e18faf554 100644 --- a/apps/banglexercise/app.js +++ b/apps/banglexercise/app.js @@ -1,15 +1,9 @@ const Layout = require("Layout"); +const heatshrink = require('heatshrink'); +let tStart; let historyY = []; let historyZ = []; -const avgSize = 10; - -const thresholdY = 2500; -const thresholdPushUpTime = 1400; // mininmal time between two push ups -let tStart; - -let avgY; -let avgZ; let historyAvgY = []; let historyAvgZ = []; let historySlopeY = []; @@ -17,103 +11,122 @@ let historySlopeZ = []; let lastZeroPassType; let lastZeroPassTime = 0; -let lastPushUpCmpltTime = 0; -let exerciseType = ""; -let pushUpCounter = 0; +let lastExerciseCmpltTime = 0; + +let exerciseType = { + "name": "" +}; +const exerciseTypes = [{ + "id": "pushup", + "name": "Push ups", + "useYaxe": true, + "useZaxe": false + } // add other exercises here +]; +let exerciseCounter = 0; let layout; - let recordActive = false; +/** + * Thresholds + */ +const avgSize = 6; +const pushUpThresholdY = 2500; +const pushUpThresholdTime = 1400; // mininmal time between two push ups -function showMenu() { +let hrtValue; + +function showMainMenu() { let menu; - if (pushUpCounter == 0) { - menu = { - "": { - title: "Banglexercise" - }, - "Start push ups": function() { - exerciseType = "push ups"; - E.showMenu(); - startRecording(); - } + menu = { + "": { + title: "BanglExercise" + } + }; + + exerciseTypes.forEach(function(et) { + menu["Do " + et.name] = function() { + exerciseType = et; + E.showMenu(); + startRecording(); }; - } else { - menu = { - "": { - title: "Banglexercise" - }, - "Last:": { - value: pushUpCounter + " push ups" - }, - "Start push ups": function() { - exerciseType = "push ups"; - E.showMenu(); - startRecording(); - } + }); + + if (exerciseCounter > 0) { + menu["----"] = {}; + menu["Last:"] = { + value: exerciseCounter + " " + exerciseType.name }; } + E.showMenu(menu); } function accelHandler(accel) { + if (!exerciseType) return; const t = Math.round(new Date().getTime()); // time in ms - const y = accel.y * 8192; - const z = accel.z * 8192; + const y = exerciseType.useYaxe ? accel.y * 8192 : 0; + const z = exerciseType.useZaxe ? accel.z * 8192 : 0; //console.log(t, y, z); - while (historyY.length > avgSize) - historyY.shift(); - historyY.push(y); + if (exerciseType.useYaxe) { + while (historyY.length > avgSize) + historyY.shift(); - if (historyY.length > avgSize / 2) - avgY = E.sum(historyY) / historyY.length; + historyY.push(y); - while (historyZ.length > avgSize) - historyZ.shift(); - historyZ.push(z); - - if (historyZ.length > avgSize / 2) - avgZ = E.sum(historyZ) / historyZ.length; - - if (avgY) { - //console.log(avgY, avgZ); - historyAvgY.push([t, avgY]); - historyAvgZ.push([t, avgZ]); + if (historyY.length > avgSize / 2) { + const avgY = E.sum(historyY) / historyY.length; + historyAvgY.push([t, avgY]); + } } - let mY; - let mZ; - // slope for Y - let l = historyAvgY.length; - if (l > 1) { - const p1 = historyAvgY[l - 2]; - const p2 = historyAvgY[l - 1]; - mY = (p2[1] - p1[1]) / (p2[0] / 1000 - p1[0] / 1000); - if (Math.abs(mY) >= thresholdY) { - historyAvgY.shift(); - historySlopeY.push([t, mY]); - //console.log(t, Math.abs(mY)); + if (exerciseType.useYaxe) { + while (historyZ.length > avgSize) + historyZ.shift(); - const lMY = historySlopeY.length; - if (lMY > 1) { - const pMY1 = historySlopeY[lMY - 2][1]; - const pMY2 = historySlopeY[lMY - 1][1]; - isValidPushUp(pMY1, pMY2, t); + historyZ.push(z); + + if (historyZ.length > avgSize / 2) { + const avgZ = E.sum(historyZ) / historyZ.length; + historyAvgZ.push([t, avgZ]); + } + } + + // slope for Y + if (exerciseType.useYaxe) { + let l = historyAvgY.length; + if (l > 1) { + const p1 = historyAvgY[l - 2]; + const p2 = historyAvgY[l - 1]; + const mY = (p2[1] - p1[1]) / (p2[0] / 1000 - p1[0] / 1000); + if (Math.abs(mY) >= pushUpThresholdY) { + historyAvgY.shift(); + historySlopeY.push([t, mY]); + //console.log(t, Math.abs(mY)); + + const lMY = historySlopeY.length; + if (lMY > 1) { + const pMY1 = historySlopeY[lMY - 2][1]; + const pMY2 = historySlopeY[lMY - 1][1]; + isValidPushUp(pMY1, pMY2, t); + } } } } // slope for Z - l = historyAvgZ.length; - if (l > 1) { - const p1 = historyAvgZ[l - 2]; - const p2 = historyAvgZ[l - 1]; - mZ = (p2[1] - p1[1]) / (p2[0] - p1[0]); - historyAvgZ.shift(); - historySlopeZ.push([p2[0] - p1[0], mZ]); + if (exerciseType.useZaxe) { + l = historyAvgZ.length; + if (l > 1) { + const p1 = historyAvgZ[l - 2]; + const p2 = historyAvgZ[l - 1]; + const mZ = (p2[1] - p1[1]) / (p2[0] - p1[0]); + historyAvgZ.shift(); + historySlopeZ.push([p2[0] - p1[0], mZ]); + } } } @@ -123,8 +136,8 @@ function isValidPushUp(p1, p2, t) { if (lastZeroPassType == "-+") { console.log(t, "Push up half complete..."); - layout.progress.label = "..."; - layout.render(layout.progress); + layout.progress.label = "*"; + layout.render(); } lastZeroPassType = "+-"; @@ -134,20 +147,19 @@ function isValidPushUp(p1, p2, t) { if (lastZeroPassType == "+-") { // potential complete push up. Let's check the time difference... - const tDiffLastPushUp = t - lastPushUpCmpltTime; + const tDiffLastPushUp = t - lastExerciseCmpltTime; const tDiffStart = t - tStart; console.log(t, "Push up maybe complete?", Math.round(tDiffLastPushUp), Math.round(tDiffStart)); - if ((lastPushUpCmpltTime <= 0 && tDiffStart >= thresholdPushUpTime) || tDiffLastPushUp >= thresholdPushUpTime) { + if ((lastExerciseCmpltTime <= 0 && tDiffStart >= pushUpThresholdTime) || tDiffLastPushUp >= pushUpThresholdTime) { console.log(t, "Push up complete!!!"); - lastPushUpCmpltTime = t; - pushUpCounter++; + lastExerciseCmpltTime = t; + exerciseCounter++; - layout.count.label = pushUpCounter; - layout.render(layout.count); + layout.count.label = exerciseCounter; layout.progress.label = ""; - layout.render(layout.progress); + layout.render(); Bangle.buzz(100, 0.3); // TODO make configurable } else { @@ -160,19 +172,6 @@ function isValidPushUp(p1, p2, t) { } } -/* - -function calcPushUps() { - const l = historySlopeY.length; - for (let i = 1; i < l; i++) { - const p1 = historySlopeY[i - 1][1]; - const p2 = historySlopeY[i][1]; - const t = historySlopeY[i][0]; - isValidPushUp(p1, p2, t); - } -} -*/ - function reset() { historyY = []; historyZ = []; @@ -183,8 +182,9 @@ function reset() { lastZeroPassType = ""; lastZeroPassTime = 0; - lastPushUpCmpltTime = 0; - pushUpCounter = 0; + lastExerciseCmpltTime = 0; + exerciseCounter = 0; + tStart = 0; } @@ -192,29 +192,54 @@ function startRecording() { if (recordActive) return; g.clear(1); reset(); + Bangle.setHRMPower(1, "banglexercise"); + if (!hrtValue) hrtValue = "..."; + layout = new Layout({ type: "v", c: [{ type: "txt", id: "type", font: "6x8:2", - label: exerciseType, + label: exerciseType.name, pad: 5 }, { - type: "txt", - id: "count", - font: "6x8:9", - label: pushUpCounter, - pad: 5, - bgCol: g.theme.bg + type: "h", + c: [{ + type: "txt", + id: "count", + font: "6x8:10", + label: exerciseCounter, + pad: 5, + bgCol: g.theme.bg + }, + { + type: "txt", + id: "progress", + font: "6x8:2", + label: "", + pad: 5 + }, + ] }, { - type: "txt", - id: "progress", - font: "6x8:2", - label: "", - pad: 5 + type: "h", + c: [{ + type: "img", + pad: 4, + src: function() { + return heatshrink.decompress(atob("h0OwYOLkmQhMkgACByVJgESpIFBpEEBAIFBCgIFCCgsABwcAgQOCAAMSpAwDyBNM")); + } + }, + { + type: "txt", + id: "hrtRate", + font: "6x8:2", + label: hrtValue, + pad: 5 + }, + ] }, { type: "txt", @@ -234,7 +259,8 @@ function startRecording() { stopRecording(); } } - ] + ], + lazy: true }); layout.render(); @@ -248,12 +274,17 @@ function startRecording() { function stopRecording() { if (!recordActive) return; g.clear(1); + + Bangle.setHRMPower(0, "banglexercise"); + Bangle.removeListener('accel', accelHandler); - showMenu(); - console.log("Found " + pushUpCounter + " push ups!"); + showMainMenu(); recordActive = false; } +Bangle.on('HRM', function(hrm) { + hrtValue = hrm.bpm; +}); + g.clear(1); -Bangle.drawWidgets(); -showMenu(); +showMainMenu(); From 0f2a58dddefe92c6377ebb35d433800036eb54e5 Mon Sep 17 00:00:00 2001 From: Jon Warrington Date: Mon, 10 Jan 2022 11:31:37 -0700 Subject: [PATCH 179/315] Adding current weather to lcars --- apps/lcars/lcars.app.js | 9 +++++++++ apps/lcars/lcars.settings.js | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/apps/lcars/lcars.app.js b/apps/lcars/lcars.app.js index 167adad2d..4e1073723 100644 --- a/apps/lcars/lcars.app.js +++ b/apps/lcars/lcars.app.js @@ -1,5 +1,6 @@ const SETTINGS_FILE = "lcars.setting.json"; const Storage = require("Storage"); +const weather = require('weather'); // ...and overwrite them with any saved values @@ -145,6 +146,14 @@ function printData(key, y, c){ text = "VREF"; value = E.getAnalogVRef().toFixed(2) + "V"; + } else if (key == "Weather"){ + text = "TEMP"; + const w = weather.get(); + if (!w) { + value = "ERR"; + } else { + value = require('locale').temp(w.temp-273.15); // applies conversion + } } g.setColor(c); diff --git a/apps/lcars/lcars.settings.js b/apps/lcars/lcars.settings.js index 0d004b002..b1fceb518 100644 --- a/apps/lcars/lcars.settings.js +++ b/apps/lcars/lcars.settings.js @@ -18,7 +18,7 @@ storage.write(SETTINGS_FILE, settings) } - var data_options = ["Battery", "Steps", "Temp.", "HRM", "VREF"]; + var data_options = ["Battery", "Steps", "Temp.", "HRM", "VREF", "Weather"]; E.showMenu({ '': { 'title': 'LCARS Clock' }, From 05215fab73314fca30696445cfe986b06b3c0d43 Mon Sep 17 00:00:00 2001 From: Jon Warrington Date: Mon, 10 Jan 2022 11:38:26 -0700 Subject: [PATCH 180/315] Updating version info for lcars --- apps.json | 2 +- apps/lcars/ChangeLog | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/apps.json b/apps.json index 389603249..8f1783f10 100644 --- a/apps.json +++ b/apps.json @@ -4498,7 +4498,7 @@ "name": "LCARS Clock", "shortName":"LCARS", "icon": "lcars.png", - "version":"0.09", + "version":"0.10", "readme": "README.md", "supports": ["BANGLEJS2"], "description": "Library Computer Access Retrieval System (LCARS) clock.", diff --git a/apps/lcars/ChangeLog b/apps/lcars/ChangeLog index f5d8346da..8a8970124 100644 --- a/apps/lcars/ChangeLog +++ b/apps/lcars/ChangeLog @@ -6,4 +6,5 @@ 0.06: Fix - Alarm disabled, if clock was closed. 0.07: Added settings to adjust data that is shown for each row. 0.08: Support for multiple screens. 24h graph for steps + HRM. Fullscreen Mode. -0.09: Tab anywhere to open the launcher. \ No newline at end of file +0.09: Tab anywhere to open the launcher. +0.10: Added getting the gadgetbridge weather \ No newline at end of file From 78dc343afafa8abfaf5fcc391353473028d015c8 Mon Sep 17 00:00:00 2001 From: Jon Warrington Date: Mon, 10 Jan 2022 11:48:57 -0700 Subject: [PATCH 181/315] Fixing a problem with the lcars settings --- apps/lcars/lcars.settings.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/lcars/lcars.settings.js b/apps/lcars/lcars.settings.js index b1fceb518..a0e54f9b4 100644 --- a/apps/lcars/lcars.settings.js +++ b/apps/lcars/lcars.settings.js @@ -25,7 +25,7 @@ '< Back': back, 'Row 1': { value: 0 | data_options.indexOf(settings.dataRow1), - min: 0, max: 4, + min: 0, max: 5, format: v => data_options[v], onchange: v => { settings.dataRow1 = data_options[v]; @@ -34,7 +34,7 @@ }, 'Row 2': { value: 0 | data_options.indexOf(settings.dataRow2), - min: 0, max: 4, + min: 0, max: 5, format: v => data_options[v], onchange: v => { settings.dataRow2 = data_options[v]; @@ -43,7 +43,7 @@ }, 'Row 3': { value: 0 | data_options.indexOf(settings.dataRow3), - min: 0, max: 4, + min: 0, max: 5, format: v => data_options[v], onchange: v => { settings.dataRow3 = data_options[v]; From 791f88b0613b1776793ee478f11f6aad22a03b70 Mon Sep 17 00:00:00 2001 From: Martin Boonk Date: Mon, 10 Jan 2022 20:27:40 +0100 Subject: [PATCH 182/315] New widget: Heart rate alarm --- apps.json | 16 +++++++++++ apps/hralarm/ChangeLog | 1 + apps/hralarm/README.md | 15 +++++++++++ apps/hralarm/settings.js | 57 +++++++++++++++++++++++++++++++++++++++ apps/hralarm/widget.js | 27 +++++++++++++++++++ apps/hralarm/widget.png | Bin 0 -> 12944 bytes 6 files changed, 116 insertions(+) create mode 100644 apps/hralarm/ChangeLog create mode 100644 apps/hralarm/README.md create mode 100644 apps/hralarm/settings.js create mode 100644 apps/hralarm/widget.js create mode 100644 apps/hralarm/widget.png diff --git a/apps.json b/apps.json index 389603249..08d6113d4 100644 --- a/apps.json +++ b/apps.json @@ -1351,6 +1351,22 @@ {"name":"pparrot.img","url":"party-parrot-icon.js","evaluate":true} ] }, + { + "id": "hralarm", + "name": "Heart rate alarm", + "shortName":"HR Alarm", + "version":"0.01", + "description": "This invisible widget vibrates whenever the heart rate gets close to the upper limit or goes over or under the configured limits", + "icon": "widget.png", + "type": "widget", + "tags": "widget", + "supports" : ["BANGLEJS2"], + "readme": "README.md", + "storage": [ + {"name":"hralarm.wid.js","url":"widget.js"}, + {"name":"hralarm.settings.js","url":"settings.js"} + ] + }, { "id": "hrings", "name": "Hypno Rings", diff --git a/apps/hralarm/ChangeLog b/apps/hralarm/ChangeLog new file mode 100644 index 000000000..4c21f3ace --- /dev/null +++ b/apps/hralarm/ChangeLog @@ -0,0 +1 @@ +0.01: New Widget! diff --git a/apps/hralarm/README.md b/apps/hralarm/README.md new file mode 100644 index 000000000..37b14ad9d --- /dev/null +++ b/apps/hralarm/README.md @@ -0,0 +1,15 @@ +# Heart rate alarm + +This invisible widget vibrates whenever the heart rate gets close to the upper limit or goes over or under the configured limits. + +## Usage + +Configure the heart rate limits in the apps settings. This widget uses both 'HRM' and 'BTHRM' events. + +## Features + +Long vibration every 10 seconds on reaching upper limit, short vibrations between upper limit and warning threshold and an single vibration when reaching the lower limit again. + +## Requests/Creator + +https://github.com/halemmerich diff --git a/apps/hralarm/settings.js b/apps/hralarm/settings.js new file mode 100644 index 000000000..3158ab8b7 --- /dev/null +++ b/apps/hralarm/settings.js @@ -0,0 +1,57 @@ +(function(back) { + var FILE = "hralarm.json"; + + var settings = Object.assign({ + enabled: false, + upper: 180, + warning: 170, + lower: 150, + }, require('Storage').readJSON(FILE, true) || {}); + + function writeSettings() { + require('Storage').writeJSON(FILE, settings); + } + + E.showMenu({ + '': { 'title': 'HR Alarm' }, + '< Back': back, + 'Enabled': { + value: !!settings.enabled, + format: v => settings.enabled ? "On" : "Off", + onchange: v => { + settings.enabled = v; + writeSettings(); + } + }, + 'Upper limit': { + value: settings.upper, + min: 0, + step:5, + max: 300, + onchange: v => { + settings.upper = v; + writeSettings(); + } + }, + 'Lower limit': { + value: settings.lower, + min: 0, + step:5, + max: 300, + onchange: v => { + settings.lower = v; + writeSettings(); + } + }, + 'Warning at': { + value: settings.warning, + min: 0, + step:5, + max: 300, + onchange: v => { + settings.warning = v; + writeSettings(); + } + } + }); +}) diff --git a/apps/hralarm/widget.js b/apps/hralarm/widget.js new file mode 100644 index 000000000..30a94fdf2 --- /dev/null +++ b/apps/hralarm/widget.js @@ -0,0 +1,27 @@ +(() => { + var settings = require('Storage').readJSON("hralarm.json", true) || {}; + if (!settings.enabled){ Bangle.setHRMPower(0, 'hralarm'); return; } + Bangle.setHRMPower(1, 'hralarm'); + var hitLimit = 0; + var checkHr = function(hr){ + if (hr.bpm > settings.warning && hr.bpm <= settings.upper){ + Bangle.buzz(100, 1); + } + if (hitLimit < getTime() && hr.bpm > settings.upper){ + hitLimit = getTime() + 10; + Bangle.buzz(2000, 1); + } + if (hitLimit > 0 && hr.bpm < settings.lower){ + hitLimit = 0; + Bangle.buzz(500, 1); + } + }; + Bangle.on("HRM", checkHr); + Bangle.on("BTHRM", checkHr); + + WIDGETS["hralarm"]={ + area:"tl", + width: 0, + draw: function(){} + }; +})() diff --git a/apps/hralarm/widget.png b/apps/hralarm/widget.png new file mode 100644 index 0000000000000000000000000000000000000000..726cf3f9bb528f4a8aecd0fba7e4862f4cc4ec2d GIT binary patch literal 12944 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 Date: Mon, 10 Jan 2022 13:47:50 -0700 Subject: [PATCH 183/315] Incrementing the version number --- apps.json | 2 +- apps/lcars/ChangeLog | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps.json b/apps.json index 8f1783f10..658adaaa8 100644 --- a/apps.json +++ b/apps.json @@ -4498,7 +4498,7 @@ "name": "LCARS Clock", "shortName":"LCARS", "icon": "lcars.png", - "version":"0.10", + "version":"0.11", "readme": "README.md", "supports": ["BANGLEJS2"], "description": "Library Computer Access Retrieval System (LCARS) clock.", diff --git a/apps/lcars/ChangeLog b/apps/lcars/ChangeLog index 8a8970124..ad5330b26 100644 --- a/apps/lcars/ChangeLog +++ b/apps/lcars/ChangeLog @@ -7,4 +7,4 @@ 0.07: Added settings to adjust data that is shown for each row. 0.08: Support for multiple screens. 24h graph for steps + HRM. Fullscreen Mode. 0.09: Tab anywhere to open the launcher. -0.10: Added getting the gadgetbridge weather \ No newline at end of file +0.11: Added getting the gadgetbridge weather \ No newline at end of file From 53f787fff740d10efb6c10efed3b828fbf7130e8 Mon Sep 17 00:00:00 2001 From: Martin Boonk Date: Mon, 10 Jan 2022 22:02:29 +0100 Subject: [PATCH 184/315] Lap Counter - Use themeable icon --- apps.json | 2 +- apps/lapcounter/ChangeLog | 1 + apps/lapcounter/app-icon.js | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/apps.json b/apps.json index 389603249..af3bb44d8 100644 --- a/apps.json +++ b/apps.json @@ -5046,7 +5046,7 @@ { "id": "lapcounter", "name": "Lap Counter", - "version": "0.01", + "version": "0.02", "description": "Click button to count laps. Shows count and total time snapshot (like a stopwatch, but laid back).", "icon": "app.png", "screenshots": [{"url":"screenshot.png"}], diff --git a/apps/lapcounter/ChangeLog b/apps/lapcounter/ChangeLog index 9db0e26c5..146ff1b05 100644 --- a/apps/lapcounter/ChangeLog +++ b/apps/lapcounter/ChangeLog @@ -1 +1,2 @@ 0.01: first release +0.02: Themeable app icon diff --git a/apps/lapcounter/app-icon.js b/apps/lapcounter/app-icon.js index a443b3a41..354c07124 100644 --- a/apps/lapcounter/app-icon.js +++ b/apps/lapcounter/app-icon.js @@ -1 +1 @@ -require("heatshrink").decompress(atob("mEwwkBiIA/AH4A/AAkQgEBAREAC6oABdZQXkI6wuKC5iPUFxoXIOpoX/C6QFCC6IsCC6ZEDC/4XcPooXOFgoXQIgwX/C7IUFC5wsIC5ouCC6hcJC5h1DF9YwBChCPOAH4A/AH4Ap")) +require("heatshrink").decompress(atob("mEwwI0xg+evPsAon+ApX8Aon4AonwAod78AFDv4FWvoFE/IFDz4FXvIFD3wFE/wFW7wFDh5xBAoUfAok/Aol/BZUXAogA6A=")) From 52647e7a8a9650e7e22389aedc3cfae80a92ecc0 Mon Sep 17 00:00:00 2001 From: Danny <31635744+DDDanny@users.noreply.github.com> Date: Tue, 11 Jan 2022 00:08:06 +0100 Subject: [PATCH 185/315] fixed typo in readme.md --- apps/antonclk/README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/antonclk/README.md b/apps/antonclk/README.md index fa4cc4919..c2c8b917e 100644 --- a/apps/antonclk/README.md +++ b/apps/antonclk/README.md @@ -40,7 +40,10 @@ The main menu contains several settings covering Anton clock in general. * **Show Weekday** - Weekday is shown in the time presentation without seconds. Weekday name depends on the current locale. If seconds are shown, the weekday is never shown as there is not enough space on the watch face. -**Show Weeknumber** - Weeknumber (ISO-8601) is shown. +* **Show Weeknumber** - Week-number (ISO-8601) is shown. (default: Off) +when weekday name "Off" it displays week #: +when weekday name "On": weekday name is cut at 6th position and .# is added +If seconds are shown, the week number is never shown as there is not enough space on the watch face. * **Vector font** - Use the built-in vector font for dates and weekday. This can improve readability. Otherwise, a scaled version of the built-in 6x8 pixels font is used. From 1a21358f2be7fe4f5dcdddb324c14e1f698aa610 Mon Sep 17 00:00:00 2001 From: Danny <31635744+DDDanny@users.noreply.github.com> Date: Tue, 11 Jan 2022 00:12:04 +0100 Subject: [PATCH 186/315] Updated readme.md typo / format --- apps/antonclk/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/antonclk/README.md b/apps/antonclk/README.md index c2c8b917e..38a42aa22 100644 --- a/apps/antonclk/README.md +++ b/apps/antonclk/README.md @@ -41,8 +41,8 @@ The main menu contains several settings covering Anton clock in general. Weekday name depends on the current locale. If seconds are shown, the weekday is never shown as there is not enough space on the watch face. * **Show Weeknumber** - Week-number (ISO-8601) is shown. (default: Off) -when weekday name "Off" it displays week #: -when weekday name "On": weekday name is cut at 6th position and .# is added +If "Show Weekday" is "Off" the week-number is displayed as week #:. +If "Show Weekday" is "On" the weekday name is cut at 6th position and .# is added. If seconds are shown, the week number is never shown as there is not enough space on the watch face. * **Vector font** - Use the built-in vector font for dates and weekday. This can improve readability. From 3e458115046ec7182edb00871ca3077f1253728d Mon Sep 17 00:00:00 2001 From: Danny <31635744+DDDanny@users.noreply.github.com> Date: Tue, 11 Jan 2022 00:13:34 +0100 Subject: [PATCH 187/315] Updated readme.md type / format --- apps/antonclk/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/antonclk/README.md b/apps/antonclk/README.md index 38a42aa22..85c03788d 100644 --- a/apps/antonclk/README.md +++ b/apps/antonclk/README.md @@ -41,8 +41,8 @@ The main menu contains several settings covering Anton clock in general. Weekday name depends on the current locale. If seconds are shown, the weekday is never shown as there is not enough space on the watch face. * **Show Weeknumber** - Week-number (ISO-8601) is shown. (default: Off) -If "Show Weekday" is "Off" the week-number is displayed as week #:. -If "Show Weekday" is "On" the weekday name is cut at 6th position and .# is added. +If "Show Weekday" is "Off" the week-number is displayed as "week #:". +If "Show Weekday" is "On" the weekday name is cut at 6th position and suffixed with ".#". If seconds are shown, the week number is never shown as there is not enough space on the watch face. * **Vector font** - Use the built-in vector font for dates and weekday. This can improve readability. From dcc4dc8e66c43eaf7bc0d54128e790572d904ee8 Mon Sep 17 00:00:00 2001 From: Danny <31635744+DDDanny@users.noreply.github.com> Date: Tue, 11 Jan 2022 00:16:40 +0100 Subject: [PATCH 188/315] app.js - bugfix: removed codefragement testdata "thursday" added todo for locale "week" --- apps/antonclk/app.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/antonclk/app.js b/apps/antonclk/app.js index be6c23789..05758cbfd 100644 --- a/apps/antonclk/app.js +++ b/apps/antonclk/app.js @@ -188,9 +188,8 @@ function draw() { g.drawString(dateStr, x, y); if (weekDay || calWeek) { var dowwumStr = require("locale").dow(date); - dowwumStr = "thursday"; if (calWeek) - dowwumStr = (weekDay ? dowwumStr.substr(0,Math.min(dowwumStr.length,6)) + (dowwumStr.length>=6 ? "." : "") : "week ") + "#" + ISO8601calWeek(date); + dowwumStr = (weekDay ? dowwumStr.substr(0,Math.min(dowwumStr.length,6)) + (dowwumStr.length>=6 ? "." : "") : "week ") + "#" + ISO8601calWeek(date); //TODO: locale for "week" if (upperCase) dowwumStr = dowwumStr.toUpperCase(); g.drawString(dowwumStr, x, y + (vectorFont ? 26 : 16)); From 7905d3cffc5a268635e13baa0b05cbdd97b9ddc1 Mon Sep 17 00:00:00 2001 From: BartS23 <10829389+BartS23@users.noreply.github.com> Date: Mon, 10 Jan 2022 16:11:09 +0100 Subject: [PATCH 189/315] Reduce FIFO_FULL messages 1. the lazy layout rendering takes too much time. 2. enable the gps at the end of the file. 3. save SATinView to detect changes. --- apps/gpsinfo/gps-info.js | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/apps/gpsinfo/gps-info.js b/apps/gpsinfo/gps-info.js index fdac3d403..79acc05fe 100644 --- a/apps/gpsinfo/gps-info.js +++ b/apps/gpsinfo/gps-info.js @@ -4,7 +4,7 @@ function satelliteImage() { var Layout = require("Layout"); var layout; -Bangle.setGPSPower(1, "app"); +//Bangle.setGPSPower(1, "app"); E.showMessage("Loading..."); // avoid showing rubbish on screen var lastFix = { @@ -19,7 +19,7 @@ var lastFix = { var SATinView = 0; var nofBD = 0; var nofGP = 0; -var listenerGPSraw = 1; +var listenerGPSraw = 0; function formatTime(now) { if (now == undefined) { @@ -87,12 +87,12 @@ function onGPS(fix) { {type:"txt", font:"6x8", pad:3, label:"Satellites used" } ]}, {type:"txt", font:"6x8", label:"", fillx:true, id:"progress" } - ]},{lazy:true}); + ]},{lazy:false}); } g.clearRect(0,24,g.getWidth(),g.getHeight()); layout.render(); } - lastFix = fix; + //lastFix = fix; if (fix.fix) { if (listenerGPSraw == 1) { Bangle.removeListener('GPS-raw', onGPSraw); @@ -108,6 +108,7 @@ function onGPS(fix) { layout.time.label = "Time: "+formatTime(fix.time); layout.sat.label = "Satellites: "+satellites; layout.maidenhead.label = "Maidenhead: "+maidenhead; + layout.render(); } else { if (listenerGPSraw == 0) { Bangle.on('GPS-raw', onGPSraw); @@ -116,7 +117,15 @@ function onGPS(fix) { layout.sat.label = fix.satellites; layout.progress.label = "in view: " + SATinView; } - layout.render(); + //layout.render(); + + if (listenerGPSraw == 0 && !fix.fix) { + setTimeout(() => Bangle.on('GPS-raw', onGPSraw), 10); + listenerGPSraw = 1; + } + + lastFix = fix; + lastFix.SATinView = SATinView; } function onGPSraw(nmea) { @@ -129,7 +138,8 @@ function onGPSraw(nmea) { Bangle.loadWidgets(); Bangle.drawWidgets(); Bangle.on('GPS', onGPS); -Bangle.on('GPS-raw', onGPSraw); +//Bangle.on('GPS-raw', onGPSraw); +Bangle.setGPSPower(1, "app"); function exitApp() { load(); From 8053de33079cc96be65ed2bb1f82557dc1dc0006 Mon Sep 17 00:00:00 2001 From: BartS23 <10829389+BartS23@users.noreply.github.com> Date: Mon, 10 Jan 2022 20:37:22 +0100 Subject: [PATCH 190/315] Fix layout and double enabling of event GPS-raw --- apps/gpsinfo/gps-info.js | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/apps/gpsinfo/gps-info.js b/apps/gpsinfo/gps-info.js index 79acc05fe..f4521f265 100644 --- a/apps/gpsinfo/gps-info.js +++ b/apps/gpsinfo/gps-info.js @@ -110,12 +110,16 @@ function onGPS(fix) { layout.maidenhead.label = "Maidenhead: "+maidenhead; layout.render(); } else { - if (listenerGPSraw == 0) { - Bangle.on('GPS-raw', onGPSraw); - listenerGPSraw = 1; + if (fix.satelites != lastFix.satelites) { + layout.clear(layout.sat); + layout.sat.label = fix.satellites; + layout.render(layout.sat); + } + if (SATinView != lastFix.SATinView) { + layout.clear(layout.progress); + layout.progress.label = "in view: " + SATinView; + layout.render(layout.progress); } - layout.sat.label = fix.satellites; - layout.progress.label = "in view: " + SATinView; } //layout.render(); From 0c0d7e9dd17ee2565aebe20682a82af66944bc94 Mon Sep 17 00:00:00 2001 From: Romek Date: Tue, 11 Jan 2022 11:10:54 +0100 Subject: [PATCH 191/315] Update changelog and version --- apps.json | 2 +- apps/gpsinfo/ChangeLog | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/apps.json b/apps.json index 02076497e..57934dff3 100644 --- a/apps.json +++ b/apps.json @@ -1520,7 +1520,7 @@ { "id": "gpsinfo", "name": "GPS Info", - "version": "0.08", + "version": "0.09", "description": "An application that displays information about altitude, lat/lon, satellites and time", "icon": "gps-info.png", "type": "app", diff --git a/apps/gpsinfo/ChangeLog b/apps/gpsinfo/ChangeLog index 8d428ce85..414b9d9fb 100644 --- a/apps/gpsinfo/ChangeLog +++ b/apps/gpsinfo/ChangeLog @@ -5,3 +5,4 @@ 0.06: Add number of satellites in view and fix crash with GPS time 0.07: Resolve one FIFO_FULL case and exit App with button press 0.08: Leave GPS power switched on on exit (will switch off after 0.5 seconds anyway) +0.09: Fix FIFO_FULL error From c9fa1b8f65db32d3dae0063630228332f0679c3f Mon Sep 17 00:00:00 2001 From: Marco Heiming Date: Tue, 11 Jan 2022 11:44:07 +0100 Subject: [PATCH 192/315] Update screenshot --- apps/banglexercise/screenshot.png | Bin 2043 -> 2181 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/apps/banglexercise/screenshot.png b/apps/banglexercise/screenshot.png index 9a325d87378dd297bab31da0521462e06d5c1ab9..417be685b08802657be55b02498c4c292128b70d 100644 GIT binary patch literal 2181 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 From d59db5ba381941c14abc0676c2fb174063a2e2d9 Mon Sep 17 00:00:00 2001 From: Marco Heiming Date: Tue, 11 Jan 2022 11:48:10 +0100 Subject: [PATCH 193/315] Show correct percentage values in circles --- apps.json | 2 +- apps/circlesclock/ChangeLog | 1 + apps/circlesclock/app.js | 13 ++++++------- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/apps.json b/apps.json index 02076497e..8d1e481a1 100644 --- a/apps.json +++ b/apps.json @@ -5097,7 +5097,7 @@ { "id": "circlesclock", "name": "Circles clock", "shortName":"Circles clock", - "version":"0.04", + "version":"0.05", "description": "A clock with circles for different data at the bottom in a probably familiar style", "icon": "app.png", "screenshots": [{"url":"screenshot-dark.png"}, {"url":"screenshot-light.png"}], diff --git a/apps/circlesclock/ChangeLog b/apps/circlesclock/ChangeLog index ca1da6e21..86b77bb6f 100644 --- a/apps/circlesclock/ChangeLog +++ b/apps/circlesclock/ChangeLog @@ -5,3 +5,4 @@ Add step distance and weather Allow switching visibility of widgets Make circles and text slightly bigger +0.05: Show correct percentage values in circles diff --git a/apps/circlesclock/app.js b/apps/circlesclock/app.js index 91d4937c4..de7bc73f9 100644 --- a/apps/circlesclock/app.js +++ b/apps/circlesclock/app.js @@ -363,22 +363,21 @@ function radians(a) { } function drawGauge(cx, cy, percent, color) { - let offset = 30; - let end = 300; - var i = 0; - var r = radiusInner + 3; + const offset = 15; + const end = 345; + const r = radiusInner + 3; if (percent <= 0) return; if (percent > 1) percent = 1; - var startrot = -offset; - var endrot = startrot - ((end - offset) * percent) - 35; + const startrot = -offset; + const endrot = startrot - ((end - offset) * percent); g.setColor(color); const size = radiusOuter - radiusInner - 2; // draw gauge - for (i = startrot; i > endrot - size; i -= size) { + for (let i = startrot; i > endrot - size; i -= size) { x = cx + r * Math.sin(radians(i)); y = cy + r * Math.cos(radians(i)); g.fillCircle(x, y, size); From 83aa32ee840a6aec7fcaf0995de8f3a1278e4a89 Mon Sep 17 00:00:00 2001 From: Marco Heiming Date: Tue, 11 Jan 2022 12:38:19 +0100 Subject: [PATCH 194/315] Moved exercise threshold values to the exercise type configuration & initial support for curls --- apps/banglexercise/README.md | 9 ++- apps/banglexercise/app.js | 148 +++++++++++++++++++++-------------- 2 files changed, 98 insertions(+), 59 deletions(-) diff --git a/apps/banglexercise/README.md b/apps/banglexercise/README.md index efc87424d..9d8ee7be4 100644 --- a/apps/banglexercise/README.md +++ b/apps/banglexercise/README.md @@ -2,7 +2,13 @@ Can automatically track exercises while wearing the Bangle.js watch. -Currently only push ups are supported. +Currently only push ups and curls are supported. + +## Disclaimer + +This app is very experimental. +It could be and is likely that the threshold values for detecting exercises do not work for everyone. +Therefore it would be great if we could improve this app together :-) ## Usage @@ -17,7 +23,6 @@ Press stop to end your exercise. ## TODO * Add other exercise types: * Rope jumps - * Curls * Sit ups * ... * Save exercises to file system diff --git a/apps/banglexercise/app.js b/apps/banglexercise/app.js index e18faf554..3f710cf1e 100644 --- a/apps/banglexercise/app.js +++ b/apps/banglexercise/app.js @@ -15,26 +15,35 @@ let lastZeroPassTime = 0; let lastExerciseCmpltTime = 0; let exerciseType = { + "id": "", "name": "" }; + +// add new exercises here: const exerciseTypes = [{ "id": "pushup", "name": "Push ups", "useYaxe": true, - "useZaxe": false - } // add other exercises here + "useZaxe": false, + "thresholdY": 2500, + "thresholdTime": 1400 // mininmal time between two push ups + }, + { + "id": "curl", + "name": "Curls", + "useYaxe": true, + "useZaxe": false, + "thresholdY": 2500, + "thresholdTime": 1000 // mininmal time between two curls + } ]; let exerciseCounter = 0; let layout; let recordActive = false; -/** - * Thresholds - */ +// Size of average window for data analysis const avgSize = 6; -const pushUpThresholdY = 2500; -const pushUpThresholdTime = 1400; // mininmal time between two push ups let hrtValue; @@ -55,7 +64,9 @@ function showMainMenu() { }); if (exerciseCounter > 0) { - menu["----"] = {}; + menu["----"] = { + value: "" + }; menu["Last:"] = { value: exerciseCounter + " " + exerciseType.name }; @@ -101,19 +112,18 @@ function accelHandler(accel) { if (l > 1) { const p1 = historyAvgY[l - 2]; const p2 = historyAvgY[l - 1]; - const mY = (p2[1] - p1[1]) / (p2[0] / 1000 - p1[0] / 1000); - if (Math.abs(mY) >= pushUpThresholdY) { - historyAvgY.shift(); - historySlopeY.push([t, mY]); - //console.log(t, Math.abs(mY)); + const slopeY = (p2[1] - p1[1]) / (p2[0] / 1000 - p1[0] / 1000); - const lMY = historySlopeY.length; - if (lMY > 1) { - const pMY1 = historySlopeY[lMY - 2][1]; - const pMY2 = historySlopeY[lMY - 1][1]; - isValidPushUp(pMY1, pMY2, t); - } + // we use this data for exercises which can be detected by using Y axis data + switch (exerciseType.id) { + case "pushup": + isValidYAxisExercise(slopeY, t); + break; + case "curl": + isValidYAxisExercise(slopeY, t); + break; } + } } @@ -123,55 +133,81 @@ function accelHandler(accel) { if (l > 1) { const p1 = historyAvgZ[l - 2]; const p2 = historyAvgZ[l - 1]; - const mZ = (p2[1] - p1[1]) / (p2[0] - p1[0]); + const slopeZ = (p2[1] - p1[1]) / (p2[0] - p1[0]); historyAvgZ.shift(); - historySlopeZ.push([p2[0] - p1[0], mZ]); + historySlopeZ.push([p2[0] - p1[0], slopeZ]); + + // TODO: we can use this data for some exercises which can be detected by using Z axis data } } } -function isValidPushUp(p1, p2, t) { - if (p1 > 0 && p2 < 0) { +/* + * Check if slope value of Y-axis data looks like an exercise + * + * In detail we look for slop values which are bigger than the configured Y threshold for the current exercise + * Then we look for two consecutive slope values of which one is above 0 and the other is below zero. + * If we find one pair of these values this could be part of one exercise. + * Then we look for a pair of values which cross the zero from the otherwise direction + */ +function isValidYAxisExercise(slopeY, t) { + if (!exerciseType) return; - if (lastZeroPassType == "-+") { - console.log(t, "Push up half complete..."); + const thresholdY = exerciseType.thresholdY; + const thresholdTime = exerciseType.thresholdTime; + const exerciseName = exerciseType.name; - layout.progress.label = "*"; - layout.render(); - } + if (Math.abs(slopeY) >= thresholdY) { + historyAvgY.shift(); + historySlopeY.push([t, slopeY]); + //console.log(t, Math.abs(slopeY)); - lastZeroPassType = "+-"; - lastZeroPassTime = t; - } - if (p2 > 0 && p1 < 0) { + const lSlopeY = historySlopeY.length; + if (lSlopeY > 1) { + const p1 = historySlopeY[lSlopeY - 2][1]; + const p2 = historySlopeY[lSlopeY - 1][1]; + if (p1 > 0 && p2 < 0) { + if (lastZeroPassType == "-+") { + console.log(t, exerciseName + " half complete..."); - if (lastZeroPassType == "+-") { - // potential complete push up. Let's check the time difference... - const tDiffLastPushUp = t - lastExerciseCmpltTime; - const tDiffStart = t - tStart; - console.log(t, "Push up maybe complete?", Math.round(tDiffLastPushUp), Math.round(tDiffStart)); + layout.progress.label = "*"; + layout.render(); + } - if ((lastExerciseCmpltTime <= 0 && tDiffStart >= pushUpThresholdTime) || tDiffLastPushUp >= pushUpThresholdTime) { - console.log(t, "Push up complete!!!"); + lastZeroPassType = "+-"; + lastZeroPassTime = t; + } + if (p2 > 0 && p1 < 0) { + if (lastZeroPassType == "+-") { + // potential complete exercise. Let's check the time difference... + const tDiffLastPushUp = t - lastExerciseCmpltTime; + const tDiffStart = t - tStart; + console.log(t, exerciseName + " maybe complete?", Math.round(tDiffLastPushUp), Math.round(tDiffStart)); - lastExerciseCmpltTime = t; - exerciseCounter++; + if ((lastExerciseCmpltTime <= 0 && tDiffStart >= thresholdTime) || tDiffLastPushUp >= thresholdTime) { + console.log(t, exerciseName + " complete!!!"); - layout.count.label = exerciseCounter; - layout.progress.label = ""; - layout.render(); + lastExerciseCmpltTime = t; + exerciseCounter++; - Bangle.buzz(100, 0.3); // TODO make configurable - } else { - console.log(t, "Push up to quick for threshold!"); + layout.count.label = exerciseCounter; + layout.progress.label = ""; + layout.render(); + + Bangle.buzz(100, 0.4); // TODO make configurable + } else { + console.log(t, exerciseName + " to quick for time threshold!"); + } + } + + lastZeroPassType = "-+"; + lastZeroPassTime = t; } } - - lastZeroPassType = "-+"; - lastZeroPassTime = t; } } + function reset() { historyY = []; historyZ = []; @@ -252,14 +288,12 @@ function startRecording() { }, ] }, { - btns: [ - { - label: "STOP", - cb: () => { - stopRecording(); - } + btns: [{ + label: "STOP", + cb: () => { + stopRecording(); } - ], + }], lazy: true }); layout.render(); From d12a415740bd5236d9d475551a9fac69e2bee62a Mon Sep 17 00:00:00 2001 From: Marco Heiming Date: Tue, 11 Jan 2022 13:52:19 +0100 Subject: [PATCH 195/315] Show humidity as weather circle data --- apps/circlesclock/README.md | 3 +++ apps/circlesclock/app.js | 5 +++++ 2 files changed, 8 insertions(+) diff --git a/apps/circlesclock/README.md b/apps/circlesclock/README.md index 9aaa4bc8e..c3704e3d7 100644 --- a/apps/circlesclock/README.md +++ b/apps/circlesclock/README.md @@ -10,6 +10,9 @@ It can show the following information (this can be configured): * Heart rate (automatically updates when screen is on and unlocked) * Battery (including charging status and battery low warning) * Weather (requires [weather app](https://banglejs.com/apps/#weather)) + * Humidity as circle progress + * Temperature inside circle + * Condition as icon below circle ## Screenshots ![Screenshot dark theme](screenshot-dark.png) diff --git a/apps/circlesclock/app.js b/apps/circlesclock/app.js index de7bc73f9..822802afa 100644 --- a/apps/circlesclock/app.js +++ b/apps/circlesclock/app.js @@ -283,6 +283,7 @@ function drawWeather(w) { if (!w) w = getCirclePosition("weather"); const weather = getWeather(); const tempString = weather ? locale.temp(weather.temp - 273.15) : undefined; + const humidity = weather ? weather.hum : undefined; const code = weather ? weather.code : -1; // Draw rectangle background: @@ -292,6 +293,10 @@ function drawWeather(w) { g.setColor(colorGrey); g.fillCircle(w, h3, radiusOuter); + if (humidity >= 0) { + drawGauge(w, h3, humidity / 100, colorYellow); + } + g.setColor(colorBg); g.fillCircle(w, h3, radiusInner); From a29dbeedd3cf3b0084999fca59244d739bb0ee4b Mon Sep 17 00:00:00 2001 From: Marco Heiming Date: Tue, 11 Jan 2022 14:08:48 +0100 Subject: [PATCH 196/315] Update changelog --- apps/circlesclock/ChangeLog | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/circlesclock/ChangeLog b/apps/circlesclock/ChangeLog index 86b77bb6f..5464a8103 100644 --- a/apps/circlesclock/ChangeLog +++ b/apps/circlesclock/ChangeLog @@ -6,3 +6,4 @@ Allow switching visibility of widgets Make circles and text slightly bigger 0.05: Show correct percentage values in circles + Show humidity as weather circle data From a3ada12a928931646e078a083bc394012f3c646e Mon Sep 17 00:00:00 2001 From: Marco Heiming Date: Tue, 11 Jan 2022 16:04:54 +0100 Subject: [PATCH 197/315] Add settings for buzz; more timeouts to better detect activities; reduce memory usage --- apps.json | 6 ++- apps/banglexercise/app.js | 99 ++++++++++++++++++++++------------ apps/banglexercise/settings.js | 21 ++++++++ 3 files changed, 92 insertions(+), 34 deletions(-) create mode 100644 apps/banglexercise/settings.js diff --git a/apps.json b/apps.json index 0adb4abc5..230a37b67 100644 --- a/apps.json +++ b/apps.json @@ -5518,7 +5518,11 @@ "readme": "README.md", "storage": [ {"name":"banglexercise.app.js","url":"app.js"}, - {"name":"banglexercise.img","url":"app-icon.js","evaluate":true} + {"name":"banglexercise.img","url":"app-icon.js","evaluate":true}, + {"name":"banglexercise.settings.js","url":"settings.js"} + ], + "data": [ + {"name":"banglexercise.json"} ] } ] diff --git a/apps/banglexercise/app.js b/apps/banglexercise/app.js index 3f710cf1e..ac4153239 100644 --- a/apps/banglexercise/app.js +++ b/apps/banglexercise/app.js @@ -9,10 +9,11 @@ let historyAvgZ = []; let historySlopeY = []; let historySlopeZ = []; -let lastZeroPassType; +let lastZeroPassCameFromPositive; let lastZeroPassTime = 0; -let lastExerciseCmpltTime = 0; +let lastExerciseCompletionTime = 0; +let lastExerciseHalfCompletionTime = 0; let exerciseType = { "id": "", @@ -22,19 +23,23 @@ let exerciseType = { // add new exercises here: const exerciseTypes = [{ "id": "pushup", - "name": "Push ups", + "name": "push ups", "useYaxe": true, "useZaxe": false, "thresholdY": 2500, - "thresholdTime": 1400 // mininmal time between two push ups + "thresholdMinTime": 1400, // mininmal time between two push ups in ms + "thresholdMaxTime": 5000, // maximal time between two push ups in ms + "thresholdMinDurationTime": 700, // mininmal duration of half a push ups in ms }, { "id": "curl", - "name": "Curls", + "name": "curls", "useYaxe": true, "useZaxe": false, "thresholdY": 2500, - "thresholdTime": 1000 // mininmal time between two curls + "thresholdMinTime": 1000, // mininmal time between two curls in ms + "thresholdMaxTime": 5000, // maximal time between two curls in ms + "thresholdMinDurationTime": 500, // mininmal duration of half a push ups in ms } ]; let exerciseCounter = 0; @@ -47,6 +52,10 @@ const avgSize = 6; let hrtValue; +let settings = storage.readJSON("banglexercise.json", 1) || { + 'buzz': true +}; + function showMainMenu() { let menu; menu = { @@ -64,7 +73,7 @@ function showMainMenu() { }); if (exerciseCounter > 0) { - menu["----"] = { + menu["--------"] = { value: "" }; menu["Last:"] = { @@ -91,6 +100,8 @@ function accelHandler(accel) { if (historyY.length > avgSize / 2) { const avgY = E.sum(historyY) / historyY.length; historyAvgY.push([t, avgY]); + while (historyAvgY.length > avgSize) + historyAvgY.shift(); } } @@ -103,6 +114,8 @@ function accelHandler(accel) { if (historyZ.length > avgSize / 2) { const avgZ = E.sum(historyZ) / historyZ.length; historyAvgZ.push([t, avgZ]); + while (historyAvgZ.length > avgSize) + historyAvgZ.shift(); } } @@ -113,7 +126,6 @@ function accelHandler(accel) { const p1 = historyAvgY[l - 2]; const p2 = historyAvgY[l - 1]; const slopeY = (p2[1] - p1[1]) / (p2[0] / 1000 - p1[0] / 1000); - // we use this data for exercises which can be detected by using Y axis data switch (exerciseType.id) { case "pushup": @@ -154,7 +166,9 @@ function isValidYAxisExercise(slopeY, t) { if (!exerciseType) return; const thresholdY = exerciseType.thresholdY; - const thresholdTime = exerciseType.thresholdTime; + const thresholdMinTime = exerciseType.thresholdMinTime; + const thresholdMaxTime = exerciseType.thresholdMaxTime; + const thresholdMinDurationTime = exerciseType.thresholdMinDurationTime; const exerciseName = exerciseType.name; if (Math.abs(slopeY) >= thresholdY) { @@ -164,43 +178,61 @@ function isValidYAxisExercise(slopeY, t) { const lSlopeY = historySlopeY.length; if (lSlopeY > 1) { - const p1 = historySlopeY[lSlopeY - 2][1]; - const p2 = historySlopeY[lSlopeY - 1][1]; + const p1 = historySlopeY[lSlopeY - 1][1]; + const p2 = historySlopeY[lSlopeY - 2][1]; if (p1 > 0 && p2 < 0) { - if (lastZeroPassType == "-+") { + if (lastZeroPassCameFromPositive == false) { + lastExerciseHalfCompletionTime = t; console.log(t, exerciseName + " half complete..."); - layout.progress.label = "*"; + layout.progress.label = "½"; layout.render(); } - lastZeroPassType = "+-"; + lastZeroPassCameFromPositive = true; lastZeroPassTime = t; } if (p2 > 0 && p1 < 0) { - if (lastZeroPassType == "+-") { - // potential complete exercise. Let's check the time difference... - const tDiffLastPushUp = t - lastExerciseCmpltTime; + if (lastZeroPassCameFromPositive == true) { + const tDiffLastExercise = t - lastExerciseCompletionTime; const tDiffStart = t - tStart; - console.log(t, exerciseName + " maybe complete?", Math.round(tDiffLastPushUp), Math.round(tDiffStart)); + console.log(t, exerciseName + " maybe complete?", Math.round(tDiffLastExercise), Math.round(tDiffStart)); - if ((lastExerciseCmpltTime <= 0 && tDiffStart >= thresholdTime) || tDiffLastPushUp >= thresholdTime) { - console.log(t, exerciseName + " complete!!!"); + // check minimal time between exercises: + if ((lastExerciseCompletionTime <= 0 && tDiffStart >= thresholdMinTime) || tDiffLastExercise >= thresholdMinTime) { - lastExerciseCmpltTime = t; - exerciseCounter++; + // check maximal time between exercises: + if (lastExerciseCompletionTime <= 0 || tDiffLastExercise <= thresholdMaxTime) { - layout.count.label = exerciseCounter; - layout.progress.label = ""; - layout.render(); + // check minimal duration of exercise: + const tDiffExerciseHalfCompletion = t - lastExerciseHalfCompletionTime; + if (tDiffExerciseHalfCompletion > thresholdMinDurationTime) { + console.log(t, exerciseName + " complete!!!"); - Bangle.buzz(100, 0.4); // TODO make configurable + lastExerciseCompletionTime = t; + exerciseCounter++; + + layout.count.label = exerciseCounter; + layout.progress.label = ""; + layout.render(); + + if (settings.buzz) + Bangle.buzz(100, 0.4); + } else { + console.log(t, exerciseName + " to quick for duration time threshold!"); + lastExerciseCompletionTime = t; + } + } else { + console.log(t, exerciseName + " to slow for time threshold!"); + lastExerciseCompletionTime = t; + } } else { console.log(t, exerciseName + " to quick for time threshold!"); + lastExerciseCompletionTime = t; } } - lastZeroPassType = "-+"; + lastZeroPassCameFromPositive = false; lastZeroPassTime = t; } } @@ -216,9 +248,10 @@ function reset() { historySlopeY = []; historySlopeZ = []; - lastZeroPassType = ""; + lastZeroPassCameFromPositive = undefined; lastZeroPassTime = 0; - lastExerciseCmpltTime = 0; + lastExerciseHalfCompletionTime = 0; + lastExerciseCompletionTime = 0; exerciseCounter = 0; tStart = 0; } @@ -300,18 +333,18 @@ function startRecording() { Bangle.setPollInterval(80); // 12.5 Hz Bangle.on('accel', accelHandler); - Bangle.buzz(200, 1); tStart = new Date().getTime(); recordActive = true; + if (settings.buzz) + Bangle.buzz(200, 1); } function stopRecording() { if (!recordActive) return; + g.clear(1); - - Bangle.setHRMPower(0, "banglexercise"); - Bangle.removeListener('accel', accelHandler); + Bangle.setHRMPower(0, "banglexercise"); showMainMenu(); recordActive = false; } diff --git a/apps/banglexercise/settings.js b/apps/banglexercise/settings.js new file mode 100644 index 000000000..3208c6eca --- /dev/null +++ b/apps/banglexercise/settings.js @@ -0,0 +1,21 @@ +(function(back) { + const SETTINGS_FILE = "banglexercise.json"; + const storage = require('Storage'); + let settings = storage.readJSON(SETTINGS_FILE, 1) || {}; + function save(key, value) { + settings[key] = value; + storage.write(SETTINGS_FILE, settings); + } + E.showMenu({ + '': { 'title': 'BanglExercise' }, + '< Back': back, + 'Buzz': { + value: "buzz" in settings ? settings.buzz : false, + format: () => (settings.buzz ? 'Yes' : 'No'), + onchange: () => { + settings.buzz = !settings.buzz; + save('buzz', settings.buzz); + } + } + }); +}); From cc5a1f5d5a3756bc99d9b8cb66783a7cc34f0890 Mon Sep 17 00:00:00 2001 From: Marco Heiming Date: Tue, 11 Jan 2022 16:09:02 +0100 Subject: [PATCH 198/315] Fix missing module requirement --- apps/banglexercise/app.js | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/banglexercise/app.js b/apps/banglexercise/app.js index ac4153239..3e53cff61 100644 --- a/apps/banglexercise/app.js +++ b/apps/banglexercise/app.js @@ -1,5 +1,6 @@ const Layout = require("Layout"); const heatshrink = require('heatshrink'); +const storage = require('storage'); let tStart; let historyY = []; From 800624f2d405270deb9f7ed5cab41946d494b41e Mon Sep 17 00:00:00 2001 From: Marco Heiming Date: Tue, 11 Jan 2022 16:18:10 +0100 Subject: [PATCH 199/315] Fix missing module requirement --- apps/banglexercise/app.js | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/banglexercise/app.js b/apps/banglexercise/app.js index ac4153239..f5a532408 100644 --- a/apps/banglexercise/app.js +++ b/apps/banglexercise/app.js @@ -1,5 +1,6 @@ const Layout = require("Layout"); const heatshrink = require('heatshrink'); +const storage = require('Storage'); let tStart; let historyY = []; From e669138023cfb661bd599308c4b8b21e427c3cc1 Mon Sep 17 00:00:00 2001 From: Andreas Rozek Date: Tue, 11 Jan 2022 16:28:48 +0100 Subject: [PATCH 200/315] Update apps.json --- apps.json | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/apps.json b/apps.json index c93efd152..a62bb19cf 100644 --- a/apps.json +++ b/apps.json @@ -5538,5 +5538,22 @@ {"name":"limelight.settings.js","url":"limelight.settings.js"}, {"name":"limelight.img","url":"limelight.icon.js","evaluate":true} ] + }, + { "id": "configurable_clock", + "name": "Configurable Analog Clock", + "shortName":"Configurable Clock", + "version":"0.02", + "description": "an analog clock with several kinds of faces, hands and colors to choose from", + "icon": "app-icon.png", + "type": "clock", + "tags": "clock", + "supports" : ["BANGLEJS2"], + "allow_emulator": true, + "screenshots": [{"url":"app-screenshot.png"}], + "readme": "README.md", + "storage": [ + {"name":"configurable_clock.app.js","url":"app.js"}, + {"name":"configurable_clock.img","url":"app-icon.js","evaluate":true} + ] } ] From 216610780f734f111704c99964f567fb2b8b24a0 Mon Sep 17 00:00:00 2001 From: Andreas Rozek Date: Tue, 11 Jan 2022 16:29:19 +0100 Subject: [PATCH 201/315] Create app.js --- apps/ac_ac/app.js | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 apps/ac_ac/app.js diff --git a/apps/ac_ac/app.js b/apps/ac_ac/app.js new file mode 100644 index 000000000..1d9b2e3c6 --- /dev/null +++ b/apps/ac_ac/app.js @@ -0,0 +1,2 @@ +let Clockwork = require('https://raw.githubusercontent.com/rozek/banglejs-2-simple-clockwork/main/Clockwork.js'); +Clockwork.windUp(); \ No newline at end of file From 0666181c8d8b83161364b54264de82d8fc774e5a Mon Sep 17 00:00:00 2001 From: Andreas Rozek Date: Tue, 11 Jan 2022 16:29:24 +0100 Subject: [PATCH 202/315] Create README.md --- apps/ac_ac/README.md | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 apps/ac_ac/README.md diff --git a/apps/ac_ac/README.md b/apps/ac_ac/README.md new file mode 100644 index 000000000..0e0084b64 --- /dev/null +++ b/apps/ac_ac/README.md @@ -0,0 +1,34 @@ +# AC-AC - A Configurable Analog Clock # + +This app implements an analog clock with various faces, hands and complications +to choose from before uploading to a Bangle.js 2. + +It is based on the [Analog Clock Construction Kit (ACCK)](https://github.com/rozek/banglejs-2-analog-clock-construction-kit) +and makes most of the currently implemented parts available with a few mouse +clicks - just click on "Upload" and you will be directed to a web form where +you compose your very own, personal analog clock. + +You currently have the choice between + +* 2 different clock sizes, +* 4 different clock faces, +* 3 different clock hands and +* 4 different complications + +Alternatively, you may specify the GitHub URL of ACCK compatible modules for +external clock sizes, faces, hands or complications. + +Additionally, you may use the currently configured global theme or configure +your own colors for clock fore- and background and second hands. + +Consequently, even without external modules you already have the choice between +87552 combinations! + + + +## License ## + +[MIT License](LICENSE) From 16b50228bdaee15584a5c2b5e7a9b5d38ff1cdbe Mon Sep 17 00:00:00 2001 From: Andreas Rozek Date: Tue, 11 Jan 2022 16:30:27 +0100 Subject: [PATCH 203/315] Update apps.json --- apps.json | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/apps.json b/apps.json index a62bb19cf..aa626a609 100644 --- a/apps.json +++ b/apps.json @@ -5555,5 +5555,23 @@ {"name":"configurable_clock.app.js","url":"app.js"}, {"name":"configurable_clock.img","url":"app-icon.js","evaluate":true} ] + }, + { "id": "ac_ac", + "name": "A Configurable Analog Clock", + "shortName":"Configurable Clock", + "version":"0.02", + "description": "a highly customizable analog clock", + "icon": "app-icon.png", + "type": "clock", + "tags": "clock", + "supports" : ["BANGLEJS2"], + "allow_emulator": true, + "screenshots": [{"url":"app-screenshot.png"}], + "readme": "README.md", + "custom": "Customizer.html", + "storage": [ + {"name":"ac_ac.app.js","url":"app.js"}, + {"name":"ac_ac.img","url":"app-icon.js","evaluate":true} + ] } ] From 3715ae433a796088c1ac0444b507c42162329b7f Mon Sep 17 00:00:00 2001 From: Andreas Rozek Date: Tue, 11 Jan 2022 16:30:48 +0100 Subject: [PATCH 204/315] Create Customizer.html --- apps/ac_ac/Customizer.html | 91 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 apps/ac_ac/Customizer.html diff --git a/apps/ac_ac/Customizer.html b/apps/ac_ac/Customizer.html new file mode 100644 index 000000000..6637b5df4 --- /dev/null +++ b/apps/ac_ac/Customizer.html @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + +

A Configurable Analog Clock

+ + Please customize your analog clock for the Bangle.js 2 according to your needs. + When finished, click on "Upload". + +

Clock Size Calculation

+ +
+
+ +  
+ +

Clock Face

+ +
+
+  
+
+  
+
+  
+ +

Clock Hands

+ +
+
+
+   Hand Fill Color
+ +

Complications

+ +

Settings

+ + Foreground Color:
+ + Background Color:
+ + Second Hand Color:
+ + + + + From 7b1c19f67ff50d962de810380bd365bc3dc0ec02 Mon Sep 17 00:00:00 2001 From: David Peer Date: Tue, 11 Jan 2022 17:22:17 +0100 Subject: [PATCH 205/315] Removed swipe gestures to be compatible with the ecosystem --- apps/lcars/lcars.app.js | 91 ++++++++++++++++++++++------------------- 1 file changed, 48 insertions(+), 43 deletions(-) diff --git a/apps/lcars/lcars.app.js b/apps/lcars/lcars.app.js index 3535f57d5..34a3a2e12 100644 --- a/apps/lcars/lcars.app.js +++ b/apps/lcars/lcars.app.js @@ -241,8 +241,8 @@ function drawPosition0(){ // The last line is a battery indicator too var bat = E.getBattery() / 100.0; var batX2 = parseInt((172 - 35) * bat + 35); - drawHorizontalBgLine(cOrange, 35, batX2, 171, 5); - drawHorizontalBgLine(cGrey, batX2+10, 172, 171, 5); + drawHorizontalBgLine(cOrange, 35, batX2-5, 171, 5); + drawHorizontalBgLine(cGrey, batX2+5, 172, 171, 5); // Draw Infos drawInfo(); @@ -253,15 +253,15 @@ function drawPosition0(){ var currentDate = new Date(); var timeStr = locale.time(currentDate,1); g.setFontAntonioLarge(); - g.drawString(timeStr, 29, 10); + g.drawString(timeStr, 27, 10); // Write date g.setColor(cWhite); g.setFontAntonioMedium(); var dayStr = locale.dow(currentDate, true).toUpperCase(); dayStr += " " + currentDate.getDate(); - dayStr += " " + currentDate.getFullYear(); - g.drawString(dayStr, 32, 56); + dayStr += " " + locale.month(currentDate, 1).toUpperCase(); + g.drawString(dayStr, 30, 56); // Draw data g.setFontAlign(-1, -1, 0); @@ -408,6 +408,7 @@ function draw(){ */ function getSteps() { var steps = 0; + let health; try { health = require("health"); } catch(ex) { @@ -511,49 +512,53 @@ function decreaseAlarm(){ Storage.writeJSON(SETTINGS_FILE, settings); } +function feedback(){ + Bangle.buzz(40, 0.3); +} -// Thanks to the app "gbmusic" for this code to detect swipes in all 4 directions. -Bangle.on("drag", e => { - if (!drag) { // start dragging - drag = {x: e.x, y: e.y}; - } else if (!e.b) { // released - const dx = e.x-drag.x, dy = e.y-drag.y; - drag = null; +// Touch gestures to control clock. We don't use swipe to be compatible with the bangle ecosystem +Bangle.on('touch', function(btn, e){ + var left = parseInt(g.getWidth() * 0.2); + var right = g.getWidth() - left; + var upper = parseInt(g.getHeight() * 0.2); + var lower = g.getHeight() - upper; - // Horizontal swipe - if (Math.abs(dx)>Math.abs(dy)+10) { - if(dx > 0){ - lcarsViewPos = 0; - } else { - lcarsViewPos = 1; - } - - // Vertical swipe - } else if (Math.abs(dy)>Math.abs(dx)+10) { - if(lcarsViewPos == 0){ - if(dy > 0){ - decreaseAlarm(); - } else { - increaseAlarm(); - } - - // Only update the state and return to - // avoid a full draw as this is much faster. - drawState(); - return; - } - - if(lcarsViewPos == 1){ - plotWeek = dy < 0 ? true : false; - } - } + var is_left = e.x < left; + var is_right = e.x > right; + var is_upper = e.y < upper; + var is_lower = e.y > lower; + if(is_left && lcarsViewPos == 1){ + feedback(); + lcarsViewPos = 0; draw(); - } -}); + return; -Bangle.on("touch", e => { - Bangle.showLauncher(); + } else if(is_right && lcarsViewPos == 0){ + feedback(); + lcarsViewPos = 1; + draw(); + return; + } + + if(lcarsViewPos == 0){ + if(is_upper){ + feedback(); + increaseAlarm(); + drawState(); + return; + } if(is_lower){ + feedback(); + decreaseAlarm(); + drawState(); + return; + } + } else if (lcarsViewPos == 1 && (is_upper || is_lower) && plotWeek != is_lower){ + feedback(); + plotWeek = is_lower; + draw(); + return; + } }); From 1cdcedc997db4286270eaa5c3b7782b57310f073 Mon Sep 17 00:00:00 2001 From: David Peer Date: Tue, 11 Jan 2022 17:41:02 +0100 Subject: [PATCH 206/315] Bugfix: If the weather module does not exist, an exception was thrown. Now its hidden in a function. --- apps/lcars/lcars.app.js | 36 +++++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/apps/lcars/lcars.app.js b/apps/lcars/lcars.app.js index 09998ccf5..39d01a687 100644 --- a/apps/lcars/lcars.app.js +++ b/apps/lcars/lcars.app.js @@ -1,10 +1,5 @@ const SETTINGS_FILE = "lcars.setting.json"; -const Storage = require("Storage"); -const weather = require('weather'); - - -// ...and overwrite them with any saved values -// This way saved values are preserved if a new version adds more settings +const locale = require('locale'); const storage = require('Storage') let settings = { alarm: -1, @@ -39,7 +34,7 @@ var disableInfoUpdate = true; // When gadgetbridge connects, step infos cannot b /* * Requirements and globals */ -const locale = require('locale'); + var bgLeft = { width : 27, height : 176, bpp : 3, @@ -124,7 +119,7 @@ function queueDraw() { function printData(key, y, c){ g.setFontAlign(-1,-1,0); var text = "ERR"; - var value = "NOT FOUND"; + var value = "ERR"; if(key == "Battery"){ text = "BAT"; @@ -136,7 +131,7 @@ function printData(key, y, c){ } else if(key == "Temp."){ text = "TEMP"; - value = Math.floor(E.getTemperature()) + "C"; + value = locale.temp(parseInt(E.getTemperature())); } else if(key == "HRM"){ text = "HRM"; @@ -148,12 +143,8 @@ function printData(key, y, c){ } else if (key == "Weather"){ text = "TEMP"; - const w = weather.get(); - if (!w) { - value = "ERR"; - } else { - value = require('locale').temp(w.temp-273.15); // applies conversion - } + var weather = getWeather(); + value = locale.temp(parseInt(weather.temp-273.15)); } g.setColor(c); @@ -429,6 +420,21 @@ function getSteps() { } +function getWeather(){ + let weather; + + try { + weather = require('weather'); + } catch(ex) { + return { + temp: 0.0 + }; + } + + return weather.get(); +} + + /* * Handle alarm */ From 5de8ca8184909f17b65900e1883204810b82c3e5 Mon Sep 17 00:00:00 2001 From: David Peer Date: Tue, 11 Jan 2022 18:10:05 +0100 Subject: [PATCH 207/315] Updated changelog, readme, screenshots etc. More consistent naming of datapoints. --- apps/lcars/ChangeLog | 4 ++-- apps/lcars/README.md | 36 +++++++++++++++------------- apps/lcars/lcars.app.js | 45 ++++++++++++++++------------------- apps/lcars/lcars.settings.js | 2 +- apps/lcars/screenshot.png | Bin 5259 -> 5547 bytes 5 files changed, 44 insertions(+), 43 deletions(-) diff --git a/apps/lcars/ChangeLog b/apps/lcars/ChangeLog index 45d7a8dd7..bcaddeb56 100644 --- a/apps/lcars/ChangeLog +++ b/apps/lcars/ChangeLog @@ -7,5 +7,5 @@ 0.07: Added settings to adjust data that is shown for each row. 0.08: Support for multiple screens. 24h graph for steps + HRM. Fullscreen Mode. 0.09: Tab anywhere to open the launcher. -0.10: Fix - Clock is unresponsive, if gadgetbridge connects. -0.11: Added getting the gadgetbridge weather \ No newline at end of file +0.10: Removed swipes to be compatible with the Pattern Launcher. Stability improvements. +0.11: Show the gadgetbridge weather temperature (settings). \ No newline at end of file diff --git a/apps/lcars/README.md b/apps/lcars/README.md index 4bf5218f6..510e5637c 100644 --- a/apps/lcars/README.md +++ b/apps/lcars/README.md @@ -4,20 +4,27 @@ A simple LCARS inspired clock. Note: To display the steps, the health app is required. If this app is not installed, the data will not be shown. To contribute you can open a PR at this [GitHub Repo]( https://github.com/peerdavid/BangleApps) +## Control + * Tap left / right to change between screens. + * Tap top / bottom to control the current screen. + ## Features * LCARS Style watch face. - * Full screen mode - widgets are still loaded. - * Supports multiple screens with different data. - * Tab anywhere to open the launcher. - * [Screen 1] Date + Time + Lock status. - * [Screen 1] Shows randomly images of real planets. - * [Screen 1] Shows different states such as (charging, out of battery, GPS on etc.) - * [Screen 1] Swipe up/down to activate an alarm. - * [Screen 1] Shows 3 customizable datapoints on the first screen. - * [Screen 1] The lower orange line indicates the battery level. - * [Screen 2] Display graphs for steps + hrm on the second screen. - * [Screen 2] Switch between day/month via swipe up/down. + * Full screen mode - widgets are still loaded but not shown. + * Tab on left/right to switch between different screens. + * Cusomizable data that is shown on screen 1 (steps, weather etc.) + * Shows random images of real planets. + * Tap on top/bottom of screen 1 to activate an alarm. + * The lower orange line indicates the battery level. + * Display graphs for steps + hrm on the second screen. +## Data that can be configured + * Steps - Steps loaded via the health module + * Battery - Current battery level in % + * VREF - Voltage of battery + * HRM - Last measured HRM + * Temp - Weather temperature loaded via the weather module + gadgetbridge + * CoreT - Temperature of device ## Multiple screens support Access different screens via swipe left/ right @@ -26,10 +33,7 @@ Access different screens via swipe left/ right ![](screenshot_2.png) -## Icons - - - ## Contributors -- Creator: [David Peer](https://github.com/peerdavid). +- Initial creation and improvements: [David Peer](https://github.com/peerdavid). - Improvements: [Adam Schmalhofer](https://github.com/adamschmalhofer). +- Improvements: [Jon Warrington](https://github.com/BartokW). diff --git a/apps/lcars/lcars.app.js b/apps/lcars/lcars.app.js index 39d01a687..521f661e7 100644 --- a/apps/lcars/lcars.app.js +++ b/apps/lcars/lcars.app.js @@ -28,7 +28,7 @@ let cGrey = "#9E9E9E"; let lcarsViewPos = 0; let drag; let hrmValue = 0; -var plotWeek = false; +var plotMonth = false; var disableInfoUpdate = true; // When gadgetbridge connects, step infos cannot be loaded /* @@ -118,33 +118,30 @@ function queueDraw() { function printData(key, y, c){ g.setFontAlign(-1,-1,0); - var text = "ERR"; + key = key.toUpperCase() + var text = key; var value = "ERR"; - if(key == "Battery"){ - text = "BAT"; - value = E.getBattery() + "%"; - - } else if(key == "Steps"){ + if(key == "STEPS"){ text = "STEP"; value = getSteps(); - } else if(key == "Temp."){ - text = "TEMP"; - value = locale.temp(parseInt(E.getTemperature())); - - } else if(key == "HRM"){ - text = "HRM"; - value = hrmValue; + } else if(key == "BATTERY"){ + text = "BAT"; + value = E.getBattery() + "%"; } else if (key == "VREF"){ - text = "VREF"; value = E.getAnalogVRef().toFixed(2) + "V"; - } else if (key == "Weather"){ - text = "TEMP"; + } else if(key == "HRM"){ + value = hrmValue; + + } else if (key == "TEMP"){ var weather = getWeather(); value = locale.temp(parseInt(weather.temp-273.15)); + + } else if(key == "CORET"){ + value = locale.temp(parseInt(E.getTemperature())); } g.setColor(c); @@ -300,7 +297,7 @@ function drawPosition1(){ } // Plot HRM graph - if(plotWeek){ + if(plotMonth){ var data = new Uint16Array(32); var cnt = new Uint8Array(32); health.readDailySummaries(new Date(), h=>{ @@ -337,8 +334,8 @@ function drawPosition1(){ g.setFontAlign(1, 1, 0); g.setFontAntonioMedium(); g.setColor(cWhite); - g.drawString("WEEK HRM", 154, 27); - g.drawString("WEEK STEPS [K]", 154, 115); + g.drawString("M-HRM", 154, 27); + g.drawString("M-STEPS [K]", 154, 115); // Plot day } else { @@ -378,8 +375,8 @@ function drawPosition1(){ g.setFontAlign(1, 1, 0); g.setFontAntonioMedium(); g.setColor(cWhite); - g.drawString("DAY HRM", 154, 27); - g.drawString("DAY STEPS", 154, 115); + g.drawString("D-HRM", 154, 27); + g.drawString("D-STEPS", 154, 115); } } @@ -568,9 +565,9 @@ Bangle.on('touch', function(btn, e){ drawState(); return; } - } else if (lcarsViewPos == 1 && (is_upper || is_lower) && plotWeek != is_lower){ + } else if (lcarsViewPos == 1 && (is_upper || is_lower) && plotMonth != is_lower){ feedback(); - plotWeek = is_lower; + plotMonth = is_lower; draw(); return; } diff --git a/apps/lcars/lcars.settings.js b/apps/lcars/lcars.settings.js index a0e54f9b4..1dd6e8d73 100644 --- a/apps/lcars/lcars.settings.js +++ b/apps/lcars/lcars.settings.js @@ -18,7 +18,7 @@ storage.write(SETTINGS_FILE, settings) } - var data_options = ["Battery", "Steps", "Temp.", "HRM", "VREF", "Weather"]; + var data_options = ["Steps", "Battery", "VREF", "HRM", "Temp", "CoreT"]; E.showMenu({ '': { 'title': 'LCARS Clock' }, diff --git a/apps/lcars/screenshot.png b/apps/lcars/screenshot.png index 5d7603b45e6c7aadcc01aa0afdf13ff4d579eb93..5381492b242865bae924e11daf9a5cd40313188f 100644 GIT binary patch literal 5547 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 literal 5259 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 Date: Tue, 11 Jan 2022 18:11:49 +0100 Subject: [PATCH 208/315] Updated screenshot. --- apps/lcars/screenshot.png | Bin 5547 -> 5721 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/apps/lcars/screenshot.png b/apps/lcars/screenshot.png index 5381492b242865bae924e11daf9a5cd40313188f..319062dcce36640c38e24378d97b7724ab3a9f74 100644 GIT binary patch literal 5721 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 From 755f44cf3f3896a3a646f96bea49ce48aa94b90d Mon Sep 17 00:00:00 2001 From: David Peer Date: Tue, 11 Jan 2022 18:20:53 +0100 Subject: [PATCH 209/315] Bugfix: Alarm not working. --- apps/lcars/ChangeLog | 3 ++- apps/lcars/lcars.app.js | 6 +++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/apps/lcars/ChangeLog b/apps/lcars/ChangeLog index bcaddeb56..bb5270b70 100644 --- a/apps/lcars/ChangeLog +++ b/apps/lcars/ChangeLog @@ -8,4 +8,5 @@ 0.08: Support for multiple screens. 24h graph for steps + HRM. Fullscreen Mode. 0.09: Tab anywhere to open the launcher. 0.10: Removed swipes to be compatible with the Pattern Launcher. Stability improvements. -0.11: Show the gadgetbridge weather temperature (settings). \ No newline at end of file +0.11: Show the gadgetbridge weather temperature (settings). +0.12: Refactoring and stability improvements. \ No newline at end of file diff --git a/apps/lcars/lcars.app.js b/apps/lcars/lcars.app.js index 521f661e7..c4e675873 100644 --- a/apps/lcars/lcars.app.js +++ b/apps/lcars/lcars.app.js @@ -470,7 +470,7 @@ function handleAlarm(){ .then(() => { // Update alarm state to disabled settings.alarm = -1; - Storage.writeJSON(SETTINGS_FILE, settings); + storage.writeJSON(SETTINGS_FILE, settings); }); } @@ -510,7 +510,7 @@ function increaseAlarm(){ settings.alarm = getCurrentTimeInMinutes() + 5; } - Storage.writeJSON(SETTINGS_FILE, settings); + storage.writeJSON(SETTINGS_FILE, settings); } @@ -521,7 +521,7 @@ function decreaseAlarm(){ settings.alarm = -1; } - Storage.writeJSON(SETTINGS_FILE, settings); + storage.writeJSON(SETTINGS_FILE, settings); } function feedback(){ From 8467a8810af3a651ae85af6d6866f97222f2abeb Mon Sep 17 00:00:00 2001 From: Richard de Boer Date: Tue, 11 Jan 2022 19:16:05 +0100 Subject: [PATCH 210/315] messages: app-specific icon colors --- apps.json | 2 +- apps/messages/ChangeLog | 1 + apps/messages/app.js | 31 +++++++++++++++++++++++++++++-- 3 files changed, 31 insertions(+), 3 deletions(-) diff --git a/apps.json b/apps.json index b5929a56c..71a60ec88 100644 --- a/apps.json +++ b/apps.json @@ -77,7 +77,7 @@ { "id": "messages", "name": "Messages", - "version": "0.17", + "version": "0.18", "description": "App to display notifications from iOS and Gadgetbridge", "icon": "app.png", "type": "app", diff --git a/apps/messages/ChangeLog b/apps/messages/ChangeLog index 4f0498e92..84dc67288 100644 --- a/apps/messages/ChangeLog +++ b/apps/messages/ChangeLog @@ -24,3 +24,4 @@ 0.15: Don't buzz when Quiet Mode is active 0.16: Fix text wrapping so it fits the screen even if title is big (fix #1147) 0.17: Fix: Get dynamic dimensions of notify icon, fixed notification font +0.18: Use app-specific icon colors diff --git a/apps/messages/app.js b/apps/messages/app.js index 6e51c2b33..f670c39a2 100644 --- a/apps/messages/app.js +++ b/apps/messages/app.js @@ -101,6 +101,31 @@ function getMessageImage(msg) { if (msg.id=="back") return getBackImage(); return getNotificationImage(); } +function getMessageImageCol(msg,def) { + return { + // generic colors, using B2-safe colors + "calendar": "#f00", + "mail": "#ff0", + "music": "#f0f", + "phone": "#0f0", + "sms message": "#0ff", + // brands, according to https://www.schemecolor.com/?s (picking one for multicolored logos) + // all dithered on B2, but we only use the color for the icons. (Could maybe pick the closest 3-bit color for B2?) + "facebook": "#4267b2", + "gmail": "#ea4335", + "google home": "#fbbc05", + "hangouts": "#1ba261", + "instagram": "#dd2a7b", + "messenger": "#0078ff", + "outlook mail": "#0072c6", + "skype": "#00aff0", + "slack": "#e51670", + "telegram": "#0088cc", + "twitter": "#1da1f2", + "whatsapp": "#4fce5d", + "wordfeud": "#dcc8bd", + }[(msg.src||"").toLowerCase()]||(def !== undefined?def:g.theme.fg); +} function showMapMessage(msg) { var m; @@ -248,7 +273,7 @@ function showMessage(msgid) { var body = (lines.length>4) ? lines.slice(0,4).join("\n")+"..." : lines.join("\n"); layout = new Layout({ type:"v", c: [ {type:"h", fillx:1, bgCol:colBg, c: [ - { type:"btn", src:getMessageImage(msg), pad: 3, cb:()=>{ + { type:"btn", src:getMessageImage(msg), col:getMessageImageCol(msg), pad: 3, cb:()=>{ cancelReloadTimeout(); // don't auto-reload to clock now showMessageSettings(msg); }}, @@ -310,7 +335,9 @@ function checkMessages(options) { body = msg.track; } if (img) { - g.drawImage(img, x+24, r.y+24, {rotate:0}); // force centering + var fg = g.getColor(); + g.setColor(getMessageImageCol(msg,fg)).drawImage(img, x+24, r.y+24, {rotate:0}) // force centering + .setColor(fg); // only color the icon x += 50; } var m = msg.title+"\n"+msg.body; From d32674f825a0906ca9d1149505371dc4e0f101e2 Mon Sep 17 00:00:00 2001 From: Richard de Boer Date: Tue, 11 Jan 2022 19:17:16 +0100 Subject: [PATCH 211/315] messages: Spread message action buttons out --- apps/messages/ChangeLog | 1 + apps/messages/app.js | 2 ++ 2 files changed, 3 insertions(+) diff --git a/apps/messages/ChangeLog b/apps/messages/ChangeLog index 84dc67288..4a28f7cd9 100644 --- a/apps/messages/ChangeLog +++ b/apps/messages/ChangeLog @@ -25,3 +25,4 @@ 0.16: Fix text wrapping so it fits the screen even if title is big (fix #1147) 0.17: Fix: Get dynamic dimensions of notify icon, fixed notification font 0.18: Use app-specific icon colors + Spread message action buttons out diff --git a/apps/messages/app.js b/apps/messages/app.js index f670c39a2..5161ce665 100644 --- a/apps/messages/app.js +++ b/apps/messages/app.js @@ -253,6 +253,7 @@ function showMessage(msgid) { }} // back ]; if (msg.positive) { + buttons.push({fillx:1}); buttons.push({type:"btn", src:getPosImage(), cb:()=>{ msg.new = false; saveMessages(); cancelReloadTimeout(); // don't auto-reload to clock now @@ -261,6 +262,7 @@ function showMessage(msgid) { }}); } if (msg.negative) { + buttons.push({fillx:1}); buttons.push({type:"btn", src:getNegImage(), cb:()=>{ msg.new = false; saveMessages(); cancelReloadTimeout(); // don't auto-reload to clock now From a945a32f51a7d2a1a42a5a70bed38309aab2d555 Mon Sep 17 00:00:00 2001 From: Richard de Boer Date: Tue, 11 Jan 2022 19:18:19 +0100 Subject: [PATCH 212/315] messages: Back button now goes back to list of messages --- apps/messages/ChangeLog | 1 + apps/messages/app.js | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/messages/ChangeLog b/apps/messages/ChangeLog index 4a28f7cd9..0c02a76e1 100644 --- a/apps/messages/ChangeLog +++ b/apps/messages/ChangeLog @@ -26,3 +26,4 @@ 0.17: Fix: Get dynamic dimensions of notify icon, fixed notification font 0.18: Use app-specific icon colors Spread message action buttons out + Back button now goes back to list of messages diff --git a/apps/messages/app.js b/apps/messages/app.js index 5161ce665..4704c422f 100644 --- a/apps/messages/app.js +++ b/apps/messages/app.js @@ -249,7 +249,7 @@ function showMessage(msgid) { {type:"btn", src:getBackImage(), cb:()=>{ msg.new = false; saveMessages(); // read mail cancelReloadTimeout(); // don't auto-reload to clock now - checkMessages({clockIfNoMsg:1,clockIfAllRead:0,showMsgIfUnread:1}); + checkMessages({clockIfNoMsg:1,clockIfAllRead:0,showMsgIfUnread:0}); }} // back ]; if (msg.positive) { From 1f06e6cfc578473c86214f76c5c43d9715b905a4 Mon Sep 17 00:00:00 2001 From: David Peer Date: Tue, 11 Jan 2022 21:24:23 +0100 Subject: [PATCH 213/315] Added humidity --- apps/lcars/README.md | 1 + apps/lcars/lcars.app.js | 28 +++++++++++++++++++--------- apps/lcars/lcars.settings.js | 10 +++++----- 3 files changed, 25 insertions(+), 14 deletions(-) diff --git a/apps/lcars/README.md b/apps/lcars/README.md index 510e5637c..46e134f78 100644 --- a/apps/lcars/README.md +++ b/apps/lcars/README.md @@ -24,6 +24,7 @@ To contribute you can open a PR at this [GitHub Repo]( https://github.com/peerda * VREF - Voltage of battery * HRM - Last measured HRM * Temp - Weather temperature loaded via the weather module + gadgetbridge + * Humidity - Humidity loaded via the weather module + gadgetbridge * CoreT - Temperature of device ## Multiple screens support diff --git a/apps/lcars/lcars.app.js b/apps/lcars/lcars.app.js index c4e675873..0005e9016 100644 --- a/apps/lcars/lcars.app.js +++ b/apps/lcars/lcars.app.js @@ -3,9 +3,9 @@ const locale = require('locale'); const storage = require('Storage') let settings = { alarm: -1, - dataRow1: "Battery", - dataRow2: "Steps", - dataRow3: "Temp." + dataRow1: "Steps", + dataRow2: "Temp", + dataRow3: "Battery" }; let saved_settings = storage.readJSON(SETTINGS_FILE, 1) || settings; for (const key in saved_settings) { @@ -140,6 +140,11 @@ function printData(key, y, c){ var weather = getWeather(); value = locale.temp(parseInt(weather.temp-273.15)); + } else if (key == "HUMIDITY"){ + text = "HUM"; + var weather = getWeather(); + value = parseInt(weather.hum) + "%"; + } else if(key == "CORET"){ value = locale.temp(parseInt(E.getTemperature())); } @@ -418,17 +423,22 @@ function getSteps() { function getWeather(){ - let weather; + var weather = { + temp: 0, + hum: 0, + txt: "", + wind: 0, + wdir: 0, + wrose: "" + }; try { - weather = require('weather'); + weather = require('weather').get(); } catch(ex) { - return { - temp: 0.0 - }; + // Return default } - return weather.get(); + return weather; } diff --git a/apps/lcars/lcars.settings.js b/apps/lcars/lcars.settings.js index 1dd6e8d73..ba630799a 100644 --- a/apps/lcars/lcars.settings.js +++ b/apps/lcars/lcars.settings.js @@ -7,7 +7,7 @@ alarm: -1, dataRow1: "Battery", dataRow2: "Steps", - dataRow3: "Temp." + dataRow3: "Temp" }; let saved_settings = storage.readJSON(SETTINGS_FILE, 1) || settings; for (const key in saved_settings) { @@ -18,14 +18,14 @@ storage.write(SETTINGS_FILE, settings) } - var data_options = ["Steps", "Battery", "VREF", "HRM", "Temp", "CoreT"]; + var data_options = ["Steps", "Battery", "VREF", "HRM", "Temp", "Humidity", "CoreT"]; E.showMenu({ '': { 'title': 'LCARS Clock' }, '< Back': back, 'Row 1': { value: 0 | data_options.indexOf(settings.dataRow1), - min: 0, max: 5, + min: 0, max: 6, format: v => data_options[v], onchange: v => { settings.dataRow1 = data_options[v]; @@ -34,7 +34,7 @@ }, 'Row 2': { value: 0 | data_options.indexOf(settings.dataRow2), - min: 0, max: 5, + min: 0, max: 6, format: v => data_options[v], onchange: v => { settings.dataRow2 = data_options[v]; @@ -43,7 +43,7 @@ }, 'Row 3': { value: 0 | data_options.indexOf(settings.dataRow3), - min: 0, max: 5, + min: 0, max: 6, format: v => data_options[v], onchange: v => { settings.dataRow3 = data_options[v]; From 009df38104965fc2b3119ebdd5fcb8e95d3223f5 Mon Sep 17 00:00:00 2001 From: Danny <31635744+DDDanny@users.noreply.github.com> Date: Wed, 12 Jan 2022 00:16:01 +0100 Subject: [PATCH 214/315] fixed and aligned for bangle2 *bugfix* stopwatch broken with v0.03 setUI realigned quick n dirty screen positions help adjusted to fit bangle1 & bangle2 screen-size with widgets fixed bangle2 colors for chrono and last lap highlight added screen for bangle2 and a small README --- apps.json | 5 +- apps/devstopwatch/ChangeLog | 5 ++ apps/devstopwatch/README.md | 16 ++++++ apps/devstopwatch/app.js | 46 +++++++++++------- .../bangle1-dev-stopwatch-screenshot.png | Bin 3825 -> 2469 bytes .../bangle2-dev-stopwatch-screenshot.png | Bin 0 -> 2382 bytes 6 files changed, 52 insertions(+), 20 deletions(-) create mode 100644 apps/devstopwatch/README.md create mode 100644 apps/devstopwatch/bangle2-dev-stopwatch-screenshot.png diff --git a/apps.json b/apps.json index b5929a56c..f1872f337 100644 --- a/apps.json +++ b/apps.json @@ -2095,12 +2095,13 @@ "id": "devstopwatch", "name": "Dev Stopwatch", "shortName": "Dev Stopwatch", - "version": "0.03", + "version": "0.04", "description": "Stopwatch with 5 laps supported (cyclically replaced)", "icon": "app.png", "tags": "stopwatch,chrono,timer,chronometer", "supports": ["BANGLEJS","BANGLEJS2"], - "screenshots": [{"url":"bangle1-dev-stopwatch-screenshot.png"}], + "screenshots": [{"url":"bangle1-dev-stopwatch-screenshot.png"},{"url":"bangle2-dev-stopwatch-screenshot.png"}], + "readme": "README.md", "allow_emulator": true, "storage": [ {"name":"devstopwatch.app.js","url":"app.js"}, diff --git a/apps/devstopwatch/ChangeLog b/apps/devstopwatch/ChangeLog index e2b392fe9..7e90e061e 100644 --- a/apps/devstopwatch/ChangeLog +++ b/apps/devstopwatch/ChangeLog @@ -1,3 +1,8 @@ 0.01: App created 0.02: Persist state to storage to enable stopwatch to continue in the background 0.03: Modified to use setUI, theme and different screens +0.04: *bugfix* stopwatch broken with v0.03 setUI + realigned quick n dirty screen positions + help adjusted to fit bangle1 & bangle2 screen-size with widgets + fixed bangle2 colors for chrono and last lap highlight + added screen for bangle2 and a small README \ No newline at end of file diff --git a/apps/devstopwatch/README.md b/apps/devstopwatch/README.md new file mode 100644 index 000000000..c068aadfe --- /dev/null +++ b/apps/devstopwatch/README.md @@ -0,0 +1,16 @@ +# dev stop watch + +stores state at kill + +Look and control: + +![](bangle1-dev-stopwatch-screenshot.png) +BTN1: start/lap +BTN2: launcher +BTN3: reset + +![](bangle2-dev-stopwatch-screenshot.png) +TAP top right: start/lap +TAP bottom right: reset +Use BTN to get to launcher + diff --git a/apps/devstopwatch/app.js b/apps/devstopwatch/app.js index 83bb693a9..d2a4b1117 100644 --- a/apps/devstopwatch/app.js +++ b/apps/devstopwatch/app.js @@ -3,11 +3,11 @@ const EMPTY_H = '00:00:000'; const MAX_LAPS = 6; const XY_CENTER = g.getWidth() / 2; const big = g.getWidth()>200; -const Y_CHRONO = 40; -const Y_HEADER = big?80:60; -const Y_LAPS = big?125:90; +const Y_CHRONO = big?40:30; +const Y_HEADER = big?95:65; +const Y_LAPS = big?125:80; const H_LAPS = big?15:8; -const Y_BTN3 = big?225:165; +const Y_HELP = big?225:135; const FONT = '6x8'; const CHRONO = '/* C H R O N O */'; @@ -27,18 +27,17 @@ var state = require("Storage").readJSON("devstopwatch.state.json",1) || { // Show launcher when button pressed Bangle.setUI("clockupdown", btn=>{ - if (btn==0) { - reset = false; - - if (state.started) { - changeLap(); - } else { - if (!reset) { - chronoInterval = setInterval(chronometer, 10); - } + switch (btn) { + case -1: + if (state.started) { + changeLap(); + } else { + chronoInterval = setInterval(chronometer, 10); + } + break; + case 1: resetChrono(); break; + default: Bangle.showLauncher(); break; //launcher handeled by ROM } -} - if (btn==1) resetChrono(); }); function resetChrono() { @@ -105,6 +104,7 @@ function printChrono() { var print = ''; + g.setColor(g.theme.fg); g.setFont(FONT, big?2:1); print = CHRONO; g.drawString(print, XY_CENTER, Y_CHRONO, true); @@ -124,7 +124,8 @@ function printChrono() { let suffix = ' '; if (state.currentLapIndex === i) { let suffix = '*'; - g.setColor("#f70"); + if (process.env.HWVERSION==2) g.setColor("#0ee"); + else g.setColor("#f70"); } const lapLine = `L${i - 1} ${state.laps[i]} ${suffix}\n`; @@ -133,8 +134,17 @@ function printChrono() { g.setColor(g.theme.fg); g.setFont(FONT, 1); - print = 'Press 3 to reset'; - g.drawString(print, XY_CENTER, Y_BTN3, true); + //help for model 2 or 1 + if (process.env.HWVERSION==2) { + print = /*LANG*/'TAP right top/bottom'; + g.drawString(print, XY_CENTER, Y_HELP, true); + print = /*LANG*/'start&lap/reset, BTN1: EXIT'; + g.drawString(print, XY_CENTER, Y_HELP+10, true); + } + else { + print = /*LANG*/'BTNs 1:startlap 2:exit 3:reset'; + g.drawString(print, XY_CENTER, Y_HELP, true); + } g.flip(); } diff --git a/apps/devstopwatch/bangle1-dev-stopwatch-screenshot.png b/apps/devstopwatch/bangle1-dev-stopwatch-screenshot.png index b668794b1f94f728fff6fbce8cfcfdc3c28e7787..8a9c9b46e33b4aa403bc90a43e0e4eca14b908ac 100644 GIT binary patch literal 2469 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 Z7IZMz?QhEcvOf^uGQ`cL@{-@9-vN`~z(@c9 literal 0 HcmV?d00001 From 30f8546319c83f79221fa73dcc9708aa6f131b31 Mon Sep 17 00:00:00 2001 From: Danny <31635744+DDDanny@users.noreply.github.com> Date: Wed, 12 Jan 2022 00:17:23 +0100 Subject: [PATCH 215/315] Update README.md --- apps/devstopwatch/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/devstopwatch/README.md b/apps/devstopwatch/README.md index c068aadfe..efead677b 100644 --- a/apps/devstopwatch/README.md +++ b/apps/devstopwatch/README.md @@ -5,11 +5,13 @@ stores state at kill Look and control: ![](bangle1-dev-stopwatch-screenshot.png) + BTN1: start/lap BTN2: launcher BTN3: reset ![](bangle2-dev-stopwatch-screenshot.png) + TAP top right: start/lap TAP bottom right: reset Use BTN to get to launcher From 382dce1176f8794fd117f587825fac2bb3453e9d Mon Sep 17 00:00:00 2001 From: Danny <31635744+DDDanny@users.noreply.github.com> Date: Wed, 12 Jan 2022 00:18:52 +0100 Subject: [PATCH 216/315] Update README.md --- apps/devstopwatch/README.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/apps/devstopwatch/README.md b/apps/devstopwatch/README.md index efead677b..02a13151f 100644 --- a/apps/devstopwatch/README.md +++ b/apps/devstopwatch/README.md @@ -2,17 +2,17 @@ stores state at kill -Look and control: - +## Bangle 1 ![](bangle1-dev-stopwatch-screenshot.png) -BTN1: start/lap -BTN2: launcher -BTN3: reset +* BTN1: start/lap +* BTN2: launcher +* BTN3: reset +## Bangle 2 ![](bangle2-dev-stopwatch-screenshot.png) -TAP top right: start/lap -TAP bottom right: reset -Use BTN to get to launcher +* TAP top right: start/lap +* TAP bottom right: reset +* Use BTN to get to launcher From dfd04df0f3d6237559e8319957eca9c0c5021f39 Mon Sep 17 00:00:00 2001 From: David Peer Date: Wed, 12 Jan 2022 07:20:08 +0100 Subject: [PATCH 217/315] Fixed weather --- apps/lcars/lcars.app.js | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/apps/lcars/lcars.app.js b/apps/lcars/lcars.app.js index 0005e9016..2674d323f 100644 --- a/apps/lcars/lcars.app.js +++ b/apps/lcars/lcars.app.js @@ -138,7 +138,7 @@ function printData(key, y, c){ } else if (key == "TEMP"){ var weather = getWeather(); - value = locale.temp(parseInt(weather.temp-273.15)); + value = weather.temp; } else if (key == "HUMIDITY"){ text = "HUM"; @@ -423,14 +423,7 @@ function getSteps() { function getWeather(){ - var weather = { - temp: 0, - hum: 0, - txt: "", - wind: 0, - wdir: 0, - wrose: "" - }; + var weather; try { weather = require('weather').get(); @@ -438,6 +431,19 @@ function getWeather(){ // Return default } + if (weather === undefined){ + weather = { + temp: "-", + hum: "-", + txt: "-", + wind: "-", + wdir: "-", + wrose: "-" + }; + } else { + weather.temp = locale.temp(parseInt(weather.temp-273.15)) + } + return weather; } From 2e564e06913e10ff6f06b67477dc9d3104e92440 Mon Sep 17 00:00:00 2001 From: David Peer Date: Wed, 12 Jan 2022 07:20:52 +0100 Subject: [PATCH 218/315] Created V0.12 --- apps.json | 6 +++--- apps/lcars/ChangeLog | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apps.json b/apps.json index b5929a56c..0a4a80a72 100644 --- a/apps.json +++ b/apps.json @@ -1357,7 +1357,7 @@ "shortName":"HR Alarm", "version":"0.01", "description": "This invisible widget vibrates whenever the heart rate gets close to the upper limit or goes over or under the configured limits", - "icon": "widget.png", + "icon": "widget.png", "type": "widget", "tags": "widget", "supports" : ["BANGLEJS2"], @@ -4514,7 +4514,7 @@ "name": "LCARS Clock", "shortName":"LCARS", "icon": "lcars.png", - "version":"0.11", + "version":"0.12", "readme": "README.md", "supports": ["BANGLEJS2"], "description": "Library Computer Access Retrieval System (LCARS) clock.", @@ -5184,7 +5184,7 @@ {"name":"mmind.app.js","url":"mmind.app.js"}, {"name":"mmind.img","url":"mmind.icon.js","evaluate":true} ] - }, + }, { "id": "presentor", "name": "Presentor", diff --git a/apps/lcars/ChangeLog b/apps/lcars/ChangeLog index bb5270b70..702ef58b9 100644 --- a/apps/lcars/ChangeLog +++ b/apps/lcars/ChangeLog @@ -9,4 +9,4 @@ 0.09: Tab anywhere to open the launcher. 0.10: Removed swipes to be compatible with the Pattern Launcher. Stability improvements. 0.11: Show the gadgetbridge weather temperature (settings). -0.12: Refactoring and stability improvements. \ No newline at end of file +0.12: Added humidity to data. \ No newline at end of file From fcfa78cb989f9b0823c69cc70367fe78932b5fb0 Mon Sep 17 00:00:00 2001 From: Andreas Rozek Date: Wed, 12 Jan 2022 08:50:21 +0100 Subject: [PATCH 219/315] Create none.png --- apps/ac_ac/none.png | Bin 0 -> 1430 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 apps/ac_ac/none.png diff --git a/apps/ac_ac/none.png b/apps/ac_ac/none.png new file mode 100644 index 0000000000000000000000000000000000000000..6f8d8ae14912ac974d77928fd613c80692486969 GIT binary patch literal 1430 zcmeAS@N?(olHy`uVBq!ia0vp^8$g(Y4M?uv{v-}aF%}28J29*~C-ahlfi=L>#WAEJ z?(NKreX|WjT&Dm3pRp>oQ_HEdmiOBx=03iL^sPW(`mO0Skq@3{2jSlPg$`F}`FIh>(&$tZcyNVcu}y z(hmu_#zKc(j4acR9sj`5!+eQXVS|ZXn|p%Hggl1Er5_D#m>xHb8i_Y7qdE5E-mahY zd!O^yrH$9~_Wi%LR=%?FF5}q>>ACR*+KqS1rb~X3`(7|LA}S$V!}w^e`i9GaPGJds ze2-^Y@B1LeR9v#+^c%H}OAfr*SDJWUTkuC!`Q>#b%?4{{9O}IjSNBtP#$)G$w=N4U z=XLOVa8dRNPxhBz*W3%9-u`p>eEo8BrvCk3F0Yf&{jc+8xnq@e<$JsN>)ywfpV|EC zr){IQ{zH=r?mU&f%-NE>b-R`tF^9&%=>#} z)(YbfmznO>*11mT>e=f*^;Ge{Q&KE;wHK4w|7mAkd*+a!*r>fbo7LL7VChoVY`4?v z=gf@Gt~xLM^Sh*bhon%rRb)&4uiU3)4?gGbwp}0^vDftK{i5pq%<+OdK1G+UZ{BRW zch6IddEPN9Jb1$7w*4jBLfs92?1X^@ OErX}4pUXO@geCxFHD;9n literal 0 HcmV?d00001 From 4b4a4e117b4f436d22528cf0f8b2c5164e0beb66 Mon Sep 17 00:00:00 2001 From: Andreas Rozek Date: Wed, 12 Jan 2022 08:50:25 +0100 Subject: [PATCH 220/315] Create custom.png --- apps/ac_ac/custom.png | Bin 0 -> 1668 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 apps/ac_ac/custom.png diff --git a/apps/ac_ac/custom.png b/apps/ac_ac/custom.png new file mode 100644 index 0000000000000000000000000000000000000000..14d797ba32005a45ae28d36b2f6775989a01836a GIT binary patch literal 1668 zcmeAS@N?(olHy`uVBq!ia0vp^8$g(Y4M?uv{v-}aF%}28J29*~C-ahlfz8g-#WAEJ z?(NNsMYr7qTrPh2Z$C@ZdYaeKh8K}e3TaO!hw~q}cU!!>wP^SK_uuRPv>ymyGH2q? z^?P%lg~O-iA`6GjF1v@EXBtOYGz$ZL(H~{IYt0Jw-`{$1#)0eW>W;p-bUl@+ob}R; zg{K#n-YJOUxbrmA?(l@ZrSg&K+rP#r6_|6lbNOEXw`FTtb@9H~2YC#W8r=W?UC#NZ z+kLrdtkwsAJFA+G`zzlp=6`(s_3kyV*E0Rj-JQSvZr1^J&XUS3e!b+EpXTp+rZ@Xy zs`ZEa1vNiTS{F>;y4Ux?V*fX`UoG2o zDF5Zwtp+un2ecPV;yC{vnP9V_&ZonV+U5By15-!?uFy9Z#dZS8V0qu%ac&r(RXb%fH#n z{`lrBjz0>|y(ad{b40Jd9g_9*`?oZ$Np)vJ&TqQ9bMfo7G4V4!g_iSO()%y_|K2x_ zK*0ijho`?n8~6W<(<;vnU&|F^`TU)%ecaA{n=)-aseR~c6lFXwQnC8N)P4)5`s4p* zy-#HScX-7v>vdi+wF273SIygGExPyH1Zuu`?W_GcUHn(h#HpV*%2q^9oUXSch5g>I zh6vmErJt`~tgp9mT4G-rTDEs@sr=dMFOBw9Z0qWT_oTeM7x?+#vG{ckb=$b#>+aDy zf6DgTzb{`Z=C^#fx%ZOuN1gm%yNg@hcO8GFHd&%(`;Phf7EJ%!7X`iO3Yf}Xxaq*l z-oj}c{#OUbs}?-vyl>@R7whnK<@z_v*4G>ft*?Lmbx+Zp9}&f-kFCodT;2XM(rN!& zo;|+;H*bA#>c7Pe=C2ihvpC)B?dPtZU&|gMH|12+r8B42&3aclZNv0;2iDhU?BQ;? zzf$;x();}R_bOX{^u_MzyZJY(QE;LHh^WG0rpn7)je z42{Oh!o8dVI|?lqr82Rc>+vxGDmeDEV;ZM`g|X4a84Qim)0Lw}H4Tw~_@IArAD4~) T%p(VY)e3{BtDnm{r-UW|FwpmH literal 0 HcmV?d00001 From 4039f71dd60df8137121de6631403d54544b9f66 Mon Sep 17 00:00:00 2001 From: Andreas Rozek Date: Wed, 12 Jan 2022 08:50:37 +0100 Subject: [PATCH 221/315] Create fourfoldClockFace.png --- apps/ac_ac/fourfoldClockFace.png | Bin 0 -> 2121 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 apps/ac_ac/fourfoldClockFace.png diff --git a/apps/ac_ac/fourfoldClockFace.png b/apps/ac_ac/fourfoldClockFace.png new file mode 100644 index 0000000000000000000000000000000000000000..391303b31d4d1ce4b1bacdb4bd67501a22ab53a2 GIT binary patch literal 2121 zcmeHJ`#;oq7ytVD4qr|9&S+6)t*=WWCE>%CpR~m?kDEVN4gwrDvYkbNTK051t>+=Y2lsbzbMZU+28e>zuNn zKws4@JGKA-pz81E6(YyBe+sN5e_OjGG&v|74e|8=T81bu0RUF?_i_)*p)FjA&bn@i z5FTx6E$lVyEw=L8u)X?QYQscB*dpBPfAhtg4+T;JcA9(<5pvQ;|I)MbNM2E9-Gb?o zD-pYp#M5M6G9~4t*2VK>)}`Ak@KZNjs@ja1RGMLg89o#QY05gXMizK?UNekON_F~> zNCA_TOtK8%-=aLLOykDFW(S`{b(Sxd;r9vl+9kNp@!)Ci=h}tkzwh^?&yan-*J8!; z)+hGKKOuRN{L5=OPO}=%MgAqr)~T+l*cmG0v(=ffLoLI7K{KXKx-i2lft0i2mwfz( zQvBC&H@c(!z;(&&s3TZ8jDy(IM3~WU{8{%q!$pke^YK$7+J;<{ z94j$;HHSUm{B2!#{!{j!_GO60z=S2F8RAJtZ%xbTLKV12&_Ey3t-ZRox&72E|gOvqZ1$0_Ai2leKmb)&sr7QRp@bGmLzd)zBBJ?({wG4ouiR z2?nDFA7h?^T#vKkp6XcNTvRb43|Ra|w>7lnS{Q`3ff4z;z|w!InqX<~7NUpP{``7n zxg}es2eCU|mCFf~gpf|+TOt|gefoCr$?M%WzZEG zMo>Fa&RXRcp4(0CBasTbh2P zT)QkAl9D1Ducp2w5L`NV@axfF*R@077lUgHEnKDj%4132)~AuMVNoVY*m5;>mH_dq zcnq|_;Z;I?q`0Y!izg7TjgPp@G=MSTG>5jYy(b=OY$-ULOA_9^mOM5n>ABm@Kp8v! zOt|7F<_f6FocUYzxn!)B$!WrV|FX7(o$$Jvzz-dNP7xaXkh!Qu;5YF+8R(Eq^lF9( zK8>10Q>FvoEgosd4FvgXYP_!RWAaHig2cg+o;&z$@7h9XI*SPD`cFouqIoh4*Mdv^ zf~1~z3q#xmtD3Oss+3wY>C{jbcdSKeGD1AwdNE43_p2jzf#jTi^S&&T)IHK+pO{@~ z2kZh7?cBm}T@P_9m9oonn!h5Bg*IQY_5J9QjY*=KvGl9EX+^kzTWDa@fIpuSqL$N~ zCA?I#yIDtv;3L{xek=tWvuEhJp_OYN`L!t!*s4BYQ!#NK9L>zEXQ^Z3fbT{pb@+^T z!8XufsWA73E+0}7%@$bwq(g*CHu&8WG~T%7afqEk3GRBF`H5Q2ZcB9OorlYL*16Te z(dsX>2z5#4#uOWp*U38_EJ93|TLh{YYbBEQV`(b5#F_h}^+_cf zZ%o-I*3cS}jF=Da=V#KEXM4_f6)TCp^IHd0XcGVCp4b~87 zrV9jV)BYZ{dm4xkPWe>!oK-p%3cm?2cOhZat!`qohj6X;dvh(U!_t7M83kFOR2CV` z5R)Hn8`Lktqv8h5(IVXFqDhrEfOQC}qCEhNY8h&H8UPbmMqMWXu$q3;Pg4OJ(x;}V zC_omy`&ee6JSKaR48jLbT+)w%5c|_+zZgMCH)P}eGpr|1lTMX`O8luflAOWM5;o%Y z|Ahauq=C58m!rGieJI!&rk5^n24>MbF!if`y53y)Hc&Y&d60YFZCXzVQ;6ximkxw+ zG}@cH5;MdA-){%-SR2EAnDdD+<=?6=xHQndqFPjdV7LOq$c}k*yO&x~Pnnw-xcOhF z8fVLV2_RsgWHhUehcflojCE}6rs}TtEOGbH#Q+CUIQ>+kb7iB5s%;Bmifq2oxAP`n zyS;p7fY|#f4EjUdJ9@$t*>V_P#LMd~flP_mEKz Date: Wed, 12 Jan 2022 08:50:40 +0100 Subject: [PATCH 222/315] Create twelvefoldClockFace.png --- apps/ac_ac/twelvefoldClockFace.png | Bin 0 -> 2493 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 apps/ac_ac/twelvefoldClockFace.png diff --git a/apps/ac_ac/twelvefoldClockFace.png b/apps/ac_ac/twelvefoldClockFace.png new file mode 100644 index 0000000000000000000000000000000000000000..fc04d865e38f930ea094d7e03dd4729eaae70a66 GIT binary patch literal 2493 zcmV;u2}1UXP)Px;cS%G+RCr$Poo$z^Dhx(%|NoEfUCy)}k5x!QKoa)(cGiRto@^s8Y9G(%^Z6hD zP#~xR4*(9DIl}%?0Du7@v;qL^kiN&`@$n*=k?rlbhLSc8VWxBez>R6uz<9Jhb`8k- zWB{;Uv){SbuIlbxlpq9Pqu7OJ0BqFsIBj_U{|eyJG($TDF@~J782}s8x8vu4n zsTN@1^${L`eRTY6tJS6ufa@gq%S}jtwev=;y+vY41)d4s5t>+Z)V2u+uoeQXy;i`t zy%ykFrMAW)X*Ws}Ni3~4VF1>id}-~Qg{R!x_g6z%yoLP)qjXzd3M<+iReY7(Xb zYsJ^v-$vEIjx%Z!2H=5trmH{-0C1pW5$d-B01OqO6#(GS=_7amhJnxu0C4E^5j+6H zKxhR3ICT059)MvWv;qJeI(-BWz%US60RRr2K7t2e7znKZ0EbRroZyd7!bxAot&PwH zVC`p8?4jS=C>Xq{*fVCgn+hjkh&|ZUypVoCo;FWVTz(=WTZ@8BJ?lqWo z(trO*x13oQV4nE~;QLt!6@g~aem1by_FskbX}ydNo~Xc~I5Y)oS-4-Vb*`q9+Q6v5 zTE!N$FKvZM>YsPj{pX^f0xw9UV#qVYyA6X1tVrf+rma(kAHZHee&aP|U=F+*g@*CA zR^4}(z2Uv30w1r$5rZ`3aM>na@E)sgNl?i=`l`Ko3Q;@bes_3w*l`t1%RrVT&S~JD z;GR|B6abg5O5k-O(cq>ByoNALP0SV8)EkYaQy?u*yq`iw z2RYl`u4a9aej6=wHD0yqF1HUXg?JMtN;L-FUyRdN;Ll`#_i9V+7Bw@(fctOumH}7` z@{AAz?|1204&a~LPQYpmyyy4LB>|39jRChj;aeKu*{d<|)>bPEE#hiYNT(H}=Ef`U z?bdR&+%}q25Glkxx7(dGM5^XFZqY7;#-S*}U`B4$_y91K_i(CKDHf+cPf@DCwZw_4 zPB2)n!mVksZ+EK84qm{$IFtb3{#T0>~Y}+ck!A2Y`XM4)12s4DgkcWA`NFJ0YLD7x2nxtyr1n zz;B<`Io`#&zDwkRoou=t=f7O+wuCkTeAZ>jp)JIOtqxmfz+29-bB~^X^SS44%7=XQ$RQUm5m0TQLc*y1H1Asl$r22ZOXz~HTCfRn4 zfVWk_ruG2bB;U`I*X%sBYS_>ofE&aE-WKtE+5&Kkj#S?k^<3HlaEpup+@hXKTL8Ao z2)tJ1T-yP#RZal5D(Bh`fGu(YuSK;kZ2;IJD*#(m>(T~*wXy=QR!pvGSwn3-Oq6W zZ&!GaQ_j}AbGIpk=T+8S(R~L1++A)@HktuWwTJ`W?(j}mf!`zUbyPS+(Z50Pp}wJl zw|C}Jf!o8FzysBHf+Xle0AQ-Go|=hT0PydmjH$y!P-;Q}U;x(eGMy~|1MqZEY61da zrVkokrn3cL0G-SQB8X zZ<^}@fYYRM&4GjjxcOC;MJsT#ZWCT3>jAtdyuSyI4-tZ`Z%K$caWVp6Cm|!a0pI{x zD!#6=aP{3+;7Ap=hFr)BTpCpACDYX(n=EQmBW2RRrvjMjTiG*x&4G^}*xOn~t;#6@ zK265r(+BAyE*i*d01Ui8rCG9w1K^wHN=zT>!b?5_7Hv9_rUJ8gs{<@q`~q;Bj;7XB zUz2SAH1hmfPJ1+R4=F0}tkw58=e&Dm? zX@_*GT!aUB##`U4084fv?z*^C)b5Pa06dHE5mx#szGL@-I6T1CE4Np>jK{UTwDRx^ zz#b~@Z)pjSYn>%>bqBz%a^^hka+b)|9RRz^3Bb;BR^0(`RU(~1ghiZgL~~mMuycMg z9u_!DyA%N6yOgJ27X|(YT-Iz_?m;3>00000NkvXX Hu0mjfm>s5V literal 0 HcmV?d00001 From d20f6ddd1e06370dadcf0afe7debc8bf0f563334 Mon Sep 17 00:00:00 2001 From: Andreas Rozek Date: Wed, 12 Jan 2022 08:50:43 +0100 Subject: [PATCH 223/315] Create RainbowClockFace.png --- apps/ac_ac/RainbowClockFace.png | Bin 0 -> 3493 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 apps/ac_ac/RainbowClockFace.png diff --git a/apps/ac_ac/RainbowClockFace.png b/apps/ac_ac/RainbowClockFace.png new file mode 100644 index 0000000000000000000000000000000000000000..2defa759bc33a9c441c844e9f9950c6e0801ab5f GIT binary patch literal 3493 zcmV;W4O;SvP)Px?Ur9tkRCr$Poo$&*rMw)23-b%D47b9vJHaSt$iU`hqXOye^9$#i!! zEA*rQ>q-+^bIiECh8eb*OL3C|tmi>3T})l8#X<|ON7Zp%flc3F^Mi}mC~T|EYOBsd z52^CT$7xXF8N)cG0&8$|x<(=VpR%gV*E`T7suJMiAuUYxj=Hhdow_M-ygDo>GR4}~ z9GV{P_9L~Y7m5L{FBWePh3pZK0@u#2S%I}b;3)=Jw*sd?QWaSHdS6#yS>aRDJ4Jz8 zDi~@8s>~3T3ardWD05mBIIUt(a%Yrb#v2U-SZdW+Yrn1SOFUo|xToq$-~Ofh$6R{@ z0p_nX#4y(07Jk%a5pNe`9Enljo-=SUTvChO_j815(V$z%K!CTA^DHWl*GAl1UEp5G z#I#2Ne3kvmt$S1(;;KP(ZSHd>+&@bzFsC!qG$8!Hx?e+d@j&e{wn7TrtJ;u475*>4 zFUBq6ZH6f@=g2k%j$sXoT%HwcYoD_fTGw#hTF-y9wx{|htP**oNypwQCVxx-oJOWq zQCr*Z$xrk)aJr@;w>F}+Jr`}Rz#l!y^_1UY2Bg4m;CXWK78`rD4LNa71@4&}i!1Pm zbq%eG+SrQ)p};+>6CD8Nt2ST*>I!^&$`u$(jiPp~irU&<(NIBCMkp|76k`K% z1!lAr-IXiwSOrE0ilL!VfRD7LJeBeEoGUN`NrSpD3UFIhp;fU5#fo&=5jil)P~t(X z0FS6Rgh#|{hr4+G^!f&c=i>Nu%|tw%9QT7&aH8);4olZSl-$vKUPG!fVFchX|5X1S zf>v5PkzNG7gUms6X)Q!@Eq9-pbAUOb>wOIKz!U%v^Nyc*Sr4$L5X*Ye2R_UL4)8G7 z`-wR`-~e-Y(fb(Y0S9=P>;1$W4|ZgLN7Z~i>~=ih0NaV>k|S||mkhfPI`#lLg`m2z zHT8(wZ|9tGdY9@e?Z?Fmy2oa~)MZzITVPDvronWO$KjoV`-)9Rkh=g}g0Tjn13V5; z=*&w4yg?h_EbrS;-nFMS1%ZO$pSO9S_Ta_wP}XM6y^at(?h82ieH+U8Yz^=)c7TKQ z2A@3e6=2Ho=oI4E*WlOrjrg&WTn4OLN=T3ep4|K8sGj99u0Luc^ ztM?n+XJLy1@79ATz?@ETfH}Q6rmsA_XQ9(t6(V)913U&gjEQ5==XDIznrr@GAkdgrKz6SHZm|lnBFYdDS|En(TnStUIJr_GI7a5ikZmi1>i`#SH4rR4 z)fi*T%J9B&;A01!u!h~{>=Y(N!hj?FkObMV9Ju$p6_4qO$3q;~8yFZ!w6}o(l1eF{ z^DYPO>FCmA#tUFq;OC_U0mYS4KBKI z>;PB3EZ)S-5Ck1Yjh}tILohYCn*$2B`~9QJ!W@beGXh**#b&X(fdx5+@eS@7?K5)I zgNq@s0ypOHv<(};VHI0(PhW=pB`5=wJf;QWyKT64K4yx&ceN_SSzjRJ zbeb>7FSeB+<%Tz3*CARSsu1bghtl7Pr%`iQ$PmbjQ`C$^#t>f%A>-H2y*jvf7nUIA zEJP)h^}l1TdcPgg?uoJDMyumZJiOh$!3WV>@_4}41Ap+NtL_KqaUF_V5Byz$x$M=@ zkAtfr3TH*Vu!@asF^`_1ez(NI{qDnFJvhLLr#;W@g&xm&9N^QBuDU!x_3mYPfF0c4 z$nlCF_GvvT{VvjQKR-rcL+!V<^Bj4%69a688P13VCb z4LY<6!10!&e}5reNWJ0ssP;e(R_y?DtrI?WYrMgQst~FJxuS6;P&oi5^wE$)5PDAn zT+ee|g{Qb4pfY|K1m!`FfEXI!uL^u9ZJ621O;*@@6J!b?TaBC*;MQ@5_Ro55O=Ss} zAJr&7j^6`=!iQGi))D6?B1&s3_U;ovoR8i2214}j#c8^->Y(h;ciH)0bN-spAg zZ3hK__xMKkjz*m(g)=gqnpuJS`s95!SK#A&6mnN>@^?mvMn>Hjz%^G^_NgBk0q%1L z1@5h|+~Yv@w+_G|y|A1J58(yD>joq(eLx6ma4U@-WR|=FLl%gBKB#n-f}4&}ItMNJ zw4*YLhBZk_q1S|a*}{LGQMvC(fNOPNS71iQy5yz<(uWw{R}LC!g_H`HAeDeufuavg zA*8DlgVP5oKrtEumD0FUap@2u#ySpQX$2mgK7>t>;~?~ex&$#7ylKgfvtIf$ZP}C+0i%!*6EM$Ryn}meb~^0PJpG;iv|ZZHy!;D*K9CUI}W+R zum2)=#8`9!yv;=peX|4MxniyL%*b+SLJjT@rxZO@qI$t-uugz2D6koTU4a>|w+Xrm zDr*H`{&OAu>=cTaJn z7d|!GSD|}OfM>2!P^CulI9Fgv?|R?vfwBiCRp3fUXGkx46FITMLawq0u%{RAm`|MJ zt_QFya0X!AlMxW4wa*PIFv1;{AUB*IAR>8fqJ?Q|r;Vja1xsTg5atRzS>5v$V^`qE zHWY+wz~CX8R85mD3PZi70z-ko Date: Wed, 12 Jan 2022 08:50:48 +0100 Subject: [PATCH 224/315] Create simpleClockSize.png --- apps/ac_ac/simpleClockSize.png | Bin 0 -> 3203 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 apps/ac_ac/simpleClockSize.png diff --git a/apps/ac_ac/simpleClockSize.png b/apps/ac_ac/simpleClockSize.png new file mode 100644 index 0000000000000000000000000000000000000000..49650586e01cdda1e25b2ac3aa464cb58f80d042 GIT binary patch literal 3203 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 Date: Wed, 12 Jan 2022 08:50:51 +0100 Subject: [PATCH 225/315] Create smartClockSize.png --- apps/ac_ac/smartClockSize.png | Bin 0 -> 3291 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 apps/ac_ac/smartClockSize.png diff --git a/apps/ac_ac/smartClockSize.png b/apps/ac_ac/smartClockSize.png new file mode 100644 index 0000000000000000000000000000000000000000..6891acc89e7b1a3bbdd28e1d6e0944673e67aace GIT binary patch literal 3291 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 Z{{b@j@|O7s$qE1f002ovPDHLkV1h@MC+z?L literal 0 HcmV?d00001 From 4fcad7444e3d6bcf2334ecf48c520704a71f8632 Mon Sep 17 00:00:00 2001 From: Andreas Rozek Date: Wed, 12 Jan 2022 08:50:53 +0100 Subject: [PATCH 226/315] Create simpleClockHands.png --- apps/ac_ac/simpleClockHands.png | Bin 0 -> 1446 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 apps/ac_ac/simpleClockHands.png diff --git a/apps/ac_ac/simpleClockHands.png b/apps/ac_ac/simpleClockHands.png new file mode 100644 index 0000000000000000000000000000000000000000..820606f27cc11a8cbce78c9d8ef2da401f61dc12 GIT binary patch literal 1446 zcmeAS@N?(olHy`uVBq!ia0vp^8$g(Y4M?uv{v-}aF%}28J29*~C-ahlfi=O?#WAEJ z?(N;zWs4$2S}%V3D}PHa?a8%HH> zcK*G_a6n;+G=qh$-9yGSg}V#~UVh}{H(-9r#^BfQU(q1xVa`xcRda~>jKeO*hRctI zpQFVAN_lJhh{_eLbUNg

zG{7^zIy>?kTHy4;|a4cR+f^ zi5MlYrYOq{nf0@GOs(bl{q3RhVa5DMe(#yB^FK&49bWX8V_Wmu>K)2Q*dO%U|4>wX zpYd9b>x2KEc9%Vy*H%j$*#1F|>to-?cmLGh$vyC9+->Xk=F5qK9kX|6c9gSMK9Bxx z;NG!b`u+FwnmaysDD3a$-&D%a{zLFYy=|rSe_OdeRI47I-~DiJ zl@!a5XkBNevXmd6U)mlBe>Ib-aV!@zV58R?Opr_w>HYJ$>w@;vwr5yUHpEJUq3bbzC7w*yynKyTE+?{|OoA_dD!zXfM9c^kC=Nzd!b6cjy=B$J^H{ z=YM;=t##A8m$?ja6|?5cCzrCmi=W<9bx(m|-u2sW-&gGqoc*o(LVdi Date: Wed, 12 Jan 2022 08:50:56 +0100 Subject: [PATCH 227/315] Create roundedClockHands.png --- apps/ac_ac/roundedClockHands.png | Bin 0 -> 1390 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 apps/ac_ac/roundedClockHands.png diff --git a/apps/ac_ac/roundedClockHands.png b/apps/ac_ac/roundedClockHands.png new file mode 100644 index 0000000000000000000000000000000000000000..cbd48e856985e2cb0c840b2336394bcb719f788a GIT binary patch literal 1390 zcmeAS@N?(olHy`uVBq!ia0vp^8$g(Y4M?uv{v-}aF%}28J29*~C-ahlfmOrP#WAEJ z?(LnoeYYY6SS~#MD?dy0qLARU{%%9zU9X;`A8T8;PWd(46ib=@VF3?1;uUF*euUzCW1E zxZbW;abB;5)CaAk{|9DwTgVw4DK1>+6UTUCXGQCwGuf*cfGXy8KTlZ4yr&B&#`ehT zfWY|!JB?Cx6P`a3mAhZ>Yy05p@{PqG%ahoC?2ilEx3gI9pWP9L_!6d%-x+Jo1P_>- zZDG1O@sZ@(`9CcWlz-#-c%Gr=dn`lUhJ&I<&K-R(RP(;BVg4KbN8cN2f8{lZo9|(| zxwE2hrga?K2kz4?KU!1&URcVof5!`uYJI)0y{8%PZP+7vWP6|R^4~JXW;%Z^+HdJM z+f}*vyTbgis`uh+9QIV+HP8RTa&O1^@Q?HEKkK<&oc#FF`aI@}$8z$viSzfW>^X0? ziZH)zlAlFulsjz^0!~_ zx7SVD_<6_Uc)ka7wPRX$7Tx`t(I@v`pZkF<<9vIi>TlU`+aK&TPqWTyC}*juTIt^L zzSeHfXO7VLX$*U|&*MIFUH|W!lQorp=lQ?9{Cb()O2&T-58U;CzTlpazW7b26|2dC z^H*vfJpXRzeD71(+ZBxW7NxaU+xl~36M3W_ Date: Wed, 12 Jan 2022 08:50:59 +0100 Subject: [PATCH 228/315] Create hollowClockHands.png --- apps/ac_ac/hollowClockHands.png | Bin 0 -> 1669 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 apps/ac_ac/hollowClockHands.png diff --git a/apps/ac_ac/hollowClockHands.png b/apps/ac_ac/hollowClockHands.png new file mode 100644 index 0000000000000000000000000000000000000000..2dce42ef598eece0c07beaf0fe57fb6b38555834 GIT binary patch literal 1669 zcmeHI`#02i82)@`%#g@V%E=5iO|eMGu`^OExisVwyRk8Ju*z)=a=%Rx$EnS#M2Fp3 zotW%oMvVI~-?hogEv6z3^W}(!#tf~?4#w)Vf5QH_KfKTLoacGZdEfK?@)r7dxoN87 z)d2vSlrzr0J6!jv)UZ3qZJr6}mg@z}G4K0r`BUqRB6e?SIK8-^pThVMX!I1LdOK0)lvn&z0o>K6uv)AR|)0ld#7B z>eCGn9>b!vZ*(Qyd_u3AYfLwVNxU^KVRA#@7+m0!)GYymt|+|!yVl^feT+D(vS$ki zOgUv(d53Lvyi0YT4O3m7HNu%lGql&5Hi6tKnXG}iEsB?F3x<^upEbr(5h)%Hlsq^# zBSg`%MzHaoPg$y>^s0aiR6xVPTy45KZ0@hVHhp1?1$}Tow>yG2E&=Vn&XF$zNJo&@ zX4f;8TFO`$Q9>2n0-GvQ=@h@$zF!|4Md1D@^hWMcLq&GA_`h1qH0ux5Ew|p2RSNt!}D{;xV&t6s1|tLT3vEq+GKHV7u8QlvyP7b*&g8hssb*G%xuk^P)3zMDh~_F z0x%obXp#CXW4kf_BU?x6=DnuINV#ka+vT;@9f9q_x4x7M?=;IjXm&5Jyf%j>YZ`KJ z;#Fn#=o_|pW^1F#p{t_`1L7#Mi7)}PWuo+`K~&PCI@Gnt}> zvzHjVq5L=clY8g*4_~eq9rjJ3lq{z7GD+l{!KXu z<0^`6(5TK*{f^MgHv7Fp!O>vwO!7s(ho7w?A<#^DlN`7TT8`9KHC_if2_Xh)$I<-# z^mF`6_xk~Q)9mW&=s$|RQ4n@L7FAo8A(+&V>%hjX_RhouIBR%#u_GHw8W((Q$0W|O ze1LMFJY2X&JzHC5?eMdvCCoIEFURBh0n1hSdqj2ISG+3kk`|}D>9_GX*mKIYIzgDP zb%Sbn;ZAO|%@gVo~yCyYv-V3~{%XtddMD zKx@#S_SQuMY-&J7aTf@7?_DvRo|D@EbSAmW90N8@PYF|Q)NqP02M`WYuZ3Q>Jtri+ z9ph|38gdT2I;n^B1&f6E()88 zETtPHa!52bGNRMq>bOHCR?R0!h?TYfccG|%CxXv8pof+<%`*YKWt|fG--U8j>OiIW U{v?a^oxcJoE?&+Yr;FGA0bv~;9{>OV literal 0 HcmV?d00001 From 657cf26dc54e0b94bac8baa9cd865493202e2a37 Mon Sep 17 00:00:00 2001 From: Andreas Rozek Date: Wed, 12 Jan 2022 09:43:39 +0100 Subject: [PATCH 229/315] Update Customizer.html --- apps/ac_ac/Customizer.html | 531 ++++++++++++++++++++++++++++++++++--- 1 file changed, 491 insertions(+), 40 deletions(-) diff --git a/apps/ac_ac/Customizer.html b/apps/ac_ac/Customizer.html index 6637b5df4..203235e3d 100644 --- a/apps/ac_ac/Customizer.html +++ b/apps/ac_ac/Customizer.html @@ -19,73 +19,524 @@ } + + + + + + + + + + - - - + + + -

A Configurable Analog Clock

- +

Please customize your analog clock for the Bangle.js 2 according to your needs. - When finished, click on "Upload". + When finished, click on "Upload" at the bottom of this form. +

-

Clock Size Calculation

+

Clock Size Calculation

-
-
- -  
+

+ Click on the desired clock size calculator (if you installed some widgets + on your Bangle.js 2, the smart one may produce larger clock faces than the + simple one): +

+ + + -

Clock Face

+ -
-
-  
-
-  
-
-  
+ + +
+
+ simple +
+
+ smart +
+
+ (custom) +
+

+ If you prefer a "custom" clock size calculator, please enter the URL + of its JavaScript module below: +

+ custom URL: +

-

Clock Hands

+

Clock Face

-
-
-
-   Hand Fill Color
+

+ Click on the desired clock face: +

+ + + -

Complications

+ -

Settings

+ - Foreground Color:
+ - Background Color:
+ + +
+
+ none +
+
+ four-fold +
+
+ twelve-fold +
+
+ "rainbow"
colored +
+
+ (custom) +
+

+ Clock faces are drawn in the configured foreground and background colors + (you may select them at the end of this form) +

+ The "twelve-fold" and "rainbow"-colored faces may be drawn with or without + dots marking the position of every minute. Which variant do you prefer? +

+ without dots
+ with dots +

+ If you prefer a "custom" clock face, please enter the URL + of its JavaScript module below: +

+ custom URL: +

- Second Hand Color:
+

Clock Hands

+

+ Click on the desired clock hands: +

+ + + + + + + + + + +
+
+ simple +
+
+ rounded +
+
+ hollow +
+
+ (custom) +
+

+ Clock hands are drawn in the configured foreground and background colors + (you may select them at the end of this form) +

+ Additionally, all clock hands may be drawn with or without second hands. + If you want them to be drawn, please click on their desired color below + (or choose "themed" to use your Bangle's configured theme) - if not, just + select "none": +

+ Second Hand Color:
+ + + + + + + + + + +

+ If you prefer "custom" clock hands, please enter the URL + of their JavaScript module below: +

+ custom URL: +

+ +

Complications

+ +

+ Complications are small displays for additional information. If you want + one or multiple complications to be added to your clock, you'll have to + specify which one to be loaded and where it should be placed. +

+ Up to 6 possible positions exist (top-left, top-right, left, right, + bottom-left and bottom-right). Alternatively, the positions "top-left" and + "top-right" may be traded for a slightly larger complication at position + "top" or "bottom-left" and "bottom-right" for one at the "bottom". +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
top-left:
  Complication: + +
custom URL:
top:
  Complication: + +
custom URL:
top-right:
  Complication: + +
custom URL:
left:
  Complication: + +
custom URL:
right:
  Complication: + +
custom URL:
bottom-left:
  Complication: + +
custom URL:
bottom:
  Complication: + +
custom URL:
bottom-right:
  Complication: + +
custom URL:
+

+ +

Settings

+ +

+ Color faces, hands and complications are often drawn using configurable + foreground and background colors. +

+ Here you may specify these colors. Click on a color to select it - or on + "themed" if you want the clock to use the currently configured theme on + your Bangle.js 2: +

+ Foreground Color:
+ +

+ +
+ + + + + + + + +

+ Background Color:
+ + + + + + + + + +

+ When you are satisfied with your configuration, just click on "Upload" in + order to generate the specified clock and upload it to your Bangle.js 2: +

+

From 10896c63ddb881ececcf1749c142989c07062dc0 Mon Sep 17 00:00:00 2001 From: Andreas Rozek Date: Wed, 12 Jan 2022 10:07:15 +0100 Subject: [PATCH 230/315] Create app-icon.png --- apps/ac_ac/app-icon.png | Bin 0 -> 4120 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 apps/ac_ac/app-icon.png diff --git a/apps/ac_ac/app-icon.png b/apps/ac_ac/app-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..b83541133fb2fcdcc215cf294baa7f5565215f58 GIT binary patch literal 4120 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 WA~L?Y2T6SZ0000 Date: Wed, 12 Jan 2022 10:07:18 +0100 Subject: [PATCH 231/315] Create app-icon.js --- apps/ac_ac/app-icon.js | 1 + 1 file changed, 1 insertion(+) create mode 100644 apps/ac_ac/app-icon.js diff --git a/apps/ac_ac/app-icon.js b/apps/ac_ac/app-icon.js new file mode 100644 index 000000000..20caf2c8e --- /dev/null +++ b/apps/ac_ac/app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwgn/ABH+AQPvBpIAI/n8/3f5/PCp/v9oHF7w1CABffGxAYMH4f9z/514YDCxW/O4gFBxwHD/ZEL7/9GgX8GwQLCBQQXH/uP/Hf/2N44IBAgIXJ7oaD/3v/3uAYIIB9wQGAA2+/iRG5oSIM4f+1nrPYgAB3aHIAC77QYYRoCAAP676ICABXYFIntDoPf3+PC5f+BoPOX4vPNBn7IogEB/eu3QXC9wNEAAeKBIP+dgbSCDYMwgEApQVEygPCeRH8iAWBAAMHPwXDgoRGAonACwYABgN5uMAC4q8GC4U0DQsAggRF9gXFgggB/2hC4kdVAQCBVAX7xwXCVAnGCwUadAeeDYfr7IhEAAf93e+A4gpB9yRB/mqcgndRgQAHzqRE1gEC/KoCjLZEsgCB9evO4gOC/RyEgqdC2KnFO4S/KgFYsC/Ga5EBs1AX5bXHgx1C2YXEnp7GCARgB4AfE64WCnawFCgf9VAK/G/3M7zWDz4PF/maXJIAD7D8EVAP85QXN3OP/42DfoQXN/wvE/ySGABa8FAC37AgepVwQ9E1SfBAAJIEAAnrBQ39xgwJ7pRHFQX+3QECCAbyG9bPDzwXC9QMBdgQXIAAf41wEC5pLCJJBcF9fZQ5IAGYYn81q7RJQwWC/wXM9/tA4veCxooDIAPv55PEABwpB97rDAAw")) \ No newline at end of file From 54ad33318a382b741a41e9d5fce4ad9b869449ae Mon Sep 17 00:00:00 2001 From: Andreas Rozek Date: Wed, 12 Jan 2022 10:08:42 +0100 Subject: [PATCH 232/315] Update README.md --- apps/ac_ac/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/ac_ac/README.md b/apps/ac_ac/README.md index 0e0084b64..05e5f4798 100644 --- a/apps/ac_ac/README.md +++ b/apps/ac_ac/README.md @@ -22,10 +22,10 @@ Additionally, you may use the currently configured global theme or configure your own colors for clock fore- and background and second hands. Consequently, even without external modules you already have the choice between -87552 combinations! +102144 combinations! From 5e353b6755d97021a349a980db632aef75486bff Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Wed, 12 Jan 2022 09:14:33 +0000 Subject: [PATCH 233/315] messages : If showMessage called with no message (eg all messages deleted) now return to the clock (fix #1267) --- apps/messages/ChangeLog | 1 + apps/messages/app.js | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/messages/ChangeLog b/apps/messages/ChangeLog index 0c02a76e1..522534af0 100644 --- a/apps/messages/ChangeLog +++ b/apps/messages/ChangeLog @@ -27,3 +27,4 @@ 0.18: Use app-specific icon colors Spread message action buttons out Back button now goes back to list of messages + If showMessage called with no message (eg all messages deleted) now return to the clock (fix #1267) diff --git a/apps/messages/app.js b/apps/messages/app.js index 4704c422f..80e4a3244 100644 --- a/apps/messages/app.js +++ b/apps/messages/app.js @@ -225,7 +225,7 @@ function showMessageSettings(msg) { function showMessage(msgid) { var msg = MESSAGES.find(m=>m.id==msgid); - if (!msg) return checkMessages({clockIfNoMsg:0,clockIfAllRead:0,showMsgIfUnread:0}); // go home if no message found + if (!msg) return checkMessages({clockIfNoMsg:1,clockIfAllRead:0,showMsgIfUnread:0}); // go home if no message found if (msg.src=="Maps") { cancelReloadTimeout(); // don't auto-reload to clock now return showMapMessage(msg); From 3e6cfc95a9c4aaa6991dbe30c9b82fca681c87a8 Mon Sep 17 00:00:00 2001 From: Marco Heiming Date: Wed, 12 Jan 2022 10:27:39 +0100 Subject: [PATCH 234/315] Improve layout and add exit menu item --- apps/banglexercise/README.md | 6 +++--- apps/banglexercise/app.js | 14 +++++++++----- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/apps/banglexercise/README.md b/apps/banglexercise/README.md index 9d8ee7be4..729fb60e3 100644 --- a/apps/banglexercise/README.md +++ b/apps/banglexercise/README.md @@ -6,7 +6,7 @@ Currently only push ups and curls are supported. ## Disclaimer -This app is very experimental. +This app is experimental but it seems to work quiet reliable for me. It could be and is likely that the threshold values for detecting exercises do not work for everyone. Therefore it would be great if we could improve this app together :-) @@ -25,8 +25,8 @@ Press stop to end your exercise. * Rope jumps * Sit ups * ... -* Save exercises to file system -* Add settings (vibration, beep, ...) +* Save exercise summaries to file system +* Configure daily goal for exercises * Find a nicer icon diff --git a/apps/banglexercise/app.js b/apps/banglexercise/app.js index f5a532408..778207d26 100644 --- a/apps/banglexercise/app.js +++ b/apps/banglexercise/app.js @@ -81,6 +81,9 @@ function showMainMenu() { value: exerciseCounter + " " + exerciseType.name }; } + menu.Exit = function() { + load(); + }; E.showMenu(menu); } @@ -187,6 +190,7 @@ function isValidYAxisExercise(slopeY, t) { console.log(t, exerciseName + " half complete..."); layout.progress.label = "½"; + g.clear(); layout.render(); } @@ -215,6 +219,7 @@ function isValidYAxisExercise(slopeY, t) { layout.count.label = exerciseCounter; layout.progress.label = ""; + g.clear(); layout.render(); if (settings.buzz) @@ -279,10 +284,9 @@ function startRecording() { c: [{ type: "txt", id: "count", - font: "6x8:10", - label: exerciseCounter, - pad: 5, - bgCol: g.theme.bg + font: exerciseCounter < 100 ? "6x8:9" : "6x8:8", + label: 10, + pad: 5 }, { type: "txt", @@ -328,7 +332,7 @@ function startRecording() { stopRecording(); } }], - lazy: true + lazy: false }); layout.render(); From 4b8490645d11ca3c69ff99a4b78c6fbd8b4dc60f Mon Sep 17 00:00:00 2001 From: Marco Heiming Date: Wed, 12 Jan 2022 10:31:05 +0100 Subject: [PATCH 235/315] Fix typo and disable debug logging --- apps/banglexercise/README.md | 2 +- apps/banglexercise/app.js | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/apps/banglexercise/README.md b/apps/banglexercise/README.md index 729fb60e3..28b276a59 100644 --- a/apps/banglexercise/README.md +++ b/apps/banglexercise/README.md @@ -13,7 +13,7 @@ Therefore it would be great if we could improve this app together :-) ## Usage -Select the exercise type you want to practive and go for it! +Select the exercise type you want to practice and go for it! Press stop to end your exercise. diff --git a/apps/banglexercise/app.js b/apps/banglexercise/app.js index 778207d26..99ebd121e 100644 --- a/apps/banglexercise/app.js +++ b/apps/banglexercise/app.js @@ -187,7 +187,7 @@ function isValidYAxisExercise(slopeY, t) { if (p1 > 0 && p2 < 0) { if (lastZeroPassCameFromPositive == false) { lastExerciseHalfCompletionTime = t; - console.log(t, exerciseName + " half complete..."); + //console.log(t, exerciseName + " half complete..."); layout.progress.label = "½"; g.clear(); @@ -201,7 +201,7 @@ function isValidYAxisExercise(slopeY, t) { if (lastZeroPassCameFromPositive == true) { const tDiffLastExercise = t - lastExerciseCompletionTime; const tDiffStart = t - tStart; - console.log(t, exerciseName + " maybe complete?", Math.round(tDiffLastExercise), Math.round(tDiffStart)); + //console.log(t, exerciseName + " maybe complete?", Math.round(tDiffLastExercise), Math.round(tDiffStart)); // check minimal time between exercises: if ((lastExerciseCompletionTime <= 0 && tDiffStart >= thresholdMinTime) || tDiffLastExercise >= thresholdMinTime) { @@ -212,7 +212,7 @@ function isValidYAxisExercise(slopeY, t) { // check minimal duration of exercise: const tDiffExerciseHalfCompletion = t - lastExerciseHalfCompletionTime; if (tDiffExerciseHalfCompletion > thresholdMinDurationTime) { - console.log(t, exerciseName + " complete!!!"); + //console.log(t, exerciseName + " complete!!!"); lastExerciseCompletionTime = t; exerciseCounter++; @@ -225,15 +225,15 @@ function isValidYAxisExercise(slopeY, t) { if (settings.buzz) Bangle.buzz(100, 0.4); } else { - console.log(t, exerciseName + " to quick for duration time threshold!"); + //console.log(t, exerciseName + " to quick for duration time threshold!"); lastExerciseCompletionTime = t; } } else { - console.log(t, exerciseName + " to slow for time threshold!"); + //console.log(t, exerciseName + " to slow for time threshold!"); lastExerciseCompletionTime = t; } } else { - console.log(t, exerciseName + " to quick for time threshold!"); + //console.log(t, exerciseName + " to quick for time threshold!"); lastExerciseCompletionTime = t; } } From 797d5fbd8185f6459187c494b5433b12a5732f84 Mon Sep 17 00:00:00 2001 From: Andreas Rozek Date: Wed, 12 Jan 2022 10:57:10 +0100 Subject: [PATCH 236/315] Update Customizer.html --- apps/ac_ac/Customizer.html | 186 +++++++++++++++++++++---------------- 1 file changed, 106 insertions(+), 80 deletions(-) diff --git a/apps/ac_ac/Customizer.html b/apps/ac_ac/Customizer.html index 203235e3d..59c08f2cd 100644 --- a/apps/ac_ac/Customizer.html +++ b/apps/ac_ac/Customizer.html @@ -26,11 +26,12 @@ default-src 'self' 'unsafe-inline' 'unsafe-eval' file: https:; "> - + + - + @@ -279,23 +302,24 @@ (or choose "themed" to use your Bangle's configured theme) - if not, just select "none":

- Second Hand Color:
- - - - - - - - - - + Second Hand Color: +

+ + + + + + + + + +

If you prefer "custom" clock hands, please enter the URL of their JavaScript module below: @@ -504,33 +528,35 @@ "themed" if you want the clock to use the currently configured theme on your Bangle.js 2:

- Foreground Color:
- -

- -
- - - - - - - - + Foreground Color:

- Background Color:
- - - - - - - - - + + + + + + + + + +

+ Background Color: +

+ + + + + + + + +

When you are satisfied with your configuration, just click on "Upload" in order to generate the specified clock and upload it to your Bangle.js 2: From f878a336529815a2ea358361d9a748fb5599cda1 Mon Sep 17 00:00:00 2001 From: Andreas Rozek Date: Wed, 12 Jan 2022 10:58:21 +0100 Subject: [PATCH 237/315] Create app-screenshot.png --- apps/ac_ac/app-screenshot.png | Bin 0 -> 4042 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 apps/ac_ac/app-screenshot.png diff --git a/apps/ac_ac/app-screenshot.png b/apps/ac_ac/app-screenshot.png new file mode 100644 index 0000000000000000000000000000000000000000..e0e3bb0b95de844ed0656d16023e71708c117f96 GIT binary patch literal 4042 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 literal 0 HcmV?d00001 From ffcdcbce6bf15fc19bc605130235dbd608f3d913 Mon Sep 17 00:00:00 2001 From: Marco Heiming Date: Wed, 12 Jan 2022 11:24:04 +0100 Subject: [PATCH 238/315] Rename "recording" to "training" (because there is no recording for now) --- apps/banglexercise/app.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/banglexercise/app.js b/apps/banglexercise/app.js index 99ebd121e..0d5c814bf 100644 --- a/apps/banglexercise/app.js +++ b/apps/banglexercise/app.js @@ -69,7 +69,7 @@ function showMainMenu() { menu["Do " + et.name] = function() { exerciseType = et; E.showMenu(); - startRecording(); + startTraining(); }; }); @@ -263,7 +263,7 @@ function reset() { } -function startRecording() { +function startTraining() { if (recordActive) return; g.clear(1); reset(); @@ -319,7 +319,7 @@ function startRecording() { type: "txt", id: "recording", font: "6x8:2", - label: "RECORDING", + label: "TRAINING", bgCol: "#f00", pad: 5, fillx: 1 @@ -329,7 +329,7 @@ function startRecording() { btns: [{ label: "STOP", cb: () => { - stopRecording(); + stopTraining(); } }], lazy: false @@ -344,7 +344,7 @@ function startRecording() { Bangle.buzz(200, 1); } -function stopRecording() { +function stopTraining() { if (!recordActive) return; g.clear(1); From ea44abb791634b60c454dbfb746c493ffac20614 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Wed, 12 Jan 2022 10:58:47 +0000 Subject: [PATCH 239/315] android 0.06: Option to keep messages after a disconnect (default false) (fix #1186) --- apps.json | 8 ++++--- apps/android/ChangeLog | 1 + apps/android/README.md | 48 ++++++++++++++++++++++++++++++++++++++++ apps/android/boot.js | 6 ++++- apps/android/settings.js | 20 +++++++++++++---- 5 files changed, 75 insertions(+), 8 deletions(-) create mode 100644 apps/android/README.md diff --git a/apps.json b/apps.json index 882816204..bb55dcc17 100644 --- a/apps.json +++ b/apps.json @@ -99,18 +99,20 @@ "id": "android", "name": "Android Integration", "shortName": "Android", - "version": "0.05", + "version": "0.06", "description": "Display notifications/music/etc sent from the Gadgetbridge app on Android. This replaces the old 'Gadgetbridge' Bangle.js widget.", "icon": "app.png", "tags": "tool,system,messages,notifications", "dependencies": {"messages":"app"}, "supports": ["BANGLEJS","BANGLEJS2"], + "readme": "README.md", "storage": [ {"name":"android.app.js","url":"app.js"}, {"name":"android.settings.js","url":"settings.js"}, {"name":"android.img","url":"app-icon.js","evaluate":true}, {"name":"android.boot.js","url":"boot.js"} ], + "data": [{"name":"android.settings.json"}], "sortorder": -8 }, { @@ -1357,7 +1359,7 @@ "shortName":"HR Alarm", "version":"0.01", "description": "This invisible widget vibrates whenever the heart rate gets close to the upper limit or goes over or under the configured limits", - "icon": "widget.png", + "icon": "widget.png", "type": "widget", "tags": "widget", "supports" : ["BANGLEJS2"], @@ -5185,7 +5187,7 @@ {"name":"mmind.app.js","url":"mmind.app.js"}, {"name":"mmind.img","url":"mmind.icon.js","evaluate":true} ] - }, + }, { "id": "presentor", "name": "Presentor", diff --git a/apps/android/ChangeLog b/apps/android/ChangeLog index c2c4ea6be..0d837fe43 100644 --- a/apps/android/ChangeLog +++ b/apps/android/ChangeLog @@ -4,3 +4,4 @@ 0.03: Handling of message actions (ok/clear) 0.04: Android icon now goes to settings page with 'find phone' 0.05: Fix handling of message actions +0.06: Option to keep messages after a disconnect (default false) (fix #1186) diff --git a/apps/android/README.md b/apps/android/README.md new file mode 100644 index 000000000..c10718aac --- /dev/null +++ b/apps/android/README.md @@ -0,0 +1,48 @@ +# Android Integration + +This app allows your Bangle.js to receive notifications [from the Gadgetbridge app on Android](http://www.espruino.com/Gadgetbridge) + +See [this link](http://www.espruino.com/Gadgetbridge) for notes on how to install +the Android app (and how it works). + +It requires the `Messages` app on Bangle.js (which should be automatically installed) to +display any notifications that are received. + +## Settings + +You can access the settings menu either from the `Android` icon in the launcher, +or from `App Settings` in the `Settings` menu. + +It contains: + +* `Connected` - shows whether there is an active Bluetooth connection or not +* `Find Phone` - opens a submenu where you can activate the `Find Phone` functionality +of Gadgetbridge - making your phone make noise so you can find it. +* `Keep Msgs` - default is `Off`. When Gadgetbridge disconnects, should Bangle.js +keep any messages it has received, or should it delete them? +* `Messages` - launches the messages app, showing a list of messages + +## How it works + +Gadgetbridge on Android connects to Bangle.js, and sends commands over the +BLE UART connection. These take the form of `GB({ ... JSON ... })\n` - so they +call a global function called `GB` which then interprets the JSON. + +Responses are sent back to Gadgetbridge simply as one line of JSON. + +More info on message formats on http://www.espruino.com/Gadgetbridge + +## Testing + +Bangle.js can only hold one connection open at a time, so it's hard to see +if there are any errors when handling Gadgetbridge messages. + +However you can: + +* Use the `Gadgetbridge Debug` app on Bangle.js to display/log the messages received from Gadgetbridge +* Connect with the Web IDE and manually enter the Gadgetbridge messages on the left-hand side to +execute them as if they came from Gadgetbridge, for instance: + +``` +GB({"t":"notify","id":1575479849,"src":"Hangouts","title":"A Name","body":"message contents"}) +``` diff --git a/apps/android/boot.js b/apps/android/boot.js index 59ffe006d..fff9ad444 100644 --- a/apps/android/boot.js +++ b/apps/android/boot.js @@ -4,6 +4,7 @@ Bluetooth.println(JSON.stringify(message)); } + var settings = require("Storage").readJSON("android.settings.json",1)||{}; var _GB = global.GB; global.GB = (event) => { // feed a copy to other handlers if there were any @@ -51,7 +52,8 @@ // Battery monitor function sendBattery() { gbSend({ t: "status", bat: E.getBattery() }); } NRF.on("connect", () => setTimeout(sendBattery, 2000)); - NRF.on("disconnect", () => require("messages").clearAll()); // remove all messages on disconnect + if (!settings.keep) + NRF.on("disconnect", () => require("messages").clearAll()); // remove all messages on disconnect setInterval(sendBattery, 10*60*1000); // Health tracking Bangle.on('health', health=>{ @@ -68,4 +70,6 @@ if (isFinite(msg.id)) return gbSend({ t: "notify", n:response?"OPEN":"DISMISS", id: msg.id }); // error/warn here? }; + // remove settings object so it's not taking up RAM + delete settings; })(); diff --git a/apps/android/settings.js b/apps/android/settings.js index d241397a4..7c46a1fc0 100644 --- a/apps/android/settings.js +++ b/apps/android/settings.js @@ -2,17 +2,29 @@ function gb(j) { Bluetooth.println(JSON.stringify(j)); } + var settings = require("Storage").readJSON("android.settings.json",1)||{}; + function updateSettings() { + require("Storage").writeJSON("android.settings.json", settings); + } var mainmenu = { "" : { "title" : "Android" }, "< Back" : back, - "Connected" : { value : NRF.getSecurityStatus().connected?"Yes":"No" }, + /*LANG*/"Connected" : { value : NRF.getSecurityStatus().connected?"Yes":"No" }, "Find Phone" : () => E.showMenu({ "" : { "title" : "Find Phone" }, "< Back" : ()=>E.showMenu(mainmenu), - "On" : _=>gb({t:"findPhone",n:true}), - "Off" : _=>gb({t:"findPhone",n:false}), + /*LANG*/"On" : _=>gb({t:"findPhone",n:true}), + /*LANG*/"Off" : _=>gb({t:"findPhone",n:false}), }), - "Messages" : ()=>load("messages.app.js") + /*LANG*/"Keep Msgs" : { + value : !!settings.keep, + format : v=>v?/*LANG*/"Yes":/*LANG*/"No", + onchange: v => { + settings.keep = v; + updateSettings(); + } + }, + /*LANG*/"Messages" : ()=>load("messages.app.js") }; E.showMenu(mainmenu); }) From 569c5f9e2b5ef2d59770e244db4adffed8a1d586 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Wed, 12 Jan 2022 10:59:02 +0000 Subject: [PATCH 240/315] Add LANG tags to settings for translations --- apps/setting/settings.js | 122 +++++++++++++++++++-------------------- 1 file changed, 61 insertions(+), 61 deletions(-) diff --git a/apps/setting/settings.js b/apps/setting/settings.js index 27ce24e50..514adf1dd 100644 --- a/apps/setting/settings.js +++ b/apps/setting/settings.js @@ -63,7 +63,7 @@ const boolFormat = v => v ? /*LANG*/"On" : /*LANG*/"Off"; function showMainMenu() { const mainmenu = { - '': { 'title': 'Settings' }, + '': { 'title': /*LANG*/'Settings' }, '< Back': ()=>load(), /*LANG*/'Apps': ()=>showAppSettingsMenu(), /*LANG*/'System': ()=>showSystemMenu(), @@ -78,7 +78,7 @@ function showMainMenu() { function showSystemMenu() { const mainmenu = { - '': { 'title': 'System' }, + '': { 'title': /*LANG*/'System' }, '< Back': ()=>showMainMenu(), /*LANG*/'Theme': ()=>showThemeMenu(), /*LANG*/'LCD': ()=>showLCDMenu(), @@ -122,7 +122,7 @@ function showAlertsMenu() { } const mainmenu = { - '': { 'title': 'Alerts' }, + '': { 'title': /*LANG*/'Alerts' }, '< Back': ()=>showMainMenu(), /*LANG*/'Beep': beepMenuItem, /*LANG*/'Vibration': { @@ -159,8 +159,8 @@ function showBLEMenu() { E.showMenu({ '': { 'title': 'Bluetooth' }, '< Back': ()=>showMainMenu(), - 'Make Connectable': ()=>makeConnectable(), - 'BLE': { + /*LANG*/'Make Connectable': ()=>makeConnectable(), + /*LANG*/'BLE': { value: settings.ble, format: boolFormat, onchange: () => { @@ -168,7 +168,7 @@ function showBLEMenu() { updateSettings(); } }, - 'Programmable': { + /*LANG*/'Programmable': { value: settings.blerepl, format: boolFormat, onchange: () => { @@ -176,7 +176,7 @@ function showBLEMenu() { updateSettings(); } }, - 'HID': { + /*LANG*/'HID': { value: Math.max(0,0 | hidV.indexOf(settings.HID)), min: 0, max: 3, format: v => hidN[v], @@ -185,11 +185,11 @@ function showBLEMenu() { updateSettings(); } }, - 'Passkey BETA': { + /*LANG*/'Passkey BETA': { value: settings.passkey?settings.passkey:"none", onchange: () => setTimeout(showPasskeyMenu) // graphical_menu redraws after the call }, - 'Whitelist': { + /*LANG*/'Whitelist': { value: settings.whitelist?(settings.whitelist.length+" devs"):"off", onchange: () => setTimeout(showWhitelistMenu) // graphical_menu redraws after the call } @@ -213,7 +213,7 @@ function showThemeMenu() { var m = E.showMenu({ '':{title:'Theme'}, '< Back': ()=>showSystemMenu(), - 'Dark BW': ()=>{ + /*LANG*/'Dark BW': ()=>{ upd({ fg:cl("#fff"), bg:cl("#000"), fg2:cl("#0ff"), bg2:cl("#000"), @@ -221,7 +221,7 @@ function showThemeMenu() { dark:true }); }, - 'Light BW': ()=>{ + /*LANG*/'Light BW': ()=>{ upd({ fg:cl("#000"), bg:cl("#fff"), fg2:cl("#000"), bg2:cl("#cff"), @@ -229,7 +229,7 @@ function showThemeMenu() { dark:false }); }, - 'Customize': ()=>showCustomThemeMenu(), + /*LANG*/'Customize': ()=>showCustomThemeMenu(), }); function showCustomThemeMenu() { @@ -261,9 +261,9 @@ function showThemeMenu() { "< Back": () => showThemeMenu() }; const labels = { - fg: 'Foreground', bg: 'Background', - fg2: 'Foreground 2', bg2: 'Background 2', - fgH: 'Highlight FG', bgH: 'Highlight BG', + fg: /*LANG*/'Foreground', bg: /*LANG*/'Background', + fg2: /*LANG*/'Foreground 2', bg2: /*LANG*/'Background 2', + fgH: /*LANG*/'Highlight FG', bgH: /*LANG*/'Highlight BG', }; ["fg", "bg", "fg2", "bg2", "fgH", "bgH"].forEach(t => { menu[labels[t]] = { @@ -292,7 +292,7 @@ function showThemeMenu() { function showPasskeyMenu() { var menu = { "< Back" : ()=>showBLEMenu(), - "Disable" : () => { + /*LANG*/"Disable" : () => { settings.passkey = undefined; updateSettings(); showBLEMenu(); @@ -320,7 +320,7 @@ function showPasskeyMenu() { function showWhitelistMenu() { var menu = { "< Back" : ()=>showBLEMenu(), - "Disable" : () => { + /*LANG*/"Disable" : () => { settings.whitelist = undefined; updateSettings(); showBLEMenu(); @@ -328,7 +328,7 @@ function showWhitelistMenu() { }; if (settings.whitelist) settings.whitelist.forEach(function(d){ menu[d.substr(0,17)] = function() { - E.showPrompt('Remove\n'+d).then((v) => { + E.showPrompt(/*LANG*/'Remove\n'+d).then((v) => { if (v) { settings.whitelist.splice(settings.whitelist.indexOf(d),1); updateSettings(); @@ -337,8 +337,8 @@ function showWhitelistMenu() { }); } }); - menu['Add Device']=function() { - E.showAlert("Connect device\nto add to\nwhitelist","Whitelist").then(function() { + menu[/*LANG*/'Add Device']=function() { + E.showAlert(/*LANG*/"Connect device\nto add to\nwhitelist",/*LANG*/"Whitelist").then(function() { NRF.removeAllListeners('connect'); showWhitelistMenu(); }); @@ -358,7 +358,7 @@ function showLCDMenu() { const lcdMenu = { '': { 'title': 'LCD' }, '< Back': ()=>showSystemMenu(), - 'LCD Brightness': { + /*LANG*/'LCD Brightness': { value: settings.brightness, min: 0.1, max: 1, @@ -369,7 +369,7 @@ function showLCDMenu() { Bangle.setLCDBrightness(settings.brightness); } }, - 'LCD Timeout': { + /*LANG*/'LCD Timeout': { value: settings.timeout, min: 0, max: 60, @@ -380,7 +380,7 @@ function showLCDMenu() { Bangle.setLCDTimeout(settings.timeout); } }, - 'Wake on BTN1': { + /*LANG*/'Wake on BTN1': { value: settings.options.wakeOnBTN1, format: boolFormat, onchange: () => { @@ -391,7 +391,7 @@ function showLCDMenu() { }; if (!BANGLEJS2) Object.assign(lcdMenu, { - 'Wake on BTN2': { + /*LANG*/'Wake on BTN2': { value: settings.options.wakeOnBTN2, format: boolFormat, onchange: () => { @@ -399,7 +399,7 @@ function showLCDMenu() { updateOptions(); } }, - 'Wake on BTN3': { + /*LANG*/'Wake on BTN3': { value: settings.options.wakeOnBTN3, format: boolFormat, onchange: () => { @@ -408,7 +408,7 @@ function showLCDMenu() { } }}); Object.assign(lcdMenu, { - 'Wake on FaceUp': { + /*LANG*/'Wake on FaceUp': { value: settings.options.wakeOnFaceUp, format: boolFormat, onchange: () => { @@ -416,7 +416,7 @@ function showLCDMenu() { updateOptions(); } }, - 'Wake on Touch': { + /*LANG*/'Wake on Touch': { value: settings.options.wakeOnTouch, format: boolFormat, onchange: () => { @@ -424,7 +424,7 @@ function showLCDMenu() { updateOptions(); } }, - 'Wake on Twist': { + /*LANG*/'Wake on Twist': { value: settings.options.wakeOnTwist, format: boolFormat, onchange: () => { @@ -432,7 +432,7 @@ function showLCDMenu() { updateOptions(); } }, - 'Twist Threshold': { + /*LANG*/'Twist Threshold': { value: internalToG(settings.options.twistThreshold), min: -0.5, max: 0.5, @@ -442,7 +442,7 @@ function showLCDMenu() { updateOptions(); } }, - 'Twist Max Y': { + /*LANG*/'Twist Max Y': { value: settings.options.twistMaxY, min: -1500, max: 1500, @@ -452,7 +452,7 @@ function showLCDMenu() { updateOptions(); } }, - 'Twist Timeout': { + /*LANG*/'Twist Timeout': { value: settings.options.twistTimeout, min: 0, max: 2000, @@ -468,9 +468,9 @@ function showLCDMenu() { function showLocaleMenu() { const localemenu = { - '': { 'title': 'Locale' }, + '': { 'title': /*LANG*/'Locale' }, '< Back': ()=>showSystemMenu(), - 'Time Zone': { + /*LANG*/'Time Zone': { value: settings.timezone, min: -11, max: 13, @@ -480,7 +480,7 @@ function showLocaleMenu() { updateSettings(); } }, - 'Clock Style': { + /*LANG*/'Clock Style': { value: !!settings["12hour"], format: v => v ? "12hr" : "24hr", onchange: v => { @@ -494,29 +494,29 @@ function showLocaleMenu() { function showUtilMenu() { var menu = { - '': { 'title': 'Utilities' }, + '': { 'title': /*LANG*/'Utilities' }, '< Back': ()=>showMainMenu(), - 'Debug Info': { + /*LANG*/'Debug Info': { value: E.clip(0|settings.log,0,2), min: 0, max: 2, - format: v => ["Hide","Show","Log"][E.clip(0|v,0,2)], + format: v => [/*LANG*/"Hide",/*LANG*/"Show",/*LANG*/"Log"][E.clip(0|v,0,2)], onchange: v => { settings.log = v; updateSettings(); } }, - 'Compact Storage': () => { - E.showMessage("Compacting...\nTakes approx\n1 minute",{title:"Storage"}); + /*LANG*/'Compact Storage': () => { + E.showMessage(/*LANG*/"Compacting...\nTakes approx\n1 minute",{title:/*LANG*/"Storage"}); require("Storage").compact(); showUtilMenu(); }, - 'Rewrite Settings': () => { + /*LANG*/'Rewrite Settings': () => { require("Storage").write(".boot0","eval(require('Storage').read('bootupdate.js'));"); load("setting.app.js"); }, - 'Flatten Battery': () => { - E.showMessage('Flattening battery - this can take hours.\nLong-press button to cancel.'); + /*LANG*/'Flatten Battery': () => { + E.showMessage(/*LANG*/'Flattening battery - this can take hours.\nLong-press button to cancel.'); Bangle.setLCDTimeout(0); Bangle.setLCDPower(1); if (Bangle.setGPSPower) Bangle.setGPSPower(1,"flat"); @@ -528,8 +528,8 @@ function showUtilMenu() { var i=1000;while (i--); }, 1); }, - 'Reset Settings': () => { - E.showPrompt('Reset to Defaults?',{title:"Settings"}).then((v) => { + /*LANG*/'Reset Settings': () => { + E.showPrompt(/*LANG*/'Reset to Defaults?',{title:/*LANG*/"Settings"}).then((v) => { if (v) { E.showMessage('Resetting'); resetSettings(); @@ -540,8 +540,8 @@ function showUtilMenu() { /*LANG*/'Turn Off': ()=>{ if (Bangle.softOff) Bangle.softOff(); else Bangle.off() } }; if (Bangle.factoryReset) { - menu['Factory Reset'] = ()=>{ - E.showPrompt('This will remove everything!',{title:"Factory Reset"}).then((v) => { + menu[/*LANG*/'Factory Reset'] = ()=>{ + E.showPrompt(/*LANG*/'This will remove everything!',{title:/*LANG*/"Factory Reset"}).then((v) => { if (v) { E.showMessage(); Terminal.setConsole(); @@ -558,7 +558,7 @@ function makeConnectable() { try { NRF.wake(); } catch (e) { } Bluetooth.setConsole(1); var name = "Bangle.js " + NRF.getAddress().substr(-5).replace(":", ""); - E.showPrompt(name + "\nStay Connectable?", { title: "Connectable" }).then(r => { + E.showPrompt(name + /*LANG*/"\nStay Connectable?", { title: /*LANG*/"Connectable" }).then(r => { if (settings.ble != r) { settings.ble = r; updateSettings(); @@ -574,7 +574,7 @@ function showClockMenu() { .sort((a, b) => a.sortorder - b.sortorder); const clockMenu = { '': { - 'title': 'Select Clock', + 'title': /*LANG*/'Select Clock', }, '< Back': ()=>showSystemMenu(), }; @@ -592,7 +592,7 @@ function showClockMenu() { }; }); if (clockApps.length === 0) { - clockMenu["No Clocks Found"] = () => { }; + clockMenu[/*LANG*/"No Clocks Found"] = () => { }; } return E.showMenu(clockMenu); } @@ -600,47 +600,47 @@ function showClockMenu() { function showSetTimeMenu() { d = new Date(); const timemenu = { - '': { 'title': 'Set Time' }, + '': { 'title': /*LANG*/'Set Time' }, '< Back': function () { setTime(d.getTime() / 1000); showSystemMenu(); }, - 'Hour': { + /*LANG*/'Hour': { value: d.getHours(), onchange: function (v) { this.value = (v+24)%24; d.setHours(this.value); } }, - 'Minute': { + /*LANG*/'Minute': { value: d.getMinutes(), onchange: function (v) { this.value = (v+60)%60; d.setMinutes(this.value); } }, - 'Second': { + /*LANG*/'Second': { value: d.getSeconds(), onchange: function (v) { this.value = (v+60)%60; d.setSeconds(this.value); } }, - 'Date': { + /*LANG*/'Date': { value: d.getDate(), onchange: function (v) { this.value = ((v+30)%31)+1; d.setDate(this.value); } }, - 'Month': { + /*LANG*/'Month': { value: d.getMonth() + 1, onchange: function (v) { this.value = ((v+11)%12)+1; d.setMonth(this.value - 1); } }, - 'Year': { + /*LANG*/'Year': { value: d.getFullYear(), min: 2019, max: 2100, @@ -654,7 +654,7 @@ function showSetTimeMenu() { function showAppSettingsMenu() { let appmenu = { - '': { 'title': 'App Settings' }, + '': { 'title': /*LANG*/'App Settings' }, '< Back': ()=>showMainMenu(), } const apps = storage.list(/\.settings\.js$/) @@ -671,7 +671,7 @@ function showAppSettingsMenu() { return 0; }) if (apps.length === 0) { - appmenu['No app has settings'] = () => { }; + appmenu[/*LANG*/'No app has settings'] = () => { }; } apps.forEach(function (app) { appmenu[app.name] = () => { showAppSettings(app) }; @@ -688,17 +688,17 @@ function showAppSettings(app) { appSettings = eval(appSettings); } catch (e) { console.log(`${app.name} settings error:`, e) - return showError('Error in settings'); + return showError(/*LANG*/'Error in settings'); } if (typeof appSettings !== "function") { - return showError('Invalid settings'); + return showError(/*LANG*/'Invalid settings'); } try { // pass showAppSettingsMenu as "back" argument appSettings(()=>showAppSettingsMenu()); } catch (e) { console.log(`${app.name} settings error:`, e) - return showError('Error in settings'); + return showError(/*LANG*/'Error in settings'); } } From fc8e089fbe43621862b00df5b2a014d61f0bfca9 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Wed, 12 Jan 2022 11:05:27 +0000 Subject: [PATCH 241/315] improve sanity checking - no false warnings for apps files with `supports` field --- bin/sanitycheck.js | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/bin/sanitycheck.js b/bin/sanitycheck.js index e50256fb6..98fd1275f 100755 --- a/bin/sanitycheck.js +++ b/bin/sanitycheck.js @@ -58,6 +58,7 @@ const APP_KEYS = [ ]; const STORAGE_KEYS = ['name', 'url', 'content', 'evaluate', 'noOverwite', 'supports']; const DATA_KEYS = ['name', 'wildcard', 'storageFile', 'url', 'content', 'evaluate']; +const SUPPORTS_DEVICES = ["BANGLEJS","BANGLEJS2"]; // device IDs allowed for 'supports' const FORBIDDEN_FILE_NAME_CHARS = /[,;]/; // used as separators in appid.info const VALID_DUPLICATES = [ '.tfmodel', '.tfnames' ]; const GRANDFATHERED_ICONS = ["s7clk", "snek", "astral", "alpinenav", "slomoclock", "arrow", "pebble", "rebble"]; @@ -90,7 +91,7 @@ apps.forEach((app,appIdx) => { if (!Array.isArray(app.supports)) ERROR(`App ${app.id} has no 'supports' field or it's not an array`); else { app.supports.forEach(dev => { - if (!["BANGLEJS","BANGLEJS2"].includes(dev)) + if (!SUPPORTS_DEVICES.includes(dev)) ERROR(`App ${app.id} has unknown device in 'supports' field - ${dev}`); }); } @@ -140,6 +141,13 @@ apps.forEach((app,appIdx) => { if (char) ERROR(`App ${app.id} storage file ${file.name} contains invalid character "${char[0]}"`) if (fileNames.includes(file.name) && !file.supports) // assume that there aren't duplicates if 'supports' is set ERROR(`App ${app.id} file ${file.name} is a duplicate`); + if (file.supports && !Array.isArray(file.supports)) + ERROR(`App ${app.id} file ${file.name} supports field must be an array`); + if (file.supports) + file.supports.forEach(dev => { + if (!SUPPORTS_DEVICES.includes(dev)) + ERROR(`App ${app.id} file ${file.name} has unknown device in 'supports' field - ${dev}`); + }); fileNames.push(file.name); allFiles.push({app: app.id, file: file.name}); if (file.url) if (!fs.existsSync(appDir+file.url)) ERROR(`App ${app.id} file ${file.url} doesn't exist`); @@ -271,7 +279,8 @@ while(fileA=allFiles.pop()) { if (globA.test(nameB)||globB.test(nameA)) { if (isGlob(nameA)||isGlob(nameB)) ERROR(`App ${fileB.app} ${typeB} file ${nameB} matches app ${fileA.app} ${typeB} file ${nameA}`) - else WARN(`App ${fileB.app} ${typeB} file ${nameB} is also listed as ${typeA} file for app ${fileA.app}`) + else if (fileA.app != fileB.app) + WARN(`App ${fileB.app} ${typeB} file ${nameB} is also listed as ${typeA} file for app ${fileA.app}`) } }) } From bda5512db423bf6e2c9f7ceb0b622e874f0bf85e Mon Sep 17 00:00:00 2001 From: Andreas Rozek Date: Wed, 12 Jan 2022 13:02:52 +0100 Subject: [PATCH 242/315] Update Customizer.html --- apps/ac_ac/Customizer.html | 335 ++++++++++++++++++++++++++++++------- 1 file changed, 279 insertions(+), 56 deletions(-) diff --git a/apps/ac_ac/Customizer.html b/apps/ac_ac/Customizer.html index 59c08f2cd..5c60c0aa4 100644 --- a/apps/ac_ac/Customizer.html +++ b/apps/ac_ac/Customizer.html @@ -26,13 +26,10 @@ default-src 'self' 'unsafe-inline' 'unsafe-eval' file: https:; "> - - + - - - - + + @@ -235,17 +212,17 @@ switch (ClockSize) { case 'simple': return "require('https://raw.githubusercontent.com/rozek/banglejs-2-simple-clock-size/main/ClockSize.js')" case 'smart': return "require('https://raw.githubusercontent.com/rozek/banglejs-2-smart-clock-size/main/ClockSize.js')" - case 'custom': return 'require(' + ClockSizeURL + ')' + case 'custom': return "require('" + ClockSizeURL + "')" } } function chosenClockFace () { switch (ClockFace) { - case 'none': return undefined + case 'none': return "undefined" case 'four-fold': return "require('https://raw.githubusercontent.com/rozek/banglejs-2-four-fold-clock-face/main/ClockFace.js')" case 'twelve-fold': return "require('https://raw.githubusercontent.com/rozek/banglejs-2-twelve-fold-clock-face/main/ClockFace.js')" case 'rainbow': return "require('https://raw.githubusercontent.com/rozek/banglejs-2-rainbow-clock-face/main/ClockFace.js')" - case 'custom': return 'require(' + ClockFaceURL + ')' + case 'custom': return "require('" + ClockFaceURL + "')" } } @@ -254,18 +231,18 @@ case 'simple': return "require('https://raw.githubusercontent.com/rozek/banglejs-2-simpled-clock-hands/main/ClockHands.js')" case 'rounded': return "require('https://raw.githubusercontent.com/rozek/banglejs-2-rounded-clock-hands/main/ClockHands.js')" case 'hollow': return "require('https://raw.githubusercontent.com/rozek/banglejs-2-hollow-clock-hands/main/ClockHands.js')" - case 'custom': return 'require(' + ClockHandsURL + ')' + case 'custom': return "require('" + ClockHandsURL + "')" } } function chosenComplication (Complication, customURL) { switch (Complication) { - case 'none': return undefined + case 'none': return "undefined" case 'date': return "require('https://raw.githubusercontent.com/rozek/banglejs-2-date-complication/main/Complication.js')" case 'weekday': return "require('https://raw.githubusercontent.com/rozek/banglejs-2-weekday-complication/main/Complication.js')" case 'calendar-week': return "require('https://raw.githubusercontent.com/rozek/banglejs-2-calendar-week-complication/main/Complication.js')" case 'moon-phase': return "require('https://raw.githubusercontent.com/rozek/banglejs-2-moon-phase-complication/main/Complication.js')" - case 'custom': return 'require(' + customURL + ')' + case 'custom': return "require('" + customURL + "')" } } function chosenComplicationAt (Position) { @@ -282,7 +259,7 @@ } function chosenColor (ColorChoice) { - return (ColorChoice === 'none' ? undefined : ColorChoice) + return (ColorChoice === 'none' ? 'undefined' : "'" + ColorChoice + '"') } function chosenForeground () { return chosenColor(Foreground) } @@ -290,7 +267,7 @@ function chosenSecondHand () { return chosenColor(SecondHand) } function chosenFillColor () { return chosenColor(FillColor) } - function chosenDots () { return (ClockFaceDots === 'with-dots') } + function chosenDots () { return (ClockFaceDots === 'with-dots' ? 'true' : 'false') } let AppSource = ` let Clockwork = require('https://raw.githubusercontent.com/rozek/banglejs-2-simple-clockwork/main/Clockwork.js'); From 8bd074131da4d9c09aa9521297d603018345e4f7 Mon Sep 17 00:00:00 2001 From: Andreas Rozek Date: Wed, 12 Jan 2022 15:55:00 +0100 Subject: [PATCH 254/315] Update apps.json --- apps.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps.json b/apps.json index 1ef111b1d..fd0920156 100644 --- a/apps.json +++ b/apps.json @@ -32,7 +32,7 @@ { "id": "ac_ac", "name": "A Configurable Analog Clock", "shortName":"Configurable Clock", - "version":"0.01", + "version":"0.02", "description": "AC-AC, a highly customizable analog clock", "icon": "app-icon.png", "type": "clock", From 3636b32084fbfec92ff1db5ecfcbdacb71883adf Mon Sep 17 00:00:00 2001 From: Andreas Rozek Date: Wed, 12 Jan 2022 15:58:20 +0100 Subject: [PATCH 255/315] Update Customizer.html --- apps/ac_ac/Customizer.html | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/ac_ac/Customizer.html b/apps/ac_ac/Customizer.html index 113f4279b..2bfab8d51 100644 --- a/apps/ac_ac/Customizer.html +++ b/apps/ac_ac/Customizer.html @@ -295,6 +295,9 @@ Clockwork.windUp({ FillColor: ${chosenFillColor()} }); ` +console.log('the configured AC-AC app looks as follows:') +console.log(AppSource) + sendCustomizedApp({ storage:[ {name:'ac-ac.app.js', url:'app.js', content:AppSource}, From 4429288362574ad7b23f3bb7b495dba4aa45207c Mon Sep 17 00:00:00 2001 From: Andreas Rozek Date: Wed, 12 Jan 2022 16:02:28 +0100 Subject: [PATCH 256/315] Update Customizer.html --- apps/ac_ac/Customizer.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/ac_ac/Customizer.html b/apps/ac_ac/Customizer.html index 2bfab8d51..f2387f9dd 100644 --- a/apps/ac_ac/Customizer.html +++ b/apps/ac_ac/Customizer.html @@ -259,7 +259,7 @@ } function chosenColor (ColorChoice) { - return (ColorChoice === 'none' ? 'undefined' : "'" + ColorChoice + '"') + return (ColorChoice === 'none' ? 'undefined' : "'" + ColorChoice + "'") } function chosenForeground () { return chosenColor(Foreground) } From 40c8d69b1e64ee691eb69f66d579bcd4c260123f Mon Sep 17 00:00:00 2001 From: Andreas Rozek Date: Wed, 12 Jan 2022 16:02:30 +0100 Subject: [PATCH 257/315] Update apps.json --- apps.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps.json b/apps.json index fd0920156..1ef111b1d 100644 --- a/apps.json +++ b/apps.json @@ -32,7 +32,7 @@ { "id": "ac_ac", "name": "A Configurable Analog Clock", "shortName":"Configurable Clock", - "version":"0.02", + "version":"0.01", "description": "AC-AC, a highly customizable analog clock", "icon": "app-icon.png", "type": "clock", From 116dec3cb98aa074e72cfa8a7cd1ab6e8be7c51e Mon Sep 17 00:00:00 2001 From: Andreas Rozek Date: Wed, 12 Jan 2022 16:36:28 +0100 Subject: [PATCH 258/315] Update Customizer.html --- apps/ac_ac/Customizer.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/ac_ac/Customizer.html b/apps/ac_ac/Customizer.html index f2387f9dd..f50def79b 100644 --- a/apps/ac_ac/Customizer.html +++ b/apps/ac_ac/Customizer.html @@ -300,7 +300,7 @@ console.log(AppSource) sendCustomizedApp({ storage:[ - {name:'ac-ac.app.js', url:'app.js', content:AppSource}, + {name:'ac_ac.app.js', url:'app.js', content:AppSource}, ] }) } From f6b064d20f45be365b4463a981f6613638469701 Mon Sep 17 00:00:00 2001 From: Andreas Rozek Date: Wed, 12 Jan 2022 16:36:31 +0100 Subject: [PATCH 259/315] Update apps.json --- apps.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps.json b/apps.json index 1ef111b1d..fd0920156 100644 --- a/apps.json +++ b/apps.json @@ -32,7 +32,7 @@ { "id": "ac_ac", "name": "A Configurable Analog Clock", "shortName":"Configurable Clock", - "version":"0.01", + "version":"0.02", "description": "AC-AC, a highly customizable analog clock", "icon": "app-icon.png", "type": "clock", From 276fdd647e757b60de647b9ae6b56ecda5172fc4 Mon Sep 17 00:00:00 2001 From: Andreas Rozek Date: Wed, 12 Jan 2022 16:45:28 +0100 Subject: [PATCH 260/315] Update Customizer.html --- apps/ac_ac/Customizer.html | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/apps/ac_ac/Customizer.html b/apps/ac_ac/Customizer.html index f50def79b..a2798b6bd 100644 --- a/apps/ac_ac/Customizer.html +++ b/apps/ac_ac/Customizer.html @@ -208,6 +208,14 @@ /**** createAndUploadApp ****/ function createAndUploadApp () { + function WidgetsOnBackground () { + return ( + ClockSize === 'smart' + ? "require('https://raw.githubusercontent.com/rozek/banglejs-2-widgets-on-background/main/drawWidgets.js');" + : '' + ) + } + function chosenClockSize () { switch (ClockSize) { case 'simple': return "require('https://raw.githubusercontent.com/rozek/banglejs-2-simple-clock-size/main/ClockSize.js')" @@ -270,6 +278,8 @@ function chosenDots () { return (ClockFaceDots === 'with-dots' ? 'true' : 'false') } let AppSource = ` +${WidgetsOnBackground()} + let Clockwork = require('https://raw.githubusercontent.com/rozek/banglejs-2-simple-clockwork/main/Clockwork.js'); Clockwork.windUp({ From 3fdbfd6b850c2f4c4bb616d550a66ac3c2dea3a7 Mon Sep 17 00:00:00 2001 From: Andreas Rozek Date: Wed, 12 Jan 2022 16:45:32 +0100 Subject: [PATCH 261/315] Update apps.json --- apps.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps.json b/apps.json index fd0920156..1ef111b1d 100644 --- a/apps.json +++ b/apps.json @@ -32,7 +32,7 @@ { "id": "ac_ac", "name": "A Configurable Analog Clock", "shortName":"Configurable Clock", - "version":"0.02", + "version":"0.01", "description": "AC-AC, a highly customizable analog clock", "icon": "app-icon.png", "type": "clock", From 12254e06f3cfde37db3c5992d04c2586d2d0ecd5 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Wed, 12 Jan 2022 15:46:38 +0000 Subject: [PATCH 262/315] Add 'run' app --- apps.json | 13 ++++ apps/run/ChangeLog | 1 + apps/run/README.md | 33 +++++++++ apps/run/app-icon.js | 1 + apps/run/app.js | 159 +++++++++++++++++++++++++++++++++++++++++++ apps/run/app.png | Bin 0 -> 1479 bytes 6 files changed, 207 insertions(+) create mode 100644 apps/run/ChangeLog create mode 100644 apps/run/README.md create mode 100644 apps/run/app-icon.js create mode 100644 apps/run/app.js create mode 100644 apps/run/app.png diff --git a/apps.json b/apps.json index 93b1cf44e..adc98ff2b 100644 --- a/apps.json +++ b/apps.json @@ -2277,6 +2277,19 @@ {"name":"buffgym.img","url":"buffgym-icon.js","evaluate":true} ] }, + { "id": "run", + "name": "Run", + "version":"0.01", + "description": "Displays distance, time, steps, cadence, pace and more for runners.", + "icon": "app.png", + "tags": "run,running,fitness,outdoors,gps", + "supports" : ["BANGLEJS","BANGLEJS2"], + "readme": "README.md", + "storage": [ + {"name":"run.app.js","url":"app.js"}, + {"name":"run.img","url":"app-icon.js","evaluate":true} + ] + }, { "id": "banglerun", "name": "BangleRun", diff --git a/apps/run/ChangeLog b/apps/run/ChangeLog new file mode 100644 index 000000000..5560f00bc --- /dev/null +++ b/apps/run/ChangeLog @@ -0,0 +1 @@ +0.01: New App! diff --git a/apps/run/README.md b/apps/run/README.md new file mode 100644 index 000000000..34ad6511b --- /dev/null +++ b/apps/run/README.md @@ -0,0 +1,33 @@ +# Run App + +This app allows you to display the status of your run. + +To use it, start the app and press the middle button so that +the red `STOP` in the bottom right turns to a green `RUN`. + +## Display + +* `DIST` - the distance travelled based on the GPS (if you have a GPS lock). + * NOTE: this is based on the GPS coordinates which are not 100% accurate, especially initially. As + the GPS updates your position as it gets more satellites your position changes and the distance + shown will increase, even if you are standing still. +* `TIME` - the elapsed time for your run +* `PACE` - the number of minutes it takes you to run a kilometer **based on your run so far** +* `HEART` - Your heart rate +* `STEPS` - Steps since you started exercising +* `CADENCE` - Steps per second based on your step rate *over the last minute* +* `GPS` - this is green if you have a GPS lock. GPS is turned on automatically +so if you have no GPS lock you just need to wait. +* The current time is displayed right at the bottom of the screen +* `RUN/STOP` - whether the distance for your run is being displayed or not + +## Recording Tracks + +`Run` doesn't directly allow you to record your tracks at the moment. +However you can just install the `Recorder` app, turn recording on in +that, and then start the `Run` app. + +## TODO + +* Allow this app to trigger the `Recorder` app on and off directly. +* Keep a log of each run's stats (distance/steps/etc) diff --git a/apps/run/app-icon.js b/apps/run/app-icon.js new file mode 100644 index 000000000..a97d1b8ce --- /dev/null +++ b/apps/run/app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEw4UA///pH9vEFt9TIW0FqALJitUBZNVqoLqgo4BHZAUBtBTHgILB1XAEREV1WsEQ9AgWq1ALHgEO1WtBYxCBhWq0pdInWq2tABY8q1WVBZGq1XFBZS/IKQRvCDIsP9WsBZP60CTCBYs//+wLxALBTQ4AB///+AKHgYLB/gLK/4LHh//AIIwFitVr/8DIIwFLANXBAILIqogBn7DBEYrXBeQRgIBYKmHDgYLLZRBACBZYKJZIILKKRZeWgJGKAFQA==")) diff --git a/apps/run/app.js b/apps/run/app.js new file mode 100644 index 000000000..a10d3841f --- /dev/null +++ b/apps/run/app.js @@ -0,0 +1,159 @@ +var B2 = process.env.HWVERSION==2; +var Layout = require("Layout"); +var locale = require("locale") +var fontHeading = "6x8:2"; +var fontValue = B2 ? "6x15:2" : "6x8:3"; +var headingCol = "#888"; +var running = false; +var startTime; +var startSteps; +// This & previous GPS readings +var lastGPS, thisGPS; +var distance = 0; ///< distance in meters +var startSteps = Bangle.getStepCount(); ///< number of steps when we started +var lastStepCount = startSteps; // last time 'step' was called +var stepHistory = new Uint8Array(60); // steps each second for the last minute (0 = current minute) + +g.clear(); +Bangle.loadWidgets(); +Bangle.drawWidgets(); + +// --------------------------- + +function formatTime(ms) { + var s = Math.round(ms/1000); + var min = Math.floor(s/60).toString(); + s = (s%60).toString(); + return min.padStart(2,0)+":"+s.padStart(2,0); +} + +// Format speed in meters/second +function formatPace(speed) { + if (speed < 0.1667) { + return `__'__"`; + } + const pace = Math.round(1000 / speed); // seconds for 1km + const min = Math.floor(pace / 60); // minutes for 1km + const sec = pace % 60; + return ('0' + min).substr(-2) + `'` + ('0' + sec).substr(-2) + `"`; +} + +// --------------------------- + +function clearState() { + distance = 0; + startSteps = Bangle.getStepCount(); + stepHistory.fill(0); + layout.dist.label=locale.distance(distance); + layout.time.label="00:00"; + layout.pace.label=formatPace(0); + layout.hrm.label="--"; + layout.steps.label=0; + layout.cadence.label= "0"; + layout.status.bgCol = "#f00"; + layout.gps.bgCol = "#f00"; +} + +function onStartStop() { + running = !running; + layout.button.label = running ? "STOP" : "START"; + layout.status.label = running ? "RUN" : "STOP"; + layout.status.bgCol = running ? "#0f0" : "#f00"; + if (running) { + clearState(); + startTime = Date.now(); + } + // if stopping running, don't clear state + // so we can at least refer to what we've done + layout.render(); +} + +var layout = new Layout( { + type:"v", c: [ + { type:"h", filly:1, c:[ + {type:"txt", font:fontHeading, label:"DIST", fillx:1, col:headingCol }, + {type:"txt", font:fontHeading, label:"TIME", fillx:1, col:headingCol } + ]}, { type:"h", filly:1, c:[ + {type:"txt", font:fontValue, label:"0.00", id:"dist", fillx:1 }, + {type:"txt", font:fontValue, label:"00:00", id:"time", fillx:1 } + ]}, { type:"h", filly:1, c:[ + {type:"txt", font:fontHeading, label:"PACE", fillx:1, col:headingCol }, + {type:"txt", font:fontHeading, label:"HEART", fillx:1, col:headingCol } + ]}, { type:"h", filly:1, c:[ + {type:"txt", font:fontValue, label:`__'__"`, id:"pace", fillx:1 }, + {type:"txt", font:fontValue, label:"--", id:"hrm", fillx:1 } + ]}, { type:"h", filly:1, c:[ + {type:"txt", font:fontHeading, label:"STEPS", fillx:1, col:headingCol }, + {type:"txt", font:fontHeading, label:"CADENCE", fillx:1, col:headingCol } + ]}, { type:"h", filly:1, c:[ + {type:"txt", font:fontValue, label:"0", id:"steps", fillx:1 }, + {type:"txt", font:fontValue, label:"0", id:"cadence", fillx:1 } + ]}, { type:"h", filly:1, c:[ + {type:"txt", font:fontHeading, label:"GPS", id:"gps", fillx:1 }, + {type:"txt", font:fontHeading, label:"00:00", id:"clock", fillx:1, bgCol:g.theme.fg, col:g.theme.bg }, + {type:"txt", font:fontHeading, label:"STOP", id:"status", fillx:1 } + ]}, + + ] +},{lazy:true, btns:[{ label:"START", cb: onStartStop, id:"button"}]}); +clearState(); +layout.render(); + + + +function onTimer() { + layout.clock.label = locale.time(new Date(),1); + if (!running) { + layout.render(); + return; + } + // called once a second + var duration = Date.now() - startTime; // in ms + // set cadence based on steps over last minute + var stepsInMinute = E.sum(stepHistory); + var cadence = 60000 * stepsInMinute / Math.min(duration,60000); + // update layout + layout.time.label = formatTime(duration); + layout.steps.label = Bangle.getStepCount()-startSteps; + layout.cadence.label = Math.round(cadence); + layout.render(); + // move step history onwards + stepHistory.set(stepHistory,1); + stepHistory[0]=0; +} + +Bangle.on("GPS", function(fix) { + layout.gps.bgCol = fix.fix ? "#0f0" : "#f00"; + lastGPS = thisGPS; + thisGPS = fix; + if (running && fix.fix && lastGPS.fix) { + // work out distance - moving from a to b + var a = Bangle.project(lastGPS); + var b = Bangle.project(thisGPS); + var dx = a.x-b.x, dy = a.y-b.y; + var d = Math.sqrt(dx*dx+dy*dy); // this should be the distance in meters + distance += d; + layout.dist.label=locale.distance(distance); + var duration = Date.now() - startTime; // in ms + var speed = distance * 1000 / duration; // meters/sec + layout.pace.label = formatPace(speed); + } +}); +Bangle.on("HRM", function(h) { + layout.hrm.label = h.bpm; +}); +Bangle.on("step", function(steps) { + if (running) { + layout.steps.label = steps-Bangle.getStepCount(); + stepHistory[0] += steps-lastStepCount; + } + lastStepCount = steps; +}); + +// We always call ourselves once a second, if only to update the time +setInterval(onTimer, 1000); + +/* Turn GPS and HRM on right at the start to ensure +we get the highest chance of a lock. */ +Bangle.setHRMPower(true,"app"); +Bangle.setGPSPower(true,"app"); diff --git a/apps/run/app.png b/apps/run/app.png new file mode 100644 index 0000000000000000000000000000000000000000..7059b8b015e20039a96de8b65c8a6b68a5e51e18 GIT binary patch literal 1479 zcmV;&1vvVNP)b0~r9hI1hzN2C_Hz2bec46d zz32!1f7|Dr^Zft+eV+5aXV1bTJi@~b@gPX$zNip1Yz1>vN2mz2DMEkvlG@MN zqD@lE?a)(59(>u0=Kppec*EA5(*zQ(EG3+(+KI->CEFJ!ACP%5!I+F&=p{{UFEnH!o7WN}(7DfEF{6T=^qRTOGUUmDCINa`%K?dqCzyBw&^& zdx;n90#h)O*AZj`^*@L)UE%?ZC>&z+*w0Pj=Mr*u5X*l)p2LibbmVEnr6riETg&$lZ8)JSSrFFIvt>|1LfBuoykZR)&GJv4Nif!en;z zv+6Z;L-k`+==0YD>-(E?LK%{G3lE#^`JOB$P&RcWluLnM)#~Vk(_duC*`K_4L>V>S z)_4dF#+CBq(XN1$@$$f&f%ft_-N11%bdLd>txt@&{Fx`lWV(+H188fpdoMWEz{=c= zcS=M^psn$7;>Mk!^KP#d`utPCk6iBMM%oOs0tuJ37nQ16rohH)E z9ia`tY}y~?;W9hY+Ci=jL57GcSZ9mZX%$dBo+%nx{F~SG>u0QvN67NBtqYU0IzJ12 z!D%4xE@^d0`F6j&s+C&7&h>F)stg0CXcP_pe^xQKQS72jOY-(wh zZbX~G&?_#4KvUbwYbW!Gs64aVQ65`xr~;X3@&0)ixmMMvar5@_BseI*>bwB=Hsh4X zYQh$!?Cq~z?1DoTIA3l2sj5-q2GG>pLe-60r0n}JscF?|Pu=!AaWEs^-w{4*u-m|v z)cN}2e|5diF%6APc(zvE@zj|5xTt9M^e(*}a5ghB(al~?Yp}~eT3VX+_&;u68O^;r zFm#Zy>3N^}(KCW>&hyn7OqS~|H4F%<8>aciPOVnaXAj8ih*=;qfnl~5NeLTDd^m8~ zvnv)fz-)*f*%Y>B(}4>B-+uJwvah5;)T5WD&l4qTwmGbG5^Ni*$W&M4^}G>c@+r0 zm&L6n!K$N!Oe1_uD^fG^zOXju@RlWhrFCBC&eabb;-_mPZum831lFJkDuuov#6kU5 z4CF+`AmwiE&BPU?TrL(A+P>=nva%L?1T`4WzcBdbD0fZgQOG$4`W)s&T>c@z;lw?$ z*r#$R-lF#xBG~4P-1p~Z&LlR|e(BYTGQ71roRQk)24wckiNM_6L75_6I@Icn{4O=n ze($4X(0i|)Kwp^SEDqOJAUkp)FsXM?t`S20EwnAT>>nDL9jAl(3m`*#gmZ Date: Wed, 12 Jan 2022 16:50:37 +0100 Subject: [PATCH 263/315] Update Customizer.html --- apps/ac_ac/Customizer.html | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/apps/ac_ac/Customizer.html b/apps/ac_ac/Customizer.html index a2798b6bd..8552eaf70 100644 --- a/apps/ac_ac/Customizer.html +++ b/apps/ac_ac/Customizer.html @@ -777,7 +777,13 @@ console.log(AppSource)

-

 

+

+ This application is based on the author's + [Analog Clock Construction Kit (ACCK)](https://github.com/rozek/banglejs-2-analog-clock-construction-kit). + If you need a different "clockwork", clock size calculation or clock face, + or specific clock hands or complications, just follow the link to learn how to + implement your own clock parts. +

From 1d8febed9f0559e1a4716ed9afb1b7d12e197d7c Mon Sep 17 00:00:00 2001 From: Marco Heiming Date: Wed, 12 Jan 2022 16:57:42 +0100 Subject: [PATCH 264/315] Do not overwrite circle on event (e.g. charging) if there is a circle configured for that place --- apps/circlesclock/app.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/circlesclock/app.js b/apps/circlesclock/app.js index 822802afa..88a04d4b9 100644 --- a/apps/circlesclock/app.js +++ b/apps/circlesclock/app.js @@ -136,8 +136,10 @@ function getCirclePosition(type) { if (setting == type) return circlePosX[i - 1]; } for (let i = 0; i < defaultCircleTypes.length; i++) { - if (type == defaultCircleTypes[i]) return circlePosX[i]; - } + if (type == defaultCircleTypes[i] && (!settings || settings['circle' + (i + 1)] == undefined)) { + return circlePosX[i]; + } + } return undefined; } From 910c3c0b5bfec2d04cd206c64c0329ae6a8ea87d Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Wed, 12 Jan 2022 15:59:30 +0000 Subject: [PATCH 265/315] add screenshot, minor tweaks --- apps.json | 3 ++- apps/run/app.js | 9 ++++----- apps/run/screenshot.png | Bin 0 -> 3716 bytes 3 files changed, 6 insertions(+), 6 deletions(-) create mode 100644 apps/run/screenshot.png diff --git a/apps.json b/apps.json index adc98ff2b..4c6f3bdcf 100644 --- a/apps.json +++ b/apps.json @@ -2284,12 +2284,13 @@ "icon": "app.png", "tags": "run,running,fitness,outdoors,gps", "supports" : ["BANGLEJS","BANGLEJS2"], + "screenshots": [{"url":"screenshot.png"}], "readme": "README.md", "storage": [ {"name":"run.app.js","url":"app.js"}, {"name":"run.img","url":"app-icon.js","evaluate":true} ] - }, + }, { "id": "banglerun", "name": "BangleRun", diff --git a/apps/run/app.js b/apps/run/app.js index a10d3841f..44c42711c 100644 --- a/apps/run/app.js +++ b/apps/run/app.js @@ -51,18 +51,17 @@ function clearState() { layout.steps.label=0; layout.cadence.label= "0"; layout.status.bgCol = "#f00"; - layout.gps.bgCol = "#f00"; } function onStartStop() { running = !running; - layout.button.label = running ? "STOP" : "START"; - layout.status.label = running ? "RUN" : "STOP"; - layout.status.bgCol = running ? "#0f0" : "#f00"; if (running) { clearState(); startTime = Date.now(); } + layout.button.label = running ? "STOP" : "START"; + layout.status.label = running ? "RUN" : "STOP"; + layout.status.bgCol = running ? "#0f0" : "#f00"; // if stopping running, don't clear state // so we can at least refer to what we've done layout.render(); @@ -89,7 +88,7 @@ var layout = new Layout( { {type:"txt", font:fontValue, label:"0", id:"steps", fillx:1 }, {type:"txt", font:fontValue, label:"0", id:"cadence", fillx:1 } ]}, { type:"h", filly:1, c:[ - {type:"txt", font:fontHeading, label:"GPS", id:"gps", fillx:1 }, + {type:"txt", font:fontHeading, label:"GPS", id:"gps", fillx:1, bgCol:"#f00" }, {type:"txt", font:fontHeading, label:"00:00", id:"clock", fillx:1, bgCol:g.theme.fg, col:g.theme.bg }, {type:"txt", font:fontHeading, label:"STOP", id:"status", fillx:1 } ]}, diff --git a/apps/run/screenshot.png b/apps/run/screenshot.png new file mode 100644 index 0000000000000000000000000000000000000000..1a813f19dfe304e3d8bf711692fd2abf1013c391 GIT binary patch literal 3716 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 Date: Wed, 12 Jan 2022 17:18:29 +0100 Subject: [PATCH 266/315] Update Customizer.html --- apps/ac_ac/Customizer.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/ac_ac/Customizer.html b/apps/ac_ac/Customizer.html index 8552eaf70..2846352d6 100644 --- a/apps/ac_ac/Customizer.html +++ b/apps/ac_ac/Customizer.html @@ -779,7 +779,7 @@ console.log(AppSource)

This application is based on the author's - [Analog Clock Construction Kit (ACCK)](https://github.com/rozek/banglejs-2-analog-clock-construction-kit). + Analog Clock Construction Kit (ACCK). If you need a different "clockwork", clock size calculation or clock face, or specific clock hands or complications, just follow the link to learn how to implement your own clock parts. From 9691d0bb0466535af2858f6876b39f1ddef80dc1 Mon Sep 17 00:00:00 2001 From: The Dod Date: Wed, 12 Jan 2022 19:19:16 +0200 Subject: [PATCH 267/315] RAM efficient version of `fourTwentyTz.js` As suggested by @gfwilliams here: https://github.com/espruino/BangleApps/pull/1152#issuecomment-1009739110 Also make `apps.json` entry more accurate, and play nice with dark theme. --- apps.json | 5 +- apps/ftclock/ChangeLog | 1 + apps/ftclock/app.js | 3 +- apps/ftclock/fourTwenty.js | 12 +- apps/ftclock/fourTwentyTz.js | 492 +++------------------------------ apps/ftclock/mkFourTwentyTz.js | 17 +- 6 files changed, 57 insertions(+), 473 deletions(-) diff --git a/apps.json b/apps.json index 4c6f3bdcf..761e9d363 100644 --- a/apps.json +++ b/apps.json @@ -5169,14 +5169,13 @@ { "id": "ftclock", "name": "Four Twenty Clock", - "version": "0.01", + "version": "0.02", "description": "A clock that tells when and where it's going to be 4:20 next", "icon": "app.png", "screenshots": [{"url":"screenshot.png"}, {"url":"screenshot1.png"}], "type": "clock", "tags": "clock", - "supports": ["BANGLEJS","BANGLEJS2"], - "allow_emulator": true, + "supports": ["BANGLEJS2"], "readme": "README.md", "storage": [ {"name":"ftclock.app.js","url":"app.js"}, diff --git a/apps/ftclock/ChangeLog b/apps/ftclock/ChangeLog index 9db0e26c5..c944dd9ac 100644 --- a/apps/ftclock/ChangeLog +++ b/apps/ftclock/ChangeLog @@ -1 +1,2 @@ 0.01: first release +0.02: RAM efficient version of `fourTwentyTz.js` (as suggested by @gfwilliams). diff --git a/apps/ftclock/app.js b/apps/ftclock/app.js index 1aed8da54..b12db10f1 100644 --- a/apps/ftclock/app.js +++ b/apps/ftclock/app.js @@ -17,14 +17,13 @@ function queueDraw() { function draw() { g.reset(); - g.setBgColor("#ffffff"); let date = new Date(); let timeStr = require("locale").time(date,1); let next420 = getNextFourTwenty(); g.clearRect(0,26,g.getWidth(),g.getHeight()); g.setColor("#00ff00").setFontAlign(0,-1).setFont("Teletext10x18Ascii",2); g.drawString(next420.minutes? timeStr: `\0${leaf_img}${timeStr}\0${leaf_img}`, g.getWidth()/2, 28); - g.setColor("#000000"); + g.setColor(g.theme.fg); g.setFontAlign(-1,-1).setFont("Teletext10x18Ascii"); g.drawString(g.wrapString(next420.text, g.getWidth()-8).join("\n"),4,60); diff --git a/apps/ftclock/fourTwenty.js b/apps/ftclock/fourTwenty.js index ac15f40e6..b2a2aa8fb 100644 --- a/apps/ftclock/fourTwenty.js +++ b/apps/ftclock/fourTwenty.js @@ -1,4 +1,6 @@ -let timezones = require("fourTwentyTz").timezones; +let ftz = require("fourTwentyTz"), + offsets = ftz.offsets, + timezones = ftz.timezones; function get420offset() { let current_time = Math.floor((Date.now()%(24*3600*1000))/60000); @@ -24,10 +26,10 @@ function makeFourTwentyText(minutes, places) { function getNextFourTwenty() { let offs = get420offset(); - for (let i=0; i { if (err) { console.log("Can't open output file"); @@ -65,8 +69,17 @@ fs.createReadStream(__dirname+'/country.csv') fs.write(fd, "// Generated by mkFourTwentyTz.js\n", handleWrite); fs.write(fd, `// ${Date()}\n`, handleWrite); fs.write(fd, "// Data source: https://timezonedb.com/files/timezonedb.csv.zip\n", handleWrite); - fs.write(fd, "exports.timezones = ", handleWrite); - fs.write(fd, JSON.stringify(offsdict, null, 4), handleWrite); + fs.write(fd, "exports.offsets = ", handleWrite); + fs.write(fd, JSON.stringify(offsets), handleWrite); + fs.write(fd, ";\n", handleWrite); + fs.write(fd, "exports.timezones = function(offs) {\n", handleWrite); + fs.write(fd, " switch (offs) {\n", handleWrite); + for (o in offsdict) { + fs.write(fd, ` case ${o}: return ${JSON.stringify(offsdict[o])};\n`, handleWrite); + } + fs.write(fd, " default: return [\"Houston, we have a bug.\"];\n", handleWrite); + fs.write(fd, " };\n", handleWrite); + fs.write(fd, "};\n", handleWrite); console.log('Done.'); }); }) From 1c8083ba6e9bc423b7592390d624ed41d830fef2 Mon Sep 17 00:00:00 2001 From: The Dod Date: Wed, 12 Jan 2022 19:36:27 +0200 Subject: [PATCH 268/315] Remove a `;` that was disturbing Travis Also make `fourTwentyTz.js` sorted (to minimize diffs in the future). --- apps/ftclock/fourTwentyTz.js | 48 +++++++++++++++++----------------- apps/ftclock/mkFourTwentyTz.js | 5 ++-- 2 files changed, 27 insertions(+), 26 deletions(-) diff --git a/apps/ftclock/fourTwentyTz.js b/apps/ftclock/fourTwentyTz.js index d02402e2f..5fa6cdab7 100644 --- a/apps/ftclock/fourTwentyTz.js +++ b/apps/ftclock/fourTwentyTz.js @@ -1,33 +1,33 @@ // Generated by mkFourTwentyTz.js -// Wed Jan 12 2022 17:49:39 GMT+0200 (Israel Standard Time) +// Wed Jan 12 2022 19:35:36 GMT+0200 (Israel Standard Time) // Data source: https://timezonedb.com/files/timezonedb.csv.zip exports.offsets = [1380,1320,1260,1200,1140,1080,1020,960,900,840,780,720,660,600,540,480,420,360,300,240,180,120,60,0]; exports.timezones = function(offs) { switch (offs) { - case 0: return ["Troll, Antarctica","Ouagadougou, Burkina Faso","Abidjan, Côte d'Ivoire","Canary, Spain","Faroe, Faroe Islands","London, United Kingdom of Great Britain and Northern Ireland","Guernsey, Guernsey","Accra, Ghana","Danmarkshavn, Greenland","Banjul, Gambia","Conakry, Guinea","Bissau, Guinea-Bissau","Dublin, Ireland","Isle of_Man, Isle of Man","Reykjavik, Iceland","Jersey, Jersey","Monrovia, Liberia","Bamako, Mali","Nouakchott, Mauritania","Lisbon, Portugal","Madeira, Portugal","St Helena, Saint Helena, Ascension and Tristan da Cunha","Freetown, Sierra Leone","Dakar, Senegal","Sao Tome, Sao Tome and Principe","Lome, Togo"]; - case 60: return ["Andorra, Andorra","Tirane, Albania","Luanda, Angola","Vienna, Austria","Sarajevo, Bosnia and Herzegovina","Brussels, Belgium","Porto-Novo, Benin","Kinshasa, Congo, Democratic Republic of the","Bangui, Central African Republic","Brazzaville, Congo","Zurich, Switzerland","Douala, Cameroon","Prague, Czechia","Berlin, Germany","Busingen, Germany","Copenhagen, Denmark","Algiers, Algeria","El Aaiun, Western Sahara","Madrid, Spain","Ceuta, Spain","Paris, France","Libreville, Gabon","Gibraltar, Gibraltar","Malabo, Equatorial Guinea","Zagreb, Croatia","Budapest, Hungary","Rome, Italy","Vaduz, Liechtenstein","Luxembourg, Luxembourg","Casablanca, Morocco","Monaco, Monaco","Podgorica, Montenegro","Skopje, North Macedonia","Malta, Malta","Niamey, Niger","Lagos, Nigeria","Amsterdam, Netherlands","Oslo, Norway","Warsaw, Poland","Belgrade, Serbia","Stockholm, Sweden","Ljubljana, Slovenia","Longyearbyen, Svalbard and Jan Mayen","Bratislava, Slovakia","San Marino, San Marino","Ndjamena, Chad","Tunis, Tunisia","Vatican, Holy See"]; - case 120: return ["Mariehamn, Åland Islands","Sofia, Bulgaria","Bujumbura, Burundi","Gaborone, Botswana","Lubumbashi, Congo, Democratic Republic of the","Nicosia, Cyprus","Famagusta, Cyprus","Tallinn, Estonia","Cairo, Egypt","Helsinki, Finland","Athens, Greece","Jerusalem, Israel","Amman, Jordan","Beirut, Lebanon","Maseru, Lesotho","Vilnius, Lithuania","Riga, Latvia","Tripoli, Libya","Chisinau, Moldova, Republic of","Blantyre, Malawi","Maputo, Mozambique","Windhoek, Namibia","Gaza, Palestine, State of","Hebron, Palestine, State of","Bucharest, Romania","Kaliningrad, Russian Federation","Kigali, Rwanda","Khartoum, Sudan","Juba, South Sudan","Damascus, Syrian Arab Republic","Mbabane, Eswatini","Kiev, Ukraine","Uzhgorod, Ukraine","Zaporozhye, Ukraine","Johannesburg, South Africa","Lusaka, Zambia","Harare, Zimbabwe"]; - case 180: return ["Syowa, Antarctica","Bahrain, Bahrain","Minsk, Belarus","Djibouti, Djibouti","Asmara, Eritrea","Addis Ababa, Ethiopia","Baghdad, Iraq","Nairobi, Kenya","Comoro, Comoros","Kuwait, Kuwait","Antananarivo, Madagascar","Qatar, Qatar","Moscow, Russian Federation","Simferopol, Ukraine","Kirov, Russian Federation","Volgograd, Russian Federation","Riyadh, Saudi Arabia","Mogadishu, Somalia","Istanbul, Turkey","Dar es_Salaam, Tanzania, United Republic of","Kampala, Uganda","Aden, Yemen","Mayotte, Mayotte"]; - case 240: return ["Dubai, United Arab Emirates","Yerevan, Armenia","Baku, Azerbaijan","Tbilisi, Georgia","Mauritius, Mauritius","Muscat, Oman","Reunion, Réunion","Astrakhan, Russian Federation","Saratov, Russian Federation","Ulyanovsk, Russian Federation","Samara, Russian Federation","Mahe, Seychelles"]; + case 1380: return ["Cape Verde, Cabo Verde","Scoresbysund, Greenland","Azores, Portugal"]; + case 1320: return ["Noronha, Brazil","South Georgia, South Georgia and the South Sandwich Islands"]; + case 1260: return ["Palmer, Antarctica","Rothera, Antarctica","Buenos Aires, Argentina","Cordoba, Argentina","Salta, Argentina","Jujuy, Argentina","Tucuman, Argentina","Catamarca, Argentina","La Rioja, Argentina","San Juan, Argentina","Mendoza, Argentina","San Luis, Argentina","Rio Gallegos, Argentina","Ushuaia, Argentina","Belem, Brazil","Fortaleza, Brazil","Recife, Brazil","Araguaina, Brazil","Maceio, Brazil","Bahia, Brazil","Sao Paulo, Brazil","Santarem, Brazil","Santiago, Chile","Punta Arenas, Chile","Stanley, Falkland Islands (Malvinas)","Cayenne, French Guiana","Nuuk, Greenland","Miquelon, Saint Pierre and Miquelon","Asuncion, Paraguay","Paramaribo, Suriname","Montevideo, Uruguay"]; + case 1200: return ["Antigua, Antigua and Barbuda","Anguilla, Anguilla","Aruba, Aruba","Barbados, Barbados","St Barthelemy, Saint Barthélemy","Bermuda, Bermuda","La Paz, Bolivia (Plurinational State of)","Kralendijk, Bonaire, Sint Eustatius and Saba","Campo Grande, Brazil","Cuiaba, Brazil","Porto Velho, Brazil","Boa Vista, Brazil","Manaus, Brazil","Halifax, Canada","Glace Bay, Canada","Moncton, Canada","Goose Bay, Canada","Blanc-Sablon, Canada","Curacao, Curaçao","Dominica, Dominica","Santo Domingo, Dominican Republic","Grenada, Grenada","Thule, Greenland","Guadeloupe, Guadeloupe","Guyana, Guyana","St Kitts, Saint Kitts and Nevis","St Lucia, Saint Lucia","Marigot, Saint Martin (French part)","Martinique, Martinique","Montserrat, Montserrat","Puerto Rico, Puerto Rico","Lower Princes, Sint Maarten (Dutch part)","Port of_Spain, Trinidad and Tobago","St Vincent, Saint Vincent and the Grenadines","Caracas, Venezuela (Bolivarian Republic of)","Tortola, Virgin Islands (British)","St Thomas, Virgin Islands (U.S.)"]; + case 1140: return ["Eirunepe, Brazil","Rio Branco, Brazil","Nassau, Bahamas","Toronto, Canada","Nipigon, Canada","Thunder Bay, Canada","Iqaluit, Canada","Pangnirtung, Canada","Atikokan, Canada","Easter, Chile","Bogota, Colombia","Havana, Cuba","Guayaquil, Ecuador","Port-au-Prince, Haiti","Jamaica, Jamaica","Cayman, Cayman Islands","Cancun, Mexico","Panama, Panama","Lima, Peru","Grand Turk, Turks and Caicos Islands","New York, United States of America","Detroit, United States of America","Louisville, Kentucky","Monticello, Kentucky","Indianapolis, Indiana","Vincennes, Indiana","Winamac, Indiana","Marengo, Indiana","Petersburg, Indiana","Vevay, Indiana"]; + case 1080: return ["Belize, Belize","Winnipeg, Canada","Rainy River, Canada","Resolute, Canada","Rankin Inlet, Canada","Regina, Canada","Swift Current, Canada","Costa Rica, Costa Rica","Galapagos, Ecuador","Guatemala, Guatemala","Tegucigalpa, Honduras","Mexico City, Mexico","Merida, Mexico","Monterrey, Mexico","Matamoros, Mexico","Bahia Banderas, Mexico","Managua, Nicaragua","El Salvador, El Salvador","Chicago, United States of America","Tell City, Indiana","Knox, Indiana","Menominee, United States of America","Center, North Dakota","New_Salem, North Dakota","Beulah, North Dakota"]; + case 1020: return ["Edmonton, Canada","Cambridge Bay, Canada","Yellowknife, Canada","Inuvik, Canada","Creston, Canada","Dawson Creek, Canada","Fort Nelson, Canada","Whitehorse, Canada","Dawson, Canada","Mazatlan, Mexico","Chihuahua, Mexico","Ojinaga, Mexico","Hermosillo, Mexico","Denver, United States of America","Boise, United States of America","Phoenix, United States of America"]; + case 960: return ["Vancouver, Canada","Tijuana, Mexico","Pitcairn, Pitcairn","Los Angeles, United States of America"]; + case 900: return ["Gambier, French Polynesia","Anchorage, United States of America","Juneau, United States of America","Sitka, United States of America","Metlakatla, United States of America","Yakutat, United States of America","Nome, United States of America"]; + case 840: return ["Rarotonga, Cook Islands","Kiritimati, Kiribati","Tahiti, French Polynesia","Adak, United States of America","Honolulu, United States of America"]; + case 780: return ["McMurdo, Antarctica","Pago Pago, American Samoa","Fiji, Fiji","Kanton, Kiribati","Niue, Niue","Auckland, New Zealand","Fakaofo, Tokelau","Tongatapu, Tonga","Midway, United States Minor Outlying Islands","Apia, Samoa"]; + case 720: return ["Tarawa, Kiribati","Majuro, Marshall Islands","Kwajalein, Marshall Islands","Norfolk, Norfolk Island","Nauru, Nauru","Kamchatka, Russian Federation","Anadyr, Russian Federation","Funafuti, Tuvalu","Wake, United States Minor Outlying Islands","Wallis, Wallis and Futuna"]; + case 660: return ["Casey, Antarctica","Lord Howe, Australia","Macquarie, Australia","Hobart, Australia","Melbourne, Australia","Sydney, Australia","Pohnpei, Micronesia (Federated States of)","Kosrae, Micronesia (Federated States of)","Noumea, New Caledonia","Bougainville, Papua New Guinea","Magadan, Russian Federation","Sakhalin, Russian Federation","Srednekolymsk, Russian Federation","Guadalcanal, Solomon Islands","Efate, Vanuatu"]; + case 600: return ["DumontDUrville, Antarctica","Brisbane, Australia","Lindeman, Australia","Chuuk, Micronesia (Federated States of)","Guam, Guam","Saipan, Northern Mariana Islands","Port Moresby, Papua New Guinea","Vladivostok, Russian Federation","Ust-Nera, Russian Federation"]; + case 540: return ["Jayapura, Indonesia","Tokyo, Japan","Pyongyang, Korea (Democratic People's Republic of)","Seoul, Korea, Republic of","Palau, Palau","Chita, Russian Federation","Yakutsk, Russian Federation","Khandyga, Russian Federation","Dili, Timor-Leste"]; + case 480: return ["Perth, Australia","Brunei, Brunei Darussalam","Shanghai, China","Hong Kong, Hong Kong","Makassar, Indonesia","Ulaanbaatar, Mongolia","Choibalsan, Mongolia","Macau, Macao","Kuala Lumpur, Malaysia","Kuching, Malaysia","Manila, Philippines","Irkutsk, Russian Federation","Singapore, Singapore","Taipei, Taiwan, Province of China"]; + case 420: return ["Davis, Antarctica","Christmas, Christmas Island","Jakarta, Indonesia","Pontianak, Indonesia","Phnom Penh, Cambodia","Vientiane, Lao People's Democratic Republic","Hovd, Mongolia","Novosibirsk, Russian Federation","Barnaul, Russian Federation","Tomsk, Russian Federation","Novokuznetsk, Russian Federation","Krasnoyarsk, Russian Federation","Bangkok, Thailand","Ho Chi_Minh, Viet Nam"]; case 360: return ["Vostok, Antarctica","Dhaka, Bangladesh","Thimphu, Bhutan","Urumqi, China","Chagos, British Indian Ocean Territory","Bishkek, Kyrgyzstan","Almaty, Kazakhstan","Qostanay, Kazakhstan","Omsk, Russian Federation"]; case 300: return ["Mawson, Antarctica","Qyzylorda, Kazakhstan","Aqtobe, Kazakhstan","Aqtau, Kazakhstan","Atyrau, Kazakhstan","Oral, Kazakhstan","Maldives, Maldives","Karachi, Pakistan","Yekaterinburg, Russian Federation","Kerguelen, French Southern Territories","Dushanbe, Tajikistan","Ashgabat, Turkmenistan","Samarkand, Uzbekistan","Tashkent, Uzbekistan"]; - case 420: return ["Davis, Antarctica","Christmas, Christmas Island","Jakarta, Indonesia","Pontianak, Indonesia","Phnom Penh, Cambodia","Vientiane, Lao People's Democratic Republic","Hovd, Mongolia","Novosibirsk, Russian Federation","Barnaul, Russian Federation","Tomsk, Russian Federation","Novokuznetsk, Russian Federation","Krasnoyarsk, Russian Federation","Bangkok, Thailand","Ho Chi_Minh, Viet Nam"]; - case 480: return ["Perth, Australia","Brunei, Brunei Darussalam","Shanghai, China","Hong Kong, Hong Kong","Makassar, Indonesia","Ulaanbaatar, Mongolia","Choibalsan, Mongolia","Macau, Macao","Kuala Lumpur, Malaysia","Kuching, Malaysia","Manila, Philippines","Irkutsk, Russian Federation","Singapore, Singapore","Taipei, Taiwan, Province of China"]; - case 540: return ["Jayapura, Indonesia","Tokyo, Japan","Pyongyang, Korea (Democratic People's Republic of)","Seoul, Korea, Republic of","Palau, Palau","Chita, Russian Federation","Yakutsk, Russian Federation","Khandyga, Russian Federation","Dili, Timor-Leste"]; - case 600: return ["DumontDUrville, Antarctica","Brisbane, Australia","Lindeman, Australia","Chuuk, Micronesia (Federated States of)","Guam, Guam","Saipan, Northern Mariana Islands","Port Moresby, Papua New Guinea","Vladivostok, Russian Federation","Ust-Nera, Russian Federation"]; - case 660: return ["Casey, Antarctica","Lord Howe, Australia","Macquarie, Australia","Hobart, Australia","Melbourne, Australia","Sydney, Australia","Pohnpei, Micronesia (Federated States of)","Kosrae, Micronesia (Federated States of)","Noumea, New Caledonia","Bougainville, Papua New Guinea","Magadan, Russian Federation","Sakhalin, Russian Federation","Srednekolymsk, Russian Federation","Guadalcanal, Solomon Islands","Efate, Vanuatu"]; - case 720: return ["Tarawa, Kiribati","Majuro, Marshall Islands","Kwajalein, Marshall Islands","Norfolk, Norfolk Island","Nauru, Nauru","Kamchatka, Russian Federation","Anadyr, Russian Federation","Funafuti, Tuvalu","Wake, United States Minor Outlying Islands","Wallis, Wallis and Futuna"]; - case 780: return ["McMurdo, Antarctica","Pago Pago, American Samoa","Fiji, Fiji","Kanton, Kiribati","Niue, Niue","Auckland, New Zealand","Fakaofo, Tokelau","Tongatapu, Tonga","Midway, United States Minor Outlying Islands","Apia, Samoa"]; - case 840: return ["Rarotonga, Cook Islands","Kiritimati, Kiribati","Tahiti, French Polynesia","Adak, United States of America","Honolulu, United States of America"]; - case 900: return ["Gambier, French Polynesia","Anchorage, United States of America","Juneau, United States of America","Sitka, United States of America","Metlakatla, United States of America","Yakutat, United States of America","Nome, United States of America"]; - case 960: return ["Vancouver, Canada","Tijuana, Mexico","Pitcairn, Pitcairn","Los Angeles, United States of America"]; - case 1020: return ["Edmonton, Canada","Cambridge Bay, Canada","Yellowknife, Canada","Inuvik, Canada","Creston, Canada","Dawson Creek, Canada","Fort Nelson, Canada","Whitehorse, Canada","Dawson, Canada","Mazatlan, Mexico","Chihuahua, Mexico","Ojinaga, Mexico","Hermosillo, Mexico","Denver, United States of America","Boise, United States of America","Phoenix, United States of America"]; - case 1080: return ["Belize, Belize","Winnipeg, Canada","Rainy River, Canada","Resolute, Canada","Rankin Inlet, Canada","Regina, Canada","Swift Current, Canada","Costa Rica, Costa Rica","Galapagos, Ecuador","Guatemala, Guatemala","Tegucigalpa, Honduras","Mexico City, Mexico","Merida, Mexico","Monterrey, Mexico","Matamoros, Mexico","Bahia Banderas, Mexico","Managua, Nicaragua","El Salvador, El Salvador","Chicago, United States of America","Tell City, Indiana","Knox, Indiana","Menominee, United States of America","Center, North Dakota","New_Salem, North Dakota","Beulah, North Dakota"]; - case 1140: return ["Eirunepe, Brazil","Rio Branco, Brazil","Nassau, Bahamas","Toronto, Canada","Nipigon, Canada","Thunder Bay, Canada","Iqaluit, Canada","Pangnirtung, Canada","Atikokan, Canada","Easter, Chile","Bogota, Colombia","Havana, Cuba","Guayaquil, Ecuador","Port-au-Prince, Haiti","Jamaica, Jamaica","Cayman, Cayman Islands","Cancun, Mexico","Panama, Panama","Lima, Peru","Grand Turk, Turks and Caicos Islands","New York, United States of America","Detroit, United States of America","Louisville, Kentucky","Monticello, Kentucky","Indianapolis, Indiana","Vincennes, Indiana","Winamac, Indiana","Marengo, Indiana","Petersburg, Indiana","Vevay, Indiana"]; - case 1200: return ["Antigua, Antigua and Barbuda","Anguilla, Anguilla","Aruba, Aruba","Barbados, Barbados","St Barthelemy, Saint Barthélemy","Bermuda, Bermuda","La Paz, Bolivia (Plurinational State of)","Kralendijk, Bonaire, Sint Eustatius and Saba","Campo Grande, Brazil","Cuiaba, Brazil","Porto Velho, Brazil","Boa Vista, Brazil","Manaus, Brazil","Halifax, Canada","Glace Bay, Canada","Moncton, Canada","Goose Bay, Canada","Blanc-Sablon, Canada","Curacao, Curaçao","Dominica, Dominica","Santo Domingo, Dominican Republic","Grenada, Grenada","Thule, Greenland","Guadeloupe, Guadeloupe","Guyana, Guyana","St Kitts, Saint Kitts and Nevis","St Lucia, Saint Lucia","Marigot, Saint Martin (French part)","Martinique, Martinique","Montserrat, Montserrat","Puerto Rico, Puerto Rico","Lower Princes, Sint Maarten (Dutch part)","Port of_Spain, Trinidad and Tobago","St Vincent, Saint Vincent and the Grenadines","Caracas, Venezuela (Bolivarian Republic of)","Tortola, Virgin Islands (British)","St Thomas, Virgin Islands (U.S.)"]; - case 1260: return ["Palmer, Antarctica","Rothera, Antarctica","Buenos Aires, Argentina","Cordoba, Argentina","Salta, Argentina","Jujuy, Argentina","Tucuman, Argentina","Catamarca, Argentina","La Rioja, Argentina","San Juan, Argentina","Mendoza, Argentina","San Luis, Argentina","Rio Gallegos, Argentina","Ushuaia, Argentina","Belem, Brazil","Fortaleza, Brazil","Recife, Brazil","Araguaina, Brazil","Maceio, Brazil","Bahia, Brazil","Sao Paulo, Brazil","Santarem, Brazil","Santiago, Chile","Punta Arenas, Chile","Stanley, Falkland Islands (Malvinas)","Cayenne, French Guiana","Nuuk, Greenland","Miquelon, Saint Pierre and Miquelon","Asuncion, Paraguay","Paramaribo, Suriname","Montevideo, Uruguay"]; - case 1320: return ["Noronha, Brazil","South Georgia, South Georgia and the South Sandwich Islands"]; - case 1380: return ["Cape Verde, Cabo Verde","Scoresbysund, Greenland","Azores, Portugal"]; + case 240: return ["Dubai, United Arab Emirates","Yerevan, Armenia","Baku, Azerbaijan","Tbilisi, Georgia","Mauritius, Mauritius","Muscat, Oman","Reunion, Réunion","Astrakhan, Russian Federation","Saratov, Russian Federation","Ulyanovsk, Russian Federation","Samara, Russian Federation","Mahe, Seychelles"]; + case 180: return ["Syowa, Antarctica","Bahrain, Bahrain","Minsk, Belarus","Djibouti, Djibouti","Asmara, Eritrea","Addis Ababa, Ethiopia","Baghdad, Iraq","Nairobi, Kenya","Comoro, Comoros","Kuwait, Kuwait","Antananarivo, Madagascar","Qatar, Qatar","Moscow, Russian Federation","Simferopol, Ukraine","Kirov, Russian Federation","Volgograd, Russian Federation","Riyadh, Saudi Arabia","Mogadishu, Somalia","Istanbul, Turkey","Dar es_Salaam, Tanzania, United Republic of","Kampala, Uganda","Aden, Yemen","Mayotte, Mayotte"]; + case 120: return ["Mariehamn, Åland Islands","Sofia, Bulgaria","Bujumbura, Burundi","Gaborone, Botswana","Lubumbashi, Congo, Democratic Republic of the","Nicosia, Cyprus","Famagusta, Cyprus","Tallinn, Estonia","Cairo, Egypt","Helsinki, Finland","Athens, Greece","Jerusalem, Israel","Amman, Jordan","Beirut, Lebanon","Maseru, Lesotho","Vilnius, Lithuania","Riga, Latvia","Tripoli, Libya","Chisinau, Moldova, Republic of","Blantyre, Malawi","Maputo, Mozambique","Windhoek, Namibia","Gaza, Palestine, State of","Hebron, Palestine, State of","Bucharest, Romania","Kaliningrad, Russian Federation","Kigali, Rwanda","Khartoum, Sudan","Juba, South Sudan","Damascus, Syrian Arab Republic","Mbabane, Eswatini","Kiev, Ukraine","Uzhgorod, Ukraine","Zaporozhye, Ukraine","Johannesburg, South Africa","Lusaka, Zambia","Harare, Zimbabwe"]; + case 60: return ["Andorra, Andorra","Tirane, Albania","Luanda, Angola","Vienna, Austria","Sarajevo, Bosnia and Herzegovina","Brussels, Belgium","Porto-Novo, Benin","Kinshasa, Congo, Democratic Republic of the","Bangui, Central African Republic","Brazzaville, Congo","Zurich, Switzerland","Douala, Cameroon","Prague, Czechia","Berlin, Germany","Busingen, Germany","Copenhagen, Denmark","Algiers, Algeria","El Aaiun, Western Sahara","Madrid, Spain","Ceuta, Spain","Paris, France","Libreville, Gabon","Gibraltar, Gibraltar","Malabo, Equatorial Guinea","Zagreb, Croatia","Budapest, Hungary","Rome, Italy","Vaduz, Liechtenstein","Luxembourg, Luxembourg","Casablanca, Morocco","Monaco, Monaco","Podgorica, Montenegro","Skopje, North Macedonia","Malta, Malta","Niamey, Niger","Lagos, Nigeria","Amsterdam, Netherlands","Oslo, Norway","Warsaw, Poland","Belgrade, Serbia","Stockholm, Sweden","Ljubljana, Slovenia","Longyearbyen, Svalbard and Jan Mayen","Bratislava, Slovakia","San Marino, San Marino","Ndjamena, Chad","Tunis, Tunisia","Vatican, Holy See"]; + case 0: return ["Troll, Antarctica","Ouagadougou, Burkina Faso","Abidjan, Côte d'Ivoire","Canary, Spain","Faroe, Faroe Islands","London, United Kingdom of Great Britain and Northern Ireland","Guernsey, Guernsey","Accra, Ghana","Danmarkshavn, Greenland","Banjul, Gambia","Conakry, Guinea","Bissau, Guinea-Bissau","Dublin, Ireland","Isle of_Man, Isle of Man","Reykjavik, Iceland","Jersey, Jersey","Monrovia, Liberia","Bamako, Mali","Nouakchott, Mauritania","Lisbon, Portugal","Madeira, Portugal","St Helena, Saint Helena, Ascension and Tristan da Cunha","Freetown, Sierra Leone","Dakar, Senegal","Sao Tome, Sao Tome and Principe","Lome, Togo"]; default: return ["Houston, we have a bug."]; - }; + } }; diff --git a/apps/ftclock/mkFourTwentyTz.js b/apps/ftclock/mkFourTwentyTz.js index 2be18f88a..4571c15f7 100644 --- a/apps/ftclock/mkFourTwentyTz.js +++ b/apps/ftclock/mkFourTwentyTz.js @@ -74,11 +74,12 @@ fs.createReadStream(__dirname+'/country.csv') fs.write(fd, ";\n", handleWrite); fs.write(fd, "exports.timezones = function(offs) {\n", handleWrite); fs.write(fd, " switch (offs) {\n", handleWrite); - for (o in offsdict) { + for (i=0; i Date: Wed, 12 Jan 2022 18:36:07 +0100 Subject: [PATCH 269/315] Select which GNSS system to use fewer GNSS systems could decrease time to fix. This patch adds a checkbox for each choice. --- apps.json | 2 +- apps/assistedgps/ChangeLog | 1 + apps/assistedgps/custom.html | 34 ++++++++++++++++++++++++++++++++-- 3 files changed, 34 insertions(+), 3 deletions(-) diff --git a/apps.json b/apps.json index 4c6f3bdcf..88db38bbb 100644 --- a/apps.json +++ b/apps.json @@ -1536,7 +1536,7 @@ { "id": "assistedgps", "name": "Assisted GPS Update (AGPS)", - "version": "0.02", + "version": "0.03", "description": "Downloads assisted GPS (AGPS) data to Bangle.js 1 or 2 for faster GPS startup and more accurate fixes. **No app will be installed**, this just uploads new data to the GPS chip.", "icon": "app.png", "type": "RAM", diff --git a/apps/assistedgps/ChangeLog b/apps/assistedgps/ChangeLog index 4ec2c8f71..739ccf915 100644 --- a/apps/assistedgps/ChangeLog +++ b/apps/assistedgps/ChangeLog @@ -1,2 +1,3 @@ 0.01: New App! 0.02: Update to work with Bangle.js 2 +0.03: Select GNSS systems to use for Bangle.js 2 diff --git a/apps/assistedgps/custom.html b/apps/assistedgps/custom.html index fa11b696c..80d68a71f 100644 --- a/apps/assistedgps/custom.html +++ b/apps/assistedgps/custom.html @@ -27,6 +27,31 @@

@@ -116,8 +141,13 @@ } if (isB2) { // CASIC - // Disable BDS, use just GPS (supposedly improve lock time) - js += `\x10Serial1.println("${CASIC_CHECKSUM("$PCAS04,1")}")\n`; // set GPS-only mode + // Select what GNSS System to use for decreased fix time. + var radios = document.getElementsByName('gnss_select'); + var gnss_select="1"; + for (var i=0; i Date: Wed, 12 Jan 2022 19:33:22 +0100 Subject: [PATCH 270/315] Update app-screenshot.png --- apps/ac_ac/app-screenshot.png | Bin 4042 -> 3459 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/apps/ac_ac/app-screenshot.png b/apps/ac_ac/app-screenshot.png index e0e3bb0b95de844ed0656d16023e71708c117f96..0aef3fa3815fe19d368bcf37f6afd3aa1f9e335c 100644 GIT binary patch delta 3444 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

P0Nr8KQ7MDGw1#ySt+-U>WBeK-J~ zIf*MltOajcveRsr0B$sy2QZ_POPON%?=hH}>b#UQ@y`9#V*bGe6YD2OK@bM^g>YE)66hwe?X+jO|hJRCbJ+w#lLb1a(0p3A@w*ffL z)_&%^C5FIm6JW(Fba+#{De!Oy@=oXg^ZbQdm(qk4(+7OC(=8SS*m#bNRU)jF(Tq>j z7M#Q(7xoG{atUH<@P-r@ya;Nse-#{Dfv4XD4RpX2*gz1x3!n7Bq6%Dz)e7mwXw()~ zSj<)X0e`&mLl7)l($5#paj_xq2e2#fJLayy*mbbj=Q}~ZF`N{t_ETWWsCRm(u+vy5 zu}f^e3ve9yVs+0~j9r1z?|v0r7mFWaN!2X%#b8*!slZquC^@nQSd=zCuCQ3B9N?UX zNMI4(Fvi-!KEEFG{&jNobO)nR@VNsla9TJ-135lQ8`A!Lp56^@JHXvt m>?i2y0SCCJcfIZI9{3NXIof%KH)?hO0000 From 73062edf8321892b65d4372f6f0c2f304d2c25a3 Mon Sep 17 00:00:00 2001 From: Richard de Boer Date: Wed, 12 Jan 2022 19:08:19 +0100 Subject: [PATCH 271/315] qmsched: switch theme fixes #1266 --- apps.json | 4 +-- apps/qmsched/ChangeLog | 3 ++- apps/qmsched/README.md | 5 ++++ apps/qmsched/app.js | 60 +++++++++++++++++++++++++++++++----------- apps/qmsched/boot.js | 4 ++- apps/qmsched/lib.js | 36 ++++++++++++++++++++++++- apps/qmsched/widget.js | 2 +- 7 files changed, 93 insertions(+), 21 deletions(-) diff --git a/apps.json b/apps.json index b5929a56c..870c7b49f 100644 --- a/apps.json +++ b/apps.json @@ -3919,8 +3919,8 @@ "id": "qmsched", "name": "Quiet Mode Schedule and Widget", "shortName": "Quiet Mode", - "version": "0.06", - "description": "Automatically turn Quiet Mode on or off at set times, and change LCD options while Quiet Mode is active.", + "version": "0.07", + "description": "Automatically turn Quiet Mode on or off at set times, change theme and LCD options while Quiet Mode is active.", "icon": "app.png", "screenshots": [{"url":"screenshot_b1_main.png"},{"url":"screenshot_b1_edit.png"},{"url":"screenshot_b1_lcd.png"}, {"url":"screenshot_b2_main.png"},{"url":"screenshot_b2_edit.png"},{"url":"screenshot_b2_lcd.png"}], diff --git a/apps/qmsched/ChangeLog b/apps/qmsched/ChangeLog index 35832a300..cc0050cdd 100644 --- a/apps/qmsched/ChangeLog +++ b/apps/qmsched/ChangeLog @@ -3,4 +3,5 @@ 0.03: Bangle.js 2 support 0.04: Move Quiet Mode LCD options from global settings to this app 0.05: Avoid immediately redrawing widgets on load -0.06: Fix: don't try to redraw widget when widgets not loaded \ No newline at end of file +0.06: Fix: don't try to redraw widget when widgets not loaded +0.07: Option to switch theme diff --git a/apps/qmsched/README.md b/apps/qmsched/README.md index 535ae56e4..660bda787 100644 --- a/apps/qmsched/README.md +++ b/apps/qmsched/README.md @@ -9,6 +9,11 @@ Automatically turn Quiet Mode on or off at set times, and display a widget when | ![Edit Schedule menu](screenshot_b1_edit.png) | ![Edit Schedule menu](screenshot_b2_edit.png) | | ![LCD Options menu](screenshot_b1_lcd.png) | ![LCD Options menu](screenshot_b2_lcd.png) | +### Switch Theme: + +Switch to dark theme during Quiet Mode. + * **NOTE**: This switches between the default "Dark BW" and "Light BW" themes, so custom theme settings will be lost. + ### LCD Settings: If set, these override the default LCD settings while Quiet Mode is active. \ No newline at end of file diff --git a/apps/qmsched/app.js b/apps/qmsched/app.js index 7be3339fb..433dab409 100644 --- a/apps/qmsched/app.js +++ b/apps/qmsched/app.js @@ -3,7 +3,7 @@ Bangle.drawWidgets(); const modeNames = ["Off", "Alarms", "Silent"]; -// load global brightness setting +// load global settings let bSettings = require('Storage').readJSON('setting.json',true)||{}; let current = 0|bSettings.quiet; delete bSettings; // we don't need any other global settings @@ -18,6 +18,7 @@ delete bSettings; // we don't need any other global settings */ function save() { require('Storage').writeJSON('qmsched.json', settings); + eval(require('Storage').read('qmsched.boot.js')); // apply new schedules right away } function get(key, def) { return (key in settings) ? settings[key] : def; @@ -77,37 +78,66 @@ function formatTime(t) { const mins = Math.round((t-hrs)*60); return (" "+hrs).substr(-2)+":"+("0"+mins).substr(-2); } +/** + * Apply theme + */ +function applyTheme() { + const theme = (require("Storage").readJSON("setting.json", 1) || {}).theme; + if (theme && theme.dark===g.theme.dark) return; // already correct + g.theme = theme; + delete g.reset; + g._reset = g.reset; + g.reset = function(n) { return g._reset().setColor(g.theme.fg).setBgColor(g.theme.bg); }; + g.clear = function(n) { if (n) g.reset(); return g.clearRect(0,0,g.getWidth(),g.getHeight()); }; + g.clear(1); + Bangle.drawWidgets(); + delete m.lastIdx; // force redraw + m.draw(); +} +/** + * Library uses this to make the app update itself + * @param {int} mode New Quite Mode + */ +function setAppMode(mode) { + if (mode === current) return; + current = mode; + delete m.lastIdx; // force redraw + applyTheme(); + if (m.lastIdx===undefined) m.draw(); // applyTheme didn't redraw menu, but we need to show updated mode +} + +let m; function showMainMenu() { - let _m, menu = { + let menu = { "": {"title": "Quiet Mode"}, "< Exit": () => load() }; // "Current Mode""Silent" won't fit on Bangle.js 2 menu["Current"+((process.env.HWVERSION===2) ? "" : " Mode")] = { value: current, - format: v => modeNames[v], - onchange: function(v) { - if (v<0) {v = 2;} - if (v>2) {v = 0;} - require("qmsched").setMode(v); - current = v; - this.value = v; - }, + min:0, max:2, wrap: true, + format: () => modeNames[current], + onchange: require("qmsched").setMode, // library calls setAppMode(), which updates `current` }; scheds.sort((a, b) => (a.hr-b.hr)); scheds.forEach((sched, idx) => { menu[formatTime(sched.hr)] = { format: () => modeNames[sched.mode], // abuse format to right-align text - onchange: function() { - _m.draw = ()=> {}; // prevent redraw of main menu over edit menu + onchange: () => { + m.draw = ()=> {}; // prevent redraw of main menu over edit menu (needed because we abuse format/onchange) showEditMenu(idx); } }; }); menu["Add Schedule"] = () => showEditMenu(-1); + menu["Switch Theme"] = { + value: !!get("switchTheme"), + format: v => v ? /*LANG*/"Yes" : /*LANG*/"No", + onchange: v => v ? set("switchTheme", v) : unset("switchTheme"), + }; menu["LCD Settings"] = () => showOptionsMenu(); - _m = E.showMenu(menu); + m = E.showMenu(menu); } function showEditMenu(index) { @@ -174,7 +204,7 @@ function showEditMenu(index) { showMainMenu(); }; } - return E.showMenu(menu); + m = E.showMenu(menu); } function showOptionsMenu() { @@ -244,7 +274,7 @@ function showOptionsMenu() { onchange: () => {toggle("wakeOnTwist");}, }, }; - return E.showMenu(oMenu); + m = E.showMenu(oMenu); } loadSettings(); diff --git a/apps/qmsched/boot.js b/apps/qmsched/boot.js index c3bc49b58..c4610ce3e 100644 --- a/apps/qmsched/boot.js +++ b/apps/qmsched/boot.js @@ -1,5 +1,7 @@ // apply Quiet Mode schedules (function qm() { + if (Bangle.qmTimeout) clearTimeout(Bangle.qmTimeout); // so the app can eval() this file to apply changes right away + delete Bangle.qmTimeout; let bSettings = require('Storage').readJSON('setting.json',true)||{}; const curr = 0|bSettings.quiet; delete bSettings; @@ -18,7 +20,7 @@ let t = 3600000*(next.hr-hr); // timeout in milliseconds if (t<0) {t += 86400000;} // scheduled for tomorrow: add a day /* update quiet mode at the correct time. */ - setTimeout(() => { + Bangle.qmTimeout=setTimeout(() => { require("qmsched").setMode(mode); qm(); // schedule next update }, t); diff --git a/apps/qmsched/lib.js b/apps/qmsched/lib.js index e9ed3ec90..e048d15bf 100644 --- a/apps/qmsched/lib.js +++ b/apps/qmsched/lib.js @@ -1,5 +1,37 @@ /** - * Apply LCD options for given mode + * Apply appropriate theme for given mode + * @param {int} mode Quiet Mode + */ +function switchTheme(mode) { + if (!!mode === g.theme.dark) return; // nothing to do + let s = require("Storage").readJSON("setting.json", 1) || {}; + // default themes, copied from settings.js:showThemeMenu() + function cl(x) { return g.setColor(x).getColor(); } + s.theme = mode ? { + // 'Dark BW' + fg: cl("#fff"), bg: cl("#000"), + fg2: cl("#0ff"), bg2: cl("#000"), + fgH: cl("#fff"), bgH: cl("#00f"), + dark: true + } : { + // 'Light BW' + fg: cl("#000"), bg: cl("#fff"), + fg2: cl("#000"), bg2: cl("#cff"), + fgH: cl("#000"), bgH: cl("#0ff"), + dark: false + }; + require("Storage").writeJSON("setting.json", s); + if (typeof __FILE__ === 'string') { // undefined means it loaded the default clock + const info = require("Storage").readJSON(__FILE__.split(".")[0]+".info", 1); + if (info && info.type!=="clock") { // info can have no type (but then it isn't a clock) + return; // not a clock: wait for user to switch apps + } + } + // current app is a clock: reload it with new theme + load(global.__FILE__); +} +/** + * Apply LCD options and theme for given mode * @param {int} mode Quiet Mode */ exports.applyOptions = function(mode) { @@ -8,6 +40,7 @@ exports.applyOptions = function(mode) { Bangle.setOptions(get("options", {})); Bangle.setLCDBrightness(get("brightness", 1)); Bangle.setLCDTimeout(get("timeout", 10)); + if ((require("Storage").readJSON("qmsched.json", 1) || {}).switchTheme) switchTheme(mode); }; /** * Set new Quiet Mode and apply Bangle options @@ -20,4 +53,5 @@ exports.setMode = function(mode) { )); exports.applyOptions(mode); if (typeof WIDGETS === "object" && "qmsched" in WIDGETS) WIDGETS["qmsched"].draw(); + if (global.__FILE__ === "qmsched.app.js") setAppMode(mode); }; diff --git a/apps/qmsched/widget.js b/apps/qmsched/widget.js index b25192b06..daa11ac71 100644 --- a/apps/qmsched/widget.js +++ b/apps/qmsched/widget.js @@ -18,7 +18,7 @@ return; // drawWidgets will call draw again } let x = this.x, y = this.y; - g.clearRect(x, y, x+23, y+23); + g.reset().clearRect(x, y, x+23, y+23); // quiet mode: draw red one-way-street sign (dim red on Bangle.js 1) x = this.x+11;y = this.y+11; // center of widget g.setColor(process.env.HWVERSION===2 ? 1 : 0.8, 0, 0).fillCircle(x, y, 8); From 0b455f921c5b4d2514db5061b5ade73f817050a5 Mon Sep 17 00:00:00 2001 From: Richard de Boer Date: Wed, 12 Jan 2022 19:09:00 +0100 Subject: [PATCH 272/315] qmsched: set minutes in 5-min steps --- apps/qmsched/ChangeLog | 1 + apps/qmsched/app.js | 24 ++++++------------------ 2 files changed, 7 insertions(+), 18 deletions(-) diff --git a/apps/qmsched/ChangeLog b/apps/qmsched/ChangeLog index cc0050cdd..c868b6668 100644 --- a/apps/qmsched/ChangeLog +++ b/apps/qmsched/ChangeLog @@ -5,3 +5,4 @@ 0.05: Avoid immediately redrawing widgets on load 0.06: Fix: don't try to redraw widget when widgets not loaded 0.07: Option to switch theme + Changed time selection to 5-minute intervals \ No newline at end of file diff --git a/apps/qmsched/app.js b/apps/qmsched/app.js index 433dab409..b65761d5c 100644 --- a/apps/qmsched/app.js +++ b/apps/qmsched/app.js @@ -155,31 +155,19 @@ function showEditMenu(index) { "< Cancel": () => showMainMenu(), "Hours": { value: hrs, - onchange: function(v) { - if (v<0) {v = 23;} - if (v>23) {v = 0;} - hrs = v; - this.value = v; - }, // no arrow fn -> preserve 'this' + min:0, max:23, wrap:true, + onchange: v => {hrs = v;}, }, "Minutes": { value: mins, - onchange: function(v) { - if (v<0) {v = 59;} - if (v>59) {v = 0;} - mins = v; - this.value = v; - }, // no arrow fn -> preserve 'this' + min:0, max:55, step:5, wrap:true, + onchange: v => {mins = v;}, }, "Switch to": { value: mode, + min:0, max:2, wrap:true, format: v => modeNames[v], - onchange: function(v) { - if (v<0) {v = 2;} - if (v>2) {v = 0;} - mode = v; - this.value = v; - }, // no arrow fn -> preserve 'this' + onchange: v => {mode = v;}, }, }; function getSched() { From 8edda16ca2b9bfe47d358b50655d707657e71871 Mon Sep 17 00:00:00 2001 From: Martin Boonk Date: Wed, 12 Jan 2022 19:48:24 +0100 Subject: [PATCH 273/315] Log pressure if sensor is available --- apps/recorder/widget.js | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/apps/recorder/widget.js b/apps/recorder/widget.js index 8f82f1f37..bffa15283 100644 --- a/apps/recorder/widget.js +++ b/apps/recorder/widget.js @@ -133,8 +133,38 @@ draw : (x,y) => g.reset().drawImage(atob("DAwBAAMMeeeeeeeecOMMAAMMMMAA"),x,y) }; } - // TODO: recAltitude from pressure sensor }; + if (Bangle.getPressure){ + recorders['baro'] = function() { + var temp="",press="",alt=""; + function onPress(c) { + temp=c.temperature; + press=c.pressure; + alt=c.altitude; + } + return { + name : "Baro", + fields : ["Barometer Temperature", "Barometer Pressure", "Barometer Altitude"], + getValues : () => { + var r = [temp,press,alt]; + temp=""; + press=""; + alt=""; + return r; + }, + start : () => { + Bangle.setBarometerPower(1,"recorder"); + Bangle.on('pressure', onPress); + }, + stop : () => { + Bangle.setBarometerPower(0,"recorder"); + Bangle.removeListener('pressure', onPress); + }, + draw : (x,y) => g.setColor("#0f0").drawImage(atob("DAwBAAH4EIHIEIHIEIHIEIEIH4AA"),x,y) + }; + } + } + /* eg. foobar.recorder.js (function(recorders) { recorders.foobar = { From 58e9a4705192156ce7e58158cee79b07997145ab Mon Sep 17 00:00:00 2001 From: Martin Boonk Date: Wed, 12 Jan 2022 20:35:52 +0100 Subject: [PATCH 274/315] Record empty string if no value instead of 0 --- apps/recorder/widget.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/recorder/widget.js b/apps/recorder/widget.js index bffa15283..9d66e0a02 100644 --- a/apps/recorder/widget.js +++ b/apps/recorder/widget.js @@ -52,7 +52,7 @@ }; }, hrm:function() { - var bpm = 0, bpmConfidence = 0; + var bpm = "", bpmConfidence = ""; function onHRM(h) { if (h.confidence >= bpmConfidence) { bpmConfidence = h.confidence; @@ -64,7 +64,7 @@ fields : ["Heartrate", "Confidence"], getValues : () => { var r = [bpm,bpmConfidence]; - bpm = 0; bpmConfidence = 0; + bpm = ""; bpmConfidence = ""; return r; }, start : () => { From c9efc0958199f5ed1f515e4ec09369a0d18d33cb Mon Sep 17 00:00:00 2001 From: Martin Boonk Date: Wed, 12 Jan 2022 20:45:32 +0100 Subject: [PATCH 275/315] Always log bpm and confidence --- apps/recorder/widget.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/apps/recorder/widget.js b/apps/recorder/widget.js index 9d66e0a02..359af721f 100644 --- a/apps/recorder/widget.js +++ b/apps/recorder/widget.js @@ -54,10 +54,8 @@ hrm:function() { var bpm = "", bpmConfidence = ""; function onHRM(h) { - if (h.confidence >= bpmConfidence) { - bpmConfidence = h.confidence; - bpm = h.bpm; - } + bpmConfidence = h.confidence; + bpm = h.bpm; } return { name : "HR", From 412b5dd20c08787bb334af2f287423cd8ede4f3e Mon Sep 17 00:00:00 2001 From: Martin Boonk Date: Wed, 12 Jan 2022 19:56:03 +0100 Subject: [PATCH 276/315] Move recorder code to plugin in coretemp app --- apps.json | 3 ++- apps/coretemp/ChangeLog | 1 + apps/coretemp/recorder.js | 31 +++++++++++++++++++++++++++++++ apps/recorder/widget.js | 26 -------------------------- 4 files changed, 34 insertions(+), 27 deletions(-) create mode 100644 apps/coretemp/recorder.js diff --git a/apps.json b/apps.json index 4c6f3bdcf..e3964fd2a 100644 --- a/apps.json +++ b/apps.json @@ -5046,7 +5046,7 @@ { "id": "coretemp", "name": "CoreTemp", - "version": "0.02", + "version": "0.03", "description": "Display CoreTemp device sensor data", "icon": "coretemp.png", "type": "app", @@ -5056,6 +5056,7 @@ "storage": [ {"name":"coretemp.wid.js","url":"widget.js"}, {"name":"coretemp.app.js","url":"coretemp.js"}, + {"name":"coretemp.recorder.js","url":"recorder.js"}, {"name":"coretemp.settings.js","url":"settings.js"}, {"name":"coretemp.img","url":"coretemp-icon.js","evaluate":true}, {"name":"coretemp.boot.js","url":"boot.js"} diff --git a/apps/coretemp/ChangeLog b/apps/coretemp/ChangeLog index ea6911f1a..ad6f0742d 100644 --- a/apps/coretemp/ChangeLog +++ b/apps/coretemp/ChangeLog @@ -1,2 +1,3 @@ 0.01: New app 0.02: Cleanup interface and add settings, widget, add skin temp reporting. +0.03: Move code for recording to this app diff --git a/apps/coretemp/recorder.js b/apps/coretemp/recorder.js new file mode 100644 index 000000000..1499605f3 --- /dev/null +++ b/apps/coretemp/recorder.js @@ -0,0 +1,31 @@ +(function(recorders) { + recorders.coretemp = function() { + var core = "", skin = ""; + var hasCore = false; + function onCore(c) { + core=c.core; + skin=c.skin; + hasCore = true; + } + return { + name : "Core", + fields : ["Core","Skin"], + getValues : () => { + var r = [core,skin]; + core = ""; + skin = ""; + return r; + }, + start : () => { + hasCore = false; + Bangle.on('CoreTemp', onCore); + }, + stop : () => { + hasCore = false; + Bangle.removeListener('CoreTemp', onCore); + }, + draw : (x,y) => g.setColor(hasCore?"#0f0":"#8f8").drawImage(atob("DAyBAAHh0js3EuDMA8A8AWBnDj9A8A=="),x,y) + }; + } +}) + diff --git a/apps/recorder/widget.js b/apps/recorder/widget.js index 359af721f..de465b7c1 100644 --- a/apps/recorder/widget.js +++ b/apps/recorder/widget.js @@ -90,32 +90,6 @@ draw : (x,y) => g.setColor(Bangle.isCharging() ? "#0f0" : "#ff0").drawImage(atob("DAwBAABgH4G4EYG4H4H4H4GIH4AA"),x,y) }; }, - temp:function() { - var core = 0, skin = 0; - var hasCore = false; - function onCore(c) { - core=c.core; - skin=c.skin; - hasCore = true; - } - return { - name : "Core", - fields : ["Core","Skin"], - getValues : () => { - var r = [core,skin]; - return r; - }, - start : () => { - hasCore = false; - Bangle.on('CoreTemp', onCore); - }, - stop : () => { - hasCore = false; - Bangle.removeListener('CoreTemp', onCore); - }, - draw : (x,y) => g.setColor(hasCore?"#0f0":"#8f8").drawImage(atob("DAwBAAAOAKPOfgZgZgZgZgfgPAAA"),x,y) - }; - }, steps:function() { var lastSteps = 0; return { From 6b22bd84866a13e1d21f29fca670109f4cb10059 Mon Sep 17 00:00:00 2001 From: Martin Boonk Date: Wed, 12 Jan 2022 22:52:03 +0100 Subject: [PATCH 277/315] Bump version and changelog for recorder --- apps.json | 2 +- apps/recorder/ChangeLog | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/apps.json b/apps.json index e3964fd2a..d121ddccc 100644 --- a/apps.json +++ b/apps.json @@ -770,7 +770,7 @@ "id": "recorder", "name": "Recorder (BETA)", "shortName": "Recorder", - "version": "0.06", + "version": "0.07", "description": "Record GPS position, heart rate and more in the background, then download to your PC.", "icon": "app.png", "tags": "tool,outdoors,gps,widget", diff --git a/apps/recorder/ChangeLog b/apps/recorder/ChangeLog index dbf086f7d..e2ae0111b 100644 --- a/apps/recorder/ChangeLog +++ b/apps/recorder/ChangeLog @@ -8,3 +8,6 @@ Fix execution of other recorders (*.recorder.js) Modified icons and colors for better visibility Only show plotting speed if Latitude is available +0.07: Add recording for Barometer + Record all HRM events + Move recording for CoreTemp to its own app From 225c5566cda17464b5a5d6be0af2a06188b4b9ac Mon Sep 17 00:00:00 2001 From: Martin Boonk Date: Wed, 12 Jan 2022 20:26:07 +0100 Subject: [PATCH 278/315] Move previously registered HRM listener over if needed --- apps/bthrm/boot.js | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/apps/bthrm/boot.js b/apps/bthrm/boot.js index 0aa8d5c96..85333feb1 100644 --- a/apps/bthrm/boot.js +++ b/apps/bthrm/boot.js @@ -12,7 +12,6 @@ Bangle.isHRMOn = function() { var settings = require('Storage').readJSON("bthrm.json", true) || {}; - print(settings); if (settings.enabled && !settings.replace){ return origIsHRMOn(); } else if (settings.enabled && settings.replace){ @@ -107,8 +106,20 @@ if (settings.enabled || !isOn){ Bangle.setBTHRMPower(isOn, app); } - if (settings.enabled && !settings.replace || !isOn){ + if ((settings.enabled && !settings.replace) || !settings.enabled || !isOn){ origSetHRMPower(isOn, app); } } + + var settings = require('Storage').readJSON("bthrm.json", true) || {}; + if (settings.enabled && settings.replace){ + if (!(Bangle._PWR===undefined) && !(Bangle._PWR.HRM===undefined)){ + for (var i = 0; i < Bangle._PWR.HRM.length; i++){ + var app = Bangle._PWR.HRM[i]; + origSetHRMPower(0, app); + Bangle.setBTHRMPower(1, app); + if (Bangle._PWR.HRM===undefined) break; + } + } +} })(); From 92139253bebb1846d910e1392d83689e6b31886a Mon Sep 17 00:00:00 2001 From: Martin Boonk Date: Wed, 12 Jan 2022 19:44:18 +0100 Subject: [PATCH 279/315] Set src property if emitting an event --- apps/bthrm/boot.js | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/apps/bthrm/boot.js b/apps/bthrm/boot.js index 85333feb1..fbc872630 100644 --- a/apps/bthrm/boot.js +++ b/apps/bthrm/boot.js @@ -68,13 +68,11 @@ var interval = dv.getUint16(idx,1); // in milliseconds }*/ - - var eventName = settings.replace ? "HRM" : "BTHRM"; - - Bangle.emit(eventName, { + Bangle.emit(settings.replace?"HRM":"BTHRM", { bpm:bpm, - confidence:100 - }); + confidence:100, + src:settings.replace?"bthrm":undefined + }); }); return characteristic.startNotifications(); }).then(function() { From b02befe3dd0b9ba65b46339acee17358bd9c85d8 Mon Sep 17 00:00:00 2001 From: Martin Boonk Date: Wed, 12 Jan 2022 19:46:15 +0100 Subject: [PATCH 280/315] Record empty string if no value instead of 0 --- apps/bthrm/recorder.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/bthrm/recorder.js b/apps/bthrm/recorder.js index 40f64a676..b1c27660d 100644 --- a/apps/bthrm/recorder.js +++ b/apps/bthrm/recorder.js @@ -1,15 +1,15 @@ (function(recorders) { recorders.bthrm = function() { - var bpm = 0; + var bpm = ""; function onHRM(h) { - bpm = h.bpm; + bpm = h.bpm; } return { name : "BTHR", fields : ["BT Heartrate"], getValues : () => { result = [bpm]; - bpm = 0; + bpm = ""; return result; }, start : () => { From e0a4cea3b8d3666686d11fb8387b135915c4b88c Mon Sep 17 00:00:00 2001 From: Martin Boonk Date: Wed, 12 Jan 2022 23:24:38 +0100 Subject: [PATCH 281/315] Explicit call to setBTHRMPower is not needed --- apps/bthrm/bthrm.js | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/bthrm/bthrm.js b/apps/bthrm/bthrm.js index 7c80c735f..81d5d5997 100644 --- a/apps/bthrm/bthrm.js +++ b/apps/bthrm/bthrm.js @@ -35,7 +35,6 @@ Bangle.on('BTHRM', onBtHrm); Bangle.on('HRM', onHrm); Bangle.setHRMPower(1,'bthrm') -Bangle.setBTHRMPower(1,'bthrm') g.clear(); Bangle.loadWidgets(); From 9aba113acb72fbd6b277844cfc5abfe7a3a02ca2 Mon Sep 17 00:00:00 2001 From: Martin Boonk Date: Wed, 12 Jan 2022 23:31:44 +0100 Subject: [PATCH 282/315] Show actual source for HRM event --- apps/bthrm/bthrm.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/bthrm/bthrm.js b/apps/bthrm/bthrm.js index 81d5d5997..712344b11 100644 --- a/apps/bthrm/bthrm.js +++ b/apps/bthrm/bthrm.js @@ -9,13 +9,14 @@ function draw(y, event, type, counter) { var px = g.getWidth()/2; g.reset(); g.setFontAlign(0,0); - g.clearRect(0,y,g.getWidth(),y+80); + g.clearRect(0,y,g.getWidth(),y+75); if (type == null || event == null || counter == 0) return; var str = event.bpm + ""; g.setFontVector(40).drawString(str,px,y+20); str = "Confidence: " + event.confidence; g.setFontVector(12).drawString(str,px,y+50); str = "Event: " + type; + if (type == "HRM") str += " Source: " + (event.src ? event.src : "internal"); g.setFontVector(12).drawString(str,px,y+60); } From 56e33ed98ba854f52a807cd066ca139cfbf28062 Mon Sep 17 00:00:00 2001 From: Martin Boonk Date: Wed, 12 Jan 2022 23:10:36 +0100 Subject: [PATCH 283/315] Bump version and changelog --- apps.json | 2 +- apps/bthrm/ChangeLog | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/apps.json b/apps.json index 4c6f3bdcf..dc887d255 100644 --- a/apps.json +++ b/apps.json @@ -1042,7 +1042,7 @@ "id": "bthrm", "name": "Bluetooth Heart Rate Monitor", "shortName": "BT HRM", - "version": "0.02", + "version": "0.03", "description": "Overrides Bangle.js's build in heart rate monitor with an external Bluetooth one.", "icon": "app.png", "type": "app", diff --git a/apps/bthrm/ChangeLog b/apps/bthrm/ChangeLog index 27a58dd78..481d855c8 100644 --- a/apps/bthrm/ChangeLog +++ b/apps/bthrm/ChangeLog @@ -2,3 +2,6 @@ 0.02: Make overriding the HRM event optional Emit BTHRM event for external sensor Add recorder app plugin +0.03: Prevent readings from internal sensor mixing into BT values + Mark events with src property + Show actual source of event in app From a98a6015b1c381476901aae9abb89370034c243b Mon Sep 17 00:00:00 2001 From: hughbarney Date: Wed, 12 Jan 2022 22:45:42 +0000 Subject: [PATCH 284/315] Simple Pedometer and Lato Pedometer widgets --- apps.json | 32 ++++++++++++++++++++++++++++++++ apps/widpa/README.md | 16 ++++++++++++++++ apps/widpa/screenshot_widpa.png | Bin 0 -> 246 bytes apps/widpa/widpa.wid.js | 17 +++++++++++++++++ apps/widpb/README.md | 17 +++++++++++++++++ apps/widpb/screenshot_widpb.png | Bin 0 -> 338 bytes apps/widpb/widpb.wid.js | 20 ++++++++++++++++++++ 7 files changed, 102 insertions(+) create mode 100644 apps/widpa/README.md create mode 100644 apps/widpa/screenshot_widpa.png create mode 100644 apps/widpa/widpa.wid.js create mode 100644 apps/widpb/README.md create mode 100644 apps/widpb/screenshot_widpb.png create mode 100644 apps/widpb/widpb.wid.js diff --git a/apps.json b/apps.json index 4c6f3bdcf..56ddbed2d 100644 --- a/apps.json +++ b/apps.json @@ -5577,5 +5577,37 @@ "data": [ {"name":"banglexercise.json"} ] + }, + { + "id": "widpa", + "name": "Simple Pedometer", + "shortName":"Simple Pedometer", + "icon": "screenshot_widpa.png", + "screenshots": [{"url":"screenshot_widpa.png"}], + "version":"0.01", + "type": "widget", + "supports": ["BANGLEJS", "BANGLEJS2"], + "readme": "README.md", + "description": "Displays the current step count from `Bangle.getHealthStatus(\"day\").steps` in 12x16 font, requires firmware v2.11.21 or later", + "tags": "widget,battery", + "storage": [ + {"name":"widpa.wid.js","url":"widpa.wid.js"} + ] + }, + { + "id": "widpb", + "name": "Lato Pedometer", + "shortName":"Lato Pedometer", + "icon": "screenshot_widpb.png", + "screenshots": [{"url":"screenshot_widpb.png"}], + "version":"0.01", + "type": "widget", + "supports": ["BANGLEJS", "BANGLEJS2"], + "readme": "README.md", + "description": "Displays the current step count from `Bangle.getHealthStatus(\"day\").steps` in the Lato font, requires firmware v2.11.21 or later", + "tags": "widget,battery", + "storage": [ + {"name":"widpb.wid.js","url":"widpb.wid.js"} + ] } ] diff --git a/apps/widpa/README.md b/apps/widpa/README.md new file mode 100644 index 000000000..92fbb8c11 --- /dev/null +++ b/apps/widpa/README.md @@ -0,0 +1,16 @@ +# Simple Pedometer Widget + +*Displays the current step count from `Bangle.getHealthStatus("day").steps` in (6x8,2) font, Requires firmware v2.11.21 or later* + +* Designed to be small, minimal, does one thing well, no settings +* Supports Bangle 1 and Bangle 2 + +## Notes + +* Requires firmware v2.11.21 or later +* `Bangle.getHealthStatus("day").steps` is reset to zero if you reboot your watch with a long BTN Press +* The step count displayed may be a few steps more than that reported by widpedpm as widpedom may not always be loaded. + +![](screenshot_widpa.png) + +Written by: [Hugh Barney](https://github.com/hughbarney) For support and discussion please post in the [Bangle JS Forum](http://forum.espruino.com/microcosms/1424/) diff --git a/apps/widpa/screenshot_widpa.png b/apps/widpa/screenshot_widpa.png new file mode 100644 index 0000000000000000000000000000000000000000..e33550f50d6376cdec0f5faeaaec87a548e979f3 GIT binary patch literal 246 zcmVPx#ut`KgR9HvtR?!ZCAPAKI|7hFVXv)Gv%MBU5LKnv!1l3w=IsBm{;Y7hy!if+i zt`bDlHCbC=GLK*SD_<(j-;?;SN*ql>V`}XP=SdudYmIA4cS;~Itw=-?;acNE5}LPn zd3@HcJOjg-2t@*I71R-{-B#^qQX)w-?ftr)kiF%s-rLE#9ainMijU5kr=Io{-~9)k w#YeOA%wRYYNItLexL2&#j%#(L5?&O$01ECQ%Y=MG this.width) {this.width = w; setTimeout(() => Bangle.drawWidgets(),10); return;} + g.reset(); + g.setColor(g.theme.bg); + g.fillRect(this.x, this.y, this.x + this.width, this.y + 23); + g.setColor(g.theme.fg); + g.setFont('6x8',2); + g.setFontAlign(-1, 0); + g.drawString(steps, this.x, this.y + 12); +}}; diff --git a/apps/widpb/README.md b/apps/widpb/README.md new file mode 100644 index 000000000..bec127b6b --- /dev/null +++ b/apps/widpb/README.md @@ -0,0 +1,17 @@ +# Lato Pedometer Widget + +*Displays the current step count from `Bangle.getHealthStatus("day").steps` in the Lato font, Requires firmware v2.11.21 or later* + +* Designed to be minimal, does one thing well, no settings +* Supports Bangle 1 and Bangle 2 + +## Notes + +* Requires firmware v2.11.21 or later +* Uses the Lato custom font, so memory footprint is 500 bytes larger than 'Simple Pedometer Widget' +* `Bangle.getHealthStatus("day").steps` is reset to zero if you reboot your watch with a long BTN Press +* The step count displayed may be a few steps more than that reported by widpedpm as widpedom may not always be loaded. + +![](screenshot_widpb.png) + +Written by: [Hugh Barney](https://github.com/hughbarney) For support and discussion please post in the [Bangle JS Forum](http://forum.espruino.com/microcosms/1424/) diff --git a/apps/widpb/screenshot_widpb.png b/apps/widpb/screenshot_widpb.png new file mode 100644 index 0000000000000000000000000000000000000000..af1222e7e8663af2945d6f4c2978cad7a4cac5b8 GIT binary patch literal 338 zcmV-Y0j>UtP)Px$3`s;mR9HvtSkVrIAPhVH|D!RO!{FR#y9Yyvz8N=Y*KTlEYOVFR!BajWi>bK3 zBBhk8=207sF{40i+cA6eb$e`xCF&8hNkpP=jL6vhSvZDZ(xStFt2!bhkuB zk)~GG^WKS!M)1QD!3{x;yRIn6%d>;et2%04rqT+g+g&SrF0c*j5uRBqO$7OQ this.width) {this.width = w; setTimeout(() => Bangle.drawWidgets(),10); return;} + g.reset(); + g.setColor(g.theme.bg); + g.fillRect(this.x, this.y, this.x + this.width, this.y + 23); // erase background + g.setColor(g.theme.fg); + // Lato from fonts.google.com, Actual height 17 (17 - 1), Numeric only + const scale = 1; + g.setFontCustom(atob("AAAAABwAAOAAAgAAHAADwAD4AB8AB8AA+AAeAADAAAAOAAP+AH/8B4DwMAGBgAwMAGBgAwOAOA//gD/4AD4AAAAAAAABgAAcAwDAGAwAwP/+B//wAAGAAAwAAGAAAAAAAAIAwHgOA4DwMA+BgOwMDmBg4wOeGA/gwDwGAAAAAAAAAGAHA8A4DwMAGBhAwMMGBjgwOcOA+/gDj4AAAAABgAAcAAHgADsAA5gAOMAHBgBwMAP/+B//wABgAAMAAAAAAAgD4OB/AwOYGBjAwMYGBjBwMe8Bh/AIHwAAAAAAAAAfAAP8AHxwB8GAdgwPMGBxgwMOOAB/gAH4AAAAAAABgAAMAABgAwMAeBgPgMHwBj4AN8AB+AAPAABAAAAAAAMfAH38B/xwMcGBhgwMMGBjgwP+OA+/gDj4AAAAAAAAOAAH4AA/gQMMGBgzwME8BhvAOPgA/4AD8AAEAAAAAAGAwA4OAHBwAAA="), 46, atob("BAgMDAwMDAwMDAwMBQ=="), 21+(scale<<8)+(1<<16)); + g.setFontAlign(-1, 0); + g.drawString(steps, this.x, this.y + 12); +}}; From 60bb06a655595a6bab3f539c4f266eea1f934f63 Mon Sep 17 00:00:00 2001 From: hughbarney Date: Wed, 12 Jan 2022 22:46:16 +0000 Subject: [PATCH 285/315] Simple Pedometer and Lato Pedometer widgets --- apps/widpa/ChangeLog | 1 + apps/widpb/ChangeLog | 1 + 2 files changed, 2 insertions(+) create mode 100644 apps/widpa/ChangeLog create mode 100644 apps/widpb/ChangeLog diff --git a/apps/widpa/ChangeLog b/apps/widpa/ChangeLog new file mode 100644 index 000000000..7b83706bf --- /dev/null +++ b/apps/widpa/ChangeLog @@ -0,0 +1 @@ +0.01: First release diff --git a/apps/widpb/ChangeLog b/apps/widpb/ChangeLog new file mode 100644 index 000000000..7b83706bf --- /dev/null +++ b/apps/widpb/ChangeLog @@ -0,0 +1 @@ +0.01: First release From 223f6b6b8120f34e5063e7fa4ccde04deeb22f83 Mon Sep 17 00:00:00 2001 From: Danny <31635744+DDDanny@users.noreply.github.com> Date: Wed, 12 Jan 2022 23:57:44 +0100 Subject: [PATCH 286/315] fixes #1271 & some code rework + moved settings-helper method def to load settings method + settingsfile as const + isBangle1 via HWVERSION==1 --- apps.json | 2 +- apps/antonclk/ChangeLog | 5 ++++- apps/antonclk/README.md | 6 +++--- apps/antonclk/app.js | 36 +++++++++++++++++++++++------------- apps/antonclk/settings.js | 4 ++-- 5 files changed, 33 insertions(+), 20 deletions(-) diff --git a/apps.json b/apps.json index 4c6f3bdcf..dd2ddbcb3 100644 --- a/apps.json +++ b/apps.json @@ -4279,7 +4279,7 @@ { "id": "antonclk", "name": "Anton Clock", - "version": "0.05", + "version": "0.06", "description": "A clock using the bold Anton font, optionally showing seconds and date in ISO-8601 format.", "readme":"README.md", "icon": "app.png", diff --git a/apps/antonclk/ChangeLog b/apps/antonclk/ChangeLog index fdf20c175..4dca8053e 100644 --- a/apps/antonclk/ChangeLog +++ b/apps/antonclk/ChangeLog @@ -4,4 +4,7 @@ 0.04: Clock can optionally show seconds, date optionally in ISO-8601 format, weekdays and uppercase configurable, too. 0.05: Clock can optionally show ISO-8601 calendar weeknumber (default: Off) when weekday name "Off": week #: - when weekday name "On": weekday name is cut at 6th position and .# is added \ No newline at end of file + when weekday name "On": weekday name is cut at 6th position and .# is added +0.06: fixes #1271 - wrong settings name + when weekday name and calendar weeknumber are on then display is # + week is buffered until date or timezone changes \ No newline at end of file diff --git a/apps/antonclk/README.md b/apps/antonclk/README.md index 85c03788d..28a38f5fd 100644 --- a/apps/antonclk/README.md +++ b/apps/antonclk/README.md @@ -40,9 +40,9 @@ The main menu contains several settings covering Anton clock in general. * **Show Weekday** - Weekday is shown in the time presentation without seconds. Weekday name depends on the current locale. If seconds are shown, the weekday is never shown as there is not enough space on the watch face. -* **Show Weeknumber** - Week-number (ISO-8601) is shown. (default: Off) -If "Show Weekday" is "Off" the week-number is displayed as "week #:". -If "Show Weekday" is "On" the weekday name is cut at 6th position and suffixed with ".#". +* **Show CalWeek** - Week-number (ISO-8601) is shown. (default: Off) +If "Show Weekday" is "Off" displays the week-number as "week #". +If "Show Weekday" is "On" displays "weekday name short" with " #" . If seconds are shown, the week number is never shown as there is not enough space on the watch face. * **Vector font** - Use the built-in vector font for dates and weekday. This can improve readability. diff --git a/apps/antonclk/app.js b/apps/antonclk/app.js index 05758cbfd..7d8c8ce89 100644 --- a/apps/antonclk/app.js +++ b/apps/antonclk/app.js @@ -1,6 +1,6 @@ // Clock with large digits using the "Anton" bold font -var SETTINGSFILE = "antonclk.json"; +const SETTINGSFILE = "antonclk.json"; Graphics.prototype.setFontAnton = function(scale) { // Actual height 69 (68 - 0) @@ -28,7 +28,7 @@ var drawTimeout; var queueMillis = 1000; var secondsScreen = true; -var isBangle1 = (g.getWidth() == 240); +var isBangle1 = (process.env.HWVERSION == 1); //For development purposes /* @@ -50,13 +50,11 @@ require('Storage').writeJSON(SETTINGSFILE, { require('Storage').erase(SETTINGSFILE); */ -// Helper method for loading the settings -function def(value, def) { - return (value !== undefined ? value : def); -} - // Load settings function loadSettings() { + // Helper function default setting + function def (value, def) {return value !== undefined ? value : def;} + var settings = require('Storage').readJSON(SETTINGSFILE, true) || {}; secondsMode = def(settings.secondsMode, "Never"); secondsColoured = def(settings.secondsColoured, true); @@ -104,7 +102,14 @@ function isoStr(date) { return date.getFullYear() + "-" + ("0" + (date.getMonth() + 1)).substr(-2) + "-" + ("0" + date.getDate()).substr(-2); } +var calWeekBuffer = [false,false,false]; //buffer tz, date, week no (once calculated until other tz or date is requested) function ISO8601calWeek(date) { //copied from: https://gist.github.com/IamSilviu/5899269#gistcomment-3035480 + console.log(date); + dateNoTime = date; dateNoTime.setHours(0,0,0,0); + console.log(dateNoTime); + if (calWeekBuffer[0] === date.getTimezoneOffset() && calWeekBuffer[1] === dateNoTime) return calWeekBuffer[2]; + calWeekBuffer[0] = date.getTimezoneOffset(); + calWeekBuffer[1] = dateNoTime; var tdt = new Date(date.valueOf()); var dayn = (date.getDay() + 6) % 7; tdt.setDate(tdt.getDate() - dayn + 3); @@ -113,7 +118,8 @@ function ISO8601calWeek(date) { //copied from: https://gist.github.com/IamSilviu if (tdt.getDay() !== 4) { tdt.setMonth(0, 1 + ((4 - tdt.getDay()) + 7) % 7); } - return 1 + Math.ceil((firstThursday - tdt) / 604800000); + calWeekBuffer[2] = 1 + Math.ceil((firstThursday - tdt) / 604800000); + return calWeekBuffer[2]; } function doColor() { @@ -186,13 +192,17 @@ function draw() { else g.setFont("6x8", 2); g.drawString(dateStr, x, y); - if (weekDay || calWeek) { - var dowwumStr = require("locale").dow(date); + if (calWeek || weekDay) { + var dowcwStr = ""; if (calWeek) - dowwumStr = (weekDay ? dowwumStr.substr(0,Math.min(dowwumStr.length,6)) + (dowwumStr.length>=6 ? "." : "") : "week ") + "#" + ISO8601calWeek(date); //TODO: locale for "week" + dowcwStr = " #" + ("0" + ISO8601calWeek(date)).substring(-2); + if (weekDay) + dowcwStr = require("locale").dow(date, calWeek ? 1 : 0) + dowcwStr; //weekDay e.g. Monday or weekDayShort # e.g. Mon #01 + else //week #01 + dowcwStr = /*LANG*/"week" + dowcwStr; if (upperCase) - dowwumStr = dowwumStr.toUpperCase(); - g.drawString(dowwumStr, x, y + (vectorFont ? 26 : 16)); + dowcwStr = dowcwStr.toUpperCase(); + g.drawString(dowcwStr, x, y + (vectorFont ? 26 : 16)); } } diff --git a/apps/antonclk/settings.js b/apps/antonclk/settings.js index 293aa0438..45c89f0a4 100644 --- a/apps/antonclk/settings.js +++ b/apps/antonclk/settings.js @@ -48,10 +48,10 @@ } }, "Show Weeknumber": { - value: (settings.weekNum !== undefined ? settings.weekNum : true), + value: (settings.calWeek !== undefined ? settings.calWeek : false), format: v => v ? "On" : "Off", onchange: v => { - settings.weekNum = v; + settings.calWeek = v; writeSettings(); } }, From b9031b1844be8ad0f3951c8baa9ea301d1c70085 Mon Sep 17 00:00:00 2001 From: Danny <31635744+DDDanny@users.noreply.github.com> Date: Thu, 13 Jan 2022 00:06:49 +0100 Subject: [PATCH 287/315] settings txt weeknumber was to long --- apps/antonclk/settings.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/antonclk/settings.js b/apps/antonclk/settings.js index 45c89f0a4..e452b02c7 100644 --- a/apps/antonclk/settings.js +++ b/apps/antonclk/settings.js @@ -47,7 +47,7 @@ writeSettings(); } }, - "Show Weeknumber": { + "Show CalWeek": { value: (settings.calWeek !== undefined ? settings.calWeek : false), format: v => v ? "On" : "Off", onchange: v => { From 6098af08b8d36a6b8cdf33a8f440802de876ac69 Mon Sep 17 00:00:00 2001 From: Danny <31635744+DDDanny@users.noreply.github.com> Date: Thu, 13 Jan 2022 01:02:02 +0100 Subject: [PATCH 288/315] removed two log statements --- apps/antonclk/app.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/apps/antonclk/app.js b/apps/antonclk/app.js index 7d8c8ce89..7b40d8eb5 100644 --- a/apps/antonclk/app.js +++ b/apps/antonclk/app.js @@ -104,9 +104,7 @@ function isoStr(date) { var calWeekBuffer = [false,false,false]; //buffer tz, date, week no (once calculated until other tz or date is requested) function ISO8601calWeek(date) { //copied from: https://gist.github.com/IamSilviu/5899269#gistcomment-3035480 - console.log(date); dateNoTime = date; dateNoTime.setHours(0,0,0,0); - console.log(dateNoTime); if (calWeekBuffer[0] === date.getTimezoneOffset() && calWeekBuffer[1] === dateNoTime) return calWeekBuffer[2]; calWeekBuffer[0] = date.getTimezoneOffset(); calWeekBuffer[1] = dateNoTime; From 5e4cd77313f3f25193d50365b4bde8c4bbc539d7 Mon Sep 17 00:00:00 2001 From: Andreas Rozek Date: Thu, 13 Jan 2022 06:41:37 +0100 Subject: [PATCH 289/315] Update apps.json --- apps.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps.json b/apps.json index b90deb045..bef974af8 100644 --- a/apps.json +++ b/apps.json @@ -32,13 +32,13 @@ { "id": "ac_ac", "name": "A Configurable Analog Clock", "shortName":"Configurable Clock", - "version":"0.01", + "version":"0.02", "description": "AC-AC, a highly customizable analog clock", "icon": "app-icon.png", "type": "clock", "tags": "clock", "supports" : ["BANGLEJS2"], - "allow_emulator": true, + "allow_emulator": false, "screenshots": [{"url":"app-screenshot.png"}], "readme": "README.md", "custom": "Customizer.html", From ee02b17196fe4b62e8049ab619be3e55102ae21e Mon Sep 17 00:00:00 2001 From: Andreas Rozek Date: Thu, 13 Jan 2022 06:42:13 +0100 Subject: [PATCH 290/315] Update Customizer.html --- apps/ac_ac/Customizer.html | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/apps/ac_ac/Customizer.html b/apps/ac_ac/Customizer.html index 2846352d6..8cddbb4da 100644 --- a/apps/ac_ac/Customizer.html +++ b/apps/ac_ac/Customizer.html @@ -101,7 +101,7 @@