From 24d35eca2cf4e676832362803a378e453871e2db Mon Sep 17 00:00:00 2001
From: Red-The-Hunter <62763030+Red-The-Hunter@users.noreply.github.com>
Date: Wed, 15 Apr 2020 18:54:29 +0800
Subject: [PATCH 001/101] Update stopwatch.js
---
apps/swatch/stopwatch.js | 67 ++++++++++++++++++++++++++++------------
1 file changed, 47 insertions(+), 20 deletions(-)
diff --git a/apps/swatch/stopwatch.js b/apps/swatch/stopwatch.js
index 6f8ad9e34..478c22619 100644
--- a/apps/swatch/stopwatch.js
+++ b/apps/swatch/stopwatch.js
@@ -1,8 +1,11 @@
+var tTotal = Date.now();
var tStart = Date.now();
var tCurrent = Date.now();
var started = false;
-var timeY = 60;
+var timeY = 45;
var hsXPos = 0;
+var TtimeY = 75;
+var ThsXPos = 0;
var lapTimes = [];
var displayInterval;
@@ -12,6 +15,7 @@ function timeToText(t) {
var hs = Math.floor(t/10)%100;
return mins+":"+("0"+secs).substr(-2)+"."+("0"+hs).substr(-2);
}
+
function updateLabels() {
g.reset(1);
g.clearRect(0,23,g.getWidth()-1,g.getHeight()-24);
@@ -24,35 +28,53 @@ function updateLabels() {
g.setFontAlign(-1,-1);
for (var i in lapTimes) {
if (i<16)
- {g.drawString(lapTimes.length-i+": "+timeToText(lapTimes[i]),35,timeY + 30 + i*8);}
+ {g.drawString(lapTimes.length-i+": "+timeToText(lapTimes[i]),35,timeY + 40 + i*8);}
else if (i<32)
- {g.drawString(lapTimes.length-i+": "+timeToText(lapTimes[i]),125,timeY + 30 + (i-16)*8);}
+ {g.drawString(lapTimes.length-i+": "+timeToText(lapTimes[i]),125,timeY + 40 + (i-16)*8);}
}
drawsecs();
}
+
function drawsecs() {
var t = tCurrent-tStart;
- g.reset(1);
- g.setFont("Vector",48);
- g.setFontAlign(0,0);
+ var Tt = tCurrent-tTotal;
var secs = Math.floor(t/1000)%60;
var mins = Math.floor(t/60000);
var txt = mins+":"+("0"+secs).substr(-2);
+ var Tsecs = Math.floor(Tt/1000)%60;
+ var Tmins = Math.floor(Tt/60000);
+ var Ttxt = Tmins+":"+("0"+Tsecs).substr(-2);
var x = 100;
- g.clearRect(0,timeY-26,200,timeY+26);
- g.drawString(txt,x,timeY);
+ var Tx = 125;
+ g.reset(1);
+ g.setFont("Vector",38);
+ g.setFontAlign(0,0);
+ g.clearRect(0,timeY-21,200,timeY+21);
+ g.drawString(Ttxt,x,timeY);
hsXPos = 5+x+g.stringWidth(txt)/2;
+ g.setFont("6x8",2);
+ g.clearRect(0,TtimeY-7,200,TtimeY+7);
+ g.drawString(txt,Tx,TtimeY);
+ ThsXPos = 5+Tx+g.stringWidth(Ttxt)/2;
drawms();
}
+
function drawms() {
var t = tCurrent-tStart;
var hs = Math.floor(t/10)%100;
+ var Tt = tCurrent-tTotal;
+ var Ths = Math.floor(Tt/10)%100;
g.setFontAlign(-1,0);
g.setFont("6x8",2);
g.clearRect(hsXPos,timeY,220,timeY+20);
- g.drawString("."+("0"+hs).substr(-2),hsXPos,timeY+10);
+ g.drawString("."+("0"+Ths).substr(-2),hsXPos-5,timeY+14);
+ g.setFont("6x8",1);
+ g.clearRect(ThsXPos,TtimeY,220,TtimeY+5);
+ g.drawString("."+("0"+hs).substr(-2),ThsXPos-5,TtimeY+3);
}
+
function getLapTimesArray() {
+ lapTimes.push(tCurrent-tTotal);
return lapTimes.map(timeToText).reverse();
}
@@ -61,7 +83,8 @@ setWatch(function() { // Start/stop
Bangle.beep();
if (started)
tStart = Date.now()+tStart-tCurrent;
- tCurrent = Date.now();
+ tTotal = Date.now()+tTotal-tCurrent;
+ tCurrent = Date.now();
if (displayInterval) {
clearInterval(displayInterval);
displayInterval = undefined;
@@ -69,37 +92,41 @@ setWatch(function() { // Start/stop
updateLabels();
if (started)
displayInterval = setInterval(function() {
- var last = tCurrent;
- if (started) tCurrent = Date.now();
- if (Math.floor(last/1000)!=Math.floor(tCurrent/1000))
- drawsecs();
- else
- drawms();
+ var last = tCurrent;
+ if (started) tCurrent = Date.now();
+ if (Math.floor(last/1000)!=Math.floor(tCurrent/1000))
+ drawsecs();
+ else
+ drawms();
}, 20);
}, BTN2, {repeat:true});
+
setWatch(function() { // Lap
Bangle.beep();
if (started) {
tCurrent = Date.now();
lapTimes.unshift(tCurrent-tStart);
}
- tStart = tCurrent;
if (!started) { // save
var timenow= Date();
var filename = "swatch-"+(new Date()).toISOString().substr(0,16).replace("T","_")+".json";
// this maxes out the 28 char maximum
+ lapTimes.unshift(tCurrent-tStart);
require("Storage").writeJSON(filename, getLapTimesArray());
+ tStart = tCurrent = tTotal = Date.now();
+ lapTimes = [];
E.showMessage("Laps Saved","Stopwatch");
setTimeout(updateLabels, 1000);
} else {
+ tStart = tCurrent;
updateLabels();
}
}, BTN1, {repeat:true});
setWatch(function() { // Reset
if (!started) {
- Bangle.beep();
- tStart = tCurrent = Date.now();
- lapTimes = [];
+ Bangle.beep();
+ tStart = tCurrent = tTotal = Date.now();
+ lapTimes = [];
}
updateLabels();
}, BTN3, {repeat:true});
From 9a03c9bcce110c428d7334a11b01e4b48019ce81 Mon Sep 17 00:00:00 2001
From: Red-The-Hunter <62763030+Red-The-Hunter@users.noreply.github.com>
Date: Wed, 15 Apr 2020 18:57:52 +0800
Subject: [PATCH 002/101] Update ChangeLog
---
apps/swatch/ChangeLog | 1 +
1 file changed, 1 insertion(+)
diff --git a/apps/swatch/ChangeLog b/apps/swatch/ChangeLog
index 3246eeced..9a037fa41 100644
--- a/apps/swatch/ChangeLog
+++ b/apps/swatch/ChangeLog
@@ -5,3 +5,4 @@
Fixed bug from 0.01 where BN1 (reset) could clear the lap log when timer is running
0.04: Changed save file filename, add interface.html to allow laps to be loaded
0.05: Added widgets
+0.06: Added total running time, moved lap time to smaller display, total run time now appends as first entry in array, saving now saves last lap as well
From 5d588d6d696d00133e28269e4d125595faa8d89e Mon Sep 17 00:00:00 2001
From: Red-The-Hunter <62763030+Red-The-Hunter@users.noreply.github.com>
Date: Wed, 15 Apr 2020 19:11:54 +0800
Subject: [PATCH 003/101] Update interface.html
---
apps/swatch/interface.html | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/apps/swatch/interface.html b/apps/swatch/interface.html
index 928c5fe39..bfa7f8193 100644
--- a/apps/swatch/interface.html
+++ b/apps/swatch/interface.html
@@ -20,7 +20,7 @@ function getLapTimes() {
html += `
@@ -32,7 +32,7 @@ function getLapTimes() {
- ${ lap.d.map((d,n)=>`${n+1} | ${d} |
`).join("\n") }
+ ${ lap.d.map((d+1,n)=>`${n+1} | ${d+1} |
`).join("\n") }
From 70e9c23c54f5898a83cdf1abb61b17e5304fa66d Mon Sep 17 00:00:00 2001
From: Red-The-Hunter <62763030+Red-The-Hunter@users.noreply.github.com>
Date: Wed, 15 Apr 2020 19:17:03 +0800
Subject: [PATCH 004/101] Update interface.html
---
apps/swatch/interface.html | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/apps/swatch/interface.html b/apps/swatch/interface.html
index bfa7f8193..735f643a8 100644
--- a/apps/swatch/interface.html
+++ b/apps/swatch/interface.html
@@ -20,7 +20,7 @@ function getLapTimes() {
html += `
From 02aaf2dd166ba350019c3eb44eba757ba835dfef Mon Sep 17 00:00:00 2001
From: Red-The-Hunter <62763030+Red-The-Hunter@users.noreply.github.com>
Date: Wed, 15 Apr 2020 19:22:07 +0800
Subject: [PATCH 005/101] Update interface.html
---
apps/swatch/interface.html | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/apps/swatch/interface.html b/apps/swatch/interface.html
index 735f643a8..53f0dd503 100644
--- a/apps/swatch/interface.html
+++ b/apps/swatch/interface.html
@@ -20,7 +20,7 @@ function getLapTimes() {
html += `
From 0f20176280e15875b8c9c3ef06619b887c3c28c3 Mon Sep 17 00:00:00 2001
From: Red-The-Hunter <62763030+Red-The-Hunter@users.noreply.github.com>
Date: Wed, 15 Apr 2020 19:22:51 +0800
Subject: [PATCH 006/101] Update interface.html
---
apps/swatch/interface.html | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/apps/swatch/interface.html b/apps/swatch/interface.html
index 53f0dd503..928c5fe39 100644
--- a/apps/swatch/interface.html
+++ b/apps/swatch/interface.html
@@ -32,7 +32,7 @@ function getLapTimes() {
- ${ lap.d.map((d+1,n)=>`${n+1} | ${d+1} |
`).join("\n") }
+ ${ lap.d.map((d,n)=>`${n+1} | ${d} |
`).join("\n") }
From 32e811b2312ab99bf7ba1bcf466621c0d0a30bc2 Mon Sep 17 00:00:00 2001
From: Red-The-Hunter <62763030+Red-The-Hunter@users.noreply.github.com>
Date: Wed, 15 Apr 2020 19:32:17 +0800
Subject: [PATCH 008/101] Update apps.json
---
apps.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/apps.json b/apps.json
index 0643ad6de..5fae8f482 100644
--- a/apps.json
+++ b/apps.json
@@ -399,7 +399,7 @@
{ "id": "swatch",
"name": "Stopwatch",
"icon": "stopwatch.png",
- "version":"0.05",
+ "version":"0.06",
"interface": "interface.html",
"description": "Simple stopwatch with Lap Time logging to a JSON file",
"tags": "health",
From b8226cce8fbfaa0a86c5f13a288a6d920be74bd1 Mon Sep 17 00:00:00 2001
From: OmegaRogue
Date: Wed, 15 Apr 2020 14:00:01 +0200
Subject: [PATCH 009/101] Added DANE
Signed-off-by: OmegaRogue
---
apps.json | 22 +++++
apps/dane/ChangeLog | 4 +
apps/dane/add_to_apps.json | 22 +++++
apps/dane/app-icon.js | 1 +
apps/dane/app.js | 163 +++++++++++++++++++++++++++++++++++++
apps/dane/app.png | Bin 0 -> 15535 bytes
site.webmanifest | 4 +-
7 files changed, 214 insertions(+), 2 deletions(-)
create mode 100644 apps/dane/ChangeLog
create mode 100644 apps/dane/add_to_apps.json
create mode 100644 apps/dane/app-icon.js
create mode 100644 apps/dane/app.js
create mode 100644 apps/dane/app.png
diff --git a/apps.json b/apps.json
index 0643ad6de..91d2d249b 100644
--- a/apps.json
+++ b/apps.json
@@ -1241,5 +1241,27 @@
{"name":"calculator.app.js","url":"app.js"},
{"name":"calculator.img","url":"calculator-icon.js","evaluate":true}
]
+ },
+ {
+ "id": "dane",
+ "name": "Digital Assistant, not EDITH",
+ "shortName": "DANE",
+ "icon": "app.png",
+ "version": "0.06",
+ "description": "A detailed description of my great app",
+ "tags": "clock",
+ "type": "clock",
+ "allow_emulator": true,
+ "storage": [
+ {
+ "name": "dane.app.js",
+ "url": "app.js"
+ },
+ {
+ "name": "dane.img",
+ "url": "app-icon.js",
+ "evaluate": true
+ }
+ ]
}
]
diff --git a/apps/dane/ChangeLog b/apps/dane/ChangeLog
new file mode 100644
index 000000000..607d0adf5
--- /dev/null
+++ b/apps/dane/ChangeLog
@@ -0,0 +1,4 @@
+0.01: New App!
+0.04: Added Icon to watchface
+0.05: bugfix
+0.06: moved and resized icon
\ No newline at end of file
diff --git a/apps/dane/add_to_apps.json b/apps/dane/add_to_apps.json
new file mode 100644
index 000000000..6efb3ec85
--- /dev/null
+++ b/apps/dane/add_to_apps.json
@@ -0,0 +1,22 @@
+{
+ "id": "dane",
+ "name": "Digital Assistant, not EDITH",
+ "shortName": "DANE",
+ "icon": "app.png",
+ "version": "0.06",
+ "description": "A detailed description of my great app",
+ "tags": "clock",
+ "type": "clock",
+ "allow_emulator": true,
+ "storage": [
+ {
+ "name": "dane.app.js",
+ "url": "app.js"
+ },
+ {
+ "name": "dane.img",
+ "url": "app-icon.js",
+ "evaluate": true
+ }
+ ]
+}
\ No newline at end of file
diff --git a/apps/dane/app-icon.js b/apps/dane/app-icon.js
new file mode 100644
index 000000000..4deb12640
--- /dev/null
+++ b/apps/dane/app-icon.js
@@ -0,0 +1 @@
+require("heatshrink").decompress(atob("l8wxH+AH4A/AH4A/AFUvl8Cu4AEgUCBQIrfFQMRAAe/Aw4xbDYIlBiUS7AjCAAY5BBYMSiJkBGC4sCicTiRQJHoUSCAIwBF6sv30SikUiRMMMIISD7AvTl/YiYtPF40TF6R4BicVFqAWDF4MViaPRIwQWTF4O/IwiKRCoMRUiZHEDJ5cXJAxeOOQuQhQuShWQJIe/JJkviIuC74tTFwORRqKLD+3cmVLpsLFZtNAANKhXeDYKNOu4uEmdlDwVNBoNlsoDDmoKBhYQChcyFycVFwOTFwJcBpomBhYjCmouBAwYMCmZdBa4d3FyonBKoIoCAwIECLooucEIIjCRIYuFms1Lqq7CFwS7DLQQsDhYrBHIZdHXZkCdQpQDXoIQDFwIDBeoQQCpYuSl8RFwMT70KCRYAIhUSFwMTiMvFxm/CQUSFyp5Did3Fxi8DOBwuLDSEv7ETfoRCNDI13DIMT34ZPIYSgOaxJ3SIgZeTC7COBdgMCC58vOoakWiQvQFoQTBFqgvEiURF5gRDOKIdIDwMRiO/axMCBoMRLQItXF4Z9B7F3BxF37BZBAAQnRIYobDMAKqIl5aDAA5zJFwaCBAA6PBFxQQEAAYKBFxjSCU4IECA4YuJCAoAEFx0UikTAAIEBAwQuKCIoADFxsCI5RdiUAoAEVgIVJABRDHAH4A/AH4A/ADAA="))
\ No newline at end of file
diff --git a/apps/dane/app.js b/apps/dane/app.js
new file mode 100644
index 000000000..dc6262c58
--- /dev/null
+++ b/apps/dane/app.js
@@ -0,0 +1,163 @@
+const font = "6x8";
+const timeFontSize = 4;
+const dateFontSize = 3;
+const smallFontSize = 2;
+const yOffset = 23;
+const xyCenter = g.getWidth()/2;
+const cornerSize = 14;
+const cornerOffset = 3;
+const borderWidth = 1;
+const yposTime = 27+yOffset;
+const yposDate = 65+yOffset;
+
+const mainColor = "#26dafd";
+const mainColorDark = "#029dbb";
+const mainColorLight = "#8bebfe";
+
+const secondaryColor = "#df9527";
+const secondaryColorDark = "#8b5c15";
+const secondaryColorLight = "#ecc180";
+
+const success = "#00ff00";
+const successDark = "#000900";
+const successLight = "#060f06";
+
+const alert = "#ff0000";
+const alertDark = "#090000";
+const alertLight = "#0f0606";
+
+var img = {
+ width : 120, height : 120, bpp : 8,
+ transparent : 254,
+ buffer : require("heatshrink").decompress(atob("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"))
+}
+
+
+function drawTopLeftCorner(x,y) {
+ g.setColor(mainColor);
+ var x1 = x-cornerOffset;
+ var y1 = y-cornerOffset;
+ g.fillRect(x1,y1,x1+cornerSize,y1+cornerSize);
+ g.setColor("#000000");
+ g.fillRect(x,y,x+cornerSize-cornerOffset,y+cornerSize-cornerOffset);
+}
+function drawTopRightCorner(x,y) {
+ g.setColor(mainColor);
+ var x1 = x+cornerOffset;
+ var y1 = y-cornerOffset;
+ g.fillRect(x1,y1,x1-cornerSize,y1+cornerSize);
+ g.setColor("#000000");
+ g.fillRect(x,y,x-cornerSize-cornerOffset,y+cornerSize-cornerOffset);
+}
+function drawBottomLeftCorner(x,y) {
+ g.setColor(mainColor);
+ var x1 = x-cornerOffset;
+ var y1 = y+cornerOffset;
+ g.fillRect(x1,y1,x1+cornerSize,y1-cornerSize);
+ g.setColor("#000000");
+ g.fillRect(x,y,x+cornerSize-cornerOffset,y-cornerSize+cornerOffset);
+}
+function drawBottomRightCorner(x,y) {
+ g.setColor(mainColor);
+ var x1 = x+cornerOffset;
+ var y1 = y+cornerOffset;
+ g.fillRect(x1,y1,x1-cornerSize,y1-cornerSize);
+ g.setColor("#000000");
+ g.fillRect(x,y,x-cornerSize+cornerOffset,y-cornerSize+cornerOffset);
+}
+
+function drawFrame(x1,y1,x2,y2) {
+ drawTopLeftCorner(x1,y1);
+ drawTopRightCorner(x2,y1);
+ drawBottomLeftCorner(x1,y2);
+ drawBottomRightCorner(x2,y2);
+ g.setColor(mainColorDark);
+ g.drawRect(x1,y1,x2,y2);
+ g.setColor("#000000");
+ g.fillRect(x1+borderWidth,y1+borderWidth,x2-borderWidth,y2-borderWidth);
+}
+function drawTopFrame(x1,y1,x2,y2) {
+
+ drawBottomLeftCorner(x1,y2);
+ drawBottomRightCorner(x2,y2);
+ g.setColor(mainColorDark);
+ g.drawRect(x1,y1,x2,y2);
+ g.setColor("#000000");
+ g.fillRect(x1+borderWidth,y1+borderWidth,x2-borderWidth,y2-borderWidth);
+}
+function drawBottomFrame(x1,y1,x2,y2) {
+ drawTopLeftCorner(x1,y1);
+ drawTopRightCorner(x2,y1);
+ g.setColor(mainColorDark);
+ g.drawRect(x1,y1,x2,y2);
+ g.setColor("#000000");
+ g.fillRect(x1+borderWidth,y1+borderWidth,x2-borderWidth,y2-borderWidth);
+}
+
+function getUTCTime(d) {
+ return d.toUTCString().split(' ')[4].split(':').map(function(d){return Number(d);});
+}
+
+
+
+
+
+function drawTimeText() {
+ g.setFontAlign(0, 0);
+ var d = new Date();
+ var da = d.toString().split(" ");
+ var dutc = getUTCTime(d);
+
+ var time = da[4].split(":");
+ var hours = time[0],
+ minutes = time[1],
+ seconds = time[2];
+ g.setColor(mainColor);
+ g.setFont(font, timeFontSize);
+ g.drawString(`${hours}:${minutes}:${seconds}`, xyCenter, yposTime, true);
+ g.setFont(font, smallFontSize);
+}
+function drawDateText() {
+ g.setFontAlign(0, 0);
+ var d = new Date();
+ g.setFont(font, dateFontSize);
+ g.drawString(`${d.getDate()}.${d.getMonth()+1}.${d.getFullYear()}`, xyCenter, yposDate, true);
+}
+
+
+
+function drawClock() {
+ // main frame
+ drawFrame(3,10+yOffset,g.getWidth()-3,g.getHeight()-3);
+ // time frame
+ drawTopFrame(20,10+yOffset,220,46+yOffset);
+ // date frame
+ drawTopFrame(28,46+yOffset,212,46+yOffset+35);
+
+ // texts
+ drawTimeText();
+ drawDateText();
+ g.drawImage(img,g.getWidth()/2-(img.width/2),g.getHeight()/2);
+}
+function updateClock() {
+ drawTimeText();
+ drawDateText();
+}
+
+
+Bangle.on('lcdPower', function(on) {
+ if (on) drawClock();
+});
+g.clear();
+
+Bangle.loadWidgets();
+Bangle.drawWidgets();
+
+
+drawClock();
+
+
+setWatch(Bangle.showLauncher, BTN2, {repeat:false,edge:"falling"});
+
+// refesh every 100 milliseconds
+setInterval(updateClock, 100);
diff --git a/apps/dane/app.png b/apps/dane/app.png
new file mode 100644
index 0000000000000000000000000000000000000000..ee4f8403a82262e37b2750c9d7b245668e6cc46e
GIT binary patch
literal 15535
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
literal 0
HcmV?d00001
diff --git a/site.webmanifest b/site.webmanifest
index 0d1fb4679..0565f159c 100644
--- a/site.webmanifest
+++ b/site.webmanifest
@@ -17,6 +17,6 @@
"theme_color": "#5755d9",
"background_color": "#5755d9",
"display": "standalone",
- "start_url": "https://banglejs.com/apps/",
- "scope": "https://banglejs.com/apps/"
+ "start_url": "https://omegavoid.codes/BangleApps",
+ "scope": "https://omegavoid.codes/BangleApps"
}
From 0ef33e12dce47fe91106b7b03b5bc7880dc68c33 Mon Sep 17 00:00:00 2001
From: Purple-Tentacle <59914607+Purple-Tentacle@users.noreply.github.com>
Date: Thu, 16 Apr 2020 08:21:27 +0200
Subject: [PATCH 010/101] Distance calc and display
---
apps/activepedom/ChangeLog | 3 +-
apps/activepedom/README.md | 23 +++++++++++---
apps/activepedom/settings.js | 33 +++++++++++++++++++-
apps/activepedom/widget.js | 58 +++++++++++++++++++++++++-----------
4 files changed, 93 insertions(+), 24 deletions(-)
diff --git a/apps/activepedom/ChangeLog b/apps/activepedom/ChangeLog
index 4c21f3ace..fb0bc78e5 100644
--- a/apps/activepedom/ChangeLog
+++ b/apps/activepedom/ChangeLog
@@ -1 +1,2 @@
-0.01: New Widget!
+0.01: New Widget!
+0.02: Distance calculation and display
\ No newline at end of file
diff --git a/apps/activepedom/README.md b/apps/activepedom/README.md
index 8a10727cd..055a91f56 100644
--- a/apps/activepedom/README.md
+++ b/apps/activepedom/README.md
@@ -1,4 +1,4 @@
-# Improved pedometer
+# Active Pedometer
Pedometer that filters out arm movement and displays a step goal progress.
I changed the step counting algorithm completely.
@@ -19,8 +19,9 @@ When you reach the step threshold, the steps needed to reach the threshold are c
## Features
* Two line display
+* Can display distance (in km) or steps in each line
* Large number for good readability
-* Small number with the exact steps counted
+* Small number with the exact steps counted or more exact distance
* Large number is displayed in green when status is 'active'
* Progress bar for step goal
* Counts steps only if they are reached in a certain time
@@ -29,9 +30,23 @@ When you reach the step threshold, the steps needed to reach the threshold are c
* Steps are saved to a file and read-in at start (to not lose step progress)
* Settings can be changed in Settings - App/widget settings - Active Pedometer
-## Development version
+## Settings
-* https://github.com/Purple-Tentacle/BangleAppsDev/tree/master/apps/pedometer
+* Max time (ms): Maximum time between two steps in milliseconds, steps will not be counted if exceeded. Standard: 1100
+* Min time (ms): Minimum time between two steps in milliseconds, steps will not be counted if fallen below. Standard: 240
+* Step threshold: How many steps are needed to reach 'active' mode. If you do not reach the threshold in the 'Active Reset' time, the steps are not counted. Standard: 30
+* Act.Res. (ms): Active Reset. After how many miliseconds will the 'active mode' reset. You have to reach the step threshold in this time, otherwise the steps are not counted. Standard: 30000
+* Step sens.: Step Sensitivity. How sensitive should the sted detection be? This changes sensitivity in step detection in the firmware. Standard in firmware: 80
+* Step goal: This is your daily step goal. Standard: 10000
+* Step length: Length of one step in cm. Standard: 75
+* Line One: What to display in line one, steps or distance. Standard: steps
+* Line Two: What to display in line two, steps or distance. Standard: distance
+
+## Releases
+
+* Offifical app loader: https://github.com/espruino/BangleApps/tree/master/apps/activepedom (https://banglejs.com/apps)
+* Forked app loader: https://github.com/Purple-Tentacle/BangleApps/tree/master/apps/activepedom (https://purple-tentacle.github.io/BangleApps/#widget)
+* Development: https://github.com/Purple-Tentacle/BangleAppsDev/tree/master/apps/pedometer
## Requests
diff --git a/apps/activepedom/settings.js b/apps/activepedom/settings.js
index 43764a164..94ae435d2 100644
--- a/apps/activepedom/settings.js
+++ b/apps/activepedom/settings.js
@@ -4,6 +4,7 @@
*/
(function(back) {
const SETTINGS_FILE = 'activepedom.settings.json';
+ const LINES = ['Steps', 'Distance'];
// initialize with default settings...
let s = {
@@ -13,6 +14,9 @@
'intervalResetActive' : 30000,
'stepSensitivity' : 80,
'stepGoal' : 10000,
+ 'stepLength' : 75,
+ 'lineOne': LINES[0],
+ 'lineTwo': LINES[1],
};
// ...and overwrite them with any saved values
// This way saved values are preserved if a new version adds more settings
@@ -27,7 +31,7 @@
return function (value) {
s[key] = value;
storage.write(SETTINGS_FILE, s);
- WIDGETS["activepedom"].draw();
+ //WIDGETS["activepedom"].draw();
};
}
@@ -76,6 +80,33 @@
step: 1000,
onchange: save('stepGoal'),
},
+ 'Step length (cm)': {
+ value: s.stepLength,
+ min: 1,
+ max: 150,
+ step: 1,
+ onchange: save('stepLength'),
+ },
+ 'Line One': {
+ format: () => s.lineOne,
+ onchange: function () {
+ // cycles through options
+ const oldIndex = LINES.indexOf(s.lineOne)
+ const newIndex = (oldIndex + 1) % LINES.length
+ s.lineOne = LINES[newIndex]
+ save('lineOne')(s.lineOne)
+ },
+ },
+ 'Line Two': {
+ format: () => s.lineTwo,
+ onchange: function () {
+ // cycles through options
+ const oldIndex = LINES.indexOf(s.lineTwo)
+ const newIndex = (oldIndex + 1) % LINES.length
+ s.lineTwo = LINES[newIndex]
+ save('lineTwo')(s.lineTwo)
+ },
+ },
};
E.showMenu(menu);
});
\ No newline at end of file
diff --git a/apps/activepedom/widget.js b/apps/activepedom/widget.js
index 0c8b2438d..d569716ec 100644
--- a/apps/activepedom/widget.js
+++ b/apps/activepedom/widget.js
@@ -8,22 +8,16 @@
var active = 0; //x steps in y seconds achieved
var stepGoalPercent = 0; //percentage of step goal
var stepGoalBarLength = 0; //length og progress bar
- var lastUpdate = new Date();
- var width = 45;
+ var lastUpdate = new Date(); //used to reset counted steps on new day
+ var width = 45; //width of widget
- var stepsTooShort = 0;
+ //used for statistics and debugging
+ var stepsTooShort = 0;
var stepsTooLong = 0;
var stepsOutsideTime = 0;
- //define default settings
- const DEFAULTS = {
- 'cMaxTime' : 1100,
- 'cMinTime' : 240,
- 'stepThreshold' : 30,
- 'intervalResetActive' : 30000,
- 'stepSensitivity' : 80,
- 'stepGoal' : 10000,
- };
+ var distance = 0; //distance travelled
+
const SETTINGS_FILE = 'activepedom.settings.json';
const PEDOMFILE = "activepedom.steps.json";
@@ -32,10 +26,21 @@
function loadSettings() {
settings = require('Storage').readJSON(SETTINGS_FILE, 1) || {};
}
+
//return setting
function setting(key) {
- if (!settings) { loadSettings(); }
- return (key in settings) ? settings[key] : DEFAULTS[key];
+ //define default settings
+ const DEFAULTS = {
+ 'cMaxTime' : 1100,
+ 'cMinTime' : 240,
+ 'stepThreshold' : 30,
+ 'intervalResetActive' : 30000,
+ 'stepSensitivity' : 80,
+ 'stepGoal' : 10000,
+ 'stepLength' : 75,
+ };
+ if (!settings) { loadSettings(); }
+ return (key in settings) ? settings[key] : DEFAULTS[key];
}
function setStepSensitivity(s) {
@@ -46,7 +51,7 @@
}
//format number to make them shorter
- function kFormatter(num) {
+ function kFormatterSteps(num) {
if (num <= 999) return num; //smaller 1.000, return 600 as 600
if (num >= 1000 && num < 10000) { //between 1.000 and 10.000
num = Math.floor(num/100)*100;
@@ -99,11 +104,12 @@
else {
stepsOutsideTime++;
}
+ settings = 0; //reset settings to save memory
}
function draw() {
var height = 23; //width is deined globally
- var stepsDisplayLarge = kFormatter(stepsCounted);
+ distance = (stepsCounted * setting('stepLength')) / 100 /1000 //distance in km
//Check if same day
let date = new Date();
@@ -121,10 +127,21 @@
if (active == 1) g.setColor(0x07E0); //green
else g.setColor(0xFFFF); //white
g.setFont("6x8", 2);
- g.drawString(stepsDisplayLarge,this.x+1,this.y); //first line, big number
+
+ if (setting('lineOne') == 'Steps') {
+ g.drawString(kFormatterSteps(stepsCounted),this.x+1,this.y); //first line, big number, steps
+ }
+ if (setting('lineOne') == 'Distance') {
+ g.drawString(distance.toFixed(2),this.x+1,this.y); //first line, big number, distance
+ }
g.setFont("6x8", 1);
g.setColor(0xFFFF); //white
- g.drawString(stepsCounted,this.x+1,this.y+14); //second line, small number
+ if (setting('lineTwo') == 'Steps') {
+ g.drawString(stepsCounted,this.x+1,this.y+14); //second line, small number, steps
+ }
+ if (setting('lineTwo') == 'Distance') {
+ g.drawString(distance.toFixed(3) + "km",this.x+1,this.y+14); //second line, small number, distance
+ }
//draw step goal bar
stepGoalPercent = (stepsCounted / setting('stepGoal')) * 100;
@@ -136,6 +153,8 @@
g.fillRect(this.x, this.y+height, this.x+1, this.y+height-1); //draw start of bar
g.fillRect(this.x+width, this.y+height, this.x+width-1, this.y+height-1); //draw end of bar
g.fillRect(this.x, this.y+height, this.x+stepGoalBarLength, this.y+height); // draw progress bar
+
+ settings = 0; //reset settings to save memory
}
//This event is called just before the device shuts down for commands such as reset(), load(), save(), E.reboot() or Bangle.off()
@@ -164,6 +183,7 @@
//Read data from file and set variables
let pedomData = require("Storage").readJSON(PEDOMFILE,1);
+
if (pedomData) {
if (pedomData.lastUpdate) lastUpdate = new Date(pedomData.lastUpdate);
stepsCounted = pedomData.stepsToday|0;
@@ -172,6 +192,8 @@
stepsOutsideTime = pedomData.stepsOutsideTime;
}
+ pedomdata = 0; //reset pedomdata to save memory
+
setStepSensitivity(setting('stepSensitivity')); //set step sensitivity (80 is standard, 400 is muss less sensitive)
//Add widget
From 505730cd50cb9ab08b2100bd6064399c907be3a3 Mon Sep 17 00:00:00 2001
From: Purple-Tentacle <59914607+Purple-Tentacle@users.noreply.github.com>
Date: Thu, 16 Apr 2020 08:23:38 +0200
Subject: [PATCH 011/101] active pedometer: added readme
---
apps.json | 1 +
1 file changed, 1 insertion(+)
diff --git a/apps.json b/apps.json
index 3dbccb9b1..ec211f060 100644
--- a/apps.json
+++ b/apps.json
@@ -1116,6 +1116,7 @@
"description": "Pedometer that filters out arm movement and displays a step goal progress.",
"tags": "outdoors,widget",
"type":"widget",
+ "readme": "README.md",
"storage": [
{"name":"activepedom.wid.js","url":"widget.js"},
{"name":"activepedom.settings.js","url":"settings.js"},
From d74eb43fb6477e5958dee98c623cb43dc3213e3d Mon Sep 17 00:00:00 2001
From: Purple-Tentacle <59914607+Purple-Tentacle@users.noreply.github.com>
Date: Thu, 16 Apr 2020 08:27:13 +0200
Subject: [PATCH 012/101] active pedometer: version 0.02
---
apps.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/apps.json b/apps.json
index ec211f060..ab8af0f37 100644
--- a/apps.json
+++ b/apps.json
@@ -1112,7 +1112,7 @@
"name": "Active Pedometer",
"shortName":"Active Pedometer",
"icon": "app.png",
- "version":"0.01",
+ "version":"0.02",
"description": "Pedometer that filters out arm movement and displays a step goal progress.",
"tags": "outdoors,widget",
"type":"widget",
From 078a3e6d5f31363a7ab7042859870f02cf3a1126 Mon Sep 17 00:00:00 2001
From: Gordon Williams
Date: Thu, 16 Apr 2020 08:16:27 +0100
Subject: [PATCH 013/101] change default temperature for israel as per #248
---
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 ebf28e53d..508c92015 100644
--- a/apps/locale/locales.js
+++ b/apps/locale/locales.js
@@ -220,7 +220,7 @@ var locales = {
int_curr_symbol: "ILS",
speed: "kmh",
distance: { 0: "m", 1: "km" },
- temperature: "°F",
+ temperature: "°C",
ampm: { 0: "am", 1: "pm" },
timePattern: { 0: "%HH:%MM:%SS ", 1: "%HH:%MM" },
datePattern: { 0: "%A, %B %d, %Y", "1": "%d/%m/%Y" }, // Sunday, 1 March 2020 // 01/03/2020
From 944693eaf966fe4b54cbfeaef5148f5b1efc444d Mon Sep 17 00:00:00 2001
From: Purple-Tentacle <59914607+Purple-Tentacle@users.noreply.github.com>
Date: Thu, 16 Apr 2020 10:06:44 +0200
Subject: [PATCH 014/101] Chronowid initial
---
apps/chronowid/ChangeLog | 1 +
1 file changed, 1 insertion(+)
create mode 100644 apps/chronowid/ChangeLog
diff --git a/apps/chronowid/ChangeLog b/apps/chronowid/ChangeLog
new file mode 100644
index 000000000..a6f342f01
--- /dev/null
+++ b/apps/chronowid/ChangeLog
@@ -0,0 +1 @@
+0.01: New widget and app!
From 1a935951b03efdeca39d61da79302ff83c73ea18 Mon Sep 17 00:00:00 2001
From: Purple-Tentacle <59914607+Purple-Tentacle@users.noreply.github.com>
Date: Thu, 16 Apr 2020 10:07:39 +0200
Subject: [PATCH 015/101] Chronowid initial
---
apps/chronowid/README.md | 35 ++++++++++++++
apps/chronowid/app-icon.js | 1 +
apps/chronowid/app.js | 91 ++++++++++++++++++++++++++++++++++++
apps/chronowid/app.png | Bin 0 -> 1060 bytes
apps/chronowid/widget.js | 93 +++++++++++++++++++++++++++++++++++++
5 files changed, 220 insertions(+)
create mode 100644 apps/chronowid/README.md
create mode 100644 apps/chronowid/app-icon.js
create mode 100644 apps/chronowid/app.js
create mode 100644 apps/chronowid/app.png
create mode 100644 apps/chronowid/widget.js
diff --git a/apps/chronowid/README.md b/apps/chronowid/README.md
new file mode 100644
index 000000000..b6325d94f
--- /dev/null
+++ b/apps/chronowid/README.md
@@ -0,0 +1,35 @@
+# Chronometer Widget
+
+Chronometer (timer) that runs as a widget.
+The advantage is, that you can still see your normal watchface and other widgets when the timer is running.
+The widget is always active, but only shown when the timer is on.
+Hours, minutes, seconds and timer status can be set with an app.
+
+## Screenshots
+
+TBD
+
+## Features
+
+* Using other apps does not interrupt the timer, no need to keep the widget open (BUT: there will be no buzz when the time is up, for that the widget has to be loaded)
+* Target time is saved to a file and timer picks up again when widget is loaded again.
+
+## Settings
+
+There are no settings section in the settings app, timer can be set using an app.
+
+* Hours: Set the hours for the timer
+* Minutes: Set the minutes for the timer
+* Seconds: Set the seconds for the timer
+* Timer on: Starts the timer and displays the widget when set to 'On'. You have to leave the app. The widget is always there, but only visible when timer is on.
+
+
+## Releases
+
+* Offifical app loader: Not yet published.
+* Forked app loader: Not yet published.
+* Development: https://github.com/Purple-Tentacle/BangleAppsDev/tree/master/apps/chronowid
+
+## Requests
+
+If you have any feature requests, please contact me on the Espruino forum: http://forum.espruino.com/profiles/155005/
\ No newline at end of file
diff --git a/apps/chronowid/app-icon.js b/apps/chronowid/app-icon.js
new file mode 100644
index 000000000..db2010218
--- /dev/null
+++ b/apps/chronowid/app-icon.js
@@ -0,0 +1 @@
+require("heatshrink").decompress(atob("mEwwIFCn/8BYYFRABcD4AFFgIFCh/wgeAAoP//8HCYMDAoPD8EAg4FB8PwgEf+EP/H4HQOAgP8uEAvwfBv0ggBFCn4CB/EBwEfgEB+AFBh+AgfgAoI1BIoQJB4AHBAoXgg4uBAIIFCCYQFGh5rDJQJUBK4IFCNYIFVDoopDGoJiBHYYFKVYRZBWIYDBA4IFBNIQzBG4IbBToKkBAQKVFUIYICVoQUCXIQmCYoIsCaITqDAoLvDNYUAA="))
\ No newline at end of file
diff --git a/apps/chronowid/app.js b/apps/chronowid/app.js
new file mode 100644
index 000000000..cb99268af
--- /dev/null
+++ b/apps/chronowid/app.js
@@ -0,0 +1,91 @@
+g.clear();
+Bangle.loadWidgets();
+Bangle.drawWidgets();
+
+const storage = require('Storage');
+const boolFormat = v => v ? "On" : "Off";
+let settingsChronowid;
+
+function updateSettings() {
+ var now = new Date();
+ const goal = new Date(now.getFullYear(), now.getMonth(), now.getDate(),
+ now.getHours() + settingsChronowid.hours, now.getMinutes() + settingsChronowid.minutes, now.getSeconds() + settingsChronowid.seconds);
+ settingsChronowid.goal = goal.getTime();
+ storage.writeJSON('chronowid.json', settingsChronowid);
+}
+
+function resetSettings() {
+ settingsChronowid = {
+ hours : 0,
+ minutes : 0,
+ seconds : 0,
+ started : false,
+ counter : 0,
+ goal : 0,
+ };
+ updateSettings();
+}
+
+settingsChronowid = storage.readJSON('chronowid.json',1);
+if (!settingsChronowid.started) resetSettings();
+
+E.on('kill', () => {
+ print("-KILL-");
+ updateSettings();
+});
+
+function showMenu() {
+ const timerMenu = {
+ '': {
+ 'title': 'Set timer',
+ 'predraw': function() {
+ timerMenu.hours.value = settingsChronowid.hours;
+ timerMenu.minutes.value = settingsChronowid.minutes;
+ timerMenu.seconds.value = settingsChronowid.seconds;
+ timerMenu.started.value = settingsChronowid.started;
+ }
+ },
+ 'Hours': {
+ value: settingsChronowid.hours,
+ min: 0,
+ max: 24,
+ step: 1,
+ onchange: v => {
+ settingsChronowid.hours = v;
+ updateSettings();
+ }
+ },
+ 'Minutes': {
+ value: settingsChronowid.minutes,
+ min: 0,
+ max: 59,
+ step: 1,
+ onchange: v => {
+ settingsChronowid.minutes = v;
+ updateSettings();
+ }
+ },
+ 'Seconds': {
+ value: settingsChronowid.seconds,
+ min: 0,
+ max: 59,
+ step: 1,
+ onchange: v => {
+ settingsChronowid.seconds = v;
+ updateSettings();
+ }
+ },
+ 'Timer on': {
+ value: settingsChronowid.started,
+ format: boolFormat,
+ onchange: v => {
+ settingsChronowid.started = v;
+ updateSettings();
+ }
+ },
+ };
+ timerMenu['-Exit-'] = ()=>{load();};
+ return E.showMenu(timerMenu);
+}
+
+showMenu();
\ No newline at end of file
diff --git a/apps/chronowid/app.png b/apps/chronowid/app.png
new file mode 100644
index 0000000000000000000000000000000000000000..5ac7a480c5d4533c9851ba6264b74aae48035eb0
GIT binary patch
literal 1060
zcmV+<1l#+GP)*2?CL*
z=jdIsdaVqLAjyY*ycLl}Syc2;L97)RfoN7x+ost=DzrV^$!5>oot--~TQ7d$;EsFG
z_k7Qtx%ZxXXA1}qX~XsfVFXm;x<_9I=$uURJ1ZseBV6R)F#Xg92
zC;;k!X6tX2rp*iB9q=U=45ym<6tfq%{NOz;R#zF~
zJ#TM22egDKJPw=zW_$>jHUpdnVmAI3OLSh6Xa!Os2$%L1*ptsBqQH3<0V&k;dH^*J
zV!%>h8S0MJS>N^N=zw!Tp-U3u_?VrR0C%$lOrU0pB8}e`%Or|`Hefgl=b%lbJ&8}K
z0d9mSa7Pnl3h2bW9NBGIHbj6fi%XY;{Z5Sg5f5-dL;ez|^x%8cvRtS_-ANgz&(_A*
zqSmeY`$fNzK2BYIbgjB!6`wIzK6`b8=ix@{cYKKzS;Nui}lHqvFZQ(WIb6|yu`hkz&m1I8mjlf19JVWAIYSZF1nYXRZFlZI3veZ?Zx{Zz-
z8U)9%7bjUM#@w4ba1E#UKX%2CD=z$#UYuryQ`9i1TdC|xfDJ{$-!T?-V<2r9M8a*K
z9dr-w(56e^hqzvD804PIcY}spvhJGp;v`o<(?MK={xM1d>kPT%AWp~zx;ro;uD2Qn
z9RX@lgZaBNBK9n5lVt>Xh&6?IE#n8Z
zsI|x*yVnoVDxC9q0(E+jFT`XVq)WAoT2$kM2z58s3?hyzbG@mhlt>&`<*F<;=^
zP>ZwY)2MUOz$gT6YsjZjrw2i1rwDKu=QE!MZt?eMF)&KeCy_?gPVK0L$193a^SqoY
z?cz&A(mszu+>h5Mfy=-_)QTBL?Ioht=LYM$0h}wWd~8DNc^%r&ZyAGHk`M;0SHw|0
z71k@JUh*@uTUMOHnq3)qg@)Rd!MF@c(8CV;o7*RA(a
euUUTu4g4F8cKpwc4bA8P0000 {
+ const storage = require('Storage');
+ settingsChronowid = storage.readJSON("chronowid.json",1)||{}; //read settingsChronowid from file
+ var height = 23;
+ var width = 58;
+ var interval = 0; //used for the 1 second interval timer
+ var now = new Date();
+
+ var time = 0;
+ var diff = settingsChronowid.goal - now;
+
+ //Convert ms to time
+ function getTime(t) {
+ var milliseconds = parseInt((t % 1000) / 100),
+ seconds = Math.floor((t / 1000) % 60),
+ minutes = Math.floor((t / (1000 * 60)) % 60),
+ hours = Math.floor((t / (1000 * 60 * 60)) % 24);
+
+ hours = (hours < 10) ? "0" + hours : hours;
+ minutes = (minutes < 10) ? "0" + minutes : minutes;
+ seconds = (seconds < 10) ? "0" + seconds : seconds;
+
+ return hours + ":" + minutes + ":" + seconds;
+ }
+
+ function printDebug() {
+ print ("Nowtime: " + getTime(now));
+ print ("Now: " + now);
+ print ("Goaltime: " + getTime(settingsChronowid.goal));
+ print ("Goal: " + settingsChronowid.goal);
+ print("Difftime: " + getTime(diff));
+ print("Diff: " + diff);
+ print ("Started: " + settingsChronowid.started);
+ print ("----");
+ }
+
+ //counts down, calculates and displays
+ function countDown() {
+ //printDebug();
+ now = new Date();
+ diff = settingsChronowid.goal - now; //calculate difference
+ WIDGETS["chronowid"].draw();
+ //time is up
+ if (settingsChronowid.started && diff <= 0) {
+ Bangle.buzz(1500);
+ //write timer off to file
+ settingsChronowid.started = false;
+ storage.writeJSON('chronowid.json', settingsChronowid);
+ clearInterval(interval); //stop interval
+ //printDebug();
+ }
+ }
+
+ // draw your widget
+ function draw() {
+ if (!settingsChronowid.started) {
+ width = 0;
+ return; //do not draw anything if timer is not started
+ }
+ g.reset();
+ if (diff >= 0) {
+ if (diff < 600000) { //less than 1 hour left
+ width = 58;
+ g.clearRect(this.x,this.y,this.x+width,this.y+height);
+ g.setFont("6x8", 2);
+ g.drawString(getTime(diff).substring(3), this.x+1, this.y+5); //remove hour part 00:00:00 -> 00:00
+ }
+ if (diff >= 600000) { //one hour or more left
+ width = 48;
+ g.clearRect(this.x,this.y,this.x+width,this.y+height);
+ g.setFont("6x8", 1);
+ g.drawString(getTime(diff), this.x+1, this.y+((height/2)-4)); //display hour 00:00:00
+ }
+ }
+ else {
+ width = 58;
+ g.clearRect(this.x,this.y,this.x+width,this.y+height);
+ g.setFont("6x8", 2);
+ g.drawString("END", this.x+15, this.y+5);
+ }
+ }
+
+ if (settingsChronowid.started) interval = setInterval(countDown, 1000); //start countdown each second
+
+ // add the widget
+ WIDGETS["chronowid"]={area:"bl",width:width,draw:draw,reload:function() {
+ reload();
+ Bangle.drawWidgets(); // relayout all widgets
+ }};
+
+ //printDebug();
+ countDown();
+})();
\ No newline at end of file
From 6fc326bb49ae2e004c6c210e84f68c3c76906764 Mon Sep 17 00:00:00 2001
From: Purple-Tentacle <59914607+Purple-Tentacle@users.noreply.github.com>
Date: Thu, 16 Apr 2020 10:10:57 +0200
Subject: [PATCH 016/101] Chronowid initial
---
apps.json | 17 ++++++++++++++++-
1 file changed, 16 insertions(+), 1 deletion(-)
diff --git a/apps.json b/apps.json
index ab8af0f37..0d6cdd214 100644
--- a/apps.json
+++ b/apps.json
@@ -1108,7 +1108,7 @@
{"name":"openstmap.img","url":"app-icon.js","evaluate":true}
]
},
- { "id": "activepedom",
+ { "id": "activepedom",
"name": "Active Pedometer",
"shortName":"Active Pedometer",
"icon": "app.png",
@@ -1123,6 +1123,21 @@
{"name":"activepedom.img","url":"app-icon.js","evaluate":true}
]
},
+ { "id": "chronowidget",
+ "name": "Chrono Widget",
+ "shortName":"Chrono Widget",
+ "icon": "app.png",
+ "version":"0.01",
+ "description": "Chronometer (timer) which runs as widget.",
+ "tags": "tools,widget",
+ "type":"widget",
+ "readme": "README.md",
+ "storage": [
+ {"name":"chronowidget.wid.js","url":"widget.js"},
+ {"name":"chronowidget.app.js","url":"app.js"},
+ {"name":"chronowidget.img","url":"app-icon.js","evaluate":true}
+ ]
+ },
{ "id": "tabata",
"name": "Tabata",
"shortName": "Tabata - Control High-Intensity Interval Training",
From e2657a62a592ab6e4b3018bfb8f8216d0ff3412b Mon Sep 17 00:00:00 2001
From: Purple-Tentacle <59914607+Purple-Tentacle@users.noreply.github.com>
Date: Thu, 16 Apr 2020 10:13:23 +0200
Subject: [PATCH 017/101] chronowid typo
---
apps.json | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/apps.json b/apps.json
index 0d6cdd214..591ddad28 100644
--- a/apps.json
+++ b/apps.json
@@ -1123,7 +1123,7 @@
{"name":"activepedom.img","url":"app-icon.js","evaluate":true}
]
},
- { "id": "chronowidget",
+ { "id": "chronowid",
"name": "Chrono Widget",
"shortName":"Chrono Widget",
"icon": "app.png",
@@ -1133,9 +1133,9 @@
"type":"widget",
"readme": "README.md",
"storage": [
- {"name":"chronowidget.wid.js","url":"widget.js"},
- {"name":"chronowidget.app.js","url":"app.js"},
- {"name":"chronowidget.img","url":"app-icon.js","evaluate":true}
+ {"name":"chronowid.wid.js","url":"widget.js"},
+ {"name":"chronowid.app.js","url":"app.js"},
+ {"name":"chronowid.img","url":"app-icon.js","evaluate":true}
]
},
{ "id": "tabata",
From e0a3b9ae3e15274d77d1a4af5ad7c8c90b737316 Mon Sep 17 00:00:00 2001
From: Gordon Williams
Date: Thu, 16 Apr 2020 09:16:37 +0100
Subject: [PATCH 018/101] Launchers: Only store relevant app data (saves RAM
when many apps)
---
apps.json | 4 ++--
apps/launch/ChangeLog | 2 ++
apps/launch/app.js | 2 +-
apps/toucher/ChangeLog | 3 ++-
apps/toucher/app.js | 8 ++++----
5 files changed, 11 insertions(+), 8 deletions(-)
create mode 100644 apps/launch/ChangeLog
diff --git a/apps.json b/apps.json
index d3dd95b26..167df46f6 100644
--- a/apps.json
+++ b/apps.json
@@ -41,7 +41,7 @@
"name": "Default Launcher",
"shortName":"Launcher",
"icon": "app.png",
- "version":"0.01",
+ "version":"0.02",
"description": "This is needed by Bangle.js to display a menu allowing you to choose your own applications. You can replace this with a customised launcher.",
"tags": "tool,system,launcher",
"type":"launch",
@@ -1050,7 +1050,7 @@
"name": "Touch Launcher",
"shortName":"Menu",
"icon": "app.png",
- "version":"0.05",
+ "version":"0.06",
"description": "Touch enable left to right launcher.",
"tags": "tool,system,launcher",
"type":"launch",
diff --git a/apps/launch/ChangeLog b/apps/launch/ChangeLog
new file mode 100644
index 000000000..9e4a1eaf3
--- /dev/null
+++ b/apps/launch/ChangeLog
@@ -0,0 +1,2 @@
+0.01: New App!
+0.02: Only store relevant app data (saves RAM when many apps)
diff --git a/apps/launch/app.js b/apps/launch/app.js
index 682122f82..a256b6909 100644
--- a/apps/launch/app.js
+++ b/apps/launch/app.js
@@ -1,5 +1,5 @@
var s = require("Storage");
-var apps = s.list(/\.info$/).map(app=>s.readJSON(app,1)||{name:"DEAD: "+app.substr(1)}).filter(app=>app.type=="app" || app.type=="clock" || !app.type);
+var apps = s.list(/\.info$/).map(app=>{var a=s.readJSON(app,1);return a&&{name:a.name,type:a.type,icon:a.icon,sortorder:a.sortorder,src:a.src}}).filter(app=>app && (app.type=="app" || app.type=="clock" || !app.type));
apps.sort((a,b)=>{
var n=(0|a.sortorder)-(0|b.sortorder);
if (n) return n; // do sortorder first
diff --git a/apps/toucher/ChangeLog b/apps/toucher/ChangeLog
index a2a709ee3..0c97d9e13 100644
--- a/apps/toucher/ChangeLog
+++ b/apps/toucher/ChangeLog
@@ -2,4 +2,5 @@
0.02: Add swipe support and doucle tap to run application
0.03: Close launcher when lcd turn off
0.04: Complete rewrite to add animation and loop ( issue #210 )
-0.05: Improve perf
\ No newline at end of file
+0.05: Improve perf
+0.06: Only store relevant app data (saves RAM when many apps)
diff --git a/apps/toucher/app.js b/apps/toucher/app.js
index b67e5b26c..cf7d5333b 100644
--- a/apps/toucher/app.js
+++ b/apps/toucher/app.js
@@ -5,8 +5,8 @@ g.flip();
const Storage = require("Storage");
function getApps(){
- return Storage.list(/\.info$/).filter(app => app.endsWith('.info')).map(app => Storage.readJSON(app,1) || { name: "DEAD: "+app.substr(1) })
- .filter(app=>app.type=="app" || app.type=="clock" || !app.type)
+ return Storage.list(/\.info$/).map(app=>{var a=Storage.readJSON(app,1);return a&&{name:a.name,type:a.type,icon:a.icon,sortorder:a.sortorder,src:a.src,version:a.version}})
+ .filter(app=>app && (app.type=="app" || app.type=="clock" || !app.type))
.sort((a,b)=>{
var n=(0|a.sortorder)-(0|b.sortorder);
if (n) return n; // do sortorder first
@@ -19,7 +19,7 @@ function getApps(){
const HEIGHT = g.getHeight();
const WIDTH = g.getWidth();
const HALF = WIDTH/2;
-const ANIMATION_FRAME = 4;
+const ANIMATION_FRAME = 4;
const ANIMATION_STEP = HALF / ANIMATION_FRAME;
function getPosition(index){
@@ -192,4 +192,4 @@ Bangle.on('swipe', dir => {
// close launcher when lcd is off
Bangle.on('lcdPower', on => {
if(!on) return load();
-});
\ No newline at end of file
+});
From 8c2decfa7b1d8a2d059129622207bbe810645d6a Mon Sep 17 00:00:00 2001
From: Purple-Tentacle <59914607+Purple-Tentacle@users.noreply.github.com>
Date: Thu, 16 Apr 2020 10:17:14 +0200
Subject: [PATCH 019/101] readme update
---
apps/chronowid/README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/apps/chronowid/README.md b/apps/chronowid/README.md
index b6325d94f..f31c24c7b 100644
--- a/apps/chronowid/README.md
+++ b/apps/chronowid/README.md
@@ -27,7 +27,7 @@ There are no settings section in the settings app, timer can be set using an app
## Releases
* Offifical app loader: Not yet published.
-* Forked app loader: Not yet published.
+* Forked app loader: https://github.com/Purple-Tentacle/BangleApps/tree/master/apps/chronowid (https://purple-tentacle.github.io/BangleApps/index.html#)
* Development: https://github.com/Purple-Tentacle/BangleAppsDev/tree/master/apps/chronowid
## Requests
From 9704522813daaf13354e63f79ba0f655546161b4 Mon Sep 17 00:00:00 2001
From: Purple-Tentacle <59914607+Purple-Tentacle@users.noreply.github.com>
Date: Thu, 16 Apr 2020 10:26:32 +0200
Subject: [PATCH 020/101] removed type widget
---
apps.json | 1 -
1 file changed, 1 deletion(-)
diff --git a/apps.json b/apps.json
index 591ddad28..0a894353b 100644
--- a/apps.json
+++ b/apps.json
@@ -1130,7 +1130,6 @@
"version":"0.01",
"description": "Chronometer (timer) which runs as widget.",
"tags": "tools,widget",
- "type":"widget",
"readme": "README.md",
"storage": [
{"name":"chronowid.wid.js","url":"widget.js"},
From 8c6b78ebe19b29e7513d708a8f9bfe34d1f51cdf Mon Sep 17 00:00:00 2001
From: Purple-Tentacle <59914607+Purple-Tentacle@users.noreply.github.com>
Date: Thu, 16 Apr 2020 10:32:41 +0200
Subject: [PATCH 021/101] Bugfix json creation
---
apps/chronowid/app.js | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/apps/chronowid/app.js b/apps/chronowid/app.js
index cb99268af..48401a7bb 100644
--- a/apps/chronowid/app.js
+++ b/apps/chronowid/app.js
@@ -27,7 +27,7 @@ function resetSettings() {
}
settingsChronowid = storage.readJSON('chronowid.json',1);
-if (!settingsChronowid.started) resetSettings();
+if (!settingsChronowid) resetSettings();
E.on('kill', () => {
print("-KILL-");
@@ -88,4 +88,4 @@ function showMenu() {
return E.showMenu(timerMenu);
}
-showMenu();
\ No newline at end of file
+showMenu();
From 304e23f53ed8715d640b797e94b7d2c041f9c990 Mon Sep 17 00:00:00 2001
From: msdeibel
Date: Thu, 16 Apr 2020 11:23:19 +0200
Subject: [PATCH 022/101] Fix home button and add min/max for chart
---
apps/batchart/app.js | 28 ++++++++++++++++++++--------
1 file changed, 20 insertions(+), 8 deletions(-)
diff --git a/apps/batchart/app.js b/apps/batchart/app.js
index deb406d8b..2d0d8e585 100644
--- a/apps/batchart/app.js
+++ b/apps/batchart/app.js
@@ -65,9 +65,7 @@ function loadData() {
// Top up to MaxValueCount from previous days as required
let previousDay = decrementDay(startingDay);
- while (dataLines.length < MaxValueCount
- && previousDay !== startingDay) {
-
+ while (dataLines.length < MaxValueCount && previousDay !== startingDay) {
let topUpLogFileName = "bclog" + previousDay;
let remainingLines = MaxValueCount - dataLines.length;
let topUpLines = loadLinesFromFile(remainingLines, topUpLogFileName);
@@ -126,6 +124,12 @@ function renderData(dataArray) {
const batteryIndex = 1;
const temperatureIndex = 2;
const switchabelsIndex = 3;
+
+ const minTemperature = 20;
+ const maxTemparature = 40;
+
+ const belowMinIndicatorValue = minTemperature - 1;
+ const aboveMaxIndicatorValue = maxTemparature + 1;
var allConsumers = switchableConsumers.none | switchableConsumers.lcd | switchableConsumers.compass | switchableConsumers.bluetooth | switchableConsumers.gps | switchableConsumers.hrm;
@@ -140,8 +144,19 @@ function renderData(dataArray) {
// Temperature
g.setColor(0.4, 0.4, 1);
- let scaledTemp = Math.floor(((parseFloat(dataInfo[temperatureIndex]) * 100) - 2000)/20) + ((((parseFloat(dataInfo[temperatureIndex]) * 100) - 2000) % 100)/25);
+
+ let datapointTemp = parseFloat(dataInfo[temperatureIndex]);
+ if (datapointTemp < minTemperature) {
+ datapointTemp = belowMinIndicatorValue;
+ }
+ if (datapointTemp > maxTemparature) {
+ datapointTemp = aboveMaxIndicatorValue;
+ }
+
+ // Scale down the range of 20 - 40°C to a 100px y-axis, where 1px = .25°
+ let scaledTemp = Math.floor(((datapointTemp * 100) - 2000) / 20) + ((((datapointTemp * 100) - 2000) % 100) / 25);
+
g.setPixel(GraphXZero + i, GraphYZero - scaledTemp);
// LCD state
@@ -213,8 +228,6 @@ function switchOffApp(){
// special function to handle display switch on
Bangle.on('lcdPower', (on) => {
if (on) {
- // call your app function here
- // If you clear the screen, do Bangle.drawWidgets();
g.clear();
Bangle.loadWidgets();
Bangle.drawWidgets();
@@ -222,12 +235,11 @@ Bangle.on('lcdPower', (on) => {
}
});
-setWatch(switchOffApp, BTN2, {edge:"rising", debounce:50, repeat:true});
+setWatch(switchOffApp, BTN2, {edge:"falling", debounce:50, repeat:true});
g.clear();
Bangle.loadWidgets();
Bangle.drawWidgets();
-// call your app function here
renderHomeIcon();
From 24eb0f33fef2431bb589d59f95c342005b08a03a Mon Sep 17 00:00:00 2001
From: msdeibel
Date: Thu, 16 Apr 2020 11:24:17 +0200
Subject: [PATCH 023/101] Minor changes based on JSLint hints
---
apps/batchart/widget.js | 34 +++++++++++++++++-----------------
1 file changed, 17 insertions(+), 17 deletions(-)
diff --git a/apps/batchart/widget.js b/apps/batchart/widget.js
index 53f8b3549..1b8ce79ba 100644
--- a/apps/batchart/widget.js
+++ b/apps/batchart/widget.js
@@ -12,8 +12,8 @@
var batChartFile; // file for battery percentage recording
const recordingInterval10Min = 60 * 10 * 1000;
- const recordingInterval1Min = 60*1000; //For testing
- const recordingInterval10S = 10*1000; //For testing
+ const recordingInterval1Min = 60 * 1000; //For testing
+ const recordingInterval10S = 10 * 1000; //For testing
var recordingInterval = null;
var compassEventReceived = false;
@@ -26,15 +26,15 @@
let y = this.y;
g.setColor(0, 1, 0);
- g.fillPoly([x+5, y, x+5, y+4, x+1, y+4, x+1, y+20, x+18, y+20, x+18, y+4, x+13, y+4, x+13, y], true);
+ g.fillPoly([x + 5, y, x + 5, y + 4, x + 1, y + 4, x + 1, y + 20, x + 18, y + 20, x + 18, y + 4, x + 13, y + 4, x + 13, y], true);
- g.setColor(0,0,0);
- g.drawPoly([x+5, y+6, x+8, y+12, x+13, y+12, x+16, y+18], false);
+ g.setColor(0, 0, 0);
+ g.drawPoly([x + 5, y + 6, x + 8, y + 12, x + 13, y + 12, x + 16, y + 18], false);
g.reset();
}
- function onMag(){
+ function onMag() {
compassEventReceived = true;
// Stop handling events when no longer necessarry
Bangle.removeListener("mag", onMag);
@@ -51,6 +51,7 @@
}
function getEnabledConsumersValue() {
+ // Wait for an event from each of the devices to see if they are switched on
var enabledConsumers = switchableConsumers.none;
Bangle.on('mag', onMag);
@@ -58,13 +59,12 @@
Bangle.on('HRM', onHrm);
// Wait two seconds, that should be enough for each of the events to get raised once
- setTimeout(() => {
+ setTimeout(() => {
Bangle.removeAllListeners();
}, 2000);
if (Bangle.isLCDOn())
enabledConsumers = enabledConsumers | switchableConsumers.lcd;
- // Already added in the hope they will be available soon to get more details
if (compassEventReceived)
enabledConsumers = enabledConsumers | switchableConsumers.compass;
if (gpsEventReceived)
@@ -90,8 +90,7 @@
const logFileName = "bclog" + currentWriteDay;
// Change log target on day change
- if (!isNaN(previousWriteDay)
- && previousWriteDay != currentWriteDay) {
+ if (!isNaN(previousWriteDay) && previousWriteDay != currentWriteDay) {
//Remove a log file containing data from a week ago
Storage.open(logFileName, "r").erase();
Storage.open(previousWriteLogName, "w").write(parseInt(currentWriteDay));
@@ -111,7 +110,7 @@
}
function reload() {
- WIDGETS["batchart"].width = 24;
+ WIDGETS.batchart.width = 24;
recordingInterval = setInterval(logBatteryData, recordingInterval10Min);
@@ -119,11 +118,12 @@
}
// add the widget
- WIDGETS["batchart"]={area:"tl",width:24,draw:draw,reload:function() {
- reload();
- Bangle.drawWidgets(); // relayout all widgets
- }};
+ WIDGETS.batchart = {
+ area: "tl", width: 24, draw: draw, reload: function () {
+ reload();
+ Bangle.drawWidgets();
+ }
+ };
- // load settings, set correct widget width
reload();
-})()
\ No newline at end of file
+})();
\ No newline at end of file
From bb42044aa92f25f5375112194488c82ce76f0a37 Mon Sep 17 00:00:00 2001
From: Gordon Williams
Date: Thu, 16 Apr 2020 10:25:13 +0100
Subject: [PATCH 024/101] Show elapsed time, and tweak stopwatch so lap times
don't overlap the bottom widget area
---
apps/swatch/interface.html | 3 ++-
apps/swatch/stopwatch.js | 22 +++++++++++-----------
2 files changed, 13 insertions(+), 12 deletions(-)
diff --git a/apps/swatch/interface.html b/apps/swatch/interface.html
index 928c5fe39..45391fb6e 100644
--- a/apps/swatch/interface.html
+++ b/apps/swatch/interface.html
@@ -17,11 +17,12 @@ function getLapTimes() {
\n`;
lapData.forEach((lap,lapIndex) => {
lap.date = lap.n.substr(7,16).replace("_"," ");
+ lap.elapsed = lap.d.shift(); // remove first item
html += `
diff --git a/apps/swatch/stopwatch.js b/apps/swatch/stopwatch.js
index 478c22619..659f0606d 100644
--- a/apps/swatch/stopwatch.js
+++ b/apps/swatch/stopwatch.js
@@ -27,10 +27,10 @@ function updateLabels() {
g.setFont("6x8",1);
g.setFontAlign(-1,-1);
for (var i in lapTimes) {
- if (i<16)
+ if (i<15)
{g.drawString(lapTimes.length-i+": "+timeToText(lapTimes[i]),35,timeY + 40 + i*8);}
- else if (i<32)
- {g.drawString(lapTimes.length-i+": "+timeToText(lapTimes[i]),125,timeY + 40 + (i-16)*8);}
+ else if (i<30)
+ {g.drawString(lapTimes.length-i+": "+timeToText(lapTimes[i]),125,timeY + 40 + (i-15)*8);}
}
drawsecs();
}
@@ -92,12 +92,12 @@ setWatch(function() { // Start/stop
updateLabels();
if (started)
displayInterval = setInterval(function() {
- var last = tCurrent;
- if (started) tCurrent = Date.now();
- if (Math.floor(last/1000)!=Math.floor(tCurrent/1000))
- drawsecs();
- else
- drawms();
+ var last = tCurrent;
+ if (started) tCurrent = Date.now();
+ if (Math.floor(last/1000)!=Math.floor(tCurrent/1000))
+ drawsecs();
+ else
+ drawms();
}, 20);
}, BTN2, {repeat:true});
@@ -108,10 +108,10 @@ setWatch(function() { // Lap
lapTimes.unshift(tCurrent-tStart);
}
if (!started) { // save
- var timenow= Date();
var filename = "swatch-"+(new Date()).toISOString().substr(0,16).replace("T","_")+".json";
+ if (tCurrent!=tStart)
+ lapTimes.unshift(tCurrent-tStart);
// this maxes out the 28 char maximum
- lapTimes.unshift(tCurrent-tStart);
require("Storage").writeJSON(filename, getLapTimesArray());
tStart = tCurrent = tTotal = Date.now();
lapTimes = [];
From de2dc3a2cc23010af7d1cdb454048401ece9cf33 Mon Sep 17 00:00:00 2001
From: msdeibel
Date: Thu, 16 Apr 2020 11:26:57 +0200
Subject: [PATCH 025/101] Add readme and increment version
---
apps.json | 3 +-
apps/batchart/ChangeLog | 3 +-
apps/batchart/README.md | 67 +++++++++++++++++++++++++++++++++++++++++
3 files changed, 71 insertions(+), 2 deletions(-)
create mode 100644 apps/batchart/README.md
diff --git a/apps.json b/apps.json
index 7449a233b..7985c6776 100644
--- a/apps.json
+++ b/apps.json
@@ -1178,7 +1178,8 @@
"name": "Battery Chart",
"shortName":"Battery Chart",
"icon": "app.png",
- "version":"0.07",
+ "version":"0.08",
+ "readme": "README.md",
"description": "A widget and an app for recording and visualizing battery percentage over time.",
"tags": "app,widget,battery,time,record,chart,tool",
"storage": [
diff --git a/apps/batchart/ChangeLog b/apps/batchart/ChangeLog
index ba9e4e847..439d877be 100644
--- a/apps/batchart/ChangeLog
+++ b/apps/batchart/ChangeLog
@@ -4,4 +4,5 @@
0.04: chart in the app is now active.
0.05: Display temperature and LCD state in chart
0.06: Fixes widget events and charting of component states
-0.07: Improve logging and charting of component states and add widget icon
\ No newline at end of file
+0.07: Improve logging and charting of component states and add widget icon
+0.08: Fix for Home button in the app and README added.
\ No newline at end of file
diff --git a/apps/batchart/README.md b/apps/batchart/README.md
new file mode 100644
index 000000000..0ce2c646d
--- /dev/null
+++ b/apps/batchart/README.md
@@ -0,0 +1,67 @@
+# Summary
+
+Battery Chart contains a widget that records the battery usage as well as information that might influence this usage.
+
+The app that comes with provides a graph that accumulates this information in a single screen.
+
+## How the widget works
+
+The widget records data in a fixed interval of ten minutes.
+
+When this timespan has passed, it saves the following information to a file called `bclogx` where `x` is
+
+the current day retrieved by `new Date().getDay()`:
+
+- Battery percentage
+- Temperature (of the die)
+- LCD state
+- Compass state
+- HRM state
+- GPS state
+
+After seven days the logging rolls over and the previous data is overwritten.
+
+To properly handle the roll-over, the day of the previous logging operation is stored in `bcprvday`.
+
+The value is changed with the first recording operation of the new day.
+
+## How the App works
+
+### Events
+
+The app charts the last 144 (6/h * 24h) datapoints that have been recorded.
+
+If for the current day the 144 events have not been reached the list is padded with
+
+events from the previous `bclog` file(s).
+
+### Graph
+
+The graph then contains the battery percentage (left y-axis) and the temperature (right y-axis).
+
+In case the recorded temperature is outside the limits of the graph, the value is set to a minimum of 19 or a maximum of 41 and thus should be clearly visible outside of the graph's boundaries for the y-axis.
+
+The states of the various SoC devices are depicted below the graph. If at the time of recording the device was enabled a marker in the respective color is set, if not the pixels for this point in time stay black.
+
+If a device was not enabled during the 144 selected events, the name is not displayed.
+
+## File schema
+
+You can download the `bclog` files for your own analysis. They are `CSV` files without header rows and contain
+
+```
+timestamp,batteryPercentage,temperatureInDegreeC,deviceStates
+```
+
+with the `deviceStates` resembling a flag set consisting of
+
+```
+const switchableConsumers = {
+ none: 0,
+ lcd: 1,
+ compass: 2,
+ bluetooth: 4,
+ gps: 8,
+ hrm: 16
+};
+```
From a4ec9965ba5dae7768b20f25aadec9e6459411b4 Mon Sep 17 00:00:00 2001
From: Gordon Williams
Date: Thu, 16 Apr 2020 10:31:59 +0100
Subject: [PATCH 026/101] Make widget play well with other Gadgetbridge
widgets/apps
---
apps.json | 2 +-
apps/gbridge/ChangeLog | 1 +
apps/gbridge/widget.js | 2 ++
3 files changed, 4 insertions(+), 1 deletion(-)
diff --git a/apps.json b/apps.json
index e6fb7aaac..447d45154 100644
--- a/apps.json
+++ b/apps.json
@@ -93,7 +93,7 @@
{ "id": "gbridge",
"name": "Gadgetbridge",
"icon": "app.png",
- "version":"0.09",
+ "version":"0.10",
"description": "The default notification handler for Gadgetbridge notifications from Android",
"tags": "tool,system,android,widget",
"type":"widget",
diff --git a/apps/gbridge/ChangeLog b/apps/gbridge/ChangeLog
index 53f8a1b4c..f23a4eb6d 100644
--- a/apps/gbridge/ChangeLog
+++ b/apps/gbridge/ChangeLog
@@ -8,3 +8,4 @@
0.07: Move configuration to settings menu
0.08: Don't turn on LCD at start of every song
0.09: Update Bluetooth connection state automatically
+0.10: Make widget play well with other Gadgetbridge widgets/apps
diff --git a/apps/gbridge/widget.js b/apps/gbridge/widget.js
index 03c622443..a87b9d1ec 100644
--- a/apps/gbridge/widget.js
+++ b/apps/gbridge/widget.js
@@ -145,6 +145,7 @@
}
}
+ var _GB = global.GB;
global.GB = (event) => {
switch (event.t) {
case "notify":
@@ -160,6 +161,7 @@
handleCallEvent(event);
break;
}
+ if(_GB)setTimeout(_GB,0,event);
};
// Touch control
From eb4ac302ccd3464bd3d97b6f18b5fa635fcbe436 Mon Sep 17 00:00:00 2001
From: Gordon Williams
Date: Thu, 16 Apr 2020 11:33:36 +0100
Subject: [PATCH 027/101] Reduce memory usage further when running app settings
page
---
apps.json | 2 +-
apps/setting/ChangeLog | 1 +
apps/setting/settings.js | 2 +-
3 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/apps.json b/apps.json
index 447d45154..0adf7de0b 100644
--- a/apps.json
+++ b/apps.json
@@ -120,7 +120,7 @@
{ "id": "setting",
"name": "Settings",
"icon": "settings.png",
- "version":"0.15",
+ "version":"0.16",
"description": "A menu for setting up Bangle.js",
"tags": "tool,system",
"storage": [
diff --git a/apps/setting/ChangeLog b/apps/setting/ChangeLog
index 3d82be9c0..3acfb5fb0 100644
--- a/apps/setting/ChangeLog
+++ b/apps/setting/ChangeLog
@@ -17,3 +17,4 @@
Move LCD Brightness menu into more general LCD menu
0.14: Reduce memory usage when running app settings page
0.15: Reduce memory usage when running default clock chooser (#294)
+0.16: Reduce memory usage further when running app settings page
diff --git a/apps/setting/settings.js b/apps/setting/settings.js
index 9e343a68e..d0d88ce20 100644
--- a/apps/setting/settings.js
+++ b/apps/setting/settings.js
@@ -417,7 +417,7 @@ function showAppSettingsMenu() {
'< Back': ()=>showMainMenu(),
}
const apps = storage.list(/\.info$/)
- .map(app => {var a=storage.readJSON(app, 1);return (a&&a.settings)?a:undefined})
+ .map(app => {var a=storage.readJSON(app, 1);return (a&&a.settings)?{sortorder:a.sortorder,name:a.name,settings:a.settings}:undefined})
.filter(app => app) // filter out any undefined apps
.sort((a, b) => a.sortorder - b.sortorder)
if (apps.length === 0) {
From 92c24e2cfc5f5d5f1b391b61a57674641c20becd Mon Sep 17 00:00:00 2001
From: OmegaRogue
Date: Thu, 16 Apr 2020 12:35:43 +0200
Subject: [PATCH 028/101] Fix URLs in Webmanifest
Signed-off-by: OmegaRogue
---
site.webmanifest | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/site.webmanifest b/site.webmanifest
index 0565f159c..0d1fb4679 100644
--- a/site.webmanifest
+++ b/site.webmanifest
@@ -17,6 +17,6 @@
"theme_color": "#5755d9",
"background_color": "#5755d9",
"display": "standalone",
- "start_url": "https://omegavoid.codes/BangleApps",
- "scope": "https://omegavoid.codes/BangleApps"
+ "start_url": "https://banglejs.com/apps/",
+ "scope": "https://banglejs.com/apps/"
}
From b02af77e514aa4bbcb41a8ab2039bb81762a1b03 Mon Sep 17 00:00:00 2001
From: OmegaRogue
Date: Thu, 16 Apr 2020 12:48:35 +0200
Subject: [PATCH 029/101] Add Description, Remove add_to_apps.json
Add Description
Remove add_to_apps.json
Signed-off-by: OmegaRogue
---
apps.json | 4 ++--
apps/dane/ChangeLog | 3 ++-
apps/dane/add_to_apps.json | 22 ----------------------
3 files changed, 4 insertions(+), 25 deletions(-)
delete mode 100644 apps/dane/add_to_apps.json
diff --git a/apps.json b/apps.json
index 91d2d249b..c29bf8018 100644
--- a/apps.json
+++ b/apps.json
@@ -1247,8 +1247,8 @@
"name": "Digital Assistant, not EDITH",
"shortName": "DANE",
"icon": "app.png",
- "version": "0.06",
- "description": "A detailed description of my great app",
+ "version": "0.07",
+ "description": "A Watchface inspired by Tony Stark's EDITH",
"tags": "clock",
"type": "clock",
"allow_emulator": true,
diff --git a/apps/dane/ChangeLog b/apps/dane/ChangeLog
index 607d0adf5..419109ec1 100644
--- a/apps/dane/ChangeLog
+++ b/apps/dane/ChangeLog
@@ -1,4 +1,5 @@
0.01: New App!
0.04: Added Icon to watchface
0.05: bugfix
-0.06: moved and resized icon
\ No newline at end of file
+0.06: moved and resized icon
+0.07: Added Description
\ No newline at end of file
diff --git a/apps/dane/add_to_apps.json b/apps/dane/add_to_apps.json
deleted file mode 100644
index 6efb3ec85..000000000
--- a/apps/dane/add_to_apps.json
+++ /dev/null
@@ -1,22 +0,0 @@
-{
- "id": "dane",
- "name": "Digital Assistant, not EDITH",
- "shortName": "DANE",
- "icon": "app.png",
- "version": "0.06",
- "description": "A detailed description of my great app",
- "tags": "clock",
- "type": "clock",
- "allow_emulator": true,
- "storage": [
- {
- "name": "dane.app.js",
- "url": "app.js"
- },
- {
- "name": "dane.img",
- "url": "app-icon.js",
- "evaluate": true
- }
- ]
-}
\ No newline at end of file
From 217d19815456966c0fd268e31153d6bf8ac57e63 Mon Sep 17 00:00:00 2001
From: Richard de Boer
Date: Sun, 12 Apr 2020 00:26:08 +0200
Subject: [PATCH 030/101] Add a "data" section to apps.json, with data files to
clean on uninstall
These are added to `appid.info` as "dataFiles" or "storageFiles", and
can contain wildcards.
---
README.md | 25 ++++++++++++++++++++-----
bin/sanitycheck.js | 33 +++++++++++++++++++++++++++++++++
js/appinfo.js | 13 +++++++++++++
js/comms.js | 24 +++++++++++++++++++++---
js/index.js | 13 +++++++++++++
js/utils.js | 12 ++++++++++++
6 files changed, 112 insertions(+), 8 deletions(-)
diff --git a/README.md b/README.md
index ca874ad2f..7a96ad335 100644
--- a/README.md
+++ b/README.md
@@ -202,6 +202,13 @@ and which gives information about the app for the Launcher.
"files:"file1,file2,file3",
// added by BangleApps loader on upload - lists all files
// that belong to the app so it can be deleted
+ "dataFiles":"appid.data.json,appid.data?.json"
+ // added by BangleApps loader on upload - lists files that
+ // the app might write, so they can be deleted on uninstall
+ // typically these files are not uploaded, but created by the app
+ // these can include '*' or '?' wildcards
+ "storageFiles":"
+ // same as "dataFiles", except the app handles these as storageFile
}
```
@@ -240,16 +247,27 @@ and which gives information about the app for the Launcher.
"evaluate":true // if supplied, data isn't quoted into a String before upload
// (eg it's evaluated as JS)
},
+ ]
+ "data": [ // list of files the app writes to
+ {"name":"appid.data.json", // filename used in storage
+ "storageFile":true // if supplied, file is treated as storageFile
+ },
+ {"wildcard":"appid.data.*" // wildcard of filenames used in storage
+ }, // this is mutually exclusive with using "name"
+ ],
"sortorder" : 0, // optional - choose where in the list this goes.
// this should only really be used to put system
// stuff at the top
- ]
}
```
* name, icon and description present the app in the app loader.
* tags is used for grouping apps in the library, separate multiple entries by comma. Known tags are `tool`, `system`, `clock`, `game`, `sound`, `gps`, `widget`, `launcher` or empty.
* storage is used to identify the app files and how to handle them
+* data is used to clean up files when the app is uninstalled
+ (If the app has settings but no data section, it is assumed settings are
+ stored in `appid.settings.json`, so there is no need to add a data section
+ containing only that file)
### `apps.json`: `custom` element
@@ -351,19 +369,16 @@ Example `settings.js`
E.showMenu(appMenu)
})
```
-In this example the app needs to add both `app.settings.js` and
-`app.settings.json` to `apps.json`:
+In this example the app needs to add `app.settings.js` to `apps.json`:
```json
{ "id": "app",
...
"storage": [
...
{"name":"app.settings.js","url":"settings.js"},
- {"name":"app.settings.json","content":"{}"}
]
},
```
-That way removing the app also cleans up `app.settings.json`.
## Coding hints
diff --git a/bin/sanitycheck.js b/bin/sanitycheck.js
index 62b111ae0..fdf15a26b 100755
--- a/bin/sanitycheck.js
+++ b/bin/sanitycheck.js
@@ -74,6 +74,8 @@ apps.forEach((app,appIdx) => {
var fileNames = [];
app.storage.forEach((file) => {
if (!file.name) ERROR(`App ${app.id} has a file with no name`);
+ if (file.name.includes('?') || file.name.includes('*'))
+ ERROR(`App ${app.id} storage file ${file.name} contains wildcards`);
if (fileNames.includes(file.name))
ERROR(`App ${app.id} file ${file.name} is a duplicate`);
fileNames.push(file.name);
@@ -115,6 +117,37 @@ apps.forEach((app,appIdx) => {
if (!STORAGE_KEYS.includes(key)) ERROR(`App ${app.id}'s ${file.name} has unknown key ${key}`);
}
});
+ let dataNames = [];
+ (app.data||[]).forEach((data)=>{
+ if (!data.name && !data.wildcard) ERROR(`App ${app.id} has a data file with no name`);
+ if (dataNames.includes(data.name||data.wildcard))
+ ERROR(`App ${app.id} data file ${data.name||data.wildcard} is a duplicate`);
+ dataNames.push(data.name||data.wildcard)
+ if ('name' in data && 'wildcard' in data)
+ ERROR(`App ${app.id} data file ${data.name} has both name and wildcard`);
+ if (data.name) {
+ if (data.name.includes('?') || data.name.includes('*'))
+ ERROR(`App ${app.id} data file name ${data.name} contains wildcards`);
+ }
+ if (data.wildcard) {
+ if (!data.wildcard.includes('?') && !data.wildcard.includes('*'))
+ ERROR(`App ${app.id} data file wildcard ${data.wildcard} does not actually contains wildcard`);
+ if (data.wildcard.replace(/\?|\*/g,'') === '')
+ ERROR(`App ${app.id} data file wildcard ${data.wildcard} does not contain regular characters`);
+ else if (data.wildcard.replace(/\?|\*/g,'').length < 3)
+ WARN(`App ${app.id} data file wildcard ${data.wildcard} is very broad`);
+ else if (!data.wildcard.includes(app.id))
+ WARN(`App ${app.id} data file wildcard ${data.wildcard} does not include app ID`);
+ }
+ if ('storageFile' in data && typeof data.storageFile !== 'boolean')
+ ERROR(`App ${app.id} data file ${data.name||data.wildcard} has non-boolean value for "storageFile"`);
+ for (const key in data) {
+ if (!['name','wildcard','storageFile'].includes(key))
+ ERROR(`App ${app.id} data file ${data.name||data.wildcard} has unknown property "${key}"`);
+ }
+ });
+ if (fileNames.includes(app.id+".settings.js") && dataNames.length===1 && dataNames[0] === app.id+'.settings.json')
+ WARN(`App ${app.id} has settings, so does not need to declare data file ${app.id+'.settings.json'}`)
//console.log(fileNames);
if (isApp && !fileNames.includes(app.id+".app.js")) ERROR(`App ${app.id} has no entrypoint`);
if (isApp && !fileNames.includes(app.id+".img")) ERROR(`App ${app.id} has no JS icon`);
diff --git a/js/appinfo.js b/js/appinfo.js
index f4ab498b1..04c5da893 100644
--- a/js/appinfo.js
+++ b/js/appinfo.js
@@ -69,6 +69,19 @@ var AppInfo = {
var fileList = fileContents.map(storageFile=>storageFile.name);
fileList.unshift(appJSONName); // do we want this? makes life easier!
json.files = fileList.join(",");
+ let dataFileList = [], storageFileList = [];
+ if ('data' in app) {
+ // add "data" files to appropriate list
+ app.data.forEach(d=>{
+ if (d.storageFile) storageFileList.push(d.name||d.wildcard)
+ else dataFileList.push(d.name||d.wildcard)
+ })
+ } else if (json.settings) {
+ // settings but no data files: assume app uses .settings.json file
+ dataFileList.push(app.id + '.settings.json')
+ }
+ if (dataFileList.length) json.dataFiles = dataFileList.join(",");
+ if (storageFileList.length) json.storageFiles = storageFileList.join(",");
fileContents.push({
name : appJSONName,
content : JSON.stringify(json)
diff --git a/js/comms.js b/js/comms.js
index 1f840ada7..1e8250305 100644
--- a/js/comms.js
+++ b/js/comms.js
@@ -94,10 +94,28 @@ getInstalledApps : () => {
});
},
removeApp : app => { // expects an appid.info structure (i.e. with `files`)
- if (app.files === '') return Promise.resolve(); // nothing to erase
+ if (!app.files && !app.dataFiles && !app.storageFiles) return Promise.resolve(); // nothing to erase
Progress.show({title:`Removing ${app.name}`,sticky:true});
- var cmds = app.files.split(',').map(file=>{
- return `\x10require("Storage").erase(${toJS(file)});\n`;
+ let cmds = '\x10const s=require("Storage");\n';
+ // remove App files (regular files, exact names only)
+ cmds += app.files.split(',').map(file => `\x10s.erase(${toJS(file)});\n`).join("");
+ // remove Data files (regular files, can use wildcards)
+ cmds += (app.dataFiles||[]).split(',').map(file => {
+ const isGlob = (file.includes('*') || file.includes('?'))
+ if (!isGlob) return `\x10s.erase(${toJS(file)});\n`;
+ const regex = new RegExp(globToRegex(file))
+ return `\x10s.list(${regex}).forEach(f=>s.erase(f));\n`;
+ }).join("");
+ // remove Storage files (storageFiles, can use wildcards)
+ cmds += (app.storageFiles||[]).split(',').map(file => {
+ const isGlob = (file.includes('*') || file.includes('?'))
+ if (!isGlob) return `\x10s.open(${toJS(file)},'r').erase();\n`;
+ // storageFiles have a chunk number appended to their real name
+ const regex = globToRegex(file+'\u0001')
+ // open() doesn't want the chunk number though
+ let cmd = `\x10s.list(${regex}).forEach(f=>s.open(f.substring(0,f.length-1),'r').erase());\n`
+ // using a literal \u0001 char fails (not sure why), so escape it
+ return cmd.replace('\u0001', '\\x01')
}).join("");
console.log("removeApp", cmds);
return Comms.reset().then(new Promise((resolve,reject) => {
diff --git a/js/index.js b/js/index.js
index ef9bcb4f1..c48920315 100644
--- a/js/index.js
+++ b/js/index.js
@@ -349,6 +349,19 @@ function updateApp(app) {
.filter(f => f !== app.id + '.info')
.filter(f => !app.storage.some(s => s.name === f))
.join(',');
+ let dataFiles = (remove.dataFiles||'').split(','),
+ storageFiles = (remove.storageFiles||'').split(',')
+ if ('data' in app) {
+ // keep declared (in new version) data files
+ dataFiles = dataFiles.filter(f => app.data.some(d => (d.name||d.wildcard) === f))
+ storageFiles = storageFiles.filter(f => app.data.some(d => (d.name||d.wildcard) === f))
+ }
+ else if (remove.settings || app.settings) {
+ // app with settings but no data files declared: keep .settings.json
+ dataFiles = dataFiles.filter(f => f !== (app.id + '.settings.json'))
+ }
+ if (dataFiles.length) remove.dataFiles = dataFiles.join(',');
+ if (storageFiles.length) remove.storageFiles = storageFiles.join(',')
return Comms.removeApp(remove);
}).then(()=>{
showToast(`Updating ${app.name}...`);
diff --git a/js/utils.js b/js/utils.js
index d8c1b8063..50d319338 100644
--- a/js/utils.js
+++ b/js/utils.js
@@ -8,6 +8,18 @@ function escapeHtml(text) {
};
return text.replace(/[&<>"']/g, function(m) { return map[m]; });
}
+// simple glob to regex conversion, only supports "*" and "?" wildcards
+function globToRegex(pattern) {
+ const ESCAPE = '.*+-?^${}()|[]\\';
+ const regex = pattern.replace(/./g, c => {
+ switch (c) {
+ case '?': return '.';
+ case '*': return '.*';
+ default: return ESCAPE.includes(c) ? ('\\' + c) : c;
+ }
+ });
+ return new RegExp('^'+regex+'$');
+}
function htmlToArray(collection) {
return [].slice.call(collection);
}
From 9e0fd91339dc48acd38c4c0687000f199ddb5c23 Mon Sep 17 00:00:00 2001
From: Richard de Boer
Date: Wed, 15 Apr 2020 21:30:44 +0200
Subject: [PATCH 031/101] Data files: save all data files as a single string
Separate regular and storage files by a semicolon
---
README.md | 4 +---
bin/sanitycheck.js | 5 +++--
js/appinfo.js | 39 ++++++++++++++++++++++++++++++++-------
js/comms.js | 14 ++++++++------
js/index.js | 18 ++++++++----------
5 files changed, 52 insertions(+), 28 deletions(-)
diff --git a/README.md b/README.md
index 7a96ad335..a04ee95b2 100644
--- a/README.md
+++ b/README.md
@@ -202,13 +202,11 @@ and which gives information about the app for the Launcher.
"files:"file1,file2,file3",
// added by BangleApps loader on upload - lists all files
// that belong to the app so it can be deleted
- "dataFiles":"appid.data.json,appid.data?.json"
+ "data":"appid.data.json,appid.data?.json;appidStorageFile,appidStorageFile*"
// added by BangleApps loader on upload - lists files that
// the app might write, so they can be deleted on uninstall
// typically these files are not uploaded, but created by the app
// these can include '*' or '?' wildcards
- "storageFiles":"
- // same as "dataFiles", except the app handles these as storageFile
}
```
diff --git a/bin/sanitycheck.js b/bin/sanitycheck.js
index fdf15a26b..197ebf57e 100755
--- a/bin/sanitycheck.js
+++ b/bin/sanitycheck.js
@@ -39,9 +39,10 @@ try{
const APP_KEYS = [
'id', 'name', 'shortName', 'version', 'icon', 'description', 'tags', 'type',
- 'sortorder', 'readme', 'custom', 'interface', 'storage', 'allow_emulator',
+ 'sortorder', 'readme', 'custom', 'interface', 'storage', 'data', 'allow_emulator',
];
const STORAGE_KEYS = ['name', 'url', 'content', 'evaluate'];
+const DATA_KEYS = ['name', 'wildcard', 'storageFile'];
apps.forEach((app,appIdx) => {
if (!app.id) ERROR(`App ${appIdx} has no id`);
@@ -142,7 +143,7 @@ apps.forEach((app,appIdx) => {
if ('storageFile' in data && typeof data.storageFile !== 'boolean')
ERROR(`App ${app.id} data file ${data.name||data.wildcard} has non-boolean value for "storageFile"`);
for (const key in data) {
- if (!['name','wildcard','storageFile'].includes(key))
+ if (!DATA_KEYS.includes(key))
ERROR(`App ${app.id} data file ${data.name||data.wildcard} has unknown property "${key}"`);
}
});
diff --git a/js/appinfo.js b/js/appinfo.js
index 04c5da893..413098bc4 100644
--- a/js/appinfo.js
+++ b/js/appinfo.js
@@ -69,26 +69,51 @@ var AppInfo = {
var fileList = fileContents.map(storageFile=>storageFile.name);
fileList.unshift(appJSONName); // do we want this? makes life easier!
json.files = fileList.join(",");
- let dataFileList = [], storageFileList = [];
+ let data = {dataFiles: [], storageFiles: []};
if ('data' in app) {
// add "data" files to appropriate list
app.data.forEach(d=>{
- if (d.storageFile) storageFileList.push(d.name||d.wildcard)
- else dataFileList.push(d.name||d.wildcard)
+ if (d.storageFile) data.storageFiles.push(d.name||d.wildcard)
+ else data.dataFiles.push(d.name||d.wildcard)
})
} else if (json.settings) {
// settings but no data files: assume app uses .settings.json file
- dataFileList.push(app.id + '.settings.json')
+ data.dataFiles.push(app.id + '.settings.json')
}
- if (dataFileList.length) json.dataFiles = dataFileList.join(",");
- if (storageFileList.length) json.storageFiles = storageFileList.join(",");
+ const dataString = AppInfo.makeDataString(data)
+ if (dataString) json.data = dataString
fileContents.push({
name : appJSONName,
content : JSON.stringify(json)
});
resolve(fileContents);
});
- }
+ },
+ // (.info).data holds filenames of data: both regular and storageFiles
+ // These are stored as: (note comma vs semicolons)
+ // "fil1,file2", "file1,file2;storageFileA,storageFileB" or ";storageFileA"
+ /**
+ * Convert appid.info "data" to object with file names/patterns
+ * Passing in undefined works
+ * @param data "data" as stored in appid.info
+ * @returns {{storageFiles:[], dataFiles:[]}}
+ */
+ parseDataString(data) {
+ data = data || '';
+ let [files = [], storage = []] = data.split(';').map(d => d.split(','))
+ return {dataFiles: files, storageFiles: storage}
+ },
+ /**
+ * Convert object with file names/patterns to appid.info "data" string
+ * Passing in an incomplete object will not work
+ * @param data {{storageFiles:[], dataFiles:[]}}
+ * @returns {string} "data" to store in appid.info
+ */
+ makeDataString(data) {
+ if (!data.dataFiles.length && !data.storageFiles.length) { return '' }
+ if (!data.storageFiles.length) { return data.dataFiles.join(',') }
+ return [data.dataFiles.join(','),data.storageFiles.join(',')].join(';')
+ },
};
if ("undefined"!=typeof module)
diff --git a/js/comms.js b/js/comms.js
index 1e8250305..736a2b7c7 100644
--- a/js/comms.js
+++ b/js/comms.js
@@ -94,20 +94,22 @@ getInstalledApps : () => {
});
},
removeApp : app => { // expects an appid.info structure (i.e. with `files`)
- if (!app.files && !app.dataFiles && !app.storageFiles) return Promise.resolve(); // nothing to erase
+ if (!app.files && !app.data) return Promise.resolve(); // nothing to erase
Progress.show({title:`Removing ${app.name}`,sticky:true});
let cmds = '\x10const s=require("Storage");\n';
- // remove App files (regular files, exact names only)
+ // remove App files: regular files, exact names only
cmds += app.files.split(',').map(file => `\x10s.erase(${toJS(file)});\n`).join("");
- // remove Data files (regular files, can use wildcards)
- cmds += (app.dataFiles||[]).split(',').map(file => {
+ // remove app Data: (dataFiles and storageFiles)
+ const data = AppInfo.parseDataString(app.data)
+ // regular files, can use wildcards
+ cmds += data.dataFiles.map(file => {
const isGlob = (file.includes('*') || file.includes('?'))
if (!isGlob) return `\x10s.erase(${toJS(file)});\n`;
const regex = new RegExp(globToRegex(file))
return `\x10s.list(${regex}).forEach(f=>s.erase(f));\n`;
}).join("");
- // remove Storage files (storageFiles, can use wildcards)
- cmds += (app.storageFiles||[]).split(',').map(file => {
+ // storageFiles, can use wildcards
+ cmds += data.storageFiles.map(file => {
const isGlob = (file.includes('*') || file.includes('?'))
if (!isGlob) return `\x10s.open(${toJS(file)},'r').erase();\n`;
// storageFiles have a chunk number appended to their real name
diff --git a/js/index.js b/js/index.js
index c48920315..41a43730e 100644
--- a/js/index.js
+++ b/js/index.js
@@ -349,19 +349,17 @@ function updateApp(app) {
.filter(f => f !== app.id + '.info')
.filter(f => !app.storage.some(s => s.name === f))
.join(',');
- let dataFiles = (remove.dataFiles||'').split(','),
- storageFiles = (remove.storageFiles||'').split(',')
+ let data = AppInfo.parseDataString(remove.data)
if ('data' in app) {
- // keep declared (in new version) data files
- dataFiles = dataFiles.filter(f => app.data.some(d => (d.name||d.wildcard) === f))
- storageFiles = storageFiles.filter(f => app.data.some(d => (d.name||d.wildcard) === f))
- }
- else if (remove.settings || app.settings) {
+ // only remove data files which are no longer declared in new app version
+ const removeData = (f) => !app.data.some(d => (d.name || d.wildcard)===f)
+ data.dataFiles = data.dataFiles.filter(removeData)
+ data.storageFiles = data.storageFiles.filter(removeData)
+ } else if (remove.settings || app.settings) {
// app with settings but no data files declared: keep .settings.json
- dataFiles = dataFiles.filter(f => f !== (app.id + '.settings.json'))
+ data.dataFiles = data.dataFiles.filter(f => f!==(app.id+'.settings.json'))
}
- if (dataFiles.length) remove.dataFiles = dataFiles.join(',');
- if (storageFiles.length) remove.storageFiles = storageFiles.join(',')
+ remove.data = AppInfo.makeDataString(data)
return Comms.removeApp(remove);
}).then(()=>{
showToast(`Updating ${app.name}...`);
From 3e5cfcdc12cdaadbf5f761ea2883905ca8ad4583 Mon Sep 17 00:00:00 2001
From: msdeibel
Date: Thu, 16 Apr 2020 14:32:42 +0200
Subject: [PATCH 032/101] Fixed home button and added readme for WOHRM
---
apps.json | 1 +
apps/wohrm/ChangeLog | 1 +
apps/wohrm/README.md | 29 +++++++++++++++++++++++++++++
apps/wohrm/app.js | 7 ++-----
4 files changed, 33 insertions(+), 5 deletions(-)
create mode 100644 apps/wohrm/README.md
diff --git a/apps.json b/apps.json
index 899eed03e..459ecb3ab 100644
--- a/apps.json
+++ b/apps.json
@@ -891,6 +891,7 @@
"name": "Workout HRM",
"icon": "app.png",
"version":"0.06",
+ "readme": "README.md",
"description": "Workout heart rate monitor notifies you with a buzz if your heart rate goes above or below the set limits.",
"tags": "hrm,workout",
"type": "app",
diff --git a/apps/wohrm/ChangeLog b/apps/wohrm/ChangeLog
index f5c64dbee..53c451bcd 100644
--- a/apps/wohrm/ChangeLog
+++ b/apps/wohrm/ChangeLog
@@ -4,3 +4,4 @@
0.04: Only buzz on high confidence (>85%)
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
\ No newline at end of file
diff --git a/apps/wohrm/README.md b/apps/wohrm/README.md
new file mode 100644
index 000000000..ad9e82525
--- /dev/null
+++ b/apps/wohrm/README.md
@@ -0,0 +1,29 @@
+# Summary
+Workout heart rate monitor that buzzes when your heart rate hits the limits.
+
+This app is for the [Bangle.js watch](https://banglejs.com/). While active it monitors your heart rate
+and will notify you with a buzz whenever your heart rate falls below or jumps above the set limits.
+
+# How it works
+[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
+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.
+
+For setting the upper limit act accordingly after pressing button 5 (the right part of the watch's screen).
+
+## Reading Reliability
+As per the specs of the watch the HR monitor is not 100% reliable all the time.
+That's why the WOHRM displays a confidence value for each reading of the current heart rate.
+
+To the left and right of the "Current" value two colored bars indicate the confidence in
+the received value: For 85% and above the bars are green, between 84% and 50% the bars are yellow
+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.
+
+# HRM usage
+The HRM is switched on when the app is started. It stays switch on while the app is running, even
+when the watch screen goes to stand-by.
diff --git a/apps/wohrm/app.js b/apps/wohrm/app.js
index 7e0af4219..b3ce8acc8 100644
--- a/apps/wohrm/app.js
+++ b/apps/wohrm/app.js
@@ -287,13 +287,11 @@ function resetHighlightTimeout() {
setterHighlightTimeout = setTimeout(setLimitSetterToNone, 2000);
}
-// Show launcher when middle button pressed
function switchOffApp(){
Bangle.setHRMPower(0);
Bangle.showLauncher();
}
-// special function to handle display switch on
Bangle.on('lcdPower', (on) => {
g.clear();
if (on) {
@@ -312,19 +310,18 @@ Bangle.setHRMPower(1);
Bangle.on('HRM', onHrm);
setWatch(incrementLimit, BTN1, {edge:"rising", debounce:50, repeat:true});
-setWatch(switchOffApp, BTN2, {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();
-//drawTrainingHeartRate();
renderHomeIcon();
renderLowerLimitBackground();
renderUpperLimitBackground();
-// refesh every sec
setInterval(drawTrainingHeartRate, 1000);
From 9f0adf190019b5dd0bcef5f713c34dabd8ca1c3d Mon Sep 17 00:00:00 2001
From: Richard de Boer
Date: Thu, 16 Apr 2020 17:06:25 +0200
Subject: [PATCH 033/101] Data files: remove settings magic, some more
sanitychecks
---
README.md | 13 +++++----
bin/sanitycheck.js | 69 ++++++++++++++++++++++++++++++++++++++++------
js/appinfo.js | 9 ++----
js/comms.js | 7 ++---
js/index.js | 3 --
5 files changed, 73 insertions(+), 28 deletions(-)
diff --git a/README.md b/README.md
index a04ee95b2..a45647daf 100644
--- a/README.md
+++ b/README.md
@@ -263,9 +263,6 @@ and which gives information about the app for the Launcher.
* tags is used for grouping apps in the library, separate multiple entries by comma. Known tags are `tool`, `system`, `clock`, `game`, `sound`, `gps`, `widget`, `launcher` or empty.
* storage is used to identify the app files and how to handle them
* data is used to clean up files when the app is uninstalled
- (If the app has settings but no data section, it is assumed settings are
- stored in `appid.settings.json`, so there is no need to add a data section
- containing only that file)
### `apps.json`: `custom` element
@@ -351,10 +348,10 @@ Example `settings.js`
```js
// make sure to enclose the function in parentheses
(function(back) {
- let settings = require('Storage').readJSON('app.settings.json',1)||{};
+ let settings = require('Storage').readJSON('app.json',1)||{};
function save(key, value) {
settings[key] = value;
- require('Storage').write('app.settings.json',settings);
+ require('Storage').write('app.json',settings);
}
const appMenu = {
'': {'title': 'App Settings'},
@@ -367,13 +364,17 @@ Example `settings.js`
E.showMenu(appMenu)
})
```
-In this example the app needs to add `app.settings.js` to `apps.json`:
+In this example the app needs to add `app.settings.js` to `storage` in `apps.json`.
+It should also add `app.json` to `data`, to make sure it is cleaned up when the app is uninstalled.
```json
{ "id": "app",
...
"storage": [
...
{"name":"app.settings.js","url":"settings.js"},
+ ],
+ "data": [
+ {"name":"app.json"}
]
},
```
diff --git a/bin/sanitycheck.js b/bin/sanitycheck.js
index 197ebf57e..51230f6fa 100755
--- a/bin/sanitycheck.js
+++ b/bin/sanitycheck.js
@@ -43,7 +43,22 @@ const APP_KEYS = [
];
const STORAGE_KEYS = ['name', 'url', 'content', 'evaluate'];
const DATA_KEYS = ['name', 'wildcard', 'storageFile'];
+const FORBIDDEN_FILE_NAME_CHARS = /[,;]/; // used as separators in appid.info
+function globToRegex(pattern) {
+ const ESCAPE = '.*+-?^${}()|[]\\';
+ const regex = pattern.replace(/./g, c => {
+ switch (c) {
+ case '?': return '.';
+ case '*': return '.*';
+ default: return ESCAPE.includes(c) ? ('\\' + c) : c;
+ }
+ });
+ return new RegExp('^'+regex+'$');
+}
+const isGlob = f => /[?*]/.test(f)
+// All storage+data files in all apps: {app:,[file: | data:]}
+let allFiles = [];
apps.forEach((app,appIdx) => {
if (!app.id) ERROR(`App ${appIdx} has no id`);
//console.log(`Checking ${app.id}...`);
@@ -75,11 +90,13 @@ apps.forEach((app,appIdx) => {
var fileNames = [];
app.storage.forEach((file) => {
if (!file.name) ERROR(`App ${app.id} has a file with no name`);
- if (file.name.includes('?') || file.name.includes('*'))
- ERROR(`App ${app.id} storage file ${file.name} contains wildcards`);
+ if (isGlob(file.name)) ERROR(`App ${app.id} storage file ${file.name} contains wildcards`);
+ let char = file.name.match(FORBIDDEN_FILE_NAME_CHARS)
+ if (char) ERROR(`App ${app.id} storage file ${file.name} contains invalid character "${char[0]}"`)
if (fileNames.includes(file.name))
ERROR(`App ${app.id} file ${file.name} is a duplicate`);
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`);
if (!file.url && !file.content && !app.custom) ERROR(`App ${app.id} file ${file.name} has no contents`);
var fileContents = "";
@@ -124,14 +141,13 @@ apps.forEach((app,appIdx) => {
if (dataNames.includes(data.name||data.wildcard))
ERROR(`App ${app.id} data file ${data.name||data.wildcard} is a duplicate`);
dataNames.push(data.name||data.wildcard)
+ allFiles.push({app: app.id, data: (data.name||data.wildcard)});
if ('name' in data && 'wildcard' in data)
ERROR(`App ${app.id} data file ${data.name} has both name and wildcard`);
- if (data.name) {
- if (data.name.includes('?') || data.name.includes('*'))
- ERROR(`App ${app.id} data file name ${data.name} contains wildcards`);
- }
+ if (isGlob(data.name))
+ ERROR(`App ${app.id} data file name ${data.name} contains wildcards`);
if (data.wildcard) {
- if (!data.wildcard.includes('?') && !data.wildcard.includes('*'))
+ if (!isGlob(data.wildcard))
ERROR(`App ${app.id} data file wildcard ${data.wildcard} does not actually contains wildcard`);
if (data.wildcard.replace(/\?|\*/g,'') === '')
ERROR(`App ${app.id} data file wildcard ${data.wildcard} does not contain regular characters`);
@@ -140,6 +156,8 @@ apps.forEach((app,appIdx) => {
else if (!data.wildcard.includes(app.id))
WARN(`App ${app.id} data file wildcard ${data.wildcard} does not include app ID`);
}
+ let char = (data.name||data.wildcard).match(FORBIDDEN_FILE_NAME_CHARS)
+ if (char) ERROR(`App ${app.id} data file ${data.name||data.wildcard} contains invalid character "${char[0]}"`)
if ('storageFile' in data && typeof data.storageFile !== 'boolean')
ERROR(`App ${app.id} data file ${data.name||data.wildcard} has non-boolean value for "storageFile"`);
for (const key in data) {
@@ -147,8 +165,24 @@ apps.forEach((app,appIdx) => {
ERROR(`App ${app.id} data file ${data.name||data.wildcard} has unknown property "${key}"`);
}
});
- if (fileNames.includes(app.id+".settings.js") && dataNames.length===1 && dataNames[0] === app.id+'.settings.json')
- WARN(`App ${app.id} has settings, so does not need to declare data file ${app.id+'.settings.json'}`)
+ // prefer "appid.json" over "appid.settings.json" (TODO: change to ERROR once all apps comply?)
+ if (dataNames.includes(app.id+".settings.json") && !dataNames.includes(app.id+".json"))
+ WARN(`App ${app.id} uses data file ${app.id+'.settings.json'} instead of ${app.id+'.json'}`)
+ // settings files should be listed under data, not storage (TODO: change to ERROR once all apps comply?)
+ if (fileNames.includes(app.id+".settings.json"))
+ WARN(`App ${app.id} uses storage file ${app.id+'.settings.json'} instead of data file`)
+ if (fileNames.includes(app.id+".json"))
+ WARN(`App ${app.id} uses storage file ${app.id+'.json'} instead of data file`)
+ // warn if storage file matches data file of same app
+ dataNames.forEach(dataName=>{
+ const glob = globToRegex(dataName)
+ fileNames.forEach(fileName=>{
+ if (glob.test(fileName)) {
+ if (isGlob(dataName)) WARN(`App ${app.id} storage file ${fileName} matches data wildcard ${dataName}`)
+ else WARN(`App ${app.id} storage file ${fileName} is also listed in data`)
+ }
+ })
+ })
//console.log(fileNames);
if (isApp && !fileNames.includes(app.id+".app.js")) ERROR(`App ${app.id} has no entrypoint`);
if (isApp && !fileNames.includes(app.id+".img")) ERROR(`App ${app.id} has no JS icon`);
@@ -157,3 +191,20 @@ apps.forEach((app,appIdx) => {
if (!APP_KEYS.includes(key)) ERROR(`App ${app.id} has unknown key ${key}`);
}
});
+// Do not allow files from different apps to collide
+let fileA
+while(fileA=allFiles.pop()) {
+ const nameA = (fileA.file||fileA.data),
+ globA = globToRegex(nameA),
+ typeA = fileA.file?'storage':'data'
+ allFiles.forEach(fileB => {
+ const nameB = (fileB.file||fileB.data),
+ globB = globToRegex(nameB),
+ typeB = fileB.file?'storage':'data'
+ 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 ERROR(`App ${fileB.app} ${typeB} file ${nameB} is also listed as ${typeA} file for app ${fileA.app}`)
+ }
+ })
+}
diff --git a/js/appinfo.js b/js/appinfo.js
index 413098bc4..56b6ff2f8 100644
--- a/js/appinfo.js
+++ b/js/appinfo.js
@@ -69,19 +69,16 @@ var AppInfo = {
var fileList = fileContents.map(storageFile=>storageFile.name);
fileList.unshift(appJSONName); // do we want this? makes life easier!
json.files = fileList.join(",");
- let data = {dataFiles: [], storageFiles: []};
if ('data' in app) {
+ let data = {dataFiles: [], storageFiles: []};
// add "data" files to appropriate list
app.data.forEach(d=>{
if (d.storageFile) data.storageFiles.push(d.name||d.wildcard)
else data.dataFiles.push(d.name||d.wildcard)
})
- } else if (json.settings) {
- // settings but no data files: assume app uses .settings.json file
- data.dataFiles.push(app.id + '.settings.json')
+ const dataString = AppInfo.makeDataString(data)
+ if (dataString) json.data = dataString
}
- const dataString = AppInfo.makeDataString(data)
- if (dataString) json.data = dataString
fileContents.push({
name : appJSONName,
content : JSON.stringify(json)
diff --git a/js/comms.js b/js/comms.js
index 736a2b7c7..b825a06ad 100644
--- a/js/comms.js
+++ b/js/comms.js
@@ -101,17 +101,16 @@ removeApp : app => { // expects an appid.info structure (i.e. with `files`)
cmds += app.files.split(',').map(file => `\x10s.erase(${toJS(file)});\n`).join("");
// remove app Data: (dataFiles and storageFiles)
const data = AppInfo.parseDataString(app.data)
+ const isGlob = f => /[?*]/.test(f)
// regular files, can use wildcards
cmds += data.dataFiles.map(file => {
- const isGlob = (file.includes('*') || file.includes('?'))
- if (!isGlob) return `\x10s.erase(${toJS(file)});\n`;
+ if (!isGlob(file)) return `\x10s.erase(${toJS(file)});\n`;
const regex = new RegExp(globToRegex(file))
return `\x10s.list(${regex}).forEach(f=>s.erase(f));\n`;
}).join("");
// storageFiles, can use wildcards
cmds += data.storageFiles.map(file => {
- const isGlob = (file.includes('*') || file.includes('?'))
- if (!isGlob) return `\x10s.open(${toJS(file)},'r').erase();\n`;
+ if (!isGlob(file)) return `\x10s.open(${toJS(file)},'r').erase();\n`;
// storageFiles have a chunk number appended to their real name
const regex = globToRegex(file+'\u0001')
// open() doesn't want the chunk number though
diff --git a/js/index.js b/js/index.js
index 41a43730e..483dc09c7 100644
--- a/js/index.js
+++ b/js/index.js
@@ -355,9 +355,6 @@ function updateApp(app) {
const removeData = (f) => !app.data.some(d => (d.name || d.wildcard)===f)
data.dataFiles = data.dataFiles.filter(removeData)
data.storageFiles = data.storageFiles.filter(removeData)
- } else if (remove.settings || app.settings) {
- // app with settings but no data files declared: keep .settings.json
- data.dataFiles = data.dataFiles.filter(f => f!==(app.id+'.settings.json'))
}
remove.data = AppInfo.makeDataString(data)
return Comms.removeApp(remove);
From 372f5123f4fe611284d0f6f5fc5a09d30a585ae8 Mon Sep 17 00:00:00 2001
From: Purple-Tentacle <59914607+Purple-Tentacle@users.noreply.github.com>
Date: Fri, 17 Apr 2020 15:55:41 +0200
Subject: [PATCH 034/101] chronowid 0.02
---
apps/chronowid/ChangeLog | 3 ++-
apps/chronowid/README.md | 9 ++++++---
apps/chronowid/app.js | 11 +++++++++--
apps/chronowid/widget.js | 18 +++++++++---------
4 files changed, 26 insertions(+), 15 deletions(-)
diff --git a/apps/chronowid/ChangeLog b/apps/chronowid/ChangeLog
index a6f342f01..263145407 100644
--- a/apps/chronowid/ChangeLog
+++ b/apps/chronowid/ChangeLog
@@ -1 +1,2 @@
-0.01: New widget and app!
+0.01: New widget and app!
+0.02: Setting to reset values, timer buzzes at 00:00 and not later (see readme)
\ No newline at end of file
diff --git a/apps/chronowid/README.md b/apps/chronowid/README.md
index f31c24c7b..f422dd956 100644
--- a/apps/chronowid/README.md
+++ b/apps/chronowid/README.md
@@ -5,6 +5,8 @@ The advantage is, that you can still see your normal watchface and other widgets
The widget is always active, but only shown when the timer is on.
Hours, minutes, seconds and timer status can be set with an app.
+Depending on when you start the timer, it may alert up to 0,999 seconds early. This is because it checks only for full seconds. When there is less than one seconds left, it buzzes. This cannot be avoided without checking more than every second, which I would like to avoid.
+
## Screenshots
TBD
@@ -18,18 +20,19 @@ TBD
There are no settings section in the settings app, timer can be set using an app.
+* Reset values: Reset hours, minutes, seconds to 0; set timer on to false; write to settings file
* Hours: Set the hours for the timer
* Minutes: Set the minutes for the timer
* Seconds: Set the seconds for the timer
-* Timer on: Starts the timer and displays the widget when set to 'On'. You have to leave the app. The widget is always there, but only visible when timer is on.
+* Timer on: Starts the timer and displays the widget when set to 'On'. You have to leave the app to load the widget which starts the timer. The widget is always there, but only visible when timer is on.
## Releases
-* Offifical app loader: Not yet published.
+* Offifical app loader: https://github.com/espruino/BangleApps/tree/master/apps/chronowid (https://banglejs.com/apps/)
* Forked app loader: https://github.com/Purple-Tentacle/BangleApps/tree/master/apps/chronowid (https://purple-tentacle.github.io/BangleApps/index.html#)
* Development: https://github.com/Purple-Tentacle/BangleAppsDev/tree/master/apps/chronowid
## Requests
-If you have any feature requests, please contact me on the Espruino forum: http://forum.espruino.com/profiles/155005/
\ No newline at end of file
+If you have any feature requests, please write here: http://forum.espruino.com/conversations/345972/
\ No newline at end of file
diff --git a/apps/chronowid/app.js b/apps/chronowid/app.js
index 48401a7bb..dd9531233 100644
--- a/apps/chronowid/app.js
+++ b/apps/chronowid/app.js
@@ -30,7 +30,6 @@ settingsChronowid = storage.readJSON('chronowid.json',1);
if (!settingsChronowid) resetSettings();
E.on('kill', () => {
- print("-KILL-");
updateSettings();
});
@@ -45,6 +44,14 @@ function showMenu() {
timerMenu.started.value = settingsChronowid.started;
}
},
+ 'Reset values': function() {
+ settingsChronowid.hours = 0;
+ settingsChronowid.minutes = 0;
+ settingsChronowid.seconds = 0;
+ settingsChronowid.started = false;
+ updateSettings();
+ showMenu();
+ },
'Hours': {
value: settingsChronowid.hours,
min: 0,
@@ -88,4 +95,4 @@ function showMenu() {
return E.showMenu(timerMenu);
}
-showMenu();
+showMenu();
\ No newline at end of file
diff --git a/apps/chronowid/widget.js b/apps/chronowid/widget.js
index 708bc6345..557104d92 100644
--- a/apps/chronowid/widget.js
+++ b/apps/chronowid/widget.js
@@ -36,19 +36,18 @@
//counts down, calculates and displays
function countDown() {
- //printDebug();
now = new Date();
diff = settingsChronowid.goal - now; //calculate difference
WIDGETS["chronowid"].draw();
//time is up
- if (settingsChronowid.started && diff <= 0) {
+ if (settingsChronowid.started && diff < 1000) {
Bangle.buzz(1500);
//write timer off to file
settingsChronowid.started = false;
storage.writeJSON('chronowid.json', settingsChronowid);
clearInterval(interval); //stop interval
- //printDebug();
}
+ //printDebug();
}
// draw your widget
@@ -72,12 +71,13 @@
g.drawString(getTime(diff), this.x+1, this.y+((height/2)-4)); //display hour 00:00:00
}
}
- else {
- width = 58;
- g.clearRect(this.x,this.y,this.x+width,this.y+height);
- g.setFont("6x8", 2);
- g.drawString("END", this.x+15, this.y+5);
- }
+ // not needed anymoe, because we check if diff < 1000 now, so 00:00 is displayed.
+ // else {
+ // width = 58;
+ // g.clearRect(this.x,this.y,this.x+width,this.y+height);
+ // g.setFont("6x8", 2);
+ // g.drawString("END", this.x+15, this.y+5);
+ // }
}
if (settingsChronowid.started) interval = setInterval(countDown, 1000); //start countdown each second
From dcb2a6c2d9b4f327796a3aaec53a43e33e4d715d Mon Sep 17 00:00:00 2001
From: Purple-Tentacle <59914607+Purple-Tentacle@users.noreply.github.com>
Date: Fri, 17 Apr 2020 15:56:55 +0200
Subject: [PATCH 035/101] chronowid 0.02
---
apps.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/apps.json b/apps.json
index 447d45154..e2b20cca4 100644
--- a/apps.json
+++ b/apps.json
@@ -1142,7 +1142,7 @@
"name": "Chrono Widget",
"shortName":"Chrono Widget",
"icon": "app.png",
- "version":"0.01",
+ "version":"0.02",
"description": "Chronometer (timer) which runs as widget.",
"tags": "tools,widget",
"readme": "README.md",
From 9a664ecae4b9b64a7f9e773ff43adbd62c0ab3fa Mon Sep 17 00:00:00 2001
From: Purple-Tentacle <59914607+Purple-Tentacle@users.noreply.github.com>
Date: Fri, 17 Apr 2020 16:38:33 +0200
Subject: [PATCH 036/101] Compass: 0.02
---
apps/compass/ChangeLog | 2 ++
apps/compass/compass.js | 77 +++++++++++++++++++++++------------------
2 files changed, 45 insertions(+), 34 deletions(-)
create mode 100644 apps/compass/ChangeLog
diff --git a/apps/compass/ChangeLog b/apps/compass/ChangeLog
new file mode 100644
index 000000000..efd778c72
--- /dev/null
+++ b/apps/compass/ChangeLog
@@ -0,0 +1,2 @@
+0.01: New App!
+0.02: Show text if uncalibrated
\ No newline at end of file
diff --git a/apps/compass/compass.js b/apps/compass/compass.js
index 10895e3cd..a014d79ff 100644
--- a/apps/compass/compass.js
+++ b/apps/compass/compass.js
@@ -1,34 +1,43 @@
-g.clear();
-g.setColor(0,0.5,1);
-g.fillCircle(120,130,80,80);
-g.setColor(0,0,0);
-g.fillCircle(120,130,70,70);
-
-function arrow(r,c) {
- r=r*Math.PI/180;
- var p = Math.PI/2;
- g.setColor(c);
- g.fillPoly([
- 120+60*Math.sin(r), 130-60*Math.cos(r),
- 120+10*Math.sin(r+p), 130-10*Math.cos(r+p),
- 120+10*Math.sin(r+-p), 130-10*Math.cos(r-p),
- ]);
-}
-
-var oldHeading = 0;
-Bangle.on('mag', function(m) {
- if (!Bangle.isLCDOn()) return;
- g.setFont("6x8",3);
- g.setColor(0);
- g.fillRect(70,0,170,24);
- g.setColor(0xffff);
- g.setFontAlign(0,0);
- g.drawString(isNaN(m.heading)?"---":Math.round(m.heading),120,12);
- g.setColor(0,0,0);
- arrow(oldHeading,0);
- arrow(oldHeading+180,0);
- arrow(m.heading,0xF800);
- arrow(m.heading+180,0x001F);
- oldHeading = m.heading;
-});
-Bangle.setCompassPower(1);
+g.clear();
+g.setColor(0,0.5,1);
+g.fillCircle(120,130,80,80);
+g.setColor(0,0,0);
+g.fillCircle(120,130,70,70);
+
+function arrow(r,c) {
+ r=r*Math.PI/180;
+ var p = Math.PI/2;
+ g.setColor(c);
+ g.fillPoly([
+ 120+60*Math.sin(r), 130-60*Math.cos(r),
+ 120+10*Math.sin(r+p), 130-10*Math.cos(r+p),
+ 120+10*Math.sin(r+-p), 130-10*Math.cos(r-p),
+ ]);
+}
+
+var oldHeading = 0;
+Bangle.on('mag', function(m) {
+ if (!Bangle.isLCDOn()) return;
+ g.setFont("6x8",3);
+ g.setColor(0);
+ g.fillRect(0,0,230,40);
+ g.setColor(0xffff);
+ if (isNaN(m.heading)) {
+ g.setFontAlign(-1,-1);
+ g.setFont("6x8",2);
+ g.drawString("Uncalibrated",50,12);
+ g.drawString("turn 360° around",25,26);
+ }
+ else {
+ g.setFontAlign(0,0);
+ g.setFont("6x8",3);
+ g.drawString(Math.round(m.heading),120,12);
+ }
+ g.setColor(0,0,0);
+ arrow(oldHeading,0);
+ arrow(oldHeading+180,0);
+ arrow(m.heading,0xF800);
+ arrow(m.heading+180,0x001F);
+ oldHeading = m.heading;
+});
+Bangle.setCompassPower(1);
From 1017090cbe5fc6fb42101a0544fdd6e8ada983d0 Mon Sep 17 00:00:00 2001
From: Purple-Tentacle <59914607+Purple-Tentacle@users.noreply.github.com>
Date: Fri, 17 Apr 2020 16:40:25 +0200
Subject: [PATCH 037/101] compass 0.02
---
apps.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/apps.json b/apps.json
index e2b20cca4..d7bd6a7a1 100644
--- a/apps.json
+++ b/apps.json
@@ -235,7 +235,7 @@
{ "id": "compass",
"name": "Compass",
"icon": "compass.png",
- "version":"0.01",
+ "version":"0.02",
"description": "Simple compass that points North",
"tags": "tool,outdoors",
"storage": [
From 1fff62e48da25d2455294643ac66321033088c76 Mon Sep 17 00:00:00 2001
From: paul
Date: Fri, 17 Apr 2020 16:55:35 +0200
Subject: [PATCH 038/101] init hid camera app
---
apps/hidcam/ChangeLog | 1 +
apps/hidcam/add_to_apps.json | 13 +++++++++++++
apps/hidcam/app-icon.js | 1 +
apps/hidcam/app.js | 12 ++++++++++++
apps/hidcam/app.png | Bin 0 -> 1620 bytes
5 files changed, 27 insertions(+)
create mode 100644 apps/hidcam/ChangeLog
create mode 100644 apps/hidcam/add_to_apps.json
create mode 100644 apps/hidcam/app-icon.js
create mode 100644 apps/hidcam/app.js
create mode 100644 apps/hidcam/app.png
diff --git a/apps/hidcam/ChangeLog b/apps/hidcam/ChangeLog
new file mode 100644
index 000000000..5560f00bc
--- /dev/null
+++ b/apps/hidcam/ChangeLog
@@ -0,0 +1 @@
+0.01: New App!
diff --git a/apps/hidcam/add_to_apps.json b/apps/hidcam/add_to_apps.json
new file mode 100644
index 000000000..ca75a7bd8
--- /dev/null
+++ b/apps/hidcam/add_to_apps.json
@@ -0,0 +1,13 @@
+// Create an entry in apps.json as follows:
+{ "id": "7chname",
+ "name": "My app's human readable name",
+ "shortName":"Short Name",
+ "icon": "app.png",
+ "version":"0.01",
+ "description": "A detailed description of my great app",
+ "tags": "",
+ "storage": [
+ {"name":"7chname.app.js","url":"app.js"},
+ {"name":"7chname.img","url":"app-icon.js","evaluate":true}
+ ]
+}
diff --git a/apps/hidcam/app-icon.js b/apps/hidcam/app-icon.js
new file mode 100644
index 000000000..49232b838
--- /dev/null
+++ b/apps/hidcam/app-icon.js
@@ -0,0 +1 @@
+require("heatshrink").decompress(atob("mEwwJC/AH4A/AH4AgA=="))
diff --git a/apps/hidcam/app.js b/apps/hidcam/app.js
new file mode 100644
index 000000000..af367779a
--- /dev/null
+++ b/apps/hidcam/app.js
@@ -0,0 +1,12 @@
+// place your const, vars, functions or classes here
+
+// special function to handle display switch on
+Bangle.on('lcdPower', (on) => {
+ if (on) {
+ // call your app function here
+ // If you clear the screen, do Bangle.drawWidgets();
+ }
+});
+
+g.clear();
+// call your app function here
diff --git a/apps/hidcam/app.png b/apps/hidcam/app.png
new file mode 100644
index 0000000000000000000000000000000000000000..582cb2e0853a5a2899a3afbd7eb19cde2ee7f6a0
GIT binary patch
literal 1620
zcmV-a2CMmrP)1gXjloC|3_d8m;N2OpV(|i0q4YwBna<2!
zK9thw%-*|urnNbV{Gax^?eD+#{x0kLJ~)lj_;W+1>qV*k8akT^^dvctZccUyj4}H~#M%Wwee_v`
zHMv7o%BM8@dBrLshn{wGD9BDl?^eV5vSM3T96;NnHvtc6La=(qzq)xrX1d8bK-TN-
zrd_f$_O`9nEmS+_S7HTXK<&u;LDIW|qlN&KJvM}tt6TVVqL-AvNv`B*{NzNpBfSQwQP5~Sf(Dp@Vq1+3Q`N9wBQN2`J_?M^u0FIMlt?p^8
z%U3%80kIwg!T{E9<8J18S&$k1`eO)@HP+=TZKo(z3_A3VFYJB=sn`2^Q$mRE>02(+W)np;)L1!GUvU2{O{<&F_nE6Qe#D~Xf|dD
z+?d3-D1(IUiL`C2;PPv4CKw8H)v7h8^obJ&Z6D0CjVUe8Xq_NAymxUyPAMU^CCrIu
z%1M71EC`5o2if_~7E&h??0jeQ1Y3N6p?}G72FmS*)xQD)%wBE=2tW6@(+MTi!fk9H1pWKew2(jTXVu4%vk26QvSQCbGmk`Z)Y!
zBIhh)6vG2)h6mF8wC^|l$M(Eo9D?JiW}=_T2jUA>LC80foTera{^p)Wi`>}Gf;(|ZwEZQ
zS^k|*9wyt=f4ZOo!xty7{%}HKD9tBZ50g$=%v&&vMa!#@Nsf>EkEEDA*ST6fiC+An
zsNK1#>!x0obq@j$QqYU-ad3ZvbjqUU+%iw(0WahgmHV6yeLWqoYkSl4pzFQ(_Vp&I
ztO{WI-48rGLwQb?#vgVvduyd9_6W)rFRoQJq3I(J?{Xmin45#=3l9BmL6Bp<*MZej
zrsWN7oRPUr7IvrHoIHOjS=gPTCw>d)^LQK+B|=f2qbGjrWaOd5D<<9Dv>MTW0X3z>
zyPy}9`<>1~?NCx@m8G$_@rRTy5zH12YM&P)=tU+L^fgY
z^0Z&_6^qdVuwgN3wt_Ze(10?J@%{C2grBk42hsu74qEo^nd&v`X`IHN9lrxzS~GeF
S(*#!l0000
Date: Fri, 17 Apr 2020 18:56:38 +0200
Subject: [PATCH 039/101] app code and config
---
apps/hidcam/ChangeLog | 2 +-
apps/hidcam/add_to_apps.json | 13 -------------
apps/hidcam/app-icon.js | 2 +-
apps/hidcam/app.js | 12 ------------
apps/hidcam/app.png | Bin 1620 -> 1425 bytes
apps/hidcam/hidcam.app.js | 28 ++++++++++++++++++++++++++++
apps/hidcam/hidcam.app.json | 13 +++++++++++++
7 files changed, 43 insertions(+), 27 deletions(-)
delete mode 100644 apps/hidcam/add_to_apps.json
delete mode 100644 apps/hidcam/app.js
create mode 100644 apps/hidcam/hidcam.app.js
create mode 100644 apps/hidcam/hidcam.app.json
diff --git a/apps/hidcam/ChangeLog b/apps/hidcam/ChangeLog
index 5560f00bc..665c0df6e 100644
--- a/apps/hidcam/ChangeLog
+++ b/apps/hidcam/ChangeLog
@@ -1 +1 @@
-0.01: New App!
+0.01: Init
diff --git a/apps/hidcam/add_to_apps.json b/apps/hidcam/add_to_apps.json
deleted file mode 100644
index ca75a7bd8..000000000
--- a/apps/hidcam/add_to_apps.json
+++ /dev/null
@@ -1,13 +0,0 @@
-// Create an entry in apps.json as follows:
-{ "id": "7chname",
- "name": "My app's human readable name",
- "shortName":"Short Name",
- "icon": "app.png",
- "version":"0.01",
- "description": "A detailed description of my great app",
- "tags": "",
- "storage": [
- {"name":"7chname.app.js","url":"app.js"},
- {"name":"7chname.img","url":"app-icon.js","evaluate":true}
- ]
-}
diff --git a/apps/hidcam/app-icon.js b/apps/hidcam/app-icon.js
index 49232b838..aa9d5e194 100644
--- a/apps/hidcam/app-icon.js
+++ b/apps/hidcam/app-icon.js
@@ -1 +1 @@
-require("heatshrink").decompress(atob("mEwwJC/AH4A/AH4AgA=="))
+E.toArrayBuffer(atob("MDCEAzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMxERERERETMzMzMzMzMzMzMzMzMzMzMzMRERERERERMzMzMzMzMzMzMzMzMzMzMzMREREREREREzMzMzMzMzMzMzMzMAAAAzEREREREREREzMzMzMzMzMzMzMzMAAAAxERERERERERETMzMzMzMzMzMzMxERERERERERERERERERERERETMzMzMzMRERERERERERERERERERERERERMzMzMzEREREREREREAAAAAEREREREREREzMzMzEREREREREQAAAAAAABERESIiIREzMzMzEREREREREAAAAAAAAAERESIiIREzMzMzEREREREQAAAKqqqgAAABESIiIREzMzMzEREREREQAAqqqqqqoAABESIiIREzMzMzEREREREAAKqqqqqqqgAAEREREREzMzMzERERERAACqqqqqqqqqAAAREREREzMzMzERERERAAqqqiIiIqqqoAAREREREzMzMzqqqqqgAAqqoiIiIiKqoAAKqqqqozMzMzqqqqqgAKqqIiIiIiKqqgAKqqqqozMzMzqqqqqgAKqqIiqqqiKqqgAKqqqqozMzMzqqqqqgAKqqqqqqqqqqqgAKqqqqozMzMzqqqqqgAKqqqqqqqqqqqgAKqqqqozMzMzqqqqqgAKqqqqqqqqqqqgAKqqqqozMzMzqqqqqgAKqqqqqqqqqqqgAKqqqqozMzMzqqqqqgAAqqqqqqqqqqoAAKqqqqozMzMzqqqqqqAAqqqqqqqqqqoACqqqqqozMzMzqqqqqqAACqqqqqqqqqAACqqqqqozMzMzqqqqqqoAAKqqqqqqqgAAqqqqqqozMzMzqqqqqqoAAAqqqqqqoAAAqqqqqqozMzMzqqqqqqqgAAAKqqqgAAAKqqqqqqozMzMzqqqqqqqqAAAAAAAAAACqqqqqqqozMzMzqqqqqqqqqgAAAAAAAKqqqqqqqqozMzMzqqqqqqqqqqoAAAAAqqqqqqqqqqozMzMzOqqqqqqqqqqqqqqqqqqqqqqqqqMzMzMzM6qqqqqqqqqqqqqqqqqqqqqqqjMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMw=="))
diff --git a/apps/hidcam/app.js b/apps/hidcam/app.js
deleted file mode 100644
index af367779a..000000000
--- a/apps/hidcam/app.js
+++ /dev/null
@@ -1,12 +0,0 @@
-// place your const, vars, functions or classes here
-
-// special function to handle display switch on
-Bangle.on('lcdPower', (on) => {
- if (on) {
- // call your app function here
- // If you clear the screen, do Bangle.drawWidgets();
- }
-});
-
-g.clear();
-// call your app function here
diff --git a/apps/hidcam/app.png b/apps/hidcam/app.png
index 582cb2e0853a5a2899a3afbd7eb19cde2ee7f6a0..3f631a0d8c2c9a2f82ad03564f6e503e97ec3b74 100644
GIT binary patch
delta 1389
zcmV-z1(N#I43P_vHGc(0Nkl2XW^HHNnRPdH7YVh3
zAi4-C0tqZh0&gNIp^K!1F0{>?F8ZK?L=!~R#889`D}{vAtGp@*QYh5@80TYmE$3rD
zXXnhv+r_N&?d+VhW?jr54xID6@AEwW|9PMDejI3`i6)w8Vt*MB_an&A!4sV_lRgYQ
z(U60bA)%^oee%v5e=Ilm@&!mKhW3ATK_WL9^bF=wV%=wZcFZg%y|Nrf4_+Hu9Ce*+^R
zc(KwX1zV6(7k9~?h!Hyfbl2<$#^#4n_>Pe{25aG9oee=sBAVos><
zeZK4Uo0W}K0(Kub;#YIxcL|;c!>=(2h$%VihL7Ie9x1h3sya$#pG2A>uj?sd(I~Ss
z(fP@7oD9euxgs&*b+QBp??8vTYo};@fk(eQ-ni7;;|S=S+iZ&
zQ%oh|M8YB59uK{}eKm#b*!n`1?bz81c@c`J;#MU9gEb$E-r?5R7`a@wF$XD$N25$9
z;`H^e#@*T3crrpoc}d^j=`$FZd*5QTQ}=G&k&it!R5#a
z5~;sHN+RJ9nx^6DT=C!p=z5AY=&?+XoiY$
z0cl;&&o+yA*7s@|d7*&A4IY2~>ga(^KeTm$wPd}uTO2&!yS?xnk48!Bx?urTB{Y8O
zp}Gz;soP|d`93RsYw&MaTMTA}HgEpTmqCEmlE3B>kete!eU3qVk*5icj{q=sO~q-e
zpMSp+hDSipOcn0eKC-^7&AFmTK9h#|DVU2xY93ges2m+&u@!v=RuyBUGRAk-hCkwT
zHd(mu>FzIU%Vt2;Ai4OKOP92ymMNh=r@|E=O@~DvjMJ4404)_dY^MYJZcj2U)uHs1y5MFf2e3*24Yl+_d3@l_-s&
zD%LtZ@4?5YgGDLMg^}9mAF27tr*+VQKx5Z
z7#3i+xVd`{3XYEuniw^l^e(~^VJCsEUR|D=s!a{d|_>g7N8ZA(iCfm4ELF
z&rVwxsxW@gF|`+JYw@Fq{E9U_6X*QpQ!J#COL!HrkVtXhxX+mFkcUw@=#W~T_>4sc`SYWX)K1a5mj_QiwG0~G+^w0W_p
zHez$bVew
zFhhQ-(okyzE&*GOL{)@^c6%>Q%}X*JXCa*+BNxbK^Lrar)vzjd>=rk6t!Bg2Yy*Jc
zVx_5CfXEIZ)s29G-vxQ7iiXqX#cA`JBUl$AmdnVYN^4aKef`VU8(5UbfNwBZPX7|7
v5qz7=%BN2Lwq^LgCeuU{O*GNO{|o;Bs>Z}7R{Rfy00000NkvXXu0mjfd2ysS
delta 1586
zcmV-22F>}A3)BpdHGc*PNklVsi@IIDWLJF
z<-tS+MbQVNMvWngMiMVMF($}~PbV60iJqKGq6sl-z#5IgNDvG@D81m_8L(pU0#u>&
zLWh~o%w9f}(&^0JyL+a!If?wA_PXuwzxMtv>-#=9jnnvZLw~00MXDHdHZ-F~E6@xy
zAk0IFoNQ?rJ?=L3M
zHi1NI%W6w_1%Iftvl|hOhaVrR!sN{2xw@hkSSKyk8akT
z^^R7(Pu73-SLjz9%wK^oEKM9^v2d+uZBzb_ElWR@^923y?MQ5Sh3y}H359v|8R9g6#
zr~d$slVYvzX{^gvI{yK&9t6Sw)^Fo(=6P9=8U6ZW2$40`DO|&}2{l-??t>KM^xP{PQp9J>sMDt1wG0P7(^*|FxpxgxUNu=e>XY@94oX
zm34@@sD<7z%UMsx_zdi4z8GAI!3iDJ{-uogg{9
zcYkp~PAMU^CCrIu%1M71EC`5o2if_~7E&h??0jeQ1Y3N6p?}G72FSn>E+sATQ)Q)70!M+WViTAl9FdlI^_bw)
zg$_FC{~s`6^Y4_v-WecL8bso`qEiB0GeD&@Sajx!_6dmf;f#FXiqAg!jge#)(`PVmVSj|$`UsHZGo<5&Mq0i(4E(oP@&iXk=-U1(Bgrgt{}SSg8|!FVQpN1*ApW3%X$qBd
z0$g%sHPPlXP=%gv2Ryu4{+&-ACfn41x}XBX7bma&a6)1z%_mzAlTKO8TYoT%Ma!#@
zNsf>EkEEDA*ST6fiC+AnsNK1#>!x0obq@j$QqYU-ad3ZvbjqUU+%iw(0WahgmHV6y
zeLWqoYkSl4pzFQ(_Vp&ItO{WI-48rGLwQb?#vgVvduyd9_6W)rFRoQJq3I(J?{Xmi
zn45#=3l9BmL6Bp<*MZejrhnxPZJd$0O%`^i+?+grDp}Z_q9=X}=<|3S6D2}Xo}(vz
z>ty7i#49G<-Lx9fe*rb6#JivumHVB}LG4gdXO*R~xABLfz>ADt4^0(GkQeZWqQ#Jh
z>AK{zSO
Date: Fri, 17 Apr 2020 19:00:45 +0200
Subject: [PATCH 040/101] adding the extra comma as mentioned on bangle js
documentation
---
apps/hidcam/hidcam.app.json | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/apps/hidcam/hidcam.app.json b/apps/hidcam/hidcam.app.json
index df35404e4..ad3ea89fe 100644
--- a/apps/hidcam/hidcam.app.json
+++ b/apps/hidcam/hidcam.app.json
@@ -1,4 +1,4 @@
-// Create an entry in apps.json as follows:
+},
{ "id": "hidcam",
"name": "HID camera shutter",
"shortName":"HID cam",
@@ -11,3 +11,4 @@
{"name":"hidcam.img","url":"app-icon.js","evaluate":true}
],
}
+]
From 15535b0f19c232425c01311e1f1b5c33da50d78f Mon Sep 17 00:00:00 2001
From: paul
Date: Fri, 17 Apr 2020 19:06:09 +0200
Subject: [PATCH 041/101] move json info to the good place
---
apps.json | 14 +++++++++++++-
apps/hidcam/hidcam.app.json | 14 --------------
2 files changed, 13 insertions(+), 15 deletions(-)
delete mode 100644 apps/hidcam/hidcam.app.json
diff --git a/apps.json b/apps.json
index effa14aa4..d57f218be 100644
--- a/apps.json
+++ b/apps.json
@@ -1293,5 +1293,17 @@
"evaluate": true
}
]
- }
+ },
+{ "id": "hidcam",
+ "name": "HID camera shutter",
+ "shortName":"HID cam",
+ "icon": "app.png",
+ "version":"0.01",
+ "description": "Enable HID, connect to your phone, start your camera and trigger the shot on your Bangle",
+ "tags": "tools",
+ "storage": [
+ {"name":"hidcam.app.js","url":"hidcam.app.js"},
+ {"name":"hidcam.img","url":"app-icon.js","evaluate":true}
+ ],
+}
]
diff --git a/apps/hidcam/hidcam.app.json b/apps/hidcam/hidcam.app.json
deleted file mode 100644
index ad3ea89fe..000000000
--- a/apps/hidcam/hidcam.app.json
+++ /dev/null
@@ -1,14 +0,0 @@
-},
-{ "id": "hidcam",
- "name": "HID camera shutter",
- "shortName":"HID cam",
- "icon": "app.png",
- "version":"0.01",
- "description": "Enable HID, connect to your phone, start your camera and trigger the shot on your Bangle",
- "tags": "tools",
- "storage": [
- {"name":"hidcam.app.js","url":"hidcam.app.js"},
- {"name":"hidcam.img","url":"app-icon.js","evaluate":true}
- ],
-}
-]
From 1dc2e3805d0cbbde633669b88c9f36465931ab69 Mon Sep 17 00:00:00 2001
From: paul
Date: Fri, 17 Apr 2020 19:12:17 +0200
Subject: [PATCH 042/101] json format
---
apps.json | 22 +++++++++++-----------
1 file changed, 11 insertions(+), 11 deletions(-)
diff --git a/apps.json b/apps.json
index d57f218be..d89fe95b0 100644
--- a/apps.json
+++ b/apps.json
@@ -1294,16 +1294,16 @@
}
]
},
-{ "id": "hidcam",
- "name": "HID camera shutter",
- "shortName":"HID cam",
- "icon": "app.png",
- "version":"0.01",
- "description": "Enable HID, connect to your phone, start your camera and trigger the shot on your Bangle",
- "tags": "tools",
- "storage": [
- {"name":"hidcam.app.js","url":"hidcam.app.js"},
- {"name":"hidcam.img","url":"app-icon.js","evaluate":true}
- ],
+ { "id": "hidcam",
+ "name": "HID camera shutter",
+ "shortName":"HID cam",
+ "icon": "app.png",
+ "version":"0.01",
+ "description": "Enable HID, connect to your phone, start your camera and trigger the shot on your Bangle",
+ "tags": "tools",
+ "storage": [
+ {"name":"hidcam.app.js","url":"hidcam.app.js"},
+ {"name":"hidcam.img","url":"app-icon.js","evaluate":true}
+ ]
}
]
From c7f2a18caaff5a472db6f7f3765cd4234f936da1 Mon Sep 17 00:00:00 2001
From: Richard de Boer
Date: Fri, 17 Apr 2020 21:08:07 +0200
Subject: [PATCH 043/101] Remove "settings" from appid.info
---
apps.json | 2 +-
apps/setting/ChangeLog | 1 +
apps/setting/settings.js | 22 ++++++++++++++--------
js/appinfo.js | 2 --
4 files changed, 16 insertions(+), 11 deletions(-)
diff --git a/apps.json b/apps.json
index 0c97b9e57..4b8b4a6b3 100644
--- a/apps.json
+++ b/apps.json
@@ -120,7 +120,7 @@
{ "id": "setting",
"name": "Settings",
"icon": "settings.png",
- "version":"0.16",
+ "version":"0.17",
"description": "A menu for setting up Bangle.js",
"tags": "tool,system",
"storage": [
diff --git a/apps/setting/ChangeLog b/apps/setting/ChangeLog
index 3acfb5fb0..81ac1fa81 100644
--- a/apps/setting/ChangeLog
+++ b/apps/setting/ChangeLog
@@ -18,3 +18,4 @@
0.14: Reduce memory usage when running app settings page
0.15: Reduce memory usage when running default clock chooser (#294)
0.16: Reduce memory usage further when running app settings page
+0.17: Remove need for "settings" in appid.info
diff --git a/apps/setting/settings.js b/apps/setting/settings.js
index d0d88ce20..97ce464ad 100644
--- a/apps/setting/settings.js
+++ b/apps/setting/settings.js
@@ -416,10 +416,19 @@ function showAppSettingsMenu() {
'': { 'title': 'App Settings' },
'< Back': ()=>showMainMenu(),
}
- const apps = storage.list(/\.info$/)
- .map(app => {var a=storage.readJSON(app, 1);return (a&&a.settings)?{sortorder:a.sortorder,name:a.name,settings:a.settings}:undefined})
- .filter(app => app) // filter out any undefined apps
- .sort((a, b) => a.sortorder - b.sortorder)
+ const apps = storage.list(/\.settings\.js$/)
+ .map(s => s.substr(0, s.length-12))
+ .map(id => {
+ const a=storage.readJSON(id+'.info',1);
+ return {id:id,name:a.name,sortorder:a.sortorder};
+ })
+ .sort((a, b) => {
+ const n = (0|a.sortorder)-(0|b.sortorder);
+ if (n) return n; // do sortorder first
+ if (a.nameb.name) return 1;
+ return 0;
+ })
if (apps.length === 0) {
appmenu['No app has settings'] = () => { };
}
@@ -433,10 +442,7 @@ function showAppSettings(app) {
E.showMessage(`${app.name}:\n${msg}!\n\nBTN1 to go back`);
setWatch(showAppSettingsMenu, BTN1, { repeat: false });
}
- let appSettings = storage.read(app.settings);
- if (!appSettings) {
- return showError('Missing settings');
- }
+ let appSettings = storage.read(app.id+'.settings.js');
try {
appSettings = eval(appSettings);
} catch (e) {
diff --git a/js/appinfo.js b/js/appinfo.js
index 56b6ff2f8..9fff7c92a 100644
--- a/js/appinfo.js
+++ b/js/appinfo.js
@@ -60,8 +60,6 @@ var AppInfo = {
if (app.type && app.type!="app") json.type = app.type;
if (fileContents.find(f=>f.name==app.id+".app.js"))
json.src = app.id+".app.js";
- if (fileContents.find(f=>f.name==app.id+".settings.js"))
- json.settings = app.id+".settings.js";
if (fileContents.find(f=>f.name==app.id+".img"))
json.icon = app.id+".img";
if (app.sortorder) json.sortorder = app.sortorder;
From 43b0d8897e7a50556b93a58eff19d068d2f43544 Mon Sep 17 00:00:00 2001
From: Richard de Boer
Date: Fri, 17 Apr 2020 21:25:56 +0200
Subject: [PATCH 044/101] widbatpc: Save settings in data file
---
apps.json | 8 +++++---
apps/widbatpc/ChangeLog | 1 +
apps/widbatpc/settings.js | 2 +-
apps/widbatpc/widget.js | 2 +-
4 files changed, 8 insertions(+), 5 deletions(-)
diff --git a/apps.json b/apps.json
index 0c97b9e57..315120cc7 100644
--- a/apps.json
+++ b/apps.json
@@ -342,14 +342,16 @@
"name": "Battery Level Widget (with percentage)",
"shortName": "Battery Widget",
"icon": "widget.png",
- "version":"0.09",
+ "version":"0.10",
"description": "Show the current battery level and charging status in the top right of the clock, with charge percentage",
"tags": "widget,battery",
"type":"widget",
"storage": [
{"name":"widbatpc.wid.js","url":"widget.js"},
- {"name":"widbatpc.settings.js","url":"settings.js"},
- {"name":"widbatpc.settings.json","content": "{}"}
+ {"name":"widbatpc.settings.js","url":"settings.js"}
+ ],
+ "data": [
+ {"name":"widbatpc.json"}
]
},
{ "id": "widbt",
diff --git a/apps/widbatpc/ChangeLog b/apps/widbatpc/ChangeLog
index 129707320..138c1adc8 100644
--- a/apps/widbatpc/ChangeLog
+++ b/apps/widbatpc/ChangeLog
@@ -6,3 +6,4 @@
0.07: Add settings: percentage/color/charger icon
0.08: Draw percentage as inverted on monochrome battery
0.09: Fix regression stopping correct widget updates
+0.10: Don't overwrite existing settings on app update
diff --git a/apps/widbatpc/settings.js b/apps/widbatpc/settings.js
index 5c0bdbcae..88988cf22 100644
--- a/apps/widbatpc/settings.js
+++ b/apps/widbatpc/settings.js
@@ -3,7 +3,7 @@
* @param {function} back Use back() to return to settings menu
*/
(function(back) {
- const SETTINGS_FILE = 'widbatpc.settings.json'
+ const SETTINGS_FILE = 'widbatpc.json'
const COLORS = ['By Level', 'Green', 'Monochrome']
// initialize with default settings...
diff --git a/apps/widbatpc/widget.js b/apps/widbatpc/widget.js
index aca690ce0..189ca215f 100644
--- a/apps/widbatpc/widget.js
+++ b/apps/widbatpc/widget.js
@@ -11,7 +11,7 @@ const COLORS = {
'ok': 0xFD20, // "Orange"
'low':0xF800, // "Red"
}
-const SETTINGS_FILE = 'widbatpc.settings.json'
+const SETTINGS_FILE = 'widbatpc.json'
let settings
function loadSettings() {
From b691f783aa7cb956c0644658907a93e27ce836c9 Mon Sep 17 00:00:00 2001
From: Richard de Boer
Date: Fri, 17 Apr 2020 21:29:56 +0200
Subject: [PATCH 045/101] welcome: Save settings in data file
fwelcom
---
apps.json | 6 ++++--
apps/welcome/ChangeLog | 1 +
apps/welcome/boot.js | 4 ++--
apps/welcome/settings-default.json | 3 ---
apps/welcome/settings.js | 4 ++--
5 files changed, 9 insertions(+), 9 deletions(-)
delete mode 100644 apps/welcome/settings-default.json
diff --git a/apps.json b/apps.json
index 315120cc7..a8b29b685 100644
--- a/apps.json
+++ b/apps.json
@@ -78,7 +78,7 @@
{ "id": "welcome",
"name": "Welcome",
"icon": "app.png",
- "version":"0.07",
+ "version":"0.08",
"description": "Appears at first boot and explains how to use Bangle.js",
"tags": "start,welcome",
"allow_emulator":true,
@@ -86,8 +86,10 @@
{"name":"welcome.boot.js","url":"boot.js"},
{"name":"welcome.app.js","url":"app.js"},
{"name":"welcome.settings.js","url":"settings.js"},
- {"name":"welcome.settings.json","url":"settings-default.json","evaluate":true},
{"name":"welcome.img","url":"app-icon.js","evaluate":true}
+ ],
+ "data": [
+ {"name":"welcome.json"}
]
},
{ "id": "gbridge",
diff --git a/apps/welcome/ChangeLog b/apps/welcome/ChangeLog
index b8786af6a..a377fc81e 100644
--- a/apps/welcome/ChangeLog
+++ b/apps/welcome/ChangeLog
@@ -7,3 +7,4 @@
0.07: Run again when updated
Don't run again when settings app is updated (or absent)
Add "Run Now" option to settings
+0.08: Don't overwrite existing settings on app update
diff --git a/apps/welcome/boot.js b/apps/welcome/boot.js
index bc5afcc66..f6ba6d2d6 100644
--- a/apps/welcome/boot.js
+++ b/apps/welcome/boot.js
@@ -1,11 +1,11 @@
(function() {
- let s = require('Storage').readJSON('welcome.settings.json', 1)
+ let s = require('Storage').readJSON('welcome.json', 1)
|| require('Storage').readJSON('setting.json', 1)
|| {welcomed: true} // do NOT run if global settings are also absent
if (!s.welcomed && require('Storage').read('welcome.app.js')) {
setTimeout(() => {
s.welcomed = true
- require('Storage').write('welcome.settings.json', {welcomed: "yes"})
+ require('Storage').write('welcome.json', {welcomed: "yes"})
load('welcome.app.js')
})
}
diff --git a/apps/welcome/settings-default.json b/apps/welcome/settings-default.json
deleted file mode 100644
index d250efff5..000000000
--- a/apps/welcome/settings-default.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "welcomed": false
-}
diff --git a/apps/welcome/settings.js b/apps/welcome/settings.js
index b11921646..e873c2785 100644
--- a/apps/welcome/settings.js
+++ b/apps/welcome/settings.js
@@ -1,13 +1,13 @@
// The welcome app is special, and gets to use global settings
(function(back) {
- let settings = require('Storage').readJSON('welcome.settings.json', 1)
+ let settings = require('Storage').readJSON('welcome.sjson', 1)
|| require('Storage').readJSON('setting.json', 1) || {}
E.showMenu({
'': { 'title': 'Welcome App' },
'Run on Next Boot': {
value: !settings.welcomed,
format: v => v ? 'OK' : 'No',
- onchange: v => require('Storage').write('welcome.settings.json', {welcomed: !v}),
+ onchange: v => require('Storage').write('welcome.json', {welcomed: !v}),
},
'Run Now': () => load('welcome.app.js'),
'< Back': back,
From b047f14d4ada97c510edc7a773a3e1f08982bc5d Mon Sep 17 00:00:00 2001
From: Richard de Boer
Date: Fri, 17 Apr 2020 21:35:59 +0200
Subject: [PATCH 046/101] setting: Save settings in data file
---
apps.json | 6 ++++--
apps/setting/ChangeLog | 1 +
apps/setting/settings-default.json | 25 -------------------------
3 files changed, 5 insertions(+), 27 deletions(-)
delete mode 100644 apps/setting/settings-default.json
diff --git a/apps.json b/apps.json
index a8b29b685..4d5493e49 100644
--- a/apps.json
+++ b/apps.json
@@ -122,15 +122,17 @@
{ "id": "setting",
"name": "Settings",
"icon": "settings.png",
- "version":"0.16",
+ "version":"0.17",
"description": "A menu for setting up Bangle.js",
"tags": "tool,system",
"storage": [
{"name":"setting.app.js","url":"settings.js"},
{"name":"setting.boot.js","url":"boot.js"},
- {"name":"setting.json","url":"settings-default.json","evaluate":true},
{"name":"setting.img","url":"settings-icon.js","evaluate":true}
],
+ "data": [
+ {"name":"setting.json"}
+ ],
"sortorder" : -2
},
{ "id": "alarm",
diff --git a/apps/setting/ChangeLog b/apps/setting/ChangeLog
index 3acfb5fb0..773b510f0 100644
--- a/apps/setting/ChangeLog
+++ b/apps/setting/ChangeLog
@@ -18,3 +18,4 @@
0.14: Reduce memory usage when running app settings page
0.15: Reduce memory usage when running default clock chooser (#294)
0.16: Reduce memory usage further when running app settings page
+0.17: Don't overwrite existing settings on app update
diff --git a/apps/setting/settings-default.json b/apps/setting/settings-default.json
deleted file mode 100644
index c61fd6109..000000000
--- a/apps/setting/settings-default.json
+++ /dev/null
@@ -1,25 +0,0 @@
-{
- ble: true, // Bluetooth enabled by default
- blerepl: true, // Is REPL on Bluetooth - can Espruino IDE be used?
- log: false, // Do log messages appear on screen?
- timeout: 10, // Default LCD timeout in seconds
- vibrate: true, // Vibration enabled by default. App must support
- beep: "vib", // Beep enabled by default. App must support
- timezone: 0, // Set the timezone for the device
- HID : false, // BLE HID mode, off by default
- clock: null, // a string for the default clock's name
- "12hour" : false, // 12 or 24 hour clock?
- // welcomed : undefined/true (whether welcome app should show)
- brightness: 1, // LCD brightness from 0 to 1
- options: {
- wakeOnBTN1: true,
- wakeOnBTN2: true,
- wakeOnBTN3: true,
- wakeOnFaceUp: false,
- wakeOnTouch: false,
- wakeOnTwist: true,
- twistThreshold: 819.2,
- twistMaxY: -800,
- twistTimeout: 1000
- }
-}
From 9358b4b5995e2efa6a49a1ca7865a0484f0c2c3f Mon Sep 17 00:00:00 2001
From: Richard de Boer
Date: Fri, 17 Apr 2020 21:39:27 +0200
Subject: [PATCH 047/101] alarm: Save settings in data file
---
apps.json | 6 ++++--
apps/alarm/ChangeLog | 1 +
2 files changed, 5 insertions(+), 2 deletions(-)
diff --git a/apps.json b/apps.json
index 4d5493e49..30fb669d2 100644
--- a/apps.json
+++ b/apps.json
@@ -139,16 +139,18 @@
"name": "Default Alarm",
"shortName":"Alarms",
"icon": "app.png",
- "version":"0.06",
+ "version":"0.07",
"description": "Set and respond to alarms",
"tags": "tool,alarm,widget",
"storage": [
{"name":"alarm.app.js","url":"app.js"},
{"name":"alarm.boot.js","url":"boot.js"},
{"name":"alarm.js","url":"alarm.js"},
- {"name":"alarm.json","content":"[]"},
{"name":"alarm.img","url":"app-icon.js","evaluate":true},
{"name":"alarm.wid.js","url":"widget.js"}
+ ],
+ "data": [
+ {"name":"alarm.json"}
]
},
{ "id": "wclock",
diff --git a/apps/alarm/ChangeLog b/apps/alarm/ChangeLog
index 2ff60e658..ca92a0d97 100644
--- a/apps/alarm/ChangeLog
+++ b/apps/alarm/ChangeLog
@@ -4,3 +4,4 @@
0.04: Tweaks for variable size widget system
0.05: Add alarm.boot.js and move code from the bootloader
0.06: Change 'New Alarm' to 'Save', allow Deletion of Alarms
+0.07: Don't overwrite existing settings on app update
From e4c0574ab77ad2b8064e3c50dd1e900f5a2fe7fb Mon Sep 17 00:00:00 2001
From: Richard de Boer
Date: Fri, 17 Apr 2020 21:45:48 +0200
Subject: [PATCH 048/101] heart: Save settings in data file, add recording
files to data
---
apps.json | 7 +++++--
apps/heart/ChangeLog | 3 ++-
2 files changed, 7 insertions(+), 3 deletions(-)
diff --git a/apps.json b/apps.json
index 30fb669d2..6509458bf 100644
--- a/apps.json
+++ b/apps.json
@@ -300,15 +300,18 @@
{ "id": "heart",
"name": "Heart Rate Recorder",
"icon": "app.png",
- "version":"0.01",
+ "version":"0.02",
"interface": "interface.html",
"description": "Application that allows you to record your heart rate. Can run in background",
"tags": "tool,health,widget",
"storage": [
{"name":"heart.app.js","url":"app.js"},
- {"name":"heart.json","url":"app-settings.json","evaluate":true},
{"name":"heart.img","url":"app-icon.js","evaluate":true},
{"name":"heart.wid.js","url":"widget.js"}
+ ],
+ "data": [
+ {"name":"heart.json"},
+ {"wildcard":".heart?","storageFile": true}
]
},
{ "id": "slevel",
diff --git a/apps/heart/ChangeLog b/apps/heart/ChangeLog
index 4c4db83bc..70134af27 100644
--- a/apps/heart/ChangeLog
+++ b/apps/heart/ChangeLog
@@ -1,2 +1,3 @@
0.01: New App!
-
+0.02: Don't overwrite existing settings on app update
+ Clean up recordings on app removal
From db35edede6527b4613ed147298be6497def457ee Mon Sep 17 00:00:00 2001
From: Richard de Boer
Date: Fri, 17 Apr 2020 21:49:57 +0200
Subject: [PATCH 049/101] ncstart: Save settings in data file
---
apps.json | 6 ++++--
apps/ncstart/ChangeLog | 1 +
apps/ncstart/boot.js | 4 ++--
apps/ncstart/settings-default.json | 3 ---
apps/ncstart/settings.js | 4 ++--
5 files changed, 9 insertions(+), 9 deletions(-)
delete mode 100644 apps/ncstart/settings-default.json
diff --git a/apps.json b/apps.json
index 6509458bf..c3544abee 100644
--- a/apps.json
+++ b/apps.json
@@ -528,20 +528,22 @@
"id": "ncstart",
"name": "NCEU Startup",
"icon": "start.png",
- "version":"0.04",
+ "version":"0.05",
"description": "NodeConfEU 2019 'First Start' Sequence",
"tags": "start,welcome",
"storage": [
{"name":"ncstart.app.js","url":"start.js"},
{"name":"ncstart.boot.js","url":"boot.js"},
{"name":"ncstart.settings.js","url":"settings.js"},
- {"name":"ncstart.settings.json","url":"settings-default.json","evaluate":true},
{"name":"ncstart.img","url":"start-icon.js","evaluate":true},
{"name":"nc-bangle.img","url":"start-bangle.js","evaluate":true},
{"name":"nc-nceu.img","url":"start-nceu.js","evaluate":true},
{"name":"nc-nfr.img","url":"start-nfr.js","evaluate":true},
{"name":"nc-nodew.img","url":"start-nodew.js","evaluate":true},
{"name":"nc-tf.img","url":"start-tf.js","evaluate":true}
+ ],
+ "data": [
+ {"name":"ncstart.json"}
]
},
{ "id": "ncfrun",
diff --git a/apps/ncstart/ChangeLog b/apps/ncstart/ChangeLog
index f4418827e..522633f7b 100644
--- a/apps/ncstart/ChangeLog
+++ b/apps/ncstart/ChangeLog
@@ -5,3 +5,4 @@
0.04: Run again when updated
Don't run again when settings app is updated (or absent)
Add "Run Now" option to settings
+0.05: Don't overwrite existing settings on app update
diff --git a/apps/ncstart/boot.js b/apps/ncstart/boot.js
index e3f514f5b..094033094 100644
--- a/apps/ncstart/boot.js
+++ b/apps/ncstart/boot.js
@@ -1,11 +1,11 @@
(function() {
- let s = require('Storage').readJSON('ncstart.settings.json', 1)
+ let s = require('Storage').readJSON('ncstart.json', 1)
|| require('Storage').readJSON('setting.json', 1)
|| {welcomed: true} // do NOT run if global settings are also absent
if (!s.welcomed && require('Storage').read('ncstart.app.js')) {
setTimeout(() => {
s.welcomed = true
- require('Storage').write('ncstart.settings.json', s)
+ require('Storage').write('ncstart.json', s)
load('ncstart.app.js')
})
}
diff --git a/apps/ncstart/settings-default.json b/apps/ncstart/settings-default.json
deleted file mode 100644
index d250efff5..000000000
--- a/apps/ncstart/settings-default.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "welcomed": false
-}
diff --git a/apps/ncstart/settings.js b/apps/ncstart/settings.js
index 2b24095cf..6780264a7 100644
--- a/apps/ncstart/settings.js
+++ b/apps/ncstart/settings.js
@@ -1,13 +1,13 @@
// The welcome app is special, and gets to use global settings
(function(back) {
- let settings = require('Storage').readJSON('ncstart.settings.json', 1)
+ let settings = require('Storage').readJSON('ncstart.json', 1)
|| require('Storage').readJSON('setting.json', 1) || {}
E.showMenu({
'': { 'title': 'NCEU Startup' },
'Run on Next Boot': {
value: !settings.welcomed,
format: v => v ? 'OK' : 'No',
- onchange: v => require('Storage').write('ncstart.settings.json', {welcomed: !v}),
+ onchange: v => require('Storage').write('ncstart.json', {welcomed: !v}),
},
'Run Now': () => load('ncstart.app.js'),
'< Back': back,
From 595de45e348799bb38d0728dd8a82aecc5c09287 Mon Sep 17 00:00:00 2001
From: Richard de Boer
Date: Fri, 17 Apr 2020 21:52:42 +0200
Subject: [PATCH 050/101] numerals: Save settings in data file
---
apps.json | 8 +++++---
apps/numerals/ChangeLog | 3 ++-
apps/numerals/numerals-default.json | 5 -----
3 files changed, 7 insertions(+), 9 deletions(-)
delete mode 100644 apps/numerals/numerals-default.json
diff --git a/apps.json b/apps.json
index c3544abee..18fad4cfe 100644
--- a/apps.json
+++ b/apps.json
@@ -1235,7 +1235,7 @@
"name": "Numerals Clock",
"shortName": "Numerals Clock",
"icon": "numerals.png",
- "version":"0.03",
+ "version":"0.04",
"description": "A simple big numerals clock",
"tags": "numerals,clock",
"type":"clock",
@@ -1243,8 +1243,10 @@
"storage": [
{"name":"numerals.app.js","url":"numerals.app.js"},
{"name":"numerals.img","url":"numerals-icon.js","evaluate":true},
- {"name":"numerals.settings.js","url":"numerals.settings.js"},
- {"name":"numerals.json","url":"numerals-default.json","evaluate":true}
+ {"name":"numerals.settings.js","url":"numerals.settings.js"}
+ ],
+ "data":[
+ {"name":"numerals.json"}
]
},
{ "id": "bledetect",
diff --git a/apps/numerals/ChangeLog b/apps/numerals/ChangeLog
index ec465a83f..927c4ff5f 100644
--- a/apps/numerals/ChangeLog
+++ b/apps/numerals/ChangeLog
@@ -1,3 +1,4 @@
0.01: New App!
0.02: Use BTN2 for settings menu like other clocks
-0.03: maximize numerals, make menu button configurable, change icon to mac palette, add default settings file, respect 12hour setting
\ No newline at end of file
+0.03: maximize numerals, make menu button configurable, change icon to mac palette, add default settings file, respect 12hour setting
+0.04: Don't overwrite existing settings on app update
diff --git a/apps/numerals/numerals-default.json b/apps/numerals/numerals-default.json
deleted file mode 100644
index aa6a25047..000000000
--- a/apps/numerals/numerals-default.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- color:0,
- drawMode:"fill",
- menuButton:22
-}
\ No newline at end of file
From a8d1ef3e53b35732bb8871956d1b2d1d13875d5e Mon Sep 17 00:00:00 2001
From: Richard de Boer
Date: Fri, 17 Apr 2020 21:42:29 +0200
Subject: [PATCH 051/101] gpsrec: Save settings in data file, add track files
to data
---
apps.json | 7 +++++--
apps/gpsrec/ChangeLog | 2 ++
2 files changed, 7 insertions(+), 2 deletions(-)
diff --git a/apps.json b/apps.json
index 18fad4cfe..a18029abc 100644
--- a/apps.json
+++ b/apps.json
@@ -286,15 +286,18 @@
{ "id": "gpsrec",
"name": "GPS Recorder",
"icon": "app.png",
- "version":"0.07",
+ "version":"0.08",
"interface": "interface.html",
"description": "Application that allows you to record a GPS track. Can run in background",
"tags": "tool,outdoors,gps,widget",
"storage": [
{"name":"gpsrec.app.js","url":"app.js"},
- {"name":"gpsrec.json","url":"app-settings.json","evaluate":true},
{"name":"gpsrec.img","url":"app-icon.js","evaluate":true},
{"name":"gpsrec.wid.js","url":"widget.js"}
+ ],
+ "data": [
+ {"name":"gpsrec.json"},
+ {"wildcard":".gpsrc?","storageFile": true}
]
},
{ "id": "heart",
diff --git a/apps/gpsrec/ChangeLog b/apps/gpsrec/ChangeLog
index 8f1c575a1..17678bf3a 100644
--- a/apps/gpsrec/ChangeLog
+++ b/apps/gpsrec/ChangeLog
@@ -5,3 +5,5 @@
0.05: Tweaks for variable size widget system
0.06: Ensure widget update itself (fix #118) and change to using icons
0.07: Added @jeffmer's awesome track viewer
+0.08: Don't overwrite existing settings on app update
+ Clean up recorded tracks on app removal
From e615b49cd027976ca9bceb869d18cab3e30d9d7f Mon Sep 17 00:00:00 2001
From: Richard de Boer
Date: Fri, 17 Apr 2020 22:17:36 +0200
Subject: [PATCH 052/101] wohrm: fix `apps.json` version
---
apps.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/apps.json b/apps.json
index 0c97b9e57..7499b352c 100644
--- a/apps.json
+++ b/apps.json
@@ -890,7 +890,7 @@
{ "id": "wohrm",
"name": "Workout HRM",
"icon": "app.png",
- "version":"0.06",
+ "version":"0.07",
"readme": "README.md",
"description": "Workout heart rate monitor notifies you with a buzz if your heart rate goes above or below the set limits.",
"tags": "hrm,workout",
From 2278947b3d4b7a2ff0cea136bfa16d7bbb0a9497 Mon Sep 17 00:00:00 2001
From: Richard de Boer
Date: Sat, 18 Apr 2020 00:51:22 +0200
Subject: [PATCH 053/101] App Manager: Add support for data files
---
apps.json | 2 +-
apps/files/ChangeLog | 1 +
apps/files/files.js | 94 +++++++++++++++++++++++++++++++++-----------
3 files changed, 74 insertions(+), 23 deletions(-)
diff --git a/apps.json b/apps.json
index 0c97b9e57..bac885598 100644
--- a/apps.json
+++ b/apps.json
@@ -319,7 +319,7 @@
{ "id": "files",
"name": "App Manager",
"icon": "files.png",
- "version":"0.02",
+ "version":"0.03",
"description": "Show currently installed apps, free space, and allow their deletion from the watch",
"tags": "tool,system,files",
"storage": [
diff --git a/apps/files/ChangeLog b/apps/files/ChangeLog
index 8b7be7640..1140000fe 100644
--- a/apps/files/ChangeLog
+++ b/apps/files/ChangeLog
@@ -1 +1,2 @@
0.02: Fix deletion of apps - now use files list in app.info (fix #262)
+0.03: Add support for data files
diff --git a/apps/files/files.js b/apps/files/files.js
index 4775d35d0..ef0481f0c 100644
--- a/apps/files/files.js
+++ b/apps/files/files.js
@@ -30,29 +30,80 @@ function showMainMenu() {
return E.showMenu(mainmenu);
}
-function eraseApp(app) {
- E.showMessage('Erasing\n' + app.name + '...');
+function isGlob(f) {return /[?*]/.test(f)}
+function globToRegex(pattern) {
+ const ESCAPE = '.*+-?^${}()|[]\\';
+ const regex = pattern.replace(/./g, c => {
+ switch (c) {
+ case '?': return '.';
+ case '*': return '.*';
+ default: return ESCAPE.includes(c) ? ('\\' + c) : c;
+ }
+ });
+ return new RegExp('^'+regex+'$');
+}
+
+function eraseFiles(app) {
app.files.split(",").forEach(f=>storage.erase(f));
}
+function eraseData(app) {
+ if(!app.data) return;
+ const d=app.data.split(';'),
+ files=d[0].split(','),
+ sFiles=(d[1]||'').split(',');
+ let erase = f=>storage.erase(f);
+ files.forEach(f=>{
+ if (!isGlob(f)) erase(f);
+ else storage.list(globToRegex(f)).forEach(erase);
+ })
+ erase = sf=>storage.open(sf,'r').erase();
+ sFiles.forEach(sf=>{
+ if (!isGlob(sf)) erase(sf);
+ else storage.list(globToRegex(sf+'\u0001'))
+ .forEach(fs=>erase(fs.substring(0,fs.length-1)));
+ })
+}
+function eraseApp(app, files,data) {
+ E.showMessage('Erasing\n' + app.name + '...');
+ if (files) eraseFiles(app)
+ if (data) eraseData(app)
+}
+function eraseOne(app, files,data){
+ E.showPrompt('Erase\n'+app.name+'?').then((v) => {
+ if (v) {
+ Bangle.buzz(100, 1);
+ eraseApp(app, files,data)
+ showApps();
+ } else {
+ showAppMenu(app)
+ }
+ })
+}
+function eraseAll(apps, files,data) {
+ E.showPrompt('Erase all?').then((v) => {
+ if (v) {
+ Bangle.buzz(100, 1);
+ for(var n = 0; n m = showApps(),
- 'Erase': () => {
- E.showPrompt('Erase\n' + app.name + '?').then((v) => {
- if (v) {
- Bangle.buzz(100, 1);
- eraseApp(app);
- m = showApps();
- } else {
- m = showAppMenu(app)
- }
- });
- }
- };
+ }
+ if (app.data) {
+ appmenu['Erase Completely'] = () => eraseOne(app, true, true)
+ appmenu['Erase App,Keep Data'] = () => eraseOne(app,true, false)
+ appmenu['Only Erase Data'] = () => eraseOne(app,false, true)
+ } else {
+ appmenu['Erase'] = () => eraseOne(app,true, false)
+ }
return E.showMenu(appmenu);
}
@@ -78,13 +129,12 @@ function showApps() {
return menu;
}, appsmenu);
appsmenu['Erase All'] = () => {
- E.showPrompt('Erase all?').then((v) => {
- if (v) {
- Bangle.buzz(100, 1);
- for (var n = 0; n < list.length; n++)
- eraseApp(list[n]);
- }
- m = showApps();
+ E.showMenu({
+ '': {'title': 'Erase All'},
+ 'Erase Everything': () => eraseAll(list, true, true),
+ 'Erase Apps,Keep Data': () => eraseAll(list, true, false),
+ 'Only Erase Data': () => eraseAll(list, false, true),
+ '< Back': () => showApps(),
});
};
} else {
From c0f9c8b3e28b56680037a74f1666f0bac59c3cd9 Mon Sep 17 00:00:00 2001
From: Paul Cockrell
Date: Sat, 18 Apr 2020 00:38:12 +0100
Subject: [PATCH 054/101] Store GPS coords, for use on next start if user
desires
---
apps.json | 2 +-
apps/astrocalc/ChangeLog | 2 ++
apps/astrocalc/astrocalc-app.js | 51 +++++++++++++++++++++++++++++----
3 files changed, 49 insertions(+), 6 deletions(-)
diff --git a/apps.json b/apps.json
index bbe0bbfcd..60b47dbd8 100644
--- a/apps.json
+++ b/apps.json
@@ -1018,7 +1018,7 @@
{ "id": "astrocalc",
"name": "Astrocalc",
"icon": "astrocalc.png",
- "version":"0.01",
+ "version":"0.02",
"description": "Calculates interesting information on the sun and moon cycles for the current day based on your location.",
"tags": "app,sun,moon,cycles,tool,outdoors",
"allow_emulator":true,
diff --git a/apps/astrocalc/ChangeLog b/apps/astrocalc/ChangeLog
index 0c8adeb61..188fc287b 100644
--- a/apps/astrocalc/ChangeLog
+++ b/apps/astrocalc/ChangeLog
@@ -1 +1,3 @@
0.01: Create astrocalc app
+0.02: Store last GPS lock, can be used instead of waiting for new GPS on
+start.
diff --git a/apps/astrocalc/astrocalc-app.js b/apps/astrocalc/astrocalc-app.js
index 318147b13..0b0c63658 100644
--- a/apps/astrocalc/astrocalc-app.js
+++ b/apps/astrocalc/astrocalc-app.js
@@ -1,8 +1,18 @@
/**
+ * BangleJS ASTROCALC
+ *
* Inspired by: https://www.timeanddate.com
+ *
+ * Original Author: Paul Cockrell https://github.com/paulcockrell
+ * Created: April 2020
+ *
+ * Calculate the Sun and Moon positions based on watch GPS and display graphically
*/
const SunCalc = require("suncalc.js");
+const storage = require("Storage");
+const LAST_GPS_FILE = "astrocalc.gps.json";
+let lastGPS = (storage.readJSON(LAST_GPS_FILE, 1) || null);
function drawMoon(phase, x, y) {
const moonImgFiles = [
@@ -296,22 +306,50 @@ function indexPageMenu(gps) {
return E.showMenu(menu);
}
+function getCenterStringX(str) {
+ return (g.getWidth() - g.stringWidth(str)) / 2;
+}
+
/**
* GPS wait page, shows GPS locating animation until it gets a lock, then moves to the Sun page
*/
function drawGPSWaitPage() {
- const img = require("heatshrink").decompress(atob("mEwxH+AH4A/AH4AW43GF1wwsFwYwqFwowoFw4wmFxIwdE5YAPF/4vM5nN6YAE5vMF8YtHGIgvhFpQxKF7AuOGA4vXFyAwGF63MFyIABF6xeWMC4UDLwvNGpAJG5gwSdhIIDRBLyWCIgcJHAgJJDoouQF4vMQoICBBJoeGFx6GGACIfHL6YvaX6gvZeCIdFc4gAFXogvGFxgwFDwovQCAguOGAnMMBxeG5guTGAggGGAwNKFySREcA3N5vM5gDBdpQvXEY4AKXqovGGCKbFF7AwPZQwvZGJgtGF7vGdQItG5gSIF7gASF/44WEzgwRF0wwHF1AwFF1QwDF1gvwAH4A/AFAA=="))
-
+ const img = require("heatshrink").decompress(atob("mEwxH+AH4A/AH4AW43GF1wwsFwYwqFwowoFw4wmFxIwdE5YAPF/4vM5nN6YAE5vMF8YtHGIgvhFpQxKF7AuOGA4vXFyAwGF63MFyIABF6xeWMC4UDLwvNGpAJG5gwSdhIIDRBLyWCIgcJHAgJJDoouQF4vMQoICBBJoeGFx6GGACIfHL6YvaX6gvZeCIdFc4gAFXogvGFxgwFDwovQCAguOGAnMMBxeG5guTGAggGGAwNKFySREcA3N5vM5gDBdpQvXEY4AKXqovGGCKbFF7AwPZQwvZGJgtGF7vGdQItG5gSIF7gASF/44WEzgwRF0wwHF1AwFF1QwDF1gvwAH4A/AFAA=="));
+ const str1 = "Astrocalc v0.02";
+ const str2 = "Locating GPS";
+ const str3 = "Please wait...";
+
g.clear();
g.drawImage(img, 100, 50);
g.setFont("6x8", 1);
- g.drawString("Astrocalc v0.01", 80, 105);
- g.drawString("Locating GPS", 85, 140);
- g.drawString("Please wait...", 80, 155);
+ g.drawString(str1, getCenterStringX(str1), 105);
+ g.drawString(str2, getCenterStringX(str2), 140);
+ g.drawString(str3, getCenterStringX(str3), 155);
+
+ if (lastGPS) {
+ lastGPS = JSON.parse(lastGPS);
+ lastGPS.time = new Date();
+
+ const str4 = "Press Button 3 to use last GPS";
+ g.setColor("#d32e29");
+ g.fillRect(0, 190, g.getWidth(), 215);
+ g.setColor("#ffffff");
+ g.drawString(str4, getCenterStringX(str4), 200);
+
+ setWatch(() => {
+ clearWatch();
+ Bangle.setGPSPower(0);
+ lastGPS.time = new Date();
+ m = indexPageMenu(lastGPS);
+ }, BTN3, {repeat: false});
+ }
+
g.flip();
const DEBUG = false;
if (DEBUG) {
+ clearWatch();
+
const gps = {
"lat": 56.45783133333,
"lon": -3.02188583333,
@@ -330,7 +368,10 @@ function drawGPSWaitPage() {
Bangle.on('GPS', (gps) => {
if (gps.fix === 0) return;
+ clearWatch();
+ if (isNaN(gps.course)) gps.course = 0;
+ require("Storage").writeJSON(LAST_GPS_FILE, JSON.stringify(gps));
Bangle.setGPSPower(0);
Bangle.buzz();
Bangle.setLCDPower(true);
From 173969839e0a80e96b2d55065dc82382ce536cc7 Mon Sep 17 00:00:00 2001
From: Paul Cockrell
Date: Sat, 18 Apr 2020 00:39:32 +0100
Subject: [PATCH 055/101] Fix Changelog
---
apps/astrocalc/ChangeLog | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/apps/astrocalc/ChangeLog b/apps/astrocalc/ChangeLog
index 188fc287b..60ef5da0a 100644
--- a/apps/astrocalc/ChangeLog
+++ b/apps/astrocalc/ChangeLog
@@ -1,3 +1,2 @@
0.01: Create astrocalc app
-0.02: Store last GPS lock, can be used instead of waiting for new GPS on
-start.
+0.02: Store last GPS lock, can be used instead of waiting for new GPS on start
From e052a6e65fdaad4c14c99798ea7dd316cadf7345 Mon Sep 17 00:00:00 2001
From: Paul Cockrell
Date: Sat, 18 Apr 2020 00:41:15 +0100
Subject: [PATCH 056/101] Remove repeated assignment of date to gps object
---
apps/astrocalc/astrocalc-app.js | 1 -
1 file changed, 1 deletion(-)
diff --git a/apps/astrocalc/astrocalc-app.js b/apps/astrocalc/astrocalc-app.js
index 0b0c63658..6b848abda 100644
--- a/apps/astrocalc/astrocalc-app.js
+++ b/apps/astrocalc/astrocalc-app.js
@@ -339,7 +339,6 @@ function drawGPSWaitPage() {
setWatch(() => {
clearWatch();
Bangle.setGPSPower(0);
- lastGPS.time = new Date();
m = indexPageMenu(lastGPS);
}, BTN3, {repeat: false});
}
From bf4a3e0321abc7007a1fc1acede9616ff4a9cd49 Mon Sep 17 00:00:00 2001
From: Fredrik Lautrup
Date: Sat, 18 Apr 2020 09:01:15 +0200
Subject: [PATCH 057/101] Added rclock app
---
apps.json | 12 +++
apps/rclock/ChangeLog | 1 +
apps/rclock/app-icon.js | 1 +
apps/rclock/app.png | Bin 0 -> 1620 bytes
apps/rclock/rclock.app.js | 163 ++++++++++++++++++++++++++++++++++++++
5 files changed, 177 insertions(+)
create mode 100644 apps/rclock/ChangeLog
create mode 100644 apps/rclock/app-icon.js
create mode 100644 apps/rclock/app.png
create mode 100644 apps/rclock/rclock.app.js
diff --git a/apps.json b/apps.json
index bbe0bbfcd..ac7181bb4 100644
--- a/apps.json
+++ b/apps.json
@@ -1291,6 +1291,18 @@
"name": "dane.img",
"url": "app-icon.js",
"evaluate": true
+ },
+ { "id": "rclock",
+ "name": "Round clock with seconds, minutes and date",
+ "shortName":"Round Clock",
+ "icon": "app.png",
+ "version":"0.01",
+ "description": "Designed round clock with ticks for minutes and seconds",
+ "tags": "",
+ "storage": [
+ {"name":"rclock.app.js","url":"app.js"},
+ {"name":"rclock.img","url":"app-icon.js","evaluate":true}
+ ]
}
]
}
diff --git a/apps/rclock/ChangeLog b/apps/rclock/ChangeLog
new file mode 100644
index 000000000..5560f00bc
--- /dev/null
+++ b/apps/rclock/ChangeLog
@@ -0,0 +1 @@
+0.01: New App!
diff --git a/apps/rclock/app-icon.js b/apps/rclock/app-icon.js
new file mode 100644
index 000000000..49232b838
--- /dev/null
+++ b/apps/rclock/app-icon.js
@@ -0,0 +1 @@
+require("heatshrink").decompress(atob("mEwwJC/AH4A/AH4AgA=="))
diff --git a/apps/rclock/app.png b/apps/rclock/app.png
new file mode 100644
index 0000000000000000000000000000000000000000..582cb2e0853a5a2899a3afbd7eb19cde2ee7f6a0
GIT binary patch
literal 1620
zcmV-a2CMmrP)1gXjloC|3_d8m;N2OpV(|i0q4YwBna<2!
zK9thw%-*|urnNbV{Gax^?eD+#{x0kLJ~)lj_;W+1>qV*k8akT^^dvctZccUyj4}H~#M%Wwee_v`
zHMv7o%BM8@dBrLshn{wGD9BDl?^eV5vSM3T96;NnHvtc6La=(qzq)xrX1d8bK-TN-
zrd_f$_O`9nEmS+_S7HTXK<&u;LDIW|qlN&KJvM}tt6TVVqL-AvNv`B*{NzNpBfSQwQP5~Sf(Dp@Vq1+3Q`N9wBQN2`J_?M^u0FIMlt?p^8
z%U3%80kIwg!T{E9<8J18S&$k1`eO)@HP+=TZKo(z3_A3VFYJB=sn`2^Q$mRE>02(+W)np;)L1!GUvU2{O{<&F_nE6Qe#D~Xf|dD
z+?d3-D1(IUiL`C2;PPv4CKw8H)v7h8^obJ&Z6D0CjVUe8Xq_NAymxUyPAMU^CCrIu
z%1M71EC`5o2if_~7E&h??0jeQ1Y3N6p?}G72FmS*)xQD)%wBE=2tW6@(+MTi!fk9H1pWKew2(jTXVu4%vk26QvSQCbGmk`Z)Y!
zBIhh)6vG2)h6mF8wC^|l$M(Eo9D?JiW}=_T2jUA>LC80foTera{^p)Wi`>}Gf;(|ZwEZQ
zS^k|*9wyt=f4ZOo!xty7{%}HKD9tBZ50g$=%v&&vMa!#@Nsf>EkEEDA*ST6fiC+An
zsNK1#>!x0obq@j$QqYU-ad3ZvbjqUU+%iw(0WahgmHV6yeLWqoYkSl4pzFQ(_Vp&I
ztO{WI-48rGLwQb?#vgVvduyd9_6W)rFRoQJq3I(J?{Xmin45#=3l9BmL6Bp<*MZej
zrsWN7oRPUr7IvrHoIHOjS=gPTCw>d)^LQK+B|=f2qbGjrWaOd5D<<9Dv>MTW0X3z>
zyPy}9`<>1~?NCx@m8G$_@rRTy5zH12YM&P)=tU+L^fgY
z^0Z&_6^qdVuwgN3wt_Ze(10?J@%{C2grBk42hsu74qEo^nd&v`X`IHN9lrxzS~GeF
S(*#!l0000
Date: Sat, 18 Apr 2020 11:17:50 +0200
Subject: [PATCH 058/101] Fix error in app.json
---
apps.json | 25 ++++++++++++-------------
1 file changed, 12 insertions(+), 13 deletions(-)
diff --git a/apps.json b/apps.json
index ac7181bb4..89fd1a0a3 100644
--- a/apps.json
+++ b/apps.json
@@ -1291,19 +1291,18 @@
"name": "dane.img",
"url": "app-icon.js",
"evaluate": true
- },
- { "id": "rclock",
- "name": "Round clock with seconds, minutes and date",
- "shortName":"Round Clock",
- "icon": "app.png",
- "version":"0.01",
- "description": "Designed round clock with ticks for minutes and seconds",
- "tags": "",
- "storage": [
- {"name":"rclock.app.js","url":"app.js"},
- {"name":"rclock.img","url":"app-icon.js","evaluate":true}
- ]
}
]
- }
+ },
+ { "id": "rclock",
+ "name": "Round clock with seconds, minutes and date",
+ "shortName":"Round Clock",
+ "icon": "app.png",
+ "version":"0.01",
+ "description": "Designed round clock with ticks for minutes and seconds",
+ "tags": "",
+ "storage": [
+ {"name":"rclock.app.js","url":"app.js"},
+ {"name":"rclock.img","url":"app-icon.js","evaluate":true}
+ ]
]
From 8f562d817782203bdf250c7d60803b9ac3102b40 Mon Sep 17 00:00:00 2001
From: Fredrik Lautrup
Date: Sat, 18 Apr 2020 11:21:14 +0200
Subject: [PATCH 059/101] Fix error in app.json
---
apps.json | 1 +
1 file changed, 1 insertion(+)
diff --git a/apps.json b/apps.json
index 89fd1a0a3..d7e857066 100644
--- a/apps.json
+++ b/apps.json
@@ -1305,4 +1305,5 @@
{"name":"rclock.app.js","url":"app.js"},
{"name":"rclock.img","url":"app-icon.js","evaluate":true}
]
+ }
]
From 06705a6e5d0a3de5db7131c6a56684a917b6a710 Mon Sep 17 00:00:00 2001
From: Fredrik Lautrup
Date: Sat, 18 Apr 2020 11:28:08 +0200
Subject: [PATCH 060/101] Fixes
---
apps.json | 6 ++++--
apps/rclock/ChangeLog | 2 +-
apps/rclock/rclock.app.js | 1 +
3 files changed, 6 insertions(+), 3 deletions(-)
diff --git a/apps.json b/apps.json
index d7e857066..dc768218b 100644
--- a/apps.json
+++ b/apps.json
@@ -1294,13 +1294,15 @@
}
]
},
- { "id": "rclock",
+ {
+ "id": "rclock",
"name": "Round clock with seconds, minutes and date",
"shortName":"Round Clock",
"icon": "app.png",
"version":"0.01",
"description": "Designed round clock with ticks for minutes and seconds",
- "tags": "",
+ "tags": "clock",
+ "type": "clock",
"storage": [
{"name":"rclock.app.js","url":"app.js"},
{"name":"rclock.img","url":"app-icon.js","evaluate":true}
diff --git a/apps/rclock/ChangeLog b/apps/rclock/ChangeLog
index 5560f00bc..a8f708a0a 100644
--- a/apps/rclock/ChangeLog
+++ b/apps/rclock/ChangeLog
@@ -1 +1 @@
-0.01: New App!
+0.01: First published version of app
diff --git a/apps/rclock/rclock.app.js b/apps/rclock/rclock.app.js
index 27fbda772..c681e0588 100644
--- a/apps/rclock/rclock.app.js
+++ b/apps/rclock/rclock.app.js
@@ -104,6 +104,7 @@
}
first = false;
}
+
// Reset seconds
if (seconds == 59) {
g.setColor('#000000');
From 7216b188672dfe4f5141c3a0470c38128f089cae Mon Sep 17 00:00:00 2001
From: Fredrik Lautrup
Date: Sat, 18 Apr 2020 11:48:22 +0200
Subject: [PATCH 061/101] Fix error in reference to files
---
apps.json | 2 +-
package.json | 3 +++
2 files changed, 4 insertions(+), 1 deletion(-)
diff --git a/apps.json b/apps.json
index dc768218b..bf771882a 100644
--- a/apps.json
+++ b/apps.json
@@ -1304,7 +1304,7 @@
"tags": "clock",
"type": "clock",
"storage": [
- {"name":"rclock.app.js","url":"app.js"},
+ {"name":"rclock.app.js","url":"rclock.app.js"},
{"name":"rclock.img","url":"app-icon.js","evaluate":true}
]
}
diff --git a/package.json b/package.json
index 400385139..24793d86a 100644
--- a/package.json
+++ b/package.json
@@ -9,5 +9,8 @@
"scripts": {
"test": "node bin/sanitycheck.js",
"start": "npx http-server"
+ },
+ "dependencies": {
+ "acorn": "^7.1.1"
}
}
From a1f1da0341f4a8985e4f5baafcbdf1b1a1469f6a Mon Sep 17 00:00:00 2001
From: Fredrik Lautrup
Date: Sat, 18 Apr 2020 11:52:30 +0200
Subject: [PATCH 062/101] Updated grey colors
---
apps/rclock/rclock.app.js | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/apps/rclock/rclock.app.js b/apps/rclock/rclock.app.js
index c681e0588..405da7052 100644
--- a/apps/rclock/rclock.app.js
+++ b/apps/rclock/rclock.app.js
@@ -31,8 +31,8 @@
center: screen.center,
},
circle: {
- colormin: '#777777',
- colorsec: '#444444',
+ colormin: '#999999',
+ colorsec: '#777777',
width: 10,
middle: screen.middle,
center: screen.center,
From afeff2c5761ed15d7164b1b3e338b7113ddee2b3 Mon Sep 17 00:00:00 2001
From: Fredrik Lautrup
Date: Sat, 18 Apr 2020 11:55:40 +0200
Subject: [PATCH 063/101] Updated grey colors
---
apps/rclock/rclock.app.js | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/apps/rclock/rclock.app.js b/apps/rclock/rclock.app.js
index 405da7052..25ca757cd 100644
--- a/apps/rclock/rclock.app.js
+++ b/apps/rclock/rclock.app.js
@@ -31,8 +31,8 @@
center: screen.center,
},
circle: {
- colormin: '#999999',
- colorsec: '#777777',
+ colormin: '#bbbbbb',
+ colorsec: '#999999',
width: 10,
middle: screen.middle,
center: screen.center,
From 0a7a9e0b97652f96738c1a39e4bb6132c2aa9424 Mon Sep 17 00:00:00 2001
From: Fredrik Lautrup
Date: Sat, 18 Apr 2020 12:02:01 +0200
Subject: [PATCH 064/101] Align fonts
---
apps/rclock/rclock.app.js | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/apps/rclock/rclock.app.js b/apps/rclock/rclock.app.js
index 25ca757cd..bd8395116 100644
--- a/apps/rclock/rclock.app.js
+++ b/apps/rclock/rclock.app.js
@@ -20,7 +20,7 @@
font: 'Vector',
size: 60,
middle: screen.middle - 30,
- center: screen.center + 5 ,
+ center: screen.center,
},
date: {
color: '#f0af00',
@@ -31,8 +31,8 @@
center: screen.center,
},
circle: {
- colormin: '#bbbbbb',
- colorsec: '#999999',
+ colormin: '#eeeeee',
+ colorsec: '#bbbbbb',
width: 10,
middle: screen.middle,
center: screen.center,
@@ -149,6 +149,7 @@
// clean app screen
g.clear();
+ g.setFontAlign( 0, 0, 0);
Bangle.loadWidgets();
Bangle.drawWidgets();
From 6d1e87a765de9a48dee5939d66aeff0a97f3760b Mon Sep 17 00:00:00 2001
From: Fredrik Lautrup
Date: Sat, 18 Apr 2020 12:39:13 +0200
Subject: [PATCH 065/101] Added icons
---
.DS_Store | Bin 0 -> 6148 bytes
apps/.DS_Store | Bin 0 -> 6148 bytes
apps/rclock/.DS_Store | Bin 0 -> 6148 bytes
apps/rclock/app-icon.js | 2 +-
apps/rclock/app.png | Bin 1620 -> 0 bytes
apps/rclock/appp.png | Bin 0 -> 10357 bytes
6 files changed, 1 insertion(+), 1 deletion(-)
create mode 100644 .DS_Store
create mode 100644 apps/.DS_Store
create mode 100644 apps/rclock/.DS_Store
delete mode 100644 apps/rclock/app.png
create mode 100644 apps/rclock/appp.png
diff --git a/.DS_Store b/.DS_Store
new file mode 100644
index 0000000000000000000000000000000000000000..e9892b6bcf444f36764922b8e4fcf88ecca916a8
GIT binary patch
literal 6148
zcmeH~Jr2S!425mzP>H1@V-^m;4I%_5-~#-K2??Z%JxAx+@j_rm6?#VYi=A4u-_X<|
zqMPSsEi#Bm4>y&Sg~k+lCr5eUH(oE}`EJ);>!>lNF#jv{Xd}rZGKew5pFG
zR`+&jitBP{sao4bWBAbcXSFE?rnOx(A%SUjVITn#Xb8+}KG^xcgMXX3Z5S>vG!N$@uSMUZw^aNf&RBRL$6#K0_mq+u>r%+ZqEtEGfdC6p6LSC`6
zBO*G#>}Dbp5gEY^}dS)lX)N&paQ?HfPEhd+^{CLf&S^h;4J`ffUq0p-b(H1@V-^m;4Wg<&0T*E43hX&L&p$$qDprKhvt+--jT7}7np#A3
zem<@ulZcFPQ@L2!n>{z**++&mCkOWA81W14cNZlEfg7;MkzE(HCqgga^y>{tEnwC%0;vJ&^%eQ
zLs35+`xjp>T01gXjloC|3_d8m;N2OpV(|i0q4YwBna<2!
zK9thw%-*|urnNbV{Gax^?eD+#{x0kLJ~)lj_;W+1>qV*k8akT^^dvctZccUyj4}H~#M%Wwee_v`
zHMv7o%BM8@dBrLshn{wGD9BDl?^eV5vSM3T96;NnHvtc6La=(qzq)xrX1d8bK-TN-
zrd_f$_O`9nEmS+_S7HTXK<&u;LDIW|qlN&KJvM}tt6TVVqL-AvNv`B*{NzNpBfSQwQP5~Sf(Dp@Vq1+3Q`N9wBQN2`J_?M^u0FIMlt?p^8
z%U3%80kIwg!T{E9<8J18S&$k1`eO)@HP+=TZKo(z3_A3VFYJB=sn`2^Q$mRE>02(+W)np;)L1!GUvU2{O{<&F_nE6Qe#D~Xf|dD
z+?d3-D1(IUiL`C2;PPv4CKw8H)v7h8^obJ&Z6D0CjVUe8Xq_NAymxUyPAMU^CCrIu
z%1M71EC`5o2if_~7E&h??0jeQ1Y3N6p?}G72FmS*)xQD)%wBE=2tW6@(+MTi!fk9H1pWKew2(jTXVu4%vk26QvSQCbGmk`Z)Y!
zBIhh)6vG2)h6mF8wC^|l$M(Eo9D?JiW}=_T2jUA>LC80foTera{^p)Wi`>}Gf;(|ZwEZQ
zS^k|*9wyt=f4ZOo!xty7{%}HKD9tBZ50g$=%v&&vMa!#@Nsf>EkEEDA*ST6fiC+An
zsNK1#>!x0obq@j$QqYU-ad3ZvbjqUU+%iw(0WahgmHV6yeLWqoYkSl4pzFQ(_Vp&I
ztO{WI-48rGLwQb?#vgVvduyd9_6W)rFRoQJq3I(J?{Xmin45#=3l9BmL6Bp<*MZej
zrsWN7oRPUr7IvrHoIHOjS=gPTCw>d)^LQK+B|=f2qbGjrWaOd5D<<9Dv>MTW0X3z>
zyPy}9`<>1~?NCx@m8G$_@rRTy5zH12YM&P)=tU+L^fgY
z^0Z&_6^qdVuwgN3wt_Ze(10?J@%{C2grBk42hsu74qEo^nd&v`X`IHN9lrxzS~GeF
S(*#!l0000
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