From 785ce647793568fd9d1ee038303a3e552235a801 Mon Sep 17 00:00:00 2001 From: Noah Howard <3317164+nh-99@users.noreply.github.com> Date: Fri, 18 Mar 2022 18:35:44 -0400 Subject: [PATCH 001/294] Add disc golf score tracking app --- apps/discgolf/ChangeLog | 1 + apps/discgolf/README.md | 14 +++ apps/discgolf/app-icon.js | 1 + apps/discgolf/app.js | 171 +++++++++++++++++++++++++++++++ apps/discgolf/app.png | Bin 0 -> 10687 bytes apps/discgolf/metadata.json | 14 +++ apps/discgolf/summary_screen.png | Bin 0 -> 3025 bytes apps/discgolf/throw_screen.png | Bin 0 -> 2459 bytes 8 files changed, 201 insertions(+) create mode 100644 apps/discgolf/ChangeLog create mode 100644 apps/discgolf/README.md create mode 100644 apps/discgolf/app-icon.js create mode 100644 apps/discgolf/app.js create mode 100644 apps/discgolf/app.png create mode 100644 apps/discgolf/metadata.json create mode 100644 apps/discgolf/summary_screen.png create mode 100644 apps/discgolf/throw_screen.png diff --git a/apps/discgolf/ChangeLog b/apps/discgolf/ChangeLog new file mode 100644 index 000000000..220e1d1c2 --- /dev/null +++ b/apps/discgolf/ChangeLog @@ -0,0 +1 @@ +0.01: Initial version of disc golf app. Has throw and hole counter, along with summary screen. Uses buttons for holes & throws. \ No newline at end of file diff --git a/apps/discgolf/README.md b/apps/discgolf/README.md new file mode 100644 index 000000000..34a9dfe90 --- /dev/null +++ b/apps/discgolf/README.md @@ -0,0 +1,14 @@ +# Disc Golf + +Individual score tracking for disc golf on your wrist. + +![](throw_screen.png) +![](summary_screen.png) + +## Usage + +Press the side button once to increment throws. Double-tap the side button to increment holes. View your game summary with the button in the upper right of the screen. + +## Creator + +Made by [Noah Howard](https://github.com/nh-99) diff --git a/apps/discgolf/app-icon.js b/apps/discgolf/app-icon.js new file mode 100644 index 000000000..cfc07a2fa --- /dev/null +++ b/apps/discgolf/app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwxH+AH4A/ABFzudsAAImmABIppAAIQBFcYMBzwMDFbP+y5RJHYiHdLJYADG5AATzxaNFotszwuXFp5sFLq4tIVpANNF0D4FRqobFJ5peaFxKtJXgi9VzxdSLwwvUFyYvaFxIhKOYwvSFxoAEzyjJF7I/VFyzRjU5QICuYiNBxBJTQp7lFF7byQGQYwSOwovSOpJsFdpwvTao4voMQ4vQOQQwmX4oQCBAwwgCxAvWDIwvPGD4vIy4WJSSzcFMCCpGMC+eGChiUYJwjJPIRiTF5xULBxwvVEJgQQCIQOEF5X+zwfLSoY0HBYg9FF5a2QDSQvNWqJbBAQTaOMTY9PF6DFNAB4uRGLguUYygucfKwubGQgzLFsAAHFYV6Fc4A/AAw=")) \ No newline at end of file diff --git a/apps/discgolf/app.js b/apps/discgolf/app.js new file mode 100644 index 000000000..68bbd817d --- /dev/null +++ b/apps/discgolf/app.js @@ -0,0 +1,171 @@ +Bangle.loadWidgets(); + +// +// App imports +// +var Layout = require("Layout"); + +// +// App variables +// +var holeCount = 1; +var throwCount = 0; +var drawTimeout; +var currentScreen = 'throw'; +var redraw = true; +var update = true; +var holeSummary = { + "< Back" : () => { update = true; redraw = true; currentScreen = 'throw'; E.showMenu(); createThrowLayout(); }, + "Hole #1": { value: 0 }, + "Hole #2": { value: 0 }, + "Hole #3": { value: 0 }, + "Hole #4": { value: 0 }, + "Hole #5": { value: 0 }, + "Hole #6": { value: 0 }, + "Hole #7": { value: 0 }, + "Hole #8": { value: 0 }, + "Hole #9": { value: 0 }, + "Front": { value: 0 }, + "Hole #10": { value: 0 }, + "Hole #11": { value: 0 }, + "Hole #12": { value: 0 }, + "Hole #13": { value: 0 }, + "Hole #14": { value: 0 }, + "Hole #15": { value: 0 }, + "Hole #16": { value: 0 }, + "Hole #17": { value: 0 }, + "Hole #18": { value: 0 }, + "Back": { value: 0 }, +}; + +// Images +function getBackImage() { + return atob("FhYBAAAAEAAAwAAHAAA//wH//wf//g///BwB+DAB4EAHwAAPAAA8AADwAAPAAB4AAHgAB+AH/wA/+AD/wAH8AA=="); +} +function getMenuImage() { + return { + width : 20, height : 20, bpp : 1, + buffer : require("heatshrink").decompress(atob("AAk///D//8CBcDBwITB4AiVA")) + }; +} +function getBasketIcon() { + return { + width : 20, height : 20, bpp : 1, + buffer : require("heatshrink").decompress(atob("gFggF/8EH/0AiWAgtogEW0EDt0Am3ggfsgEf4EB/EA//4j//wEChEP/8AgwnDAgw")) + }; +} +function getFrisbeeIcon() { + return { + width : 20, height : 20, bpp : 1, + buffer : require("heatshrink").decompress(atob("AAf+gF/wE+uEPx0B+PAn0cgf/4F3/0G/1g9/7g1/7AJB4+f/k+v3B/Hcg4WBj/4E4ItC")) + }; +} + +var throwLayout; + +function createThrowLayout() { + throwLayout = new Layout( { + type:"v", c: [ + // Title & menu button + { + type:"h", fillx:1, valign:-1, bgCol:g.theme.bg2, col: g.theme.fg2, c: [ + {type:"img", src:getBasketIcon()}, + {type:"txt", pad:4, font:"15%", label:holeCount, id: "holeCount"}, + {type:"txt", pad:4, font:"15%", label: '', fillx:1}, + {type:"btn", src:getMenuImage(), halign:1, cb: l=>{ currentScreen = 'summary'; update = true; redraw = true; }} + ] + }, + // Throw count + { + type:"h", filly:1, c: [ + {type:"img", pad:4, src:getFrisbeeIcon() }, + {type:"txt", fillx:1, font:"6x8:2", label:"Throws: "+throwCount, id:"throwCount"} + ] + } + ] + }, {lazy:true}); +} + +function incrementHole() { + if (holeCount > 18) return; + resetThrow(); + holeCount += 1; + holeSummary["Hole #" + holeCount] = {value: 0}; +} +function incrementThrow() { + throwCount += 1; + holeSummary["Hole #" + holeCount] = {value: throwCount}; +} +function decrementThrow() { + throwCount -= 1; + holeSummary["Hole #" + holeCount] = {value: throwCount}; +} +function resetThrow() { + throwCount = 0; +} +function computeFrontScore() { + var scoreSum = 0; + for (var i = 1; i < 10; i++) { + scoreSum += holeSummary["Hole #" + i].value; + } + holeSummary.Front = {value: scoreSum}; +} +function computeBackScore() { + var scoreSum = 0; + for (var i = 1; i < 19; i++) { + scoreSum += holeSummary["Hole #" + i].value; + } + holeSummary.Back = {value: scoreSum}; +} + +// update the app state/variables +function updateApp() { + throwLayout.holeCount.label = holeCount; + throwLayout.throwCount.label = "Throws: " + throwCount; +} + +// update the screen +function draw() { + updateApp(); + if (redraw) { + throwLayout.forgetLazyState(); + redraw = false; + } + if (update) { + if (currentScreen == 'throw') { + throwLayout.render(); + } else if (currentScreen == 'summary') { + E.showMenu(holeSummary); + } + update = false; + } + // schedule a draw for the next 500ms + if (drawTimeout) clearTimeout(drawTimeout); + drawTimeout = setTimeout(function() { + drawTimeout = undefined; + draw(); + }, 500 - (Date.now() % 500)); +} + +// +// button press events +// +setWatch((p) => { + if (p.time - p.lastTime < 0.2) { + decrementThrow(); + incrementHole(); + } else { + incrementThrow(); + } + computeFrontScore(); + computeBackScore(); + update = true; +}, BTN, {edge:"rising", debounce:50, repeat:true}); + +// +// main app function start +// +g.clear(); +Bangle.drawWidgets(); +createThrowLayout(); +draw(); \ No newline at end of file diff --git a/apps/discgolf/app.png b/apps/discgolf/app.png new file mode 100644 index 0000000000000000000000000000000000000000..6aba5e54816571474aae74f0db98b39a7db7933a GIT binary patch literal 10687 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 literal 0 HcmV?d00001 diff --git a/apps/discgolf/metadata.json b/apps/discgolf/metadata.json new file mode 100644 index 000000000..6d56f05e4 --- /dev/null +++ b/apps/discgolf/metadata.json @@ -0,0 +1,14 @@ +{ "id": "discgolf", + "name": "Disc Golf", + "shortName":"Disc Golf", + "version":"0.01", + "description": "A personal disc golf score tracker", + "icon": "app.png", + "tags": "", + "supports" : ["BANGLEJS2"], + "readme": "README.md", + "storage": [ + {"name":"discgolf.app.js","url":"app.js"}, + {"name":"discgolf.img","url":"app-icon.js","evaluate":true} + ] +} diff --git a/apps/discgolf/summary_screen.png b/apps/discgolf/summary_screen.png new file mode 100644 index 0000000000000000000000000000000000000000..480d36eddfa8646b874e96458520979ac2de4ad6 GIT binary patch literal 3025 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 literal 0 HcmV?d00001 From 123d4814696eafc50062b774a62b7fdc90b80518 Mon Sep 17 00:00:00 2001 From: Salim Blume Date: Mon, 4 Apr 2022 12:22:04 -0500 Subject: [PATCH 002/294] Running setScan with active: true --- apps/bthrm/settings.js | 2 +- apps/health/README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/bthrm/settings.js b/apps/bthrm/settings.js index 4b564d670..9f409880a 100644 --- a/apps/bthrm/settings.js +++ b/apps/bthrm/settings.js @@ -127,7 +127,7 @@ }); }; } - }, { filters: [{services: [ "180d" ]}]}); + }, { active: true, filters: [{services: [ "180d" ]}]}); } diff --git a/apps/health/README.md b/apps/health/README.md index f44854e3e..e3a84068b 100644 --- a/apps/health/README.md +++ b/apps/health/README.md @@ -2,7 +2,7 @@ Logs health data to a file every 10 minutes, and provides an app to view it -**BETA - requires firmware 2v11** +**BETA - requires firmware 2v11 or later** ## Usage From d27deac8aadfa6f9393e31aa26c4c69bb4f39dd2 Mon Sep 17 00:00:00 2001 From: Salim Blume Date: Mon, 4 Apr 2022 14:47:17 -0500 Subject: [PATCH 003/294] Adding 'active: true' to NRF.requestDevice call made when btname is set --- apps/bthrm/boot.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/bthrm/boot.js b/apps/bthrm/boot.js index 3a1f1cc4c..93e72b83b 100644 --- a/apps/bthrm/boot.js +++ b/apps/bthrm/boot.js @@ -370,7 +370,7 @@ filters = [{name: settings.btname}]; } log("Requesting device with filters", filters); - promise = NRF.requestDevice({ filters: filters }); + promise = NRF.requestDevice({ filters: filters, active: true }); if (settings.gracePeriodRequest){ log("Add " + settings.gracePeriodRequest + "ms grace period after request"); From d89db8f7d7f680c11aa73780c50483364972059b Mon Sep 17 00:00:00 2001 From: Salim Blume Date: Mon, 4 Apr 2022 15:55:14 -0500 Subject: [PATCH 004/294] Removing call to function that doesn't exist --- apps/bthrm/boot.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/bthrm/boot.js b/apps/bthrm/boot.js index 93e72b83b..227f78c1a 100644 --- a/apps/bthrm/boot.js +++ b/apps/bthrm/boot.js @@ -108,7 +108,7 @@ var sensorContact; if (flags & 2){ - sensorContact = (flags & 4) ? true : false; + sensorContact = !!(flags & 4); } var idx = 2 + (flags&1); @@ -297,7 +297,7 @@ }); } else if (newCharacteristic.read){ result = result.then(()=>{ - readData(newCharacteristic); + // readData(newCharacteristic); log("Reading data for " + newCharacteristic); return newCharacteristic.read().then((data)=>{ supportedCharacteristics[newCharacteristic.uuid].handler(data); From 75c4e5b54b54181c054bbb2a68603435f02761cf Mon Sep 17 00:00:00 2001 From: Salim Blume Date: Mon, 4 Apr 2022 16:48:15 -0500 Subject: [PATCH 005/294] bthrm fixes for reading characteristics generally and displaying location --- apps/bthrm/boot.js | 17 +++++++++-------- apps/bthrm/bthrm.js | 13 +++++++++++-- typescript/types/globals.d.ts | 6 +++--- 3 files changed, 23 insertions(+), 13 deletions(-) diff --git a/apps/bthrm/boot.js b/apps/bthrm/boot.js index 227f78c1a..dd25634e5 100644 --- a/apps/bthrm/boot.js +++ b/apps/bthrm/boot.js @@ -168,14 +168,14 @@ //Body sensor location handler: function(data){ if (!lastReceivedData["0x180d"]) lastReceivedData["0x180d"] = {}; - if (!lastReceivedData["0x180d"]["0x2a38"]) lastReceivedData["0x180d"]["0x2a38"] = data.target.value; + lastReceivedData["0x180d"]["0x2a38"] = parseInt(data.buffer, 10); } }, "0x2a19": { //Battery handler: function (event){ - if (!lastReceivedData["0x180f"]) lastReceivedData["0x180f"] = {}; - if (!lastReceivedData["0x180f"]["0x2a19"]) lastReceivedData["0x180f"]["0x2a19"] = event.target.value.getUint8(0); + if (!lastReceivedData["0x180f"]) lastReceivedData["0x180f"] = { "0x2a19": null }; + lastReceivedData["0x180f"]["0x2a19"] = event.target.value.getUint8(0); } } @@ -295,12 +295,13 @@ } return startPromise; }); - } else if (newCharacteristic.read){ + } else if (newCharacteristic.readValue){ result = result.then(()=>{ - // readData(newCharacteristic); - log("Reading data for " + newCharacteristic); - return newCharacteristic.read().then((data)=>{ - supportedCharacteristics[newCharacteristic.uuid].handler(data); + log("Reading data for " + JSON.stringify(newCharacteristic)); + return newCharacteristic.readValue().then((data)=>{ + if (supportedCharacteristics[newCharacteristic.uuid] && supportedCharacteristics[newCharacteristic.uuid].handler) { + supportedCharacteristics[newCharacteristic.uuid].handler(data); + } }); }); } diff --git a/apps/bthrm/bthrm.js b/apps/bthrm/bthrm.js index cc533eedd..5ab3b0018 100644 --- a/apps/bthrm/bthrm.js +++ b/apps/bthrm/bthrm.js @@ -1,7 +1,16 @@ -var btm = g.getHeight()-1; var intervalInt; var intervalBt; +var BODY_LOCS = { + 0: 'Other', + 1: 'Chest', + 2: 'Wrist', + 3: 'Finger', + 4: 'Hand', + 5: 'Ear Lobe', + 6: 'Foot', +} + function clear(y){ g.reset(); g.clearRect(0,y,g.getWidth(),y+75); @@ -25,7 +34,7 @@ function draw(y, type, event) { if (event.battery) str += " Bat: " + (event.battery ? event.battery : ""); g.setFontVector(12).drawString(str,px,y+40); str= ""; - if (event.location) str += "Loc: " + event.location.toFixed(0) + "ms"; + if (event.location) str += "Loc: " + BODY_LOCS[event.location]; if (event.rr && event.rr.length > 0) str += " RR: " + event.rr.join(","); g.setFontVector(12).drawString(str,px,y+50); str= ""; diff --git a/typescript/types/globals.d.ts b/typescript/types/globals.d.ts index 2ef52dcdf..442140e70 100644 --- a/typescript/types/globals.d.ts +++ b/typescript/types/globals.d.ts @@ -158,9 +158,9 @@ declare type Image = { }; declare type GraphicsApi = { - reset: () => void; + reset: () => GraphicsApi; flip: () => void; - setColor: (color: string) => void; // TODO we can most likely type color more usefully than this + setColor: (color: string) => GraphicsApi; // TODO we can most likely type color more usefully than this drawImage: ( image: string | Image | ArrayBuffer, xOffset: number, @@ -169,7 +169,7 @@ declare type GraphicsApi = { rotate?: number; scale?: number; } - ) => void; + ) => GraphicsApi; // TODO add more }; From d19a68e5117904689b9a35706fceeb64f3bd04fc Mon Sep 17 00:00:00 2001 From: Salim Blume Date: Mon, 4 Apr 2022 17:29:20 -0500 Subject: [PATCH 006/294] Fix how events and reads were handled differently --- apps/bthrm/boot.js | 55 +++++++++++++++++++++++----------------------- 1 file changed, 28 insertions(+), 27 deletions(-) diff --git a/apps/bthrm/boot.js b/apps/bthrm/boot.js index dd25634e5..0a6af55b6 100644 --- a/apps/bthrm/boot.js +++ b/apps/bthrm/boot.js @@ -31,7 +31,7 @@ function addNotificationHandler(characteristic){ log("Setting notification handler: " + supportedCharacteristics[characteristic.uuid].handler); - characteristic.on('characteristicvaluechanged', supportedCharacteristics[characteristic.uuid].handler); + characteristic.on('characteristicvaluechanged', (ev) => supportedCharacteristics[characteristic.uuid].handler(ev.target.value)); } function writeCache(cache){ @@ -92,15 +92,14 @@ services: [ "180d" ] }]; - supportedServices = [ + var supportedServices = [ "0x180d", "0x180f" ]; var supportedCharacteristics = { "0x2a37": { //Heart rate measurement - handler: function (event){ - var dv = event.target.value; + handler: function (dv){ var flags = dv.getUint8(0); var bpm = (flags & 1) ? (dv.getUint16(1) / 100 /* ? */ ) : dv.getUint8(1); // 8 or 16 bit @@ -121,7 +120,7 @@ var interval; if (flags & 16) { interval = []; - maxIntervalBytes = (dv.byteLength - idx); + var maxIntervalBytes = (dv.byteLength - idx); log("Found " + (maxIntervalBytes / 2) + " rr data fields"); for(var i = 0 ; i < maxIntervalBytes / 2; i++){ interval[i] = dv.getUint16(idx,1); // in milliseconds @@ -140,14 +139,14 @@ } if (settings.replace){ - var newEvent = { + var repEvent = { bpm: bpm, confidence: (sensorContact || sensorContact === undefined)? 100 : 0, src: "bthrm" }; - log("Emitting HRM: ", newEvent); - Bangle.emit("HRM", newEvent); + log("Emitting HRM: ", repEvent); + Bangle.emit("HRM", repEvent); } var newEvent = { @@ -159,23 +158,23 @@ if (energyExpended) newEvent.energy = energyExpended; if (battery) newEvent.battery = battery; if (sensorContact) newEvent.contact = sensorContact; - + log("Emitting BTHRM: ", newEvent); Bangle.emit("BTHRM", newEvent); } }, "0x2a38": { //Body sensor location - handler: function(data){ + handler: function(dv){ if (!lastReceivedData["0x180d"]) lastReceivedData["0x180d"] = {}; - lastReceivedData["0x180d"]["0x2a38"] = parseInt(data.buffer, 10); + lastReceivedData["0x180d"]["0x2a38"] = parseInt(dv.buffer, 10); } }, "0x2a19": { //Battery - handler: function (event){ - if (!lastReceivedData["0x180f"]) lastReceivedData["0x180f"] = { "0x2a19": null }; - lastReceivedData["0x180f"]["0x2a19"] = event.target.value.getUint8(0); + handler: function (dv){ + if (!lastReceivedData["0x180f"]) lastReceivedData["0x180f"] = {}; + lastReceivedData["0x180f"]["0x2a19"] = dv.getUint8(0); } } @@ -282,6 +281,18 @@ function createCharacteristicPromise(newCharacteristic){ log("Create characteristic promise: ", newCharacteristic); var result = Promise.resolve(); + // For values that can be read, go ahead and read them, even if we might be notified in the future + // Allows for getting initial state of infrequently updating characteristics, like battery + if (newCharacteristic.readValue){ + result = result.then(()=>{ + log("Reading data for " + JSON.stringify(newCharacteristic)); + return newCharacteristic.readValue().then((data)=>{ + if (supportedCharacteristics[newCharacteristic.uuid] && supportedCharacteristics[newCharacteristic.uuid].handler) { + supportedCharacteristics[newCharacteristic.uuid].handler(data); + } + }); + }); + } if (newCharacteristic.properties.notify){ result = result.then(()=>{ log("Starting notifications for: ", newCharacteristic); @@ -295,15 +306,6 @@ } return startPromise; }); - } else if (newCharacteristic.readValue){ - result = result.then(()=>{ - log("Reading data for " + JSON.stringify(newCharacteristic)); - return newCharacteristic.readValue().then((data)=>{ - if (supportedCharacteristics[newCharacteristic.uuid] && supportedCharacteristics[newCharacteristic.uuid].handler) { - supportedCharacteristics[newCharacteristic.uuid].handler(data); - } - }); - }); } return result.then(()=>log("Handled characteristic: ", newCharacteristic)); } @@ -526,10 +528,9 @@ } }; } - - + var fallbackInterval; - + function switchInternalHrm(){ if (settings.allowFallback && !fallbackInterval){ log("Fallback to HRM enabled"); @@ -558,7 +559,7 @@ } switchInternalHrm(); } - + E.on("kill", ()=>{ if (gatt && gatt.connected){ log("Got killed, trying to disconnect"); From d9908ee6a2a77eab3b6371ade461a1ea449eec87 Mon Sep 17 00:00:00 2001 From: Salim Blume Date: Tue, 5 Apr 2022 09:53:52 -0500 Subject: [PATCH 007/294] Switch from setScan to findDevices --- apps/bthrm/boot.js | 8 +-- apps/bthrm/settings.js | 110 +++++++++++++---------------------------- 2 files changed, 38 insertions(+), 80 deletions(-) diff --git a/apps/bthrm/boot.js b/apps/bthrm/boot.js index 0a6af55b6..ad3c85591 100644 --- a/apps/bthrm/boot.js +++ b/apps/bthrm/boot.js @@ -24,7 +24,7 @@ function getCache(){ var cache = require('Storage').readJSON("bthrm.cache.json", true) || {}; - if (settings.btname && settings.btname == cache.name) return cache; + if (settings.btid && settings.btid == cache.id) return cache; clearCache(); return {}; } @@ -368,9 +368,9 @@ if (!device){ var filters = serviceFilters; - if (settings.btname){ - log("Configured device name", settings.btname); - filters = [{name: settings.btname}]; + if (settings.btid){ + log("Configured device id", settings.btid); + filters = [{id: settings.btid }]; } log("Requesting device with filters", filters); promise = NRF.requestDevice({ filters: filters, active: true }); diff --git a/apps/bthrm/settings.js b/apps/bthrm/settings.js index 9f409880a..b376d6a2d 100644 --- a/apps/bthrm/settings.js +++ b/apps/bthrm/settings.js @@ -5,14 +5,14 @@ require('Storage').writeJSON(FILE, s); readSettings(); } - + function readSettings(){ settings = Object.assign( require('Storage').readJSON("bthrm.default.json", true) || {}, require('Storage').readJSON(FILE, true) || {} ); } - + var FILE="bthrm.json"; var settings; readSettings(); @@ -61,12 +61,13 @@ } }; - if (settings.btname){ - var name = "Clear " + settings.btname; + if (settings.btname || settings.btid){ + var name = "Clear " + (settings.btname || settings.btid); mainmenu[name] = function() { - E.showPrompt("Clear current device name?").then((r)=>{ + E.showPrompt("Clear current device?").then((r)=>{ if (r) { writeSettings("btname",undefined); + writeSettings("btid",undefined); } E.showMenu(buildMainMenu()); }); @@ -78,9 +79,7 @@ mainmenu.Debug = function() { E.showMenu(submenu_debug); }; return mainmenu; } - - var submenu_debug = { '' : { title: "Debug"}, '< Back': function() { E.showMenu(buildMainMenu()); }, @@ -103,35 +102,39 @@ function createMenuFromScan(){ E.showMenu(); - E.showMessage("Scanning"); + E.showMessage("Scanning for 4 seconds"); var submenu_scan = { - '' : { title: "Scan"}, '< Back': function() { E.showMenu(buildMainMenu()); } }; - var packets=10; - var scanStart=Date.now(); - NRF.setScan(function(d) { - packets--; - if (packets<=0 || Date.now() - scanStart > 5000){ - NRF.setScan(); - E.showMenu(submenu_scan); - } else if (d.name){ - print("Found device", d); - submenu_scan[d.name] = function(){ - E.showPrompt("Set "+d.name+"?").then((r)=>{ - if (r) { - writeSettings("btname",d.name); - } - E.showMenu(buildMainMenu()); + NRF.findDevices(function(devices) { + submenu_scan[''] = { title: `Scan (${devices.length} found)`}; + if (devices.length === 0) { + E.showAlert("No devices found") + .then(() => E.showMenu(buildMainMenu())); + return; + } else { + devices.forEach((d) => { + print("Found device", d); + var shown = (d.name || d.id.substr(0, 17)); + submenu_scan[shown] = function () { + E.showPrompt("Set " + shown + "?").then((r) => { + if (r) { + writeSettings("btid", d.id); + // Store the name for displaying later. Will connect by ID + if (d.name) { + writeSettings("btname", d.name); + } + } + E.showMenu(buildMainMenu()); + }); + }; }); - }; } - }, { active: true, filters: [{services: [ "180d" ]}]}); + E.showMenu(submenu_scan); + }, { timeout: 4000, active: true, filters: [{services: [ "180d" ]}]}); } - - var submenu_custom = { '' : { title: "Custom mode"}, '< Back': function() { E.showMenu(buildMainMenu()); }, @@ -167,7 +170,7 @@ } }, }; - + var submenu_grace = { '' : { title: "Grace periods"}, '< Back': function() { E.showMenu(submenu_debug); }, @@ -212,51 +215,6 @@ } } }; - - var submenu = { - '' : { title: "Grace periods"}, - '< Back': function() { E.showMenu(buildMainMenu()); }, - 'Request': { - value: settings.gracePeriodRequest, - min: 0, - max: 3000, - step: 100, - format: v=>v+"ms", - onchange: v => { - writeSettings("gracePeriodRequest",v); - } - }, - 'Connect': { - value: settings.gracePeriodConnect, - min: 0, - max: 3000, - step: 100, - format: v=>v+"ms", - onchange: v => { - writeSettings("gracePeriodConnect",v); - } - }, - 'Notification': { - value: settings.gracePeriodNotification, - min: 0, - max: 3000, - step: 100, - format: v=>v+"ms", - onchange: v => { - writeSettings("gracePeriodNotification",v); - } - }, - 'Service': { - value: settings.gracePeriodService, - min: 0, - max: 3000, - step: 100, - format: v=>v+"ms", - onchange: v => { - writeSettings("gracePeriodService",v); - } - } - }; - + E.showMenu(buildMainMenu()); -}) +}); From 88a785df7f7d0e05023fbcd69b7ae71e85a6fb8b Mon Sep 17 00:00:00 2001 From: Salim Blume Date: Tue, 5 Apr 2022 20:58:33 -0500 Subject: [PATCH 008/294] Update some types --- typescript/types/globals.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/typescript/types/globals.d.ts b/typescript/types/globals.d.ts index 442140e70..7af19700b 100644 --- a/typescript/types/globals.d.ts +++ b/typescript/types/globals.d.ts @@ -140,7 +140,7 @@ declare const require: ((module: 'heatshrink') => { declare const Bangle: { // functions - buzz: () => void; + buzz: (duration: number, intensity: number) => Promise; drawWidgets: () => void; isCharging: () => boolean; // events From 908a41d5237f2b6e30eca2c2bfd00954dd329051 Mon Sep 17 00:00:00 2001 From: Salim Blume Date: Tue, 5 Apr 2022 20:58:47 -0500 Subject: [PATCH 009/294] Try to bond --- apps/bthrm/boot.js | 79 ++++++++++++++++++++++++--------------------- apps/bthrm/bthrm.js | 6 ++-- 2 files changed, 46 insertions(+), 39 deletions(-) diff --git a/apps/bthrm/boot.js b/apps/bthrm/boot.js index ad3c85591..8e18b3e34 100644 --- a/apps/bthrm/boot.js +++ b/apps/bthrm/boot.js @@ -3,7 +3,7 @@ require('Storage').readJSON("bthrm.default.json", true) || {}, require('Storage').readJSON("bthrm.json", true) || {} ); - + var log = function(text, param){ if (settings.debuglog){ var logline = new Date().toISOString() + " - " + text; @@ -13,9 +13,9 @@ print(logline); } }; - + log("Settings: ", settings); - + if (settings.enabled){ function clearCache(){ @@ -24,25 +24,24 @@ function getCache(){ var cache = require('Storage').readJSON("bthrm.cache.json", true) || {}; - if (settings.btid && settings.btid == cache.id) return cache; + if (settings.btid && settings.btid === cache.id) return cache; clearCache(); return {}; } - + function addNotificationHandler(characteristic){ log("Setting notification handler: " + supportedCharacteristics[characteristic.uuid].handler); characteristic.on('characteristicvaluechanged', (ev) => supportedCharacteristics[characteristic.uuid].handler(ev.target.value)); } - + function writeCache(cache){ var oldCache = getCache(); - if (oldCache != cache) { + if (oldCache !== cache) { log("Writing cache"); require('Storage').writeJSON("bthrm.cache.json", cache) } else { log("No changes, don't write cache"); } - } function characteristicsToCache(characteristics){ @@ -177,7 +176,6 @@ lastReceivedData["0x180f"]["0x2a19"] = dv.getUint8(0); } } - }; var device; @@ -185,7 +183,7 @@ var characteristics = []; var blockInit = false; var currentRetryTimeout; - var initialRetryTime = 40; + var initialRetryTime = 1000; var maxRetryTime = 60000; var retryTime = initialRetryTime; @@ -214,7 +212,6 @@ }; } - if (settings.replace){ var origIsHRMOn = Bangle.isHRMOn; @@ -309,14 +306,14 @@ } return result.then(()=>log("Handled characteristic: ", newCharacteristic)); } - + function attachCharacteristicPromise(promise, characteristic){ return promise.then(()=>{ log("Handling characteristic:", characteristic); return createCharacteristicPromise(characteristic); }); } - + function createCharacteristicsPromise(newCharacteristics){ log("Create characteristics promise: ", newCharacteristics); var result = Promise.resolve(); @@ -327,12 +324,12 @@ if (c.properties.notify){ addNotificationHandler(c); } - + result = attachCharacteristicPromise(result, c); } return result.then(()=>log("Handled characteristics")); } - + function createServicePromise(service){ log("Create service promise: ", service); var result = Promise.resolve(); @@ -342,11 +339,11 @@ }); return result.then(()=>log("Handled service" + service.uuid)); } - + function attachServicePromise(promise, service){ return promise.then(()=>createServicePromise(service)); } - + var reUseCounter = 0; function initBt() { @@ -363,9 +360,9 @@ gatt=undefined; reUseCounter = 0; } - + var promise; - + if (!device){ var filters = serviceFilters; if (settings.btid){ @@ -374,27 +371,26 @@ } log("Requesting device with filters", filters); promise = NRF.requestDevice({ filters: filters, active: true }); - + if (settings.gracePeriodRequest){ log("Add " + settings.gracePeriodRequest + "ms grace period after request"); } - + promise = promise.then((d)=>{ log("Got device: ", d); d.on('gattserverdisconnected', onDisconnect); device = d; }); - + promise = promise.then(()=>{ log("Wait after request"); return waitingPromise(settings.gracePeriodRequest); }); - } else { promise = Promise.resolve(); log("Reuse device: ", device); } - + promise = promise.then(()=>{ if (gatt){ log("Reuse GATT: ", gatt); @@ -402,7 +398,7 @@ log("GATT is new: ", gatt); characteristics = []; var cachedName = getCache().name; - if (device.name != cachedName){ + if (device.name !== cachedName){ log("Device name changed from " + cachedName + " to " + device.name + ", clearing cache"); clearCache(); } @@ -411,10 +407,10 @@ writeCache(newCache); gatt = device.gatt; } - + return Promise.resolve(gatt); }); - + promise = promise.then((gatt)=>{ if (!gatt.connected){ var connectPromise = gatt.connect(connectSettings); @@ -430,16 +426,28 @@ return Promise.resolve(); } }); - + + promise = promise.then(() => { + log(JSON.stringify(gatt.getSecurityStatus())); + if (gatt.getSecurityStatus()['bonded']) { + log("Already bonded"); + return Promise.resolve(); + } else { + log("Start bonding"); + return gatt.startBonding() + .then(() => console.log(gatt.getSecurityStatus())); + } + }); + promise = promise.then(()=>{ - if (!characteristics || characteristics.length == 0){ + if (!characteristics || characteristics.length === 0){ characteristics = characteristicsFromCache(); } }); promise = promise.then(()=>{ var characteristicsPromise = Promise.resolve(); - if (characteristics.length == 0){ + if (characteristics.length === 0){ characteristicsPromise = characteristicsPromise.then(()=>{ log("Getting services"); return gatt.getPrimaryServices(); @@ -462,17 +470,16 @@ } return result; }); - } else { for (var characteristic of characteristics){ characteristicsPromise = attachCharacteristicPromise(characteristicsPromise, characteristic, true); } } - + return characteristicsPromise; }); - promise = promise.then(()=>{ + return promise.then(()=>{ log("Connection established, waiting for notifications"); reUseCounter = 0; characteristicsToCache(characteristics); @@ -490,7 +497,7 @@ if (Bangle._PWR===undefined) Bangle._PWR={}; if (Bangle._PWR.BTHRM===undefined) Bangle._PWR.BTHRM=[]; if (isOn && !Bangle._PWR.BTHRM.includes(app)) Bangle._PWR.BTHRM.push(app); - if (!isOn && Bangle._PWR.BTHRM.includes(app)) Bangle._PWR.BTHRM = Bangle._PWR.BTHRM.filter(a=>a!=app); + if (!isOn && Bangle._PWR.BTHRM.includes(app)) Bangle._PWR.BTHRM = Bangle._PWR.BTHRM.filter(a=>a!==app); isOn = Bangle._PWR.BTHRM.length; // so now we know if we're really on if (isOn) { @@ -513,7 +520,7 @@ } } }; - + var origSetHRMPower = Bangle.setHRMPower; if (settings.startWithHrm){ @@ -563,7 +570,7 @@ E.on("kill", ()=>{ if (gatt && gatt.connected){ log("Got killed, trying to disconnect"); - var promise = gatt.disconnect().then(()=>log("Disconnected on kill")).catch((e)=>log("Error during disconnnect on kill", e)); + gatt.disconnect().then(()=>log("Disconnected on kill")).catch((e)=>log("Error during disconnnect on kill", e)); } }); } diff --git a/apps/bthrm/bthrm.js b/apps/bthrm/bthrm.js index 5ab3b0018..dd9230386 100644 --- a/apps/bthrm/bthrm.js +++ b/apps/bthrm/bthrm.js @@ -24,13 +24,13 @@ function draw(y, type, event) { g.setFontAlign(0,0); g.setFontVector(40).drawString(str,px,y+20); str = "Event: " + type; - if (type == "HRM") { + if (type === "HRM") { str += " Confidence: " + event.confidence; g.setFontVector(12).drawString(str,px,y+40); str = " Source: " + (event.src ? event.src : "internal"); g.setFontVector(12).drawString(str,px,y+50); } - if (type == "BTHRM"){ + if (type === "BTHRM"){ if (event.battery) str += " Bat: " + (event.battery ? event.battery : ""); g.setFontVector(12).drawString(str,px,y+40); str= ""; @@ -54,7 +54,7 @@ function onBtHrm(e) { firstEventBt = false; } draw(100, "BTHRM", e); - if (e.bpm == 0){ + if (e.bpm === 0){ Bangle.buzz(100,0.2); } if (intervalBt){ From 31fd2344a8ffb7e9ec9bf97635a155e8f75bf429 Mon Sep 17 00:00:00 2001 From: Salim Blume Date: Tue, 5 Apr 2022 21:05:03 -0500 Subject: [PATCH 010/294] Fix for buzz type updated in previous commit --- typescript/types/globals.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/typescript/types/globals.d.ts b/typescript/types/globals.d.ts index 7af19700b..e82c3da3d 100644 --- a/typescript/types/globals.d.ts +++ b/typescript/types/globals.d.ts @@ -140,7 +140,7 @@ declare const require: ((module: 'heatshrink') => { declare const Bangle: { // functions - buzz: (duration: number, intensity: number) => Promise; + buzz: (duration?: number, intensity?: number) => Promise; drawWidgets: () => void; isCharging: () => boolean; // events From 9eb4d8eb73684eca9ee4d0eadc8aec94bf467d6c Mon Sep 17 00:00:00 2001 From: Salim Blume Date: Thu, 7 Apr 2022 15:58:39 -0500 Subject: [PATCH 011/294] Remove bonding for now --- apps/bthrm/boot.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/bthrm/boot.js b/apps/bthrm/boot.js index 8e18b3e34..f9de2ee5d 100644 --- a/apps/bthrm/boot.js +++ b/apps/bthrm/boot.js @@ -427,7 +427,7 @@ } }); - promise = promise.then(() => { +/* promise = promise.then(() => { log(JSON.stringify(gatt.getSecurityStatus())); if (gatt.getSecurityStatus()['bonded']) { log("Already bonded"); @@ -437,7 +437,7 @@ return gatt.startBonding() .then(() => console.log(gatt.getSecurityStatus())); } - }); + });*/ promise = promise.then(()=>{ if (!characteristics || characteristics.length === 0){ From 7eeeca52ca25b2c633aed8a99c7fa12701e6d69c Mon Sep 17 00:00:00 2001 From: Salim Blume Date: Thu, 7 Apr 2022 22:04:47 -0500 Subject: [PATCH 012/294] Update README and follow linting instructions --- apps/bthrm/README.md | 13 ++-- apps/bthrm/boot.js | 124 ++++++++++++++++++--------------------- apps/bthrm/metadata.json | 2 +- 3 files changed, 66 insertions(+), 73 deletions(-) diff --git a/apps/bthrm/README.md b/apps/bthrm/README.md index 42ad619bd..8d5872670 100644 --- a/apps/bthrm/README.md +++ b/apps/bthrm/README.md @@ -2,7 +2,7 @@ When this app is installed it overrides Bangle.js's build in heart rate monitor with an external Bluetooth one. -HRM is requested it searches on Bluetooth for a heart rate monitor, connects, and sends data back using the `Bangle.on('HRM'` event as if it came from the on board monitor. +HRM is requested it searches on Bluetooth for a heart rate monitor, connects, and sends data back using the `Bangle.on('HRM')` event as if it came from the on board monitor. This means it's compatible with many Bangle.js apps including: @@ -16,19 +16,23 @@ as that requires live sensor data (rather than just BPM readings). Just install the app, then install an app that uses the heart rate monitor. -Once installed it'll automatically try and connect to the first bluetooth -heart rate monitor it finds. +Once installed you will have to go into this app's settings while your heart rate monitor + is available for bluetooth pairing and scan for devices. **To disable this and return to normal HRM, uninstall the app** ## Compatible Heart Rate Monitors This works with any heart rate monitor providing the standard Bluetooth -Heart Rate Service (`180D`) and characteristic (`2A37`). +Heart Rate Service (`180D`) and characteristic (`2A37`). It additionally supports +the location (`2A38`) characteristic and the Battery Service (`180F`), reporting +that information in the `BTHRM` event when they are available. So far it has been tested on: * CooSpo Bluetooth Heart Rate Monitor +* Polar H10 +* Polar OH1 * Wahoo TICKR X 2 ## Internals @@ -38,7 +42,6 @@ This replaces `Bangle.setHRMPower` with its own implementation. ## TODO * A widget to show connection state? -* Specify a specific device by address? ## Creator diff --git a/apps/bthrm/boot.js b/apps/bthrm/boot.js index f9de2ee5d..064f65eac 100644 --- a/apps/bthrm/boot.js +++ b/apps/bthrm/boot.js @@ -18,33 +18,33 @@ if (settings.enabled){ - function clearCache(){ + var clearCache = function() { return require('Storage').erase("bthrm.cache.json"); - } + }; - function getCache(){ + var getCache = function() { var cache = require('Storage').readJSON("bthrm.cache.json", true) || {}; if (settings.btid && settings.btid === cache.id) return cache; clearCache(); return {}; - } + }; - function addNotificationHandler(characteristic){ + var addNotificationHandler = function(characteristic) { log("Setting notification handler: " + supportedCharacteristics[characteristic.uuid].handler); characteristic.on('characteristicvaluechanged', (ev) => supportedCharacteristics[characteristic.uuid].handler(ev.target.value)); - } + }; - function writeCache(cache){ + var writeCache = function(cache) { var oldCache = getCache(); if (oldCache !== cache) { log("Writing cache"); - require('Storage').writeJSON("bthrm.cache.json", cache) + require('Storage').writeJSON("bthrm.cache.json", cache); } else { log("No changes, don't write cache"); } - } + }; - function characteristicsToCache(characteristics){ + var characteristicsToCache = function(characteristics) { log("Cache characteristics"); var cache = getCache(); if (!cache.characteristics) cache.characteristics = {}; @@ -59,9 +59,9 @@ }; } writeCache(cache); - } + }; - function characteristicsFromCache(){ + var characteristicsFromCache = function() { log("Read cached characteristics"); var cache = getCache(); if (!cache.characteristics) return []; @@ -80,19 +80,16 @@ restored.push(r); } return restored; - } + }; log("Start"); var lastReceivedData={ }; - var serviceFilters = [{ - services: [ "180d" ] - }]; - var supportedServices = [ - "0x180d", "0x180f" + "0x180d", // Heart Rate + "0x180f", // Battery ]; var supportedCharacteristics = { @@ -100,17 +97,17 @@ //Heart rate measurement handler: function (dv){ var flags = dv.getUint8(0); - + var bpm = (flags & 1) ? (dv.getUint16(1) / 100 /* ? */ ) : dv.getUint8(1); // 8 or 16 bit - + var sensorContact; - + if (flags & 2){ sensorContact = !!(flags & 4); } - + var idx = 2 + (flags&1); - + var energyExpended; if (flags & 8){ energyExpended = dv.getUint16(idx,1); @@ -123,7 +120,7 @@ log("Found " + (maxIntervalBytes / 2) + " rr data fields"); for(var i = 0 ; i < maxIntervalBytes / 2; i++){ interval[i] = dv.getUint16(idx,1); // in milliseconds - idx += 2 + idx += 2; } } @@ -143,7 +140,7 @@ confidence: (sensorContact || sensorContact === undefined)? 100 : 0, src: "bthrm" }; - + log("Emitting HRM: ", repEvent); Bangle.emit("HRM", repEvent); } @@ -151,7 +148,7 @@ var newEvent = { bpm: bpm }; - + if (location) newEvent.location = location; if (interval) newEvent.rr = interval; if (energyExpended) newEvent.energy = energyExpended; @@ -183,7 +180,7 @@ var characteristics = []; var blockInit = false; var currentRetryTimeout; - var initialRetryTime = 1000; + var initialRetryTime = 40; var maxRetryTime = 60000; var retryTime = initialRetryTime; @@ -192,7 +189,7 @@ maxInterval: 1500 }; - function waitingPromise(timeout) { + var waitingPromise = function(timeout) { return new Promise(function(resolve){ log("Start waiting for " + timeout); setTimeout(()=>{ @@ -200,7 +197,7 @@ resolve(); }, timeout); }); - } + }; if (settings.enabled){ Bangle.isBTHRMOn = function(){ @@ -225,15 +222,15 @@ }; } - function clearRetryTimeout(){ + var clearRetryTimeout = function() { if (currentRetryTimeout){ log("Clearing timeout " + currentRetryTimeout); clearTimeout(currentRetryTimeout); currentRetryTimeout = undefined; } - } + }; - function retry(){ + var retry = function() { log("Retry"); if (!currentRetryTimeout){ @@ -255,10 +252,10 @@ } else { log("Already in retry..."); } - } + }; var buzzing = false; - function onDisconnect(reason) { + var onDisconnect = function(reason) { log("Disconnect: " + reason); log("GATT: ", gatt); log("Characteristics: ", characteristics); @@ -273,9 +270,9 @@ if (Bangle.isBTHRMOn()){ retry(); } - } + }; - function createCharacteristicPromise(newCharacteristic){ + var createCharacteristicPromise = function(newCharacteristic) { log("Create characteristic promise: ", newCharacteristic); var result = Promise.resolve(); // For values that can be read, go ahead and read them, even if we might be notified in the future @@ -298,23 +295,23 @@ log("Add " + settings.gracePeriodNotification + "ms grace period after starting notifications"); startPromise = startPromise.then(()=>{ log("Wait after connect"); - waitingPromise(settings.gracePeriodNotification) + return waitingPromise(settings.gracePeriodNotification); }); } return startPromise; }); } return result.then(()=>log("Handled characteristic: ", newCharacteristic)); - } + }; - function attachCharacteristicPromise(promise, characteristic){ + var attachCharacteristicPromise = function(promise, characteristic) { return promise.then(()=>{ log("Handling characteristic:", characteristic); return createCharacteristicPromise(characteristic); }); - } + }; - function createCharacteristicsPromise(newCharacteristics){ + var createCharacteristicsPromise = function(newCharacteristics) { log("Create characteristics promise: ", newCharacteristics); var result = Promise.resolve(); for (var c of newCharacteristics){ @@ -328,9 +325,9 @@ result = attachCharacteristicPromise(result, c); } return result.then(()=>log("Handled characteristics")); - } + }; - function createServicePromise(service){ + var createServicePromise = function(service) { log("Create service promise: ", service); var result = Promise.resolve(); result = result.then(()=>{ @@ -338,15 +335,13 @@ return service.getCharacteristics().then((c)=>createCharacteristicsPromise(c)); }); return result.then(()=>log("Handled service" + service.uuid)); - } + }; - function attachServicePromise(promise, service){ + var attachServicePromise = function(promise, service) { return promise.then(()=>createServicePromise(service)); - } + }; - var reUseCounter = 0; - - function initBt() { + var initBt = function () { log("initBt with blockInit: " + blockInit); if (blockInit){ retry(); @@ -355,19 +350,15 @@ blockInit = true; - if (reUseCounter > 10){ - log("Reuse counter to high"); - gatt=undefined; - reUseCounter = 0; - } - var promise; + var filters; if (!device){ - var filters = serviceFilters; if (settings.btid){ log("Configured device id", settings.btid); - filters = [{id: settings.btid }]; + filters = [{ id: settings.btid }]; + } else { + return; } log("Requesting device with filters", filters); promise = NRF.requestDevice({ filters: filters, active: true }); @@ -397,13 +388,13 @@ } else { log("GATT is new: ", gatt); characteristics = []; - var cachedName = getCache().name; - if (device.name !== cachedName){ - log("Device name changed from " + cachedName + " to " + device.name + ", clearing cache"); + var cachedId = getCache().id; + if (device.id !== cachedId){ + log("Device ID changed from " + cachedId + " to " + device.id + ", clearing cache"); clearCache(); } var newCache = getCache(); - newCache.name = device.name; + newCache.id = device.id; writeCache(newCache); gatt = device.gatt; } @@ -465,7 +456,7 @@ log("Add " + settings.gracePeriodService + "ms grace period after services"); result = result.then(()=>{ log("Wait after services"); - return waitingPromise(settings.gracePeriodService) + return waitingPromise(settings.gracePeriodService); }); } return result; @@ -478,10 +469,9 @@ return characteristicsPromise; }); - + return promise.then(()=>{ log("Connection established, waiting for notifications"); - reUseCounter = 0; characteristicsToCache(characteristics); clearRetryTimeout(); }).catch((e) => { @@ -489,7 +479,7 @@ log("Error:", e); onDisconnect(e); }); - } + }; Bangle.setBTHRMPower = function(isOn, app) { // Do app power handling @@ -538,7 +528,7 @@ var fallbackInterval; - function switchInternalHrm(){ + var switchInternalHrm = function() { if (settings.allowFallback && !fallbackInterval){ log("Fallback to HRM enabled"); origSetHRMPower(1, "bthrm_fallback"); @@ -551,7 +541,7 @@ } }, settings.fallbackTimeout); } - } + }; if (settings.replace){ log("Replace HRM event"); diff --git a/apps/bthrm/metadata.json b/apps/bthrm/metadata.json index b35ebd6af..faff72d0f 100644 --- a/apps/bthrm/metadata.json +++ b/apps/bthrm/metadata.json @@ -6,7 +6,7 @@ "description": "Overrides Bangle.js's build in heart rate monitor with an external Bluetooth one.", "icon": "app.png", "type": "app", - "tags": "health,bluetooth", + "tags": "health,bluetooth,hrm", "supports": ["BANGLEJS","BANGLEJS2"], "readme": "README.md", "storage": [ From ab11b7068115b6678d69e70c21b7787bba778ece Mon Sep 17 00:00:00 2001 From: Salim Blume Date: Tue, 19 Apr 2022 16:54:27 -0500 Subject: [PATCH 013/294] Default custom values to the same as default mode so you can choose which pieces to change knowing the rest is the same --- apps/bthrm/default.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/bthrm/default.json b/apps/bthrm/default.json index 64e638b8a..fb284bcd2 100644 --- a/apps/bthrm/default.json +++ b/apps/bthrm/default.json @@ -7,10 +7,10 @@ "allowFallback": true, "warnDisconnect": false, "fallbackTimeout": 10, - "custom_replace": false, + "custom_replace": true, "custom_debuglog": false, - "custom_startWithHrm": false, - "custom_allowFallback": false, + "custom_startWithHrm": true, + "custom_allowFallback": true, "custom_warnDisconnect": false, "custom_fallbackTimeout": 10, "gracePeriodNotification": 0, From dbecd1ae6f009220f84b989d2bfc3666ebf27ca2 Mon Sep 17 00:00:00 2001 From: Salim Blume Date: Tue, 19 Apr 2022 16:54:50 -0500 Subject: [PATCH 014/294] Adding tag to find 'hrm' more easily --- apps/bthrm/metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/bthrm/metadata.json b/apps/bthrm/metadata.json index faff72d0f..85c19ab33 100644 --- a/apps/bthrm/metadata.json +++ b/apps/bthrm/metadata.json @@ -6,7 +6,7 @@ "description": "Overrides Bangle.js's build in heart rate monitor with an external Bluetooth one.", "icon": "app.png", "type": "app", - "tags": "health,bluetooth,hrm", + "tags": "health,bluetooth,hrm,bthrm", "supports": ["BANGLEJS","BANGLEJS2"], "readme": "README.md", "storage": [ From 650d2bd288e47bbf95f94aef62949ad22aefdd32 Mon Sep 17 00:00:00 2001 From: Salim Blume Date: Tue, 19 Apr 2022 16:55:04 -0500 Subject: [PATCH 015/294] Scaled retryTime for clampedTime instead of itself --- apps/bthrm/boot.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/bthrm/boot.js b/apps/bthrm/boot.js index 064f65eac..e9e640563 100644 --- a/apps/bthrm/boot.js +++ b/apps/bthrm/boot.js @@ -245,7 +245,7 @@ initBt(); }, clampedTime); - retryTime = Math.pow(retryTime, 1.1); + retryTime = Math.pow(clampedTime, 1.1); if (retryTime > maxRetryTime){ retryTime = maxRetryTime; } From 5f147027aaacb78b2a3908a11f67291eddcf7cb8 Mon Sep 17 00:00:00 2001 From: Zach Dixon Date: Mon, 9 May 2022 20:45:22 -0700 Subject: [PATCH 016/294] 12h clock format, option to disable autocycle --- apps/rebble/rebble.app.js | 25 +++++++++++++++++++++++-- apps/rebble/rebble.settings.js | 10 +++++++++- 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/apps/rebble/rebble.app.js b/apps/rebble/rebble.app.js index 7c7d57939..03680eca8 100644 --- a/apps/rebble/rebble.app.js +++ b/apps/rebble/rebble.app.js @@ -1,8 +1,10 @@ var SunCalc = require("https://raw.githubusercontent.com/mourner/suncalc/master/suncalc.js"); const SETTINGS_FILE = "rebble.json"; const LOCATION_FILE = "mylocation.json"; +const GLOBAL_SETTINGS = "setting.json"; let settings; let location; +let is12Hour; Graphics.prototype.setFontLECO1976Regular22 = function(scale) { // Actual height 22 (21 - 0) @@ -34,11 +36,25 @@ function loadLocation() { function loadSettings() { settings = require("Storage").readJSON(SETTINGS_FILE,1)|| {'bg': '#0f0', 'color': 'Green'}; + is12Hour = (require("Storage").readJSON(GLOBAL_SETTINGS, 1) || {})["12hour"] || false; +} + +function formatHours(hh) { + if (is12Hour) { + let hours = parseInt(hh,10); + if (hours == 0) { + hours = 12; + } else if (hours >= 12) { + if (hours>12) hours -= 12; + } + hh = (" "+hours).substr(-2); + } + return hh; } function extractTime(d){ var h = d.getHours(), m = d.getMinutes(); - return(("0"+h).substr(-2) + ":" + ("0"+m).substr(-2)); + return(formatHours(("0"+h).substr(-2)) + ":" + ("0"+m).substr(-2)); } function updateSunRiseSunSet(lat, lon){ @@ -81,6 +97,9 @@ function draw() { let da = date.toString().split(" "); let hh = da[4].substr(0,2); let mm = da[4].substr(3,2); + + hh = formatHours(hh); + //const t = 6; if (drawCount % 60 == 0) @@ -260,7 +279,9 @@ function queueDraw() { if (drawTimeout) clearTimeout(drawTimeout); drawTimeout = setTimeout(function() { drawTimeout = undefined; - nextSidebar(); + if (!settings.autoCycle) { + nextSidebar(); + } draw(); }, 60000 - (Date.now() % 60000)); } diff --git a/apps/rebble/rebble.settings.js b/apps/rebble/rebble.settings.js index db3bab878..b4d96644d 100644 --- a/apps/rebble/rebble.settings.js +++ b/apps/rebble/rebble.settings.js @@ -2,7 +2,7 @@ const SETTINGS_FILE = "rebble.json"; // initialize with default settings... - let s = {'bg': '#0f0', 'color': 'Green'} + let s = {'bg': '#0f0', 'color': 'Green', 'autoCycle': true} // ...and overwrite them with any saved values // This way saved values are preserved if a new version adds more settings @@ -33,6 +33,14 @@ s.bg = bg_code[v]; save(); }, + }, + 'Auto Cycle': { + value: "autoCycle" in s ? s.autoCycle : true, + format: () => (s.autoCycle ? 'Yes' : 'No'), + onchange: () => { + s.autoCycle = !s.autoCycle; + save(); + } } }); }) From 7822c4489d0ffadcbe8b0cad518cc89c76dafa96 Mon Sep 17 00:00:00 2001 From: Zach Dixon Date: Mon, 9 May 2022 22:30:20 -0700 Subject: [PATCH 017/294] Fix settings variable conflict and updated version --- apps/rebble/ChangeLog | 3 ++- apps/rebble/metadata.json | 2 +- apps/rebble/rebble.app.js | 2 +- apps/rebble/rebble.settings.js | 20 ++++++++++---------- 4 files changed, 14 insertions(+), 13 deletions(-) diff --git a/apps/rebble/ChangeLog b/apps/rebble/ChangeLog index b80dfef94..667dc0ad0 100644 --- a/apps/rebble/ChangeLog +++ b/apps/rebble/ChangeLog @@ -2,4 +2,5 @@ 0.02: Fix typo to Purple 0.03: Added dependancy on Pedometer Widget 0.04: Fixed icon and png to 48x48 pixels -0.05: added charging icon \ No newline at end of file +0.05: added charging icon +0.06: Add 12h support and autocycle control \ No newline at end of file diff --git a/apps/rebble/metadata.json b/apps/rebble/metadata.json index b26fb6a27..c44d1c279 100644 --- a/apps/rebble/metadata.json +++ b/apps/rebble/metadata.json @@ -2,7 +2,7 @@ "id": "rebble", "name": "Rebble Clock", "shortName": "Rebble", - "version": "0.05", + "version": "0.06", "description": "A Pebble style clock, with configurable background, three sidebars including steps, day, date, sunrise, sunset, long live the rebellion", "readme": "README.md", "icon": "rebble.png", diff --git a/apps/rebble/rebble.app.js b/apps/rebble/rebble.app.js index 03680eca8..251087ae1 100644 --- a/apps/rebble/rebble.app.js +++ b/apps/rebble/rebble.app.js @@ -35,7 +35,7 @@ function loadLocation() { } function loadSettings() { - settings = require("Storage").readJSON(SETTINGS_FILE,1)|| {'bg': '#0f0', 'color': 'Green'}; + settings = require("Storage").readJSON(SETTINGS_FILE,1)|| {'bg': '#0f0', 'color': 'Green', 'autoCycle': true}; is12Hour = (require("Storage").readJSON(GLOBAL_SETTINGS, 1) || {})["12hour"] || false; } diff --git a/apps/rebble/rebble.settings.js b/apps/rebble/rebble.settings.js index b4d96644d..91142d72d 100644 --- a/apps/rebble/rebble.settings.js +++ b/apps/rebble/rebble.settings.js @@ -2,19 +2,19 @@ const SETTINGS_FILE = "rebble.json"; // initialize with default settings... - let s = {'bg': '#0f0', 'color': 'Green', 'autoCycle': true} + let localSettings = {'bg': '#0f0', 'color': 'Green', 'autoCycle': true} // ...and overwrite them with any saved values // This way saved values are preserved if a new version adds more settings const storage = require('Storage') - let settings = storage.readJSON(SETTINGS_FILE, 1) || s; + let settings = storage.readJSON(SETTINGS_FILE, 1) || localSettings; const saved = settings || {} for (const key in saved) { - s[key] = saved[key] + localSettings[key] = saved[key] } function save() { - settings = s + settings = localSettings storage.write(SETTINGS_FILE, settings) } @@ -25,20 +25,20 @@ '': { 'title': 'Rebble Clock' }, '< Back': back, 'Colour': { - value: 0 | color_options.indexOf(s.color), + value: 0 | color_options.indexOf(localSettings.color), min: 0, max: 5, format: v => color_options[v], onchange: v => { - s.color = color_options[v]; - s.bg = bg_code[v]; + localSettings.color = color_options[v]; + localSettings.bg = bg_code[v]; save(); }, }, 'Auto Cycle': { - value: "autoCycle" in s ? s.autoCycle : true, - format: () => (s.autoCycle ? 'Yes' : 'No'), + value: "autoCycle" in localSettings ? localSettings.autoCycle : true, + format: () => (localSettings.autoCycle ? 'Yes' : 'No'), onchange: () => { - s.autoCycle = !s.autoCycle; + localSettings.autoCycle = !localSettings.autoCycle; save(); } } From 24634330a50a64c07e9e1f7f6dafb70e9883bb44 Mon Sep 17 00:00:00 2001 From: thyttan <97237430+thyttan@users.noreply.github.com> Date: Wed, 11 May 2022 17:56:36 +0200 Subject: [PATCH 018/294] Update ChangeLog --- apps/kbmulti/ChangeLog | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/kbmulti/ChangeLog b/apps/kbmulti/ChangeLog index 04b2430bb..894a609ec 100644 --- a/apps/kbmulti/ChangeLog +++ b/apps/kbmulti/ChangeLog @@ -1 +1,2 @@ 0.01: New keyboard +0.02: Introduce setting "Show help button". Remove the firstLaunch setting from settings.js. From da2aaaf16dd963d23d8be211bb8b55931f5c05b4 Mon Sep 17 00:00:00 2001 From: thyttan <97237430+thyttan@users.noreply.github.com> Date: Wed, 11 May 2022 18:21:20 +0200 Subject: [PATCH 019/294] Update settings.js --- apps/kbmulti/settings.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/kbmulti/settings.js b/apps/kbmulti/settings.js index d3148eca7..c698aca8a 100644 --- a/apps/kbmulti/settings.js +++ b/apps/kbmulti/settings.js @@ -21,11 +21,11 @@ format: v => v, onchange: v => updateSetting("charTimeout", v), }, - /*LANG*/'Show help on first launch': { - value: !!settings().firstLaunch, + /*LANG*/'Show help button': { + value: !!settings().showHelpBtn, format: v => v?"Yes":"No", - onchange: v => updateSetting("firstLaunch", v) + onchange: v => updateSetting("showHelpBtn", v) } }; E.showMenu(mainmenu); - }) \ No newline at end of file + }) From 824ab9859ec524be2ebc4c7a7fc1021199938b54 Mon Sep 17 00:00:00 2001 From: thyttan <97237430+thyttan@users.noreply.github.com> Date: Wed, 11 May 2022 18:21:47 +0200 Subject: [PATCH 020/294] Update metadata.json --- apps/kbmulti/metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/kbmulti/metadata.json b/apps/kbmulti/metadata.json index 6c813e321..1efdb8847 100644 --- a/apps/kbmulti/metadata.json +++ b/apps/kbmulti/metadata.json @@ -1,6 +1,6 @@ { "id": "kbmulti", "name": "Multitap keyboard", - "version":"0.01", + "version":"0.02", "description": "A library for text input via multitap/T9 style keypad", "icon": "app.png", "type":"textinput", From 87756ece9ef8fec132409303756d0ab3e0d371c2 Mon Sep 17 00:00:00 2001 From: thyttan <97237430+thyttan@users.noreply.github.com> Date: Wed, 11 May 2022 18:23:31 +0200 Subject: [PATCH 021/294] Update lib.js --- apps/kbmulti/lib.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/apps/kbmulti/lib.js b/apps/kbmulti/lib.js index 79c2d861a..ff987c2cc 100644 --- a/apps/kbmulti/lib.js +++ b/apps/kbmulti/lib.js @@ -6,8 +6,9 @@ exports.input = function(options) { if ("string"!=typeof text) text=""; var settings = require('Storage').readJSON("kbmulti.settings.json", true) || {}; - if (settings.firstLaunch===undefined) { settings.firstLaunch = true; } + //if (settings.firstLaunch===undefined) { settings.firstLaunch = true; } if (settings.charTimeout===undefined) { settings.charTimeout = 500; } + if (settings.showHelpBtn===undefined) { settings.showHelpBtn = true; } var fontSize = "6x15"; var Layout = require("Layout"); @@ -104,7 +105,7 @@ exports.input = function(options) { type:"v", c: [ {type:"h", c: [ {type:"txt", font:"12x20", label:text.slice(-12), id:"text", fillx:1}, - {type:"btn", font:'6x8', label:'?', cb: l=>onHelp(resolve,reject), filly:1 }, + (settings.showHelpBtn ? {type:"btn", font:'6x8', label:'?', cb: l=>onHelp(resolve,reject), filly:1 } : {}), ]}, {type:"h", c: [ {type:"btn", font:fontSize, label:letters[1], cb: l=>onKeyPad(1), id:'1', fillx:1, filly:1 }, @@ -132,7 +133,7 @@ exports.input = function(options) { return new Promise((resolve,reject) => { g.clearRect(Bangle.appRect); - if (settings.firstLaunch) { + if (!settings.firstLaunch) { onHelp(resolve,reject); settings.firstLaunch = false; require('Storage').writeJSON("kbmulti.settings.json", settings); From d6db4e6be355486fbee91a6ae0b83e81b285e6df Mon Sep 17 00:00:00 2001 From: thyttan <97237430+thyttan@users.noreply.github.com> Date: Wed, 11 May 2022 19:49:40 +0200 Subject: [PATCH 022/294] Update lib.js --- apps/kbmulti/lib.js | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/apps/kbmulti/lib.js b/apps/kbmulti/lib.js index ff987c2cc..052fd86a1 100644 --- a/apps/kbmulti/lib.js +++ b/apps/kbmulti/lib.js @@ -1,14 +1,14 @@ //Multitap logic originally from here: http://www.espruino.com/Morse+Code+Texting exports.input = function(options) { - options = options||{}; + var options = options||{}; var text = options.text; if ("string"!=typeof text) text=""; var settings = require('Storage').readJSON("kbmulti.settings.json", true) || {}; //if (settings.firstLaunch===undefined) { settings.firstLaunch = true; } if (settings.charTimeout===undefined) { settings.charTimeout = 500; } - if (settings.showHelpBtn===undefined) { settings.showHelpBtn = true; } + if (settings.showHelpBtn===undefined) { settings.showHelpBtn = false; } var fontSize = "6x15"; var Layout = require("Layout"); @@ -25,9 +25,9 @@ exports.input = function(options) { var caps = true; var layout; - function displayText() { + function displayText(charTimeout) { layout.clear(layout.text); - layout.text.label = text.slice(-12); + layout.text.label = text.slice(settings.showHelpBtn ? -12 : -13) + (charTimeout ? " " : "_"); layout.render(layout.text); } @@ -70,12 +70,12 @@ exports.input = function(options) { } var newLetter = letters[charCurrent][charIndex]; text += (caps ? newLetter.toUpperCase() : newLetter.toLowerCase()); - displayText(); // set a timeout charTimeout = setTimeout(function() { charTimeout = undefined; newCharacter(); }, settings.charTimeout); + displayText(charTimeout); } function onSwipe(dirLeftRight, dirUpDown) { @@ -139,6 +139,7 @@ exports.input = function(options) { require('Storage').writeJSON("kbmulti.settings.json", settings); } else { generateLayout(resolve,reject); + displayText(false); Bangle.on('swipe', onSwipe); layout.render(); } From b34a3415b9b9e1a85a1fb25d5a156d80310e00e1 Mon Sep 17 00:00:00 2001 From: thyttan <97237430+thyttan@users.noreply.github.com> Date: Wed, 11 May 2022 19:54:37 +0200 Subject: [PATCH 023/294] Update ChangeLog --- apps/kbmulti/ChangeLog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/kbmulti/ChangeLog b/apps/kbmulti/ChangeLog index 894a609ec..191517b30 100644 --- a/apps/kbmulti/ChangeLog +++ b/apps/kbmulti/ChangeLog @@ -1,2 +1,2 @@ 0.01: New keyboard -0.02: Introduce setting "Show help button". Remove the firstLaunch setting from settings.js. +0.02: Introduce setting "Show help button". Make setting firstLaunch invisible by removing corresponding code from settings.js. Add marker that shows when character selection timeout has run out. From 7b1bcd8b76dbc1da8b8db937546d46a021bdd0ca Mon Sep 17 00:00:00 2001 From: thyttan <97237430+thyttan@users.noreply.github.com> Date: Wed, 11 May 2022 20:01:49 +0200 Subject: [PATCH 024/294] Update lib.js --- apps/kbmulti/lib.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/kbmulti/lib.js b/apps/kbmulti/lib.js index 052fd86a1..d578a81b0 100644 --- a/apps/kbmulti/lib.js +++ b/apps/kbmulti/lib.js @@ -6,7 +6,7 @@ exports.input = function(options) { if ("string"!=typeof text) text=""; var settings = require('Storage').readJSON("kbmulti.settings.json", true) || {}; - //if (settings.firstLaunch===undefined) { settings.firstLaunch = true; } + if (settings.firstLaunch===undefined) { settings.firstLaunch = true; } if (settings.charTimeout===undefined) { settings.charTimeout = 500; } if (settings.showHelpBtn===undefined) { settings.showHelpBtn = false; } @@ -133,13 +133,13 @@ exports.input = function(options) { return new Promise((resolve,reject) => { g.clearRect(Bangle.appRect); - if (!settings.firstLaunch) { + if (settings.firstLaunch==true) { onHelp(resolve,reject); settings.firstLaunch = false; require('Storage').writeJSON("kbmulti.settings.json", settings); } else { generateLayout(resolve,reject); - displayText(false); + displayText(true); Bangle.on('swipe', onSwipe); layout.render(); } From 8eefdaa706eb560a4cfd9a12d97080ec45a4fbc6 Mon Sep 17 00:00:00 2001 From: thyttan <97237430+thyttan@users.noreply.github.com> Date: Wed, 11 May 2022 20:11:08 +0200 Subject: [PATCH 025/294] Update lib.js --- apps/kbmulti/lib.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/kbmulti/lib.js b/apps/kbmulti/lib.js index d578a81b0..8dd92d6f3 100644 --- a/apps/kbmulti/lib.js +++ b/apps/kbmulti/lib.js @@ -1,7 +1,7 @@ //Multitap logic originally from here: http://www.espruino.com/Morse+Code+Texting exports.input = function(options) { - var options = options||{}; + options = options||{}; var text = options.text; if ("string"!=typeof text) text=""; From ad63cafec6dfb12a69dddb6397b93ef77a0bfff3 Mon Sep 17 00:00:00 2001 From: thyttan <97237430+thyttan@users.noreply.github.com> Date: Wed, 11 May 2022 20:14:37 +0200 Subject: [PATCH 026/294] Update lib.js --- apps/kbmulti/lib.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/kbmulti/lib.js b/apps/kbmulti/lib.js index 8dd92d6f3..54d600fcb 100644 --- a/apps/kbmulti/lib.js +++ b/apps/kbmulti/lib.js @@ -6,7 +6,7 @@ exports.input = function(options) { if ("string"!=typeof text) text=""; var settings = require('Storage').readJSON("kbmulti.settings.json", true) || {}; - if (settings.firstLaunch===undefined) { settings.firstLaunch = true; } + //if (settings.firstLaunch===undefined) { settings.firstLaunch = true; } if (settings.charTimeout===undefined) { settings.charTimeout = 500; } if (settings.showHelpBtn===undefined) { settings.showHelpBtn = false; } @@ -133,7 +133,7 @@ exports.input = function(options) { return new Promise((resolve,reject) => { g.clearRect(Bangle.appRect); - if (settings.firstLaunch==true) { + if (!settings.firstLaunch) { onHelp(resolve,reject); settings.firstLaunch = false; require('Storage').writeJSON("kbmulti.settings.json", settings); From 8dec7e503be0a22ef2c2f66e99e86b1ec9e5ce97 Mon Sep 17 00:00:00 2001 From: thyttan <97237430+thyttan@users.noreply.github.com> Date: Wed, 11 May 2022 20:17:15 +0200 Subject: [PATCH 027/294] Update lib.js --- apps/kbmulti/lib.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/kbmulti/lib.js b/apps/kbmulti/lib.js index 54d600fcb..b0d6ae3eb 100644 --- a/apps/kbmulti/lib.js +++ b/apps/kbmulti/lib.js @@ -8,7 +8,7 @@ exports.input = function(options) { var settings = require('Storage').readJSON("kbmulti.settings.json", true) || {}; //if (settings.firstLaunch===undefined) { settings.firstLaunch = true; } if (settings.charTimeout===undefined) { settings.charTimeout = 500; } - if (settings.showHelpBtn===undefined) { settings.showHelpBtn = false; } + if (settings.showHelpBtn===undefined) { settings.showHelpBtn = true; } var fontSize = "6x15"; var Layout = require("Layout"); From c8b1d166973aa47c3c1f46e497181261a4b511c6 Mon Sep 17 00:00:00 2001 From: thyttan <97237430+thyttan@users.noreply.github.com> Date: Wed, 11 May 2022 20:18:09 +0200 Subject: [PATCH 028/294] Update lib.js --- apps/kbmulti/lib.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/kbmulti/lib.js b/apps/kbmulti/lib.js index b0d6ae3eb..da3894f0b 100644 --- a/apps/kbmulti/lib.js +++ b/apps/kbmulti/lib.js @@ -27,7 +27,7 @@ exports.input = function(options) { function displayText(charTimeout) { layout.clear(layout.text); - layout.text.label = text.slice(settings.showHelpBtn ? -12 : -13) + (charTimeout ? " " : "_"); + layout.text.label = text.slice(settings.showHelpBtn ? -11 : -13) + (charTimeout ? " " : "_"); layout.render(layout.text); } From efa1254673a84231f5a997dfc1a74609777aaed8 Mon Sep 17 00:00:00 2001 From: thyttan <97237430+thyttan@users.noreply.github.com> Date: Wed, 11 May 2022 20:24:30 +0200 Subject: [PATCH 029/294] Update lib.js --- apps/kbmulti/lib.js | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/kbmulti/lib.js b/apps/kbmulti/lib.js index da3894f0b..f1f706216 100644 --- a/apps/kbmulti/lib.js +++ b/apps/kbmulti/lib.js @@ -124,6 +124,7 @@ exports.input = function(options) { ]}, ] },{back: ()=>{ + charTimeout = undefined; Bangle.setUI(); Bangle.removeListener("swipe", onSwipe); g.clearRect(Bangle.appRect); From 7c747889ab718731b4c2bc7edd14e56df9bfbab4 Mon Sep 17 00:00:00 2001 From: thyttan <97237430+thyttan@users.noreply.github.com> Date: Wed, 11 May 2022 20:38:41 +0200 Subject: [PATCH 030/294] Update lib.js --- apps/kbmulti/lib.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/kbmulti/lib.js b/apps/kbmulti/lib.js index f1f706216..0d5b73d5f 100644 --- a/apps/kbmulti/lib.js +++ b/apps/kbmulti/lib.js @@ -6,7 +6,7 @@ exports.input = function(options) { if ("string"!=typeof text) text=""; var settings = require('Storage').readJSON("kbmulti.settings.json", true) || {}; - //if (settings.firstLaunch===undefined) { settings.firstLaunch = true; } + //if (settings.firstLaunch===undefined) { settings.firstLaunch = true; } // Unnecessary if doing if(!settings.firstLaunch) down inside the promise. But maybe it's good to keep it as in v0.01 for readability? if (settings.charTimeout===undefined) { settings.charTimeout = 500; } if (settings.showHelpBtn===undefined) { settings.showHelpBtn = true; } @@ -27,7 +27,7 @@ exports.input = function(options) { function displayText(charTimeout) { layout.clear(layout.text); - layout.text.label = text.slice(settings.showHelpBtn ? -11 : -13) + (charTimeout ? " " : "_"); + layout.text.label = text.slice(settings.showHelpBtn ? -11 : -13) + (charTimeout ? " " : "_"); // Implemented marker here. layout.render(layout.text); } @@ -124,7 +124,7 @@ exports.input = function(options) { ]}, ] },{back: ()=>{ - charTimeout = undefined; + // charTimeout = undefined; // Tried this to see if it would stop the text from being drawn after closing keyboard when doing it too soon after pressing a key. It didn't help. This problem goes back to how I've implemented the marker above. Bangle.setUI(); Bangle.removeListener("swipe", onSwipe); g.clearRect(Bangle.appRect); From c4647bfc68c45ef9e3627785c2673cd3041cf320 Mon Sep 17 00:00:00 2001 From: thyttan <97237430+thyttan@users.noreply.github.com> Date: Wed, 11 May 2022 20:43:01 +0200 Subject: [PATCH 031/294] Update settings.js --- apps/kbmulti/settings.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/kbmulti/settings.js b/apps/kbmulti/settings.js index c698aca8a..4fad8a428 100644 --- a/apps/kbmulti/settings.js +++ b/apps/kbmulti/settings.js @@ -1,7 +1,7 @@ (function(back) { function settings() { var settings = require('Storage').readJSON("kbmulti.settings.json", true) || {}; - if (settings.firstLaunch===undefined) { settings.firstLaunch = true; } + if (settings.showHelpBtn===undefined) { settings.firstLaunch = true; } if (settings.charTimeout===undefined) { settings.charTimeout = 500; } return settings; } From cb6d46d9c8aa787296e21c07c1055ad322ab498d Mon Sep 17 00:00:00 2001 From: thyttan <97237430+thyttan@users.noreply.github.com> Date: Wed, 11 May 2022 20:50:02 +0200 Subject: [PATCH 032/294] Update lib.js --- apps/kbmulti/lib.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/kbmulti/lib.js b/apps/kbmulti/lib.js index 0d5b73d5f..2d38539e8 100644 --- a/apps/kbmulti/lib.js +++ b/apps/kbmulti/lib.js @@ -6,7 +6,7 @@ exports.input = function(options) { if ("string"!=typeof text) text=""; var settings = require('Storage').readJSON("kbmulti.settings.json", true) || {}; - //if (settings.firstLaunch===undefined) { settings.firstLaunch = true; } // Unnecessary if doing if(!settings.firstLaunch) down inside the promise. But maybe it's good to keep it as in v0.01 for readability? + if (settings.firstLaunch===undefined) { settings.firstLaunch = true; } if (settings.charTimeout===undefined) { settings.charTimeout = 500; } if (settings.showHelpBtn===undefined) { settings.showHelpBtn = true; } @@ -134,7 +134,7 @@ exports.input = function(options) { return new Promise((resolve,reject) => { g.clearRect(Bangle.appRect); - if (!settings.firstLaunch) { + if (settings.firstLaunch) { onHelp(resolve,reject); settings.firstLaunch = false; require('Storage').writeJSON("kbmulti.settings.json", settings); From 04679ba3243b2686be809a7d9af1525cbbb42636 Mon Sep 17 00:00:00 2001 From: thyttan <97237430+thyttan@users.noreply.github.com> Date: Wed, 11 May 2022 20:55:11 +0200 Subject: [PATCH 033/294] Update settings.js --- apps/kbmulti/settings.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/kbmulti/settings.js b/apps/kbmulti/settings.js index 4fad8a428..ab0e26806 100644 --- a/apps/kbmulti/settings.js +++ b/apps/kbmulti/settings.js @@ -1,7 +1,7 @@ (function(back) { function settings() { var settings = require('Storage').readJSON("kbmulti.settings.json", true) || {}; - if (settings.showHelpBtn===undefined) { settings.firstLaunch = true; } + if (settings.showHelpBtn===undefined) { settings.showHelpBtn = true; } if (settings.charTimeout===undefined) { settings.charTimeout = 500; } return settings; } From 28c6103242a0ad6a168cf43de5314b6c2b82fb03 Mon Sep 17 00:00:00 2001 From: thyttan <97237430+thyttan@users.noreply.github.com> Date: Wed, 11 May 2022 20:55:54 +0200 Subject: [PATCH 034/294] Update settings.js --- apps/kbmulti/settings.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/kbmulti/settings.js b/apps/kbmulti/settings.js index ab0e26806..8a66cd8f0 100644 --- a/apps/kbmulti/settings.js +++ b/apps/kbmulti/settings.js @@ -21,7 +21,7 @@ format: v => v, onchange: v => updateSetting("charTimeout", v), }, - /*LANG*/'Show help button': { + /*LANG*/'Show help button?': { value: !!settings().showHelpBtn, format: v => v?"Yes":"No", onchange: v => updateSetting("showHelpBtn", v) From 4f296ac43438e8ca744b3556e262e55b75bc9788 Mon Sep 17 00:00:00 2001 From: thyttan <97237430+thyttan@users.noreply.github.com> Date: Wed, 11 May 2022 20:59:49 +0200 Subject: [PATCH 035/294] Update ChangeLog --- apps/kbmulti/ChangeLog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/kbmulti/ChangeLog b/apps/kbmulti/ChangeLog index 191517b30..4d2380bfa 100644 --- a/apps/kbmulti/ChangeLog +++ b/apps/kbmulti/ChangeLog @@ -1,2 +1,2 @@ 0.01: New keyboard -0.02: Introduce setting "Show help button". Make setting firstLaunch invisible by removing corresponding code from settings.js. Add marker that shows when character selection timeout has run out. +0.02: Introduce setting "Show help button". Make setting firstLaunch invisible by removing corresponding code from settings.js. Add marker that shows when character selection timeout has run out. Display opened text on launch when editing existing text string. From 8fae68bccc2271c2c9c1e77e6e647631874fabd3 Mon Sep 17 00:00:00 2001 From: thyttan <97237430+thyttan@users.noreply.github.com> Date: Wed, 11 May 2022 21:19:09 +0200 Subject: [PATCH 036/294] Update ChangeLog --- apps/kbmulti/ChangeLog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/kbmulti/ChangeLog b/apps/kbmulti/ChangeLog index 4d2380bfa..c6c606bff 100644 --- a/apps/kbmulti/ChangeLog +++ b/apps/kbmulti/ChangeLog @@ -1,2 +1,2 @@ 0.01: New keyboard -0.02: Introduce setting "Show help button". Make setting firstLaunch invisible by removing corresponding code from settings.js. Add marker that shows when character selection timeout has run out. Display opened text on launch when editing existing text string. +0.02: Introduce setting "Show help button?". Make setting firstLaunch invisible by removing corresponding code from settings.js. Add marker that shows when character selection timeout has run out. Display opened text on launch when editing existing text string. From 94690a81ee6fd651d078f8ee213bbe7eb4a76907 Mon Sep 17 00:00:00 2001 From: Alessandro Cocco Date: Wed, 11 May 2022 23:03:10 +0200 Subject: [PATCH 037/294] Add new time_utils module and move some functions from sched module to it --- apps/sched/ChangeLog | 1 + apps/sched/lib.js | 17 ------------ apps/sched/metadata.json | 2 +- apps/sched/sched.js | 4 +-- modules/time_utils.js | 57 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 61 insertions(+), 20 deletions(-) create mode 100644 modules/time_utils.js diff --git a/apps/sched/ChangeLog b/apps/sched/ChangeLog index 914bd7002..c68653a76 100644 --- a/apps/sched/ChangeLog +++ b/apps/sched/ChangeLog @@ -7,3 +7,4 @@ 0.07: Update settings Correct `decodeTime(t)` to return a more likely expected time 0.08: add day of week check to getActiveAlarms() +0.09: Move some functions to new time_utils module diff --git a/apps/sched/lib.js b/apps/sched/lib.js index ff35c94cb..fb1a7e4d6 100644 --- a/apps/sched/lib.js +++ b/apps/sched/lib.js @@ -113,20 +113,3 @@ exports.getSettings = function () { exports.setSettings = function(settings) { require("Storage").writeJSON("sched.settings.json", settings); }; - -// time in ms -> { hrs, mins } -exports.decodeTime = function(t) { - t = Math.ceil(t / 60000); // sanitise to full minutes - let hrs = 0 | (t / 60); - return { hrs: hrs, mins: t - hrs * 60 }; -} - -// time in { hrs, mins } -> ms -exports.encodeTime = function(o) { - return o.hrs * 3600000 + o.mins * 60000; -} - -exports.formatTime = function(t) { - let o = exports.decodeTime(t); - return o.hrs + ":" + ("0" + o.mins).substr(-2); -} diff --git a/apps/sched/metadata.json b/apps/sched/metadata.json index 089fffe31..b962326e3 100644 --- a/apps/sched/metadata.json +++ b/apps/sched/metadata.json @@ -1,7 +1,7 @@ { "id": "sched", "name": "Scheduler", - "version": "0.08", + "version": "0.09", "description": "Scheduling library for alarms and timers", "icon": "app.png", "type": "scheduler", diff --git a/apps/sched/sched.js b/apps/sched/sched.js index 7c97600d9..f4d1bc9ad 100644 --- a/apps/sched/sched.js +++ b/apps/sched/sched.js @@ -9,7 +9,7 @@ function showAlarm(alarm) { const settings = require("sched").getSettings(); let msg = ""; - msg += alarm.timer ? require("sched").formatTime(alarm.timer) : require("sched").formatTime(alarm.t); + msg += require("time_utils").formatTime(alarm.timer ? alarm.timer : alarm.t); if (alarm.msg) { msg += "\n"+alarm.msg; } else { @@ -26,7 +26,7 @@ function showAlarm(alarm) { E.showPrompt(msg,{ title:alarm.timer ? /*LANG*/"TIMER!" : /*LANG*/"ALARM!", - buttons : {/*LANG*/"Snooze":true,/*LANG*/"Ok":false} // default is sleep so it'll come back in 10 mins + buttons : {/*LANG*/"Snooze":true,/*LANG*/"Stop":false} // default is sleep so it'll come back in 10 mins }).then(function(sleep) { buzzCount = 0; if (sleep) { diff --git a/modules/time_utils.js b/modules/time_utils.js new file mode 100644 index 000000000..152de2fd0 --- /dev/null +++ b/modules/time_utils.js @@ -0,0 +1,57 @@ +// module "time_utils" +// +// Utility functions useful to work with time and durations. +// Functions usually receive or return a {h, m} object or a +// number of milliseconds representing a time or a duration. +// + +/** + * @param {object} time {h, m} + * @returns the milliseconds contained in the passed time object + */ +exports.encodeTime = (time) => time.h * 3600000 + time.m * 60000; + +/** + * @param {int} millis the number of milliseconds + * @returns a time object {h, m} built from the milliseconds + */ +exports.decodeTime = (millis) => { + millis = Math.ceil(millis / 60000); + var h = 0 | (millis / 60); + return { + h: h, + m: millis - h * 60 + }; +} + +/** + * @param {object|int} value {h,m} object or milliseconds + * @returns an human-readable time string like "10:25" + */ +exports.formatTime = (value) => { + var time = (value.h === undefined || value.m === undefined) ? exports.decodeTime(value) : value; + return time.h + ":" + ("0" + time.m).substr(-2); +} + +/** + * @param {object|int} value {h,m} object or milliseconds + * @returns an human-readable duration string like "1h 10m" + */ +exports.formatDuration = (value) => { + var duration; + + var time = (value.h === undefined || value.m === undefined) ? exports.decodeTime(value) : value; + + if (time.h == 0) { + duration = time.m + "m" + } else { + duration = time.h + "h" + (time.m ? (" " + time.m + "m") : "") + } + + return duration +} + +exports.getCurrentTimeMillis = () => { + var time = new Date(); + return (time.getHours() * 3600 + time.getMinutes() * 60 + time.getSeconds()) * 1000; +} From ee663ef1691f94172d3d5b60bfa54ebb4f5b38a8 Mon Sep 17 00:00:00 2001 From: Alessandro Cocco Date: Thu, 12 May 2022 22:51:41 +0200 Subject: [PATCH 038/294] [sleepphasealarm] Update to new time_utils module --- apps/sleepphasealarm/ChangeLog | 1 + apps/sleepphasealarm/app.js | 4 ++-- apps/sleepphasealarm/metadata.json | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/apps/sleepphasealarm/ChangeLog b/apps/sleepphasealarm/ChangeLog index ec3fe3a23..208058472 100644 --- a/apps/sleepphasealarm/ChangeLog +++ b/apps/sleepphasealarm/ChangeLog @@ -6,3 +6,4 @@ 0.06: Add logging use Layout library and display ETA 0.07: Add check for day of week +0.08: Update to new time_utils module diff --git a/apps/sleepphasealarm/app.js b/apps/sleepphasealarm/app.js index 8ccd43eb2..febc8a259 100644 --- a/apps/sleepphasealarm/app.js +++ b/apps/sleepphasealarm/app.js @@ -46,8 +46,8 @@ function calc_ess(acc_magn) { var nextAlarm; active.forEach(alarm => { const now = new Date(); - const t = require("sched").decodeTime(alarm.t); - var dateAlarm = new Date(now.getFullYear(), now.getMonth(), now.getDate(), t.hrs, t.mins); + const time = require("time_utils").decodeTime(alarm.t); + var dateAlarm = new Date(now.getFullYear(), now.getMonth(), now.getDate(), time.h, time.m); if (dateAlarm < now) { // dateAlarm in the past, add 24h dateAlarm.setTime(dateAlarm.getTime() + (24*60*60*1000)); } diff --git a/apps/sleepphasealarm/metadata.json b/apps/sleepphasealarm/metadata.json index d74590704..c74a617ab 100644 --- a/apps/sleepphasealarm/metadata.json +++ b/apps/sleepphasealarm/metadata.json @@ -2,7 +2,7 @@ "id": "sleepphasealarm", "name": "SleepPhaseAlarm", "shortName": "SleepPhaseAlarm", - "version": "0.07", + "version": "0.08", "description": "Uses the accelerometer to estimate sleep and wake states with the principle of Estimation of Stationary Sleep-segments (ESS, see https://ubicomp.eti.uni-siegen.de/home/datasets/ichi14/index.html.en). This app will read the next alarm from the alarm application and will wake you up to 30 minutes early at the best guessed time when you are almost already awake.", "icon": "app.png", "tags": "alarm", From f22f113687a2a3cf9943806ff73e28a8257c1777 Mon Sep 17 00:00:00 2001 From: Alessandro Cocco Date: Thu, 12 May 2022 22:59:03 +0200 Subject: [PATCH 039/294] [Alarms & Timers] Full UI rewrite --- apps/alarm/ChangeLog | 1 + apps/alarm/app.js | 488 +++++++++++++++++++++++---------------- apps/alarm/metadata.json | 2 +- apps/sched/lib.js | 6 +- 4 files changed, 288 insertions(+), 209 deletions(-) diff --git a/apps/alarm/ChangeLog b/apps/alarm/ChangeLog index ca1417b5b..b952b1dcd 100644 --- a/apps/alarm/ChangeLog +++ b/apps/alarm/ChangeLog @@ -26,3 +26,4 @@ Add "Enable All", "Disable All" and "Remove All" actions 0.25: Fix redrawing selected Alarm/Timer entry inside edit submenu 0.26: Add support for Monday as first day of the week (#1780) +0.27: New UI! diff --git a/apps/alarm/app.js b/apps/alarm/app.js index cf46823d6..0cf1f3d6f 100644 --- a/apps/alarm/app.js +++ b/apps/alarm/app.js @@ -1,20 +1,160 @@ Bangle.loadWidgets(); Bangle.drawWidgets(); +// 0 = Sunday (default), 1 = Monday +const firstDayOfWeek = (require("Storage").readJSON("setting.json", true) || {}).firstDayOfWeek || 0; +const WORKDAYS = 62 +const WEEKEND = firstDayOfWeek ? 192 : 65; +const EVERY_DAY = firstDayOfWeek ? 254 : 127; + +const iconAlarmOn = "\0" + atob("GBiBAAAAAAAAAAYAYA4AcBx+ODn/nAP/wAf/4A/n8A/n8B/n+B/n+B/n+B/n+B/h+B/4+A/+8A//8Af/4AP/wAH/gAB+AAAAAAAAAA=="); +const iconAlarmOff = "\0" + (g.theme.dark + ? atob("GBjBAP////8AAAAAAAAGAGAOAHAcfjg5/5wD/8AH/+AP5/AP5/Af5/gf5/gf5wAf5gAf4Hgf+f4P+bYP8wMH84cD84cB8wMAebYAAf4AAHg=") + : atob("GBjBAP//AAAAAAAAAAAGAGAOAHAcfjg5/5wD/8AH/+AP5/AP5/Af5/gf5/gf5wAf5gAf4Hgf+f4P+bYP8wMH84cD84cB8wMAebYAAf4AAHg=")); + +const iconTimerOn = "\0" + (g.theme.dark + ? atob("GBjBAP////8AAAAAAAAAAAAH/+AH/+ABgYABgYABgYAA/wAA/wAAfgAAPAAAPAAAfgAA5wAAwwABgYABgYABgYAH/+AH/+AAAAAAAAAAAAA=") + : atob("GBjBAP//AAAAAAAAAAAAAAAH/+AH/+ABgYABgYABgYAA/wAA/wAAfgAAPAAAPAAAfgAA5wAAwwABgYABgYABgYAH/+AH/+AAAAAAAAAAAAA=")); +const iconTimerOff = "\0" + (g.theme.dark + ? atob("GBjBAP////8AAAAAAAAAAAAH/+AH/+ABgYABgYABgYAA/wAA/wAAfgAAPAAAPAAAfgAA5HgAwf4BgbYBgwMBg4cH84cH8wMAAbYAAf4AAHg=") + : atob("GBjBAP//AAAAAAAAAAAAAAAH/+AH/+ABgYABgYABgYAA/wAA/wAAfgAAPAAAPAAAfgAA5HgAwf4BgbYBgwMBg4cH84cH8wMAAbYAAf4AAHg=")); + // An array of alarm objects (see sched/README.md) var alarms = require("sched").getAlarms(); -// 0 = Sunday -// 1 = Monday -var firstDayOfWeek = (require("Storage").readJSON("setting.json", true) || {}).firstDayOfWeek || 0; +function handleFirstDayOfWeek(dow) { + if (firstDayOfWeek == 1) { + if ((dow & 1) == 1) { + // In the scheduler API Sunday is 1. + // Here the week starts on Monday and Sunday is ON so + // when I read the dow I need to move Sunday to 128... + dow += 127; + } else if ((dow & 128) == 128) { + // ... and then when I write the dow I need to move Sunday back to 1. + dow -= 127; + } + } + return dow; +} -function getCurrentTime() { - var time = new Date(); - return ( - time.getHours() * 3600000 + - time.getMinutes() * 60000 + - time.getSeconds() * 1000 - ); +// Check the first day of week and update the dow field accordingly. +alarms.forEach(alarm => alarm.dow = handleFirstDayOfWeek(alarm.dow)); + +function showMainMenu() { + const menu = { + "": { "title": /*LANG*/"Alarms & Timers" }, + "< Back": () => load(), + /*LANG*/"New...": () => showNewMenu() + }; + + alarms.forEach((e, index) => { + var label = e.timer + ? require("time_utils").formatDuration(e.timer) + : require("time_utils").formatTime(e.t) + (e.dow > 0 ? (" " + decodeDOW(e)) : ""); + menu[label] = { + value: e.on ? (e.timer ? iconTimerOn : iconAlarmOn) : (e.timer ? iconTimerOff : iconAlarmOff), + onchange: () => setTimeout(e.timer ? showEditTimerMenu : showEditAlarmMenu, 10, e, index) + }; + }); + + menu[/*LANG*/"Advanced"] = () => showAdvancedMenu(); + + E.showMenu(menu); +} + +function showNewMenu() { + E.showMenu({ + "": { "title": /*LANG*/"New..." }, + "< Back": () => showMainMenu(), + /*LANG*/"Alarm": () => showEditAlarmMenu(undefined, undefined), + /*LANG*/"Timer": () => showEditTimerMenu(undefined, undefined) + }); +} + +function showEditAlarmMenu(selectedAlarm, alarmIndex) { + var isNew = alarmIndex === undefined; + + var alarm = require("sched").newDefaultAlarm(); + alarm.dow = handleFirstDayOfWeek(alarm.dow); + + if (selectedAlarm) { + Object.assign(alarm, selectedAlarm); + } + + var time = require("time_utils").decodeTime(alarm.t); + + const menu = { + "": { "title": isNew ? /*LANG*/"New Alarm" : /*LANG*/"Edit Alarm" }, + "< Back": () => { + saveAlarm(alarm, alarmIndex, time); + showMainMenu(); + }, + /*LANG*/"Hour": { + value: time.h, + format: v => ("0" + v).substr(-2), + min: 0, + max: 23, + wrap: true, + onchange: v => time.h = v + }, + /*LANG*/"Minute": { + value: time.m, + format: v => ("0" + v).substr(-2), + min: 0, + max: 59, + wrap: true, + onchange: v => time.m = v + }, + /*LANG*/"Enabled": { + value: alarm.on, + onchange: v => alarm.on = v + }, + /*LANG*/"Repeat": { + value: decodeDOW(alarm), + onchange: () => setTimeout(showEditRepeatMenu, 100, alarm.dow, dow => { + alarm.rp = dow > 0; + alarm.dow = dow; + alarm.t = require("time_utils").encodeTime(time); + setTimeout(showEditAlarmMenu, 10, alarm, alarmIndex); + }) + }, + /*LANG*/"Vibrate": require("buzz_menu").pattern(alarm.vibrate, v => alarm.vibrate = v), + /*LANG*/"Auto Snooze": { + value: alarm.as, + onchange: v => alarm.as = v + }, + /*LANG*/"Cancel": () => showMainMenu() + }; + + if (!isNew) { + menu[/*LANG*/"Delete"] = () => { + E.showPrompt(/*LANG*/"Are you sure?", { title: /*LANG*/"Delete Alarm" }).then((confirm) => { + if (confirm) { + alarms.splice(alarmIndex, 1); + saveAndReload(); + showMainMenu(); + } else { + alarm.t = require("time_utils").encodeTime(time); + setTimeout(showEditAlarmMenu, 10, alarm, alarmIndex); + } + }); + }; + } + + E.showMenu(menu); +} + +function saveAlarm(alarm, alarmIndex, time) { + alarm.t = require("time_utils").encodeTime(time); + alarm.last = alarm.t < require("time_utils").getCurrentTimeMillis() ? new Date().getDate() : 0; + + if (alarmIndex === undefined) { + alarms.push(alarm); + } else { + alarms[alarmIndex] = alarm; + } + + saveAndReload(); } function saveAndReload() { @@ -23,249 +163,187 @@ function saveAndReload() { require("sched").setAlarms(alarms); require("sched").reload(); + + // Fix after save + alarms.forEach(a => a.dow = handleFirstDayOfWeek(a.dow, firstDayOfWeek)); } -function showMainMenu() { - // Timer img "\0"+atob("DhKBAP////MDDAwwMGGBzgPwB4AeAPwHOBhgwMMzDez////w") - // Alarm img "\0"+atob("FBSBAABgA4YcMPDGP8Zn/mx/48//PP/zD/8A//AP/wD/8A//AP/wH/+D//w//8AAAADwAAYA") - const menu = { - '': { 'title': /*LANG*/'Alarms&Timers' }, - /*LANG*/'< Back': () => { load(); }, - /*LANG*/'New Alarm': () => editAlarm(-1), - /*LANG*/'New Timer': () => editTimer(-1) - }; - alarms.forEach((alarm, idx) => { - alarm.dow = handleFirstDayOfWeek(alarm.dow, firstDayOfWeek); +function decodeDOW(alarm) { + return alarm.rp + ? require("date_utils") + .dows(firstDayOfWeek, 2) + .map((day, index) => alarm.dow & (1 << (index + firstDayOfWeek)) ? day : "_") + .join("") + .toLowerCase() + : "Once" +} - var type, txt; // a leading space is currently required (JS error in Espruino 2v12) - if (alarm.timer) { - type = /*LANG*/"Timer"; - txt = " " + require("sched").formatTime(alarm.timer); - } else { - type = /*LANG*/"Alarm"; - txt = " " + require("sched").formatTime(alarm.t); +function showEditRepeatMenu(dow, dowChangeCallback) { + var originalDow = dow; + var isCustom = dow > 0 && dow != WORKDAYS && dow != WEEKEND && dow != EVERY_DAY; + + const menu = { + "": { "title": /*LANG*/"Repeat Alarm" }, + "< Back": () => dowChangeCallback(dow), + /*LANG*/"Once": { // No days set: the alarm will fire once + value: dow == 0, + onchange: () => dowChangeCallback(0) + }, + /*LANG*/"Workdays": { + value: dow == WORKDAYS, + onchange: () => dowChangeCallback(WORKDAYS) + }, + /*LANG*/"Weekends": { + value: dow == WEEKEND, + onchange: () => dowChangeCallback(WEEKEND) + }, + /*LANG*/"Every Day": { + value: dow == EVERY_DAY, + onchange: () => dowChangeCallback(EVERY_DAY) + }, + /*LANG*/"Custom": { + value: isCustom ? decodeDOW({ rp: true, dow: dow }) : false, + onchange: () => setTimeout(showCustomDaysMenu, 10, isCustom ? dow : EVERY_DAY, dowChangeCallback, originalDow) } - if (alarm.rp) txt += "\0" + atob("FBaBAAABgAAcAAHn//////wAHsABzAAYwAAMAADAAAAAAwAAMAADGAAzgAN4AD//////54AAOAABgAA="); - // rename duplicate alarms - if (menu[type + txt]) { - var n = 2; - while (menu[type + " " + n + txt]) n++; - txt = type + " " + n + txt; - } else txt = type + txt; - // add to menu - menu[txt] = { - value: "\0" + atob(alarm.on ? "EhKBAH//v/////////////5//x//j//H+eP+Mf/A//h//z//////////3//g" : "EhKBAH//v//8AA8AA8AA8AA8AA8AA8AA8AA8AA8AA8AA8AA8AA8AA///3//g"), - onchange: function () { - setTimeout(alarm.timer ? editTimer : editAlarm, 10, idx, alarm); - } - }; - }); + }; - if (alarms.some(e => !e.on)) { - menu[/*LANG*/"Enable All"] = () => enableAll(true); - } - if (alarms.some(e => e.on)) { - menu[/*LANG*/"Disable All"] = () => enableAll(false); - } - if (alarms.length > 0) { - menu[/*LANG*/"Delete All"] = () => deleteAll(); - } - - if (WIDGETS["alarm"]) WIDGETS["alarm"].reload(); - return E.showMenu(menu); + E.showMenu(menu); } -function editDOW(dow, onchange) { +function showCustomDaysMenu(dow, dowChangeCallback, originalDow) { const menu = { - '': { 'title': /*LANG*/'Days of Week' }, - /*LANG*/'< Back': () => onchange(dow) + "": { "title": /*LANG*/"Custom Days" }, + "< Back": () => dowChangeCallback(dow), }; require("date_utils").dows(firstDayOfWeek).forEach((day, i) => { menu[day] = { value: !!(dow & (1 << (i + firstDayOfWeek))), - format: v => v ? /*LANG*/"Yes" : /*LANG*/"No", onchange: v => v ? (dow |= 1 << (i + firstDayOfWeek)) : (dow &= ~(1 << (i + firstDayOfWeek))) }; }); + menu[/*LANG*/"Cancel"] = () => setTimeout(showEditRepeatMenu, 10, originalDow, dowChangeCallback) + E.showMenu(menu); } -function editAlarm(alarmIndex, alarm) { - var newAlarm = alarmIndex < 0; - var a = require("sched").newDefaultAlarm(); - a.dow = handleFirstDayOfWeek(a.dow, firstDayOfWeek); +function showEditTimerMenu(selectedTimer, timerIndex) { + var isNew = timerIndex === undefined; - if (!newAlarm) Object.assign(a, alarms[alarmIndex]); - if (alarm) Object.assign(a, alarm); - var t = require("sched").decodeTime(a.t); + var timer = require("sched").newDefaultTimer(); + + if (selectedTimer) { + Object.assign(timer, selectedTimer); + } + + var time = require("time_utils").decodeTime(timer.timer); const menu = { - '': { 'title': /*LANG*/'Alarm' }, - /*LANG*/'< Back': () => { - saveAlarm(newAlarm, alarmIndex, a, t); + "": { "title": isNew ? /*LANG*/"New Timer" : /*LANG*/"Edit Timer" }, + "< Back": () => { + saveTimer(timer, timerIndex, time); showMainMenu(); }, - /*LANG*/'Hours': { - value: t.hrs, min: 0, max: 23, wrap: true, - onchange: v => t.hrs = v + /*LANG*/"Hours": { + value: time.h, + min: 0, + max: 23, + wrap: true, + onchange: v => time.h = v }, - /*LANG*/'Minutes': { - value: t.mins, min: 0, max: 59, wrap: true, - onchange: v => t.mins = v + /*LANG*/"Minutes": { + value: time.m, + min: 0, + max: 59, + wrap: true, + onchange: v => time.m = v }, - /*LANG*/'Enabled': { - value: a.on, - format: v => v ? /*LANG*/"On" : /*LANG*/"Off", - onchange: v => a.on = v + /*LANG*/"Enabled": { + value: timer.on, + onchange: v => timer.on = v }, - /*LANG*/'Repeat': { - value: a.rp, - format: v => v ? /*LANG*/"Yes" : /*LANG*/"No", - onchange: v => a.rp = v - }, - /*LANG*/'Days': { - value: decodeDOW(a.dow), - onchange: () => setTimeout(editDOW, 100, a.dow, d => { - a.dow = d; - a.t = require("sched").encodeTime(t); - editAlarm(alarmIndex, a); - }) - }, - /*LANG*/'Vibrate': require("buzz_menu").pattern(a.vibrate, v => a.vibrate = v), - /*LANG*/'Auto Snooze': { - value: a.as, - format: v => v ? /*LANG*/"Yes" : /*LANG*/"No", - onchange: v => a.as = v - } + /*LANG*/"Vibrate": require("buzz_menu").pattern(timer.vibrate, v => timer.vibrate = v), }; - menu[/*LANG*/"Cancel"] = () => showMainMenu(); - - if (!newAlarm) { - menu[/*LANG*/"Delete"] = function () { - alarms.splice(alarmIndex, 1); - saveAndReload(); - showMainMenu(); + if (!isNew) { + menu[/*LANG*/"Delete"] = () => { + E.showPrompt(/*LANG*/"Are you sure?", { title: /*LANG*/"Delete Timer" }).then((confirm) => { + if (confirm) { + alarms.splice(timerIndex, 1); + saveAndReload(); + showMainMenu(); + } else { + timer.timer = require("time_utils").encodeTime(time); + setTimeout(showEditTimerMenu, 10, timer, timerIndex) + } + }); }; } - return E.showMenu(menu); + E.showMenu(menu); } -function saveAlarm(newAlarm, alarmIndex, a, t) { - a.t = require("sched").encodeTime(t); - a.last = (a.t < getCurrentTime()) ? (new Date()).getDate() : 0; +function saveTimer(timer, timerIndex, time) { + timer.timer = require("time_utils").encodeTime(time); + timer.t = require("time_utils").getCurrentTimeMillis() + timer.timer; + timer.last = 0; - if (newAlarm) { - alarms.push(a); + if (timerIndex === undefined) { + alarms.push(timer); } else { - alarms[alarmIndex] = a; + alarms[timerIndex] = timer; } saveAndReload(); } -function editTimer(alarmIndex, alarm) { - var newAlarm = alarmIndex < 0; - var a = require("sched").newDefaultTimer(); - if (!newAlarm) Object.assign(a, alarms[alarmIndex]); - if (alarm) Object.assign(a, alarm); - var t = require("sched").decodeTime(a.timer); - - const menu = { - '': { 'title': /*LANG*/'Timer' }, - /*LANG*/'< Back': () => { - saveTimer(newAlarm, alarmIndex, a, t); - showMainMenu(); - }, - /*LANG*/'Hours': { - value: t.hrs, min: 0, max: 23, wrap: true, - onchange: v => t.hrs = v - }, - /*LANG*/'Minutes': { - value: t.mins, min: 0, max: 59, wrap: true, - onchange: v => t.mins = v - }, - /*LANG*/'Enabled': { - value: a.on, - format: v => v ? /*LANG*/"On" : /*LANG*/"Off", - onchange: v => a.on = v - }, - /*LANG*/'Vibrate': require("buzz_menu").pattern(a.vibrate, v => a.vibrate = v), - }; - - menu[/*LANG*/"Cancel"] = () => showMainMenu(); - - if (!newAlarm) { - menu[/*LANG*/"Delete"] = function () { - alarms.splice(alarmIndex, 1); - saveAndReload(); - showMainMenu(); - }; - } - return E.showMenu(menu); -} - -function saveTimer(newAlarm, alarmIndex, a, t) { - a.timer = require("sched").encodeTime(t); - a.t = getCurrentTime() + a.timer; - a.last = 0; - - if (newAlarm) { - alarms.push(a); - } else { - alarms[alarmIndex] = a; - } - - saveAndReload(); -} - -function handleFirstDayOfWeek(dow, firstDayOfWeek) { - if (firstDayOfWeek == 1) { - if ((dow & 1) == 1) { - // By default 1 = Sunday. - // Here the week starts on Monday and Sunday is ON so move Sunday to 128. - dow += 127; - } else if ((dow & 128) == 128) { - dow -= 127; - } - } - return dow; -} - -function decodeDOW(dow) { - return require("date_utils") - .dows(firstDayOfWeek, 2) - .map((day, index) => dow & (1 << (index + firstDayOfWeek)) ? day : "_") - .join(""); +function showAdvancedMenu() { + E.showMenu({ + "": { "title": /*LANG*/"Advanced" }, + "< Back": () => showMainMenu(), + /*LANG*/"Scheduler Settings": () => eval(require("Storage").read("sched.settings.js"))(() => showAdvancedMenu()), + /*LANG*/"Enable All": () => enableAll(true), + /*LANG*/"Disable All": () => enableAll(false), + /*LANG*/"Delete All": () => deleteAll() + }); } function enableAll(on) { - E.showPrompt(/*LANG*/"Are you sure?", { - title: on ? /*LANG*/"Enable All" : /*LANG*/"Disable All" - }).then((confirm) => { - if (confirm) { - alarms.forEach(alarm => alarm.on = on); - saveAndReload(); - } - - showMainMenu(); - }); + if (alarms.filter(e => e.on == !on).length == 0) { + E.showPrompt(on ? /*LANG*/"Nothing to Enable" : /*LANG*/"Nothing to Disable", { + title: on ? /*LANG*/"Enable All" : /*LANG*/"Disable All", + buttons: { /*LANG*/"Ok": true } + }).then(() => showAdvancedMenu()); + } else { + E.showPrompt(/*LANG*/"Are you sure?", { title: on ? "/*LANG*/Enable All" : /*LANG*/"Disable All" }).then((confirm) => { + if (confirm) { + alarms.forEach(alarm => alarm.on = on); + saveAndReload(); + showMainMenu(); + } else { + showAdvancedMenu(); + } + }); + } } function deleteAll() { - E.showPrompt(/*LANG*/"Are you sure?", { - title: /*LANG*/"Delete All" - }).then((confirm) => { - if (confirm) { - alarms = []; - saveAndReload(); - } - - showMainMenu(); - }); + if (alarms.length == 0) { + E.showPrompt(/*LANG*/"Nothing to delete", { title: /*LANG*/"Delete All", buttons: { /*LANG*/"Ok": true } }).then(() => showAdvancedMenu()); + } else { + E.showPrompt(/*LANG*/"Are you sure?", { + title: /*LANG*/"Delete All" + }).then((confirm) => { + if (confirm) { + alarms = []; + saveAndReload(); + showMainMenu(); + } else { + showAdvancedMenu(); + } + }); + } } showMainMenu(); diff --git a/apps/alarm/metadata.json b/apps/alarm/metadata.json index c062b030d..d51e9fa19 100644 --- a/apps/alarm/metadata.json +++ b/apps/alarm/metadata.json @@ -2,7 +2,7 @@ "id": "alarm", "name": "Alarms & Timers", "shortName": "Alarms", - "version": "0.26", + "version": "0.27", "description": "Set alarms and timers on your Bangle", "icon": "app.png", "tags": "tool,alarm,widget", diff --git a/apps/sched/lib.js b/apps/sched/lib.js index fb1a7e4d6..063402e3d 100644 --- a/apps/sched/lib.js +++ b/apps/sched/lib.js @@ -61,12 +61,12 @@ exports.reload = function() { exports.newDefaultAlarm = function () { const settings = exports.getSettings(); - let alarm = { + var alarm = { t: 12 * 3600000, // Default to 12:00 on: true, rp: settings.defaultRepeat, as: settings.defaultAutoSnooze, - dow: 0b1111111, + dow: settings.defaultRepeat ? 0b1111111 : 0b0000000, last: 0, vibrate: settings.defaultAlarmPattern, }; @@ -79,7 +79,7 @@ exports.newDefaultAlarm = function () { exports.newDefaultTimer = function () { const settings = exports.getSettings(); - let timer = { + var timer = { timer: 5 * 60 * 1000, // 5 minutes on: true, rp: false, From dc0c8d7f0cf42bdf63026c08973dd524a4052135 Mon Sep 17 00:00:00 2001 From: Alessandro Cocco Date: Fri, 13 May 2022 12:05:23 +0200 Subject: [PATCH 040/294] [Alarms & Timers] Add screenshots --- apps/alarm/metadata.json | 23 ++++++++++++++++++----- apps/alarm/screenshot-1.png | Bin 0 -> 1752 bytes apps/alarm/screenshot-10.png | Bin 0 -> 1979 bytes apps/alarm/screenshot-11.png | Bin 0 -> 2326 bytes apps/alarm/screenshot-2.png | Bin 0 -> 1451 bytes apps/alarm/screenshot-3.png | Bin 0 -> 2402 bytes apps/alarm/screenshot-4.png | Bin 0 -> 2053 bytes apps/alarm/screenshot-5.png | Bin 0 -> 1948 bytes apps/alarm/screenshot-6.png | Bin 0 -> 2277 bytes apps/alarm/screenshot-7.png | Bin 0 -> 2144 bytes apps/alarm/screenshot-8.png | Bin 0 -> 2360 bytes apps/alarm/screenshot-9.png | Bin 0 -> 2274 bytes 12 files changed, 18 insertions(+), 5 deletions(-) create mode 100644 apps/alarm/screenshot-1.png create mode 100644 apps/alarm/screenshot-10.png create mode 100644 apps/alarm/screenshot-11.png create mode 100644 apps/alarm/screenshot-2.png create mode 100644 apps/alarm/screenshot-3.png create mode 100644 apps/alarm/screenshot-4.png create mode 100644 apps/alarm/screenshot-5.png create mode 100644 apps/alarm/screenshot-6.png create mode 100644 apps/alarm/screenshot-7.png create mode 100644 apps/alarm/screenshot-8.png create mode 100644 apps/alarm/screenshot-9.png diff --git a/apps/alarm/metadata.json b/apps/alarm/metadata.json index d51e9fa19..b9ce55756 100644 --- a/apps/alarm/metadata.json +++ b/apps/alarm/metadata.json @@ -6,12 +6,25 @@ "description": "Set alarms and timers on your Bangle", "icon": "app.png", "tags": "tool,alarm,widget", - "supports": ["BANGLEJS","BANGLEJS2"], + "supports": [ "BANGLEJS", "BANGLEJS2" ], "readme": "README.md", - "dependencies": {"scheduler":"type"}, + "dependencies": { "scheduler":"type" }, "storage": [ - {"name":"alarm.app.js","url":"app.js"}, - {"name":"alarm.img","url":"app-icon.js","evaluate":true}, - {"name":"alarm.wid.js","url":"widget.js"} + { "name": "alarm.app.js", "url": "app.js" }, + { "name": "alarm.img", "url": "app-icon.js", "evaluate": true }, + { "name": "alarm.wid.js", "url": "widget.js" } + ], + "screenshots": [ + { "url": "screenshot-1.png" }, + { "url": "screenshot-2.png" }, + { "url": "screenshot-3.png" }, + { "url": "screenshot-4.png" }, + { "url": "screenshot-5.png" }, + { "url": "screenshot-6.png" }, + { "url": "screenshot-7.png" }, + { "url": "screenshot-8.png" }, + { "url": "screenshot-9.png" }, + { "url": "screenshot-10.png" }, + { "url": "screenshot-11.png" } ] } diff --git a/apps/alarm/screenshot-1.png b/apps/alarm/screenshot-1.png new file mode 100644 index 0000000000000000000000000000000000000000..d2bd3a409955c711e18d5e3f093ab488df21a64a GIT binary patch literal 1752 zcmd6o{X5eOAIGO0jXUeBa@Ry2?zAonH?b*JY}`4gTJx|tDrGkjmXW6<8QHKyayD6J z9%7s{aq_rK!$@sIBFj8&A$e+D7bZ5R&iV2D1LwM4pU?Z3&rk2`dcQvz=g$65SI0mH z1On-LoI-nk)2H7Dyye?A8I0BjfwWj2XczDJ!Ubl3Lz&5TxAHLcW(-D}MCy2it?YMl(#UDM#A0WbvA3m=D11RsyUUwd1(>_%X$x z@41LTL{9tNrMb?0#YGg+h7ob<@g5#`SAe8UB;fy0$v~9t3UIf5Kqp~te74yAoHJ#= z{osG8fb=~4414+FiW0`11ri+yhX}6Gq|B=*GP>NU#Y9#Z|03xTqms9FdRxO-Nv6rU zj?#x729Go_}=yuaSmt$tcuz3fBxd%k{Io&6=1+Ifjo5SZPqrB}4`!j0h`_oAi20CMX zqZ!t6?r)?CTb(_;nq6zT3rkVrobdW6J$~7&3X0tDXSxu2` z^g@gk4iOPAoHP>-Y}AHPp4AuqXQ1wUeS_HjtAueP^3_X+n02=E&FKRKakM|S(>^Hv zXJk$nOA!7pLTON%QmwAbBgCeZ_Q09!`J-h$Rwae{mK-5<4$l&pQ?h&ti>%Usc49NW zmq&aJr_Gy(K!3lQ@h|DFLR-bYB)m7$fAhCFJbV+{$egWzys)#kx{dSrV(}9;v2!Md zBQ&sRw%>%3UPh_rAASnm=dj|C#eq<+`DZq}=#=i9&x<9#8^OG35!+H@kU zY5x#la`JDy1e*byzSK$nZg3h(Sd5dkB2!RzKx7jcP@IYah~PfHDP|_?!yR0|lM25l@$X{WlPrwk4RuZ& zeXk|2Sr5D9TR6+W#T#I`ih$8}w$3ruae})zNIqPs#RN^pw_t+atAe!);yUu>*>MH% zZh65QsiocFY}!3ZCe*#nuFGt16Q(@&mJ~^Y70GHMDiUTOwt}M)?)~c+gm~-%S$1f( zQMN)1&>vZ;+SrqH31^<^ndgaHbIguq2y-8eZF|-NjXC8tL_c>pVN6-;j8Va_t+a?m z3i8pe;bY>DEXmi0ykvb@$lZp5=_SXs?f|Y~X>xcdEAINR8=c;FfsFqV-zp0eq{@hH zgsxw*h5$u%L(c1tPkgHqHbjkGbbO5u96-`s0TE>KbYAwEO+UsQ;Oc8JgWXgV;Hf86 z!$}qc&jY&Yj3e|uUvfx!saiFK_fzA9#xtXATTzH~C=NL%q)#LO%?IN`Vi`TNYyRl~ zT3KB}>CKK>o)FUXG&i*7y*zd+bl1IIParh)$RHy_5(RY!0&(dyJ-O}AEOhMmLTf-Y iwltW3Z>4_@{ABlL;hoWkY{zdO3*_N;7R_$Q&Vw|RH|#|{o{Slx$hs(IL|rHAJ6AJ-{)a^x*w1QQ~?kOB#iWjVXhM6u_NWq3Gqz7&mO@_l7^TAoFya#(H7SkYBx7Xqi=q9VG z7tr$mij-rqo@Dk(PEU7caqd6ybJUX}-M{!D>xfzHG1C=pZ0v~cqlS0Imo#KKQt2cC znSn=~a?P0R%<`(%EW0b6reR|B@`>)~+fA|Zu6x2gk$7#HtGAm5MMQErwt?q<<9y2p%*cXC2P$_z=$wP)mz?U2`Iuj7YF zy-sY*-~*iYvJxxE$sWbET7LH?eU$!Kg%J)9wT(=k%#tCGXmpnK4qRh=)Cb61HM`DC zmVQy7zX8`F;qJYDrr*t(vFy20Ny_=QY&p*xT8$4K^E2`kihD`jSJc)Jr1?}=Qewop z(%woK!7M8FmY7^A@QW~;SLuYYj=?vq76NCgBCnvQWByHs#@29 z-np}8niz*}iAkeUL8*(WebD+jw7efD&?A@rF->!jUV+(zG(;Vf!QDUfWan=Xdtjl( z!*BeQs6g#U@8PR`g%mZ)JKZFH9TLN2+lyymG&ghBhtgZrNgK_byGGc4N*n62l9!|R ze>R-^&eoy16(@a){HDyEq>eQ-^KtCjUnN`BVa$bRo68H*uIjS0_4|XX+Z$XXmOiw^ z>l9habGkauY~r68d-)V%0zFkW3eH3J{mK)_Q?i3mr><2%p5&S44LL5+M|+sphn{w& z3=cS5pVrA-o6Yqx@3*1&Tdo+-cfp~`cGRsQB_t%kU@!y%fkL4$7!2tM=}b#1kPRRM z5FBb2R`WJ28cYL80IBvU>^55aE!d3)DRY6)R@BTZdp4% zJ-jN51QrahH_OoCs-r3Iw;A9)?p(|j12m#qyS`G(Sm8)o8; zzf0{hw2Y1U-zHGReF`i3@-a1*?<>O^xJo|APnYy}0}@tx5JehD9S**PqssjcDZ5Pl zYS0$EQ0e_xER|{uA+#%lA$@lKH1``YBo|YM3BZEqcAU7crirqS*G9JZ&)exW>0y6eUS~?#U?ZPkdxRNU^T?<7xGYAp=kN z$aY$Y{_%zl>&*@pN5h7QEVSg#XWOt^Ee)4!UU)L>cfnRns@`2SH(@uY&?TMA)DNi{ z&lkl3Ln_6`i#`lAWrf2-xV*N8GoD8;Sn zv^ecAN-;fe00r06W_sxskv}ePPc!bSf@>uOXTI=JnRRwoQtS@>?6SnZ=GQ7%-^rN> ze|0c@xAg?)Yy*=D+TuJj$o?0!|FVyC4Up7>KpkD6zqUC8RSWKhA^kPL=&1jB<(a|EIrxU%;RKh+6PGa~Y3q3I= zG>w5jIZM8DV{Kj#KSYt#8}q#Q>&bGQ*%-RQP3PQE`t^8yFUDc!0loBG(Q`tM7Qahl z#3ZJsk?=gYPAr66=zl2||6z`3UU$=`@T5iX875PZRgIm_*olKHZue#MCO{( z%<+?B%3NVd($$l;+PtPKQJAMLaI&RyILl)1E04>#NsE-bQv8|n2@P7WoTRV}CdB9- zaOYTvosZpvtqR>~A!oL?t8-UMdA$0DVYYcbqIzil z;b5G^qa!F_(QB6tJ{}Pp{2<uUl2Fe#&l(S)C~BbKj-LX=qAE%OM>l7bswSvNi69m%NE1AM;7ruMEL9$v$@Blyp{4WV@9UCubKdJ{#pyH_1 x`g9}`iQN(r+FwQjJdUcx>3Tw8|B=v--)<<~%I2c8%eS5~$jROv&&K(u{R4a~n3ezl literal 0 HcmV?d00001 diff --git a/apps/alarm/screenshot-11.png b/apps/alarm/screenshot-11.png new file mode 100644 index 0000000000000000000000000000000000000000..197c8419449afd37afa1482a31903d8975e2afd5 GIT binary patch literal 2326 zcmZvedpHw}7suV3HLTa%!fd2Ql)IS3$o=PD$#RKYD|=nCScI&Z+bEP~6w4*%-NPvZfCLKu4NFN!KI%^0NG=vJ% zGNs_hl$R*cwP!)x%uUsJb67xvxX4R2c~;sfi?6;QsCvtKUlS81sIZV=9=UHvOt}ib zMJN#V&~+U+c0O9}o6DH-$81yw%;!q{<^x&b_UMDf8*>>OFC&y=XCK*G(F9{0wZwA2 zqB4mxyTckrq^O7cMDz_}0#e#;eg?lY0acmjn4k_oT8#bptfCkmhgUNH2t^IIlEOK< zn|xfW$jQ4O7*UBBdZe~Tgho7!Rk`96BW1pzh-Tm4dF=aGGn#MnSmcES1TMf7HtS9E$Xp5%BpZF z1m{)?YQXeKFxG12CR+h;?_@Zs=;(JfVO_?aE3#o(#CWIkY2t>2O65Y`K3#uJlh2)U8=ey; zClrm+w4`z;iB06&UG_(Ci5Q$%LH!lUefIB`>sBwjK*8X~<@yZ2LZRo1@}cAAS=z11 z#wYeoD7~`#4wgfcJFfsbZ6DM!o^znrwugQtrTR5O-d=(@+=z;jJw}~|5Kwf-831G{&waAD@Lnh z&w=d~^_@|xRyoZGp*R zg;#ZqT!!8sT**+7CQ9O6>j+@fk~DUEtjLTyQoo(kd>cxcwo`A7T(!GgyukJe_DOV< zCmHNb8>oXT?VzpdFVwjm$6eH3md5zS+pyCo-q!vge^Bgq58tvuCvJuw8(dT>#pdO9 z9=yHYl~h8NX2gCU7_I#=o?t$;QnIs^wzk%(RLZSrx=?~L>+4gYcw9#=S(UC?c+Sf@ zz6E^FjqR}lElqb1VM)Bi@WxX?QqG*_)9^Y5acqZJU~|J#j#Nf2tkPoIX&9p&6(aK@ zdpFeFKtUrg0^bZovK$I0MOrO(_m!~r@_IayaV z^?jcEAwzh}8`EZvb2L%>Rk*$aXqV!e|D{e*pdi8(;Dr#$N&b^I0CvN$++Y7b7$)5P zR|-f(PaKj2aT`_L^y020kj zS)r%CZQ~8C`<8*L<5lA-8_`T|n8rFHHSYpFLzgb91*H}v#FK}Hv4>O1U}6yP)Ax!f zZ)3Imsuj`@rfd)UP-L6;!YJhVnZ~K(z&9R3Li0WYT>Gm!q)TA$IJ0myYtuVSXa&UOHv!_Zv z+wOZ){X;K@?J}7Ze|~H7)jTFL3d1NSLpjCmtq$CA5}tplrkSQKH|TNsizP{q|?Z}0n_~Q{7d}S0;J32#Ww7MUIAMI(SD1$*Z{$8RzphfUD45K56QOFRO>aR zI!%Shl*&iPhE^ox!QUWlT+QgsR2B<8_vD^WkmCG3P%EXdEy!Pe-1watPG=-QNT@}) z#zUMu_B+q~3tnM-5*{U>P@^kK7Q_oEcol&EXAe;T4(Q7+^c66@(AffRA@+X*0Kj&4 zcxTcIMehecoyreN6!1gPXzLy zZNnAi-;Okf_V)qZf@dFP6;*;|F|1ietagGt(gt^(Ngw^k<1A)$YbYqDKal7BLnk(K zZJX<_vG)Bl@SC!dgZk?-vbIN$sk}_-SnaU|*y?OP&@IyhX%O|=5BV_6vfH!FJ@|>w zYg!E5$AjUpZd90ccM~l(QgyAY!!$n$wWBkDmcux;4nX}W4mwhQK>7_9A)*BldgY&` z!2#{M`O~^on6RLrUXIn%U>HF_;VvPmH%163sQ2610k9PnyA=y_MOE)>yZ?@W{Yhu* JT9kjve*rl9J~{vZ literal 0 HcmV?d00001 diff --git a/apps/alarm/screenshot-2.png b/apps/alarm/screenshot-2.png new file mode 100644 index 0000000000000000000000000000000000000000..1cbc255a92c2d568765feb3cbf104f10a33d013b GIT binary patch literal 1451 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 L+7UxXdnWuB4r*zu literal 0 HcmV?d00001 diff --git a/apps/alarm/screenshot-4.png b/apps/alarm/screenshot-4.png new file mode 100644 index 0000000000000000000000000000000000000000..7fd7e99b65434752c2a7886124ee704c2ce3b8f1 GIT binary patch literal 2053 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 T$r{bO?_J0eXJcMvcJ20G*^k@2 literal 0 HcmV?d00001 diff --git a/apps/alarm/screenshot-5.png b/apps/alarm/screenshot-5.png new file mode 100644 index 0000000000000000000000000000000000000000..4174c5670eb9800beb19a71ca3e1acc8f58132a6 GIT binary patch literal 1948 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 literal 0 HcmV?d00001 diff --git a/apps/alarm/screenshot-7.png b/apps/alarm/screenshot-7.png new file mode 100644 index 0000000000000000000000000000000000000000..49da44710d70b2d5882b399dffade0827a9ed76e GIT binary patch literal 2144 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 Ug0Ds8;B(+HH?cy|khjAA0;8-7=l}o! literal 0 HcmV?d00001 diff --git a/apps/alarm/screenshot-8.png b/apps/alarm/screenshot-8.png new file mode 100644 index 0000000000000000000000000000000000000000..86d69cd93ca3141b1b3c47cab200e5a4bcfc129a GIT binary patch literal 2360 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 literal 0 HcmV?d00001 diff --git a/apps/alarm/screenshot-9.png b/apps/alarm/screenshot-9.png new file mode 100644 index 0000000000000000000000000000000000000000..2d8c7fc83045f4ce09531eec84c155eb314406e6 GIT binary patch literal 2274 zcmV<82p#u{P)V{QoaA4|X8|62cv=vmdgm1p_D?kk(k|oRP8C7-Ndrz{#j@qRn@R>wFG$ zjz`dR6O#@hdr^1<^U#j-j+^*tbX1!ejH7Vj`)=Y#NNaEhW^)Z`_QH4H#838UvpcW= zwoi<>i60>wIF^D=bnq!ScCNgJfk;flTJ_aU^Kthsd;EL4s1W`%JWyz^k@kt|htG6i^EZ^~5aGHALzNtc81~sL+WhQ|X-VzrTBKIrL){*2cr0T>B9>5lMCWy^p`g0;x#kx+zyf6Cu^;>k6*Y%^?ygBE+$SH z*-?A_$&Isz@}@?q6hhO~cZ?4(eGQS~yAC(;hsWhPJ4*F`Mw66W0ilL%WZe#I^;A?H zV%O*wuH7|fS6$`kTz@3I2hO?v1%Xgu&FRHfH&;xP{Zn zA;3JasGP!cpEx!wD)smoJ)5+?K1#AvmA;GYZS~QMO0MXWH-d)jnQmZ-jcWC94qcl4ATy+^0jwba0UhE94v`0Q_{P**IeDuMYY0HVlmQ6n5P*OV z0SK86VPSvFhG0<%2t*-H=&i7Obpi?j2v7)ECwbN>9%S}8!&L9h@*eJ+ z?a${uaIKJA_jIeo-w`AFsZ$95XF4d0qq9Flv3gJlj#Q_|D1`ay1lL35bLBi551LT| zg^0NCSNMGxc%Qu+7_Jz3Z7`yrCn>}b5AU;tOGLk^Qd9!Q&p3rhb{(u?cP#WC!n4wS3w<4g z`aj)9+}B5Z9A)ov!#;$NqzuMT}5e0uZoPSgH0Aze6iZLq-mEro?fpBxcMYL0Zr(EGHERg&d8#UA#^yCd z?HnnW+g693x}9L}CM=6n*)W$!$MybeJs9S9n};V_!kRdh#qkt9@n`xk6NA#P68vhR z)`PE4TOGo6%tLL&eFf&lsf@}q%nZ~PK~heQ%4#d3wv=ZvcBhg&c3SiI1Sr_cQ$E$X z>~SNWE2mbJ-du;TW)w?5)3(9+!5dTWdCI6_*i**K?EO%>yC%&RaVp!XdLsW#eoGf%&(q*nCJt@eaEG}`rXDxnZ3v*F9Fp46v|&J*g;Q}bFDDMZ>^v$1AUe1w;5lI)@C z^YCIG%_r(dg`qiDA?}M3#CIa`7!)y}ggBLX58;fM^RLMhwj%wyE2;x`HRP+bT_Mtz z=IcL7Ar{1d>W^gAJibp3RHadfRKlk#1eeD!zgK$Dv_(EwUxxz~!qvp7RK=KzQmwUV zD(As4zgKz?+LABjify;OuV zCL28?tu0%JU@0KfLGZ9wA+9T6X)E$0gz;0ehWM_}z0LN!vLEKSoZ2%_YdrMVp{;KH z_AYu^oXR`HcX&Exq-y$dxsUT_X-aAH&|inPx{XzcMR6*>K3se}>=UI(l<|H*>R&8f z@Nmbt^uH=S6kAd7Ag Date: Fri, 13 May 2022 15:04:46 +0200 Subject: [PATCH 041/294] [Alarms & Timers] Update README --- apps/alarm/README.md | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/apps/alarm/README.md b/apps/alarm/README.md index e979dbaf1..741946b0c 100644 --- a/apps/alarm/README.md +++ b/apps/alarm/README.md @@ -1,7 +1,31 @@ -Alarms & Timers -=============== +# Alarms & Timers This app allows you to add/modify any alarms and timers. -It uses the [`sched` library](https://github.com/espruino/BangleApps/blob/master/apps/sched) -to handle the alarm scheduling in an efficient way that can work alongside other apps. +It uses the [`sched` library](https://github.com/espruino/BangleApps/blob/master/apps/sched) to handle the alarm scheduling in an efficient way that can work alongside other apps. + +## Menu overview + +- `New...` + - `New Alarm` → Configure a new alarm + - `Repeat` → Select when the alarm will fire. You can select a predefined option (_Once_, _Every Day_, _Workdays_ or _Weekends_ or you can configure the days freely) + - `New Timer` → Configure a new timer +- `Advanced` + - `Scheduler settings` → Open the [Scheduler](https://github.com/espruino/BangleApps/tree/master/apps/sched) settings page, see its [README](https://github.com/espruino/BangleApps/blob/master/apps/sched/README.md) for details + - `Enable All` → Enable _all_ disabled alarms & timers + - `Disable All` → Disable _all_ enabled alarms & timers + - `Delete All` → Delete _all_ alarms & timers + +## Creator + +- [Gordon Williams](https://github.com/gfwilliams) + +## Main Contributors + +- [Alessandro Cocco](https://github.com/alessandrococco) - New UI, full rewrite, new features +- [Sabin Iacob](https://github.com/m0n5t3r) - Auto snooze support +- [storm64](https://github.com/storm64) - Fix redrawing in submenus + +## Attributions + +All icons used in this app are from [icons8](https://icons8.com). From 229d0dc1580b423385a1a82c809233094dcee889 Mon Sep 17 00:00:00 2001 From: kirktrekkie Date: Sat, 14 May 2022 10:05:42 +0200 Subject: [PATCH 042/294] Adding Dice-n-Roll app. --- apps/diceroll/ChangeLog | 1 + apps/diceroll/app-icon.js | 1 + apps/diceroll/app.js | 108 ++++++++++++++++++++++++++ apps/diceroll/app.png | Bin 0 -> 637 bytes apps/diceroll/diceroll_screenshot.png | Bin 0 -> 2408 bytes apps/diceroll/metadata.json | 14 ++++ 6 files changed, 124 insertions(+) create mode 100644 apps/diceroll/ChangeLog create mode 100644 apps/diceroll/app-icon.js create mode 100644 apps/diceroll/app.js create mode 100644 apps/diceroll/app.png create mode 100644 apps/diceroll/diceroll_screenshot.png create mode 100644 apps/diceroll/metadata.json diff --git a/apps/diceroll/ChangeLog b/apps/diceroll/ChangeLog new file mode 100644 index 000000000..89dff4011 --- /dev/null +++ b/apps/diceroll/ChangeLog @@ -0,0 +1 @@ +0.01: App created \ No newline at end of file diff --git a/apps/diceroll/app-icon.js b/apps/diceroll/app-icon.js new file mode 100644 index 000000000..4d6e7da16 --- /dev/null +++ b/apps/diceroll/app-icon.js @@ -0,0 +1 @@ +E.toArrayBuffer(atob("ICABAAAAAAAAAAAAAAAAAAHAAAAP8AAAfn4AA/APwA+DwfAPg8HwD+AH8Az4HzAMPnwwDAfgMAwBgDAMCYAwDA2YMAwhmDAMIZAwDCGDMA2BgzAMgYAwDAGAMA8BgPADwYPAAPGPgAB9ngAAH/gAAAfgAAABgAAAAAAAAAAAAAAAAAA=")) diff --git a/apps/diceroll/app.js b/apps/diceroll/app.js new file mode 100644 index 000000000..d514ce92f --- /dev/null +++ b/apps/diceroll/app.js @@ -0,0 +1,108 @@ +var init_message = true; +var acc_data; +var die_roll = 1; +var selected_die = 0; +var roll = 0; +const dices = [4, 6, 10, 12, 20]; + +g.setFontAlign(0,0); + +Bangle.on('touch', function(button, xy) { + // Change die if not rolling + if(roll < 1){ + if(selected_die <= 3){ + selected_die++; + }else{ + selected_die = 0; + } + } + //Disable initial message + init_message = false; +}); + +function rect(){ + x1 = g.getWidth()/2 - 35; + x2 = g.getWidth()/2 + 35; + y1 = g.getHeight()/2 - 35; + y2 = g.getHeight()/2 + 35; + g.drawRect(x1, y1, x2, y2); +} + +function pentagon(){ + x1 = g.getWidth()/2; + y1 = g.getHeight()/2 - 50; + x2 = g.getWidth()/2 - 50; + y2 = g.getHeight()/2 - 10; + x3 = g.getWidth()/2 - 30; + y3 = g.getHeight()/2 + 30; + x4 = g.getWidth()/2 + 30; + y4 = g.getHeight()/2 + 30; + x5 = g.getWidth()/2 + 50; + y5 = g.getHeight()/2 - 10; + g.drawPoly([x1, y1, x2, y2, x3, y3, x4, y4, x5, y5], true); +} + +function triangle(){ + x1 = g.getWidth()/2; + y1 = g.getHeight()/2 - 57; + x2 = g.getWidth()/2 - 50; + y2 = g.getHeight()/2 + 23; + x3 = g.getWidth()/2 + 50; + y3 = g.getHeight()/2 + 23; + g.drawPoly([x1, y1, x2, y2, x3, y3], true); +} + +function drawDie(variant) { + if(variant == 1){ + //Rect, 6 + rect(); + }else if(variant == 3){ + //Pentagon, 12 + pentagon(); + }else{ + //Triangle, 4, 10, 20 + triangle(); + } +} + +function initMessage(){ + g.setFont("6x8", 2); + g.drawString("Dice-n-Roll", g.getWidth()/2, 20); + g.drawString("Shake to roll", g.getWidth()/2, 60); + g.drawString("Tap to change", g.getWidth()/2, 80); + g.drawString("Tap to start", g.getWidth()/2, 150); +} + +function rollDie(){ + acc_data = Bangle.getAccel(); + if(acc_data.diff > 0.3){ + roll = 3; + } + //Mange the die "roll" by chaning the number a few times + if(roll > 0){ + g.drawString("Rolling!", g.getWidth()/2, 150); + die_roll = Math.abs(E.hwRand()) % dices[selected_die] + 1; + roll--; + } + //Draw dice graphics + drawDie(selected_die); + //Draw dice number + g.setFontAlign(0,0); + g.setFont("Vector", 45); + g.drawString(die_roll, g.getWidth()/2, g.getHeight()/2); + //Draw selected die in right corner + g.setFont("6x8", 2); + g.drawString(dices[selected_die], g.getWidth()-15, 15); +} + +function main() { + g.clear(); + if(init_message){ + initMessage(); + }else{ + rollDie(); + } + Bangle.setLCDPower(1); +} + +var interval = setInterval(main, 300); \ No newline at end of file diff --git a/apps/diceroll/app.png b/apps/diceroll/app.png new file mode 100644 index 0000000000000000000000000000000000000000..b695b7080ae9fb84e30140aa653c221fc2c7aecd GIT binary patch literal 637 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 LA>Lvy%K3i-A)as# literal 0 HcmV?d00001 diff --git a/apps/diceroll/metadata.json b/apps/diceroll/metadata.json new file mode 100644 index 000000000..81a2f8bfd --- /dev/null +++ b/apps/diceroll/metadata.json @@ -0,0 +1,14 @@ +{ "id": "diceroll", + "name": "Dice-n-Roll", + "shortName":"Dice-n-Roll", + "icon": "app.png", + "version":"0.01", + "description": "A dice app with a few different dice.", + "screenshots": [{"url":"diceroll_screenshot.png"}], + "tags": "game", + "supports": ["BANGLEJS2"], + "storage": [ + {"name":"diceroll.app.js","url":"app.js"}, + {"name":"diceroll.img","url":"app-icon.js","evaluate":true} + ] + } \ No newline at end of file From 71ebe9bca52239b4e8a1820c9c59d12f3909bcc1 Mon Sep 17 00:00:00 2001 From: Iakov Davydov Date: Sat, 14 May 2022 10:38:37 +0200 Subject: [PATCH 043/294] widbt: option to hide when no connection --- apps/widbt/ChangeLog | 1 + apps/widbt/app-icon.js | 1 + apps/widbt/metadata.json | 9 ++++++--- apps/widbt/settings.js | 22 ++++++++++++++++++++++ apps/widbt/widget.js | 24 ++++++++++++++++++++---- 5 files changed, 50 insertions(+), 7 deletions(-) create mode 100644 apps/widbt/app-icon.js create mode 100644 apps/widbt/settings.js diff --git a/apps/widbt/ChangeLog b/apps/widbt/ChangeLog index 4c2132122..55bdf4730 100644 --- a/apps/widbt/ChangeLog +++ b/apps/widbt/ChangeLog @@ -5,3 +5,4 @@ 0.06: Tweaking colors for dark/light themes and low bpp screens 0.07: Memory usage improvements 0.08: Disable LCD on, on bluetooth status change +0.09: Hide widget when disconnected (a setting) diff --git a/apps/widbt/app-icon.js b/apps/widbt/app-icon.js new file mode 100644 index 000000000..131db3a39 --- /dev/null +++ b/apps/widbt/app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwwMB/4AG/YFE/IFE/AFFv4FEn4FEj4FEg4FEgYFEHIn4oAFEsAqD/FwFQXx/F4h4FB+H4vgwC+F4vARC/E4uAdC/kYsAiC/0IoIvDgBBEwBNE4AuCAAPgL4nwNYgFFCIodFFIo1EIIpNFLIplF8BxEPoQFC/aJESo6hFVoq5FYorRFborpFeon5Aon7AogADA=")) diff --git a/apps/widbt/metadata.json b/apps/widbt/metadata.json index e2d5082a5..098d6a37e 100644 --- a/apps/widbt/metadata.json +++ b/apps/widbt/metadata.json @@ -1,13 +1,16 @@ { "id": "widbt", "name": "Bluetooth Widget", - "version": "0.08", + "version": "0.09", "description": "Show the current Bluetooth connection status in the top right of the clock", "icon": "widget.png", "type": "widget", "tags": "widget,bluetooth", "supports": ["BANGLEJS","BANGLEJS2"], "storage": [ - {"name":"widbt.wid.js","url":"widget.js"} - ] + {"name":"widbt.wid.js","url":"widget.js"}, + {"name":"widbt.settings.js","url":"settings.js"}, + {"name":"widbt.img","url":"app-icon.js","evaluate":true} + ], + "data": [{"name":"widbt.json"}] } diff --git a/apps/widbt/settings.js b/apps/widbt/settings.js new file mode 100644 index 000000000..0400a2eec --- /dev/null +++ b/apps/widbt/settings.js @@ -0,0 +1,22 @@ +(function(back) { + var FILE = "widbt.json"; + var settings = require('Storage').readJSON(FILE, true) || {}; + + function writeSettings() { + require('Storage').writeJSON(FILE, settings); + } + + E.showMenu({ + "" : { "title" : "Bluetooth Widget" }, + "< Back" : () => back(), + 'No conn. widget': { + value: !!settings.hideDisconnected, + format: v => v?"Hide":"Show", + onchange: v => { + settings.hideDisconnected = v; + writeSettings(); + if (WIDGETS.bluetooth) WIDGETS.bluetooth.changed(); + } + }, + }); +}) diff --git a/apps/widbt/widget.js b/apps/widbt/widget.js index c7ef8c0ad..24779c29d 100644 --- a/apps/widbt/widget.js +++ b/apps/widbt/widget.js @@ -1,12 +1,28 @@ -WIDGETS["bluetooth"]={area:"tr",width:15,draw:function() { +WIDGETS["bluetooth"]={area:"tr",draw:function() { + if (WIDGETS.bluetooth.width==0) + return; g.reset(); if (NRF.getSecurityStatus().connected) g.setColor((g.getBPP()>8) ? "#07f" : (g.theme.dark ? "#0ff" : "#00f")); else g.setColor(g.theme.dark ? "#666" : "#999"); g.drawImage(atob("CxQBBgDgFgJgR4jZMawfAcA4D4NYybEYIwTAsBwDAA=="),2+this.x,2+this.y); +},getWidth:function(){ + if (!NRF.getSecurityStatus().connected) { + const settings = require('Storage').readJSON("widbt.json", true) || {}; + if (settings.hideDisconnected) + return 0; + } + return 15; },changed:function() { - WIDGETS["bluetooth"].draw(); + const newWidth = WIDGETS.bluetooth.getWidth(); + if (WIDGETS.bluetooth.width != newWidth) { + WIDGETS.bluetooth.width = newWidth; + Bangle.drawWidgets(); + } else { + WIDGETS.bluetooth.draw(); + } }}; -NRF.on('connect',WIDGETS["bluetooth"].changed); -NRF.on('disconnect',WIDGETS["bluetooth"].changed); +WIDGETS.bluetooth.width = WIDGETS.bluetooth.getWidth(); +NRF.on('connect',WIDGETS.bluetooth.changed); +NRF.on('disconnect',WIDGETS.bluetooth.changed); From 6c88688a5011b76f278e2509091dcb8b550aca2a Mon Sep 17 00:00:00 2001 From: frigis1 <63980066+frigis1@users.noreply.github.com> Date: Sat, 14 May 2022 11:23:22 -0700 Subject: [PATCH 044/294] Create app.js --- apps/multitimer/app.js | 660 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 660 insertions(+) create mode 100644 apps/multitimer/app.js diff --git a/apps/multitimer/app.js b/apps/multitimer/app.js new file mode 100644 index 000000000..caf2637f0 --- /dev/null +++ b/apps/multitimer/app.js @@ -0,0 +1,660 @@ +Bangle.loadWidgets(); +Bangle.drawWidgets(); + +var R = Bangle.appRect; +var layer; +var drag; +var timerInt1 = []; +var timerInt2 = []; + +function getCurrentTime() { + let time = new Date(); + return ( + time.getHours() * 3600000 + + time.getMinutes() * 60000 + + time.getSeconds() * 1000 + ); +} + +function decodeTime(t) { + let hrs = 0 | Math.floor(t / 3600000 % 24); + let mins = 0 | Math.floor(t / 60000 % 60); + let secs = 0 | Math.floor(t / 1000 % 60); + return { hrs: hrs, mins: mins, secs: secs }; +} + +function encodeTime(o) { + return o.hrs * 3600000 + o.mins * 60000 + o.secs * 1000; +} + +function formatTime(t) { + let o = decodeTime(t); + return o.hrs + ":" + ("0" + o.mins).substr(-2) + ":" + ("0" + o.secs).substr(-2); +} + +function decodeTimeDecis(t) { + let hrs = 0 | Math.floor(t / 3600000 % 24); + let mins = 0 | Math.floor(t / 60000 % 60); + let secs = 0 | Math.floor(t / 1000 % 60); + let decis = 0 | Math.floor(t / 100 % 100); + return { hrs: hrs, mins: mins, secs: secs, decis: decis }; +} + +function formatTimeDecis(t) { + let o = decodeTimeDecis(t); + return o.hrs + ":" + ("0" + o.mins).substr(-2) + ":" + ("0" + o.secs).substr(-2) + "." + ("0" + o.decis).substr(-1); +} + +function clearInt() { + for (let i = 0; i < timerInt1.length; i++) { + if (timerInt1[i]) clearTimeout(timerInt1[i]); + } + for (let i = 0; i < timerInt2.length; i++) { + if (timerInt2[i]) clearInterval(timerInt2[i]); + } + timerInt1 = []; + timerInt2 = []; +} + +function drawTimers() { + layer = 0; + var timers = require("sched").getAlarms().filter(a => a.timer && a.appid == "multitimer"); + var alarms = require("sched").getAlarms(); + + function updateTimers(idx) { + if (!timerInt1[idx]) timerInt1[idx] = setTimeout(function() { + s.drawItem(idx+1); + if (!timerInt2[idx]) timerInt2[idx] = setInterval(function(){ + s.drawItem(idx+1); + }, 1000); + }, 1000 - (timers[idx].t % 1000)); + } + + var s = E.showScroller({ + h : 40, c : timers.length+2, + back : function() {load();}, + draw : (idx, r) => { + function drawMenuItem(a) { + g.setClipRect(R.x,R.y,R.x2,R.y2); + if (idx > 0 && timers[idx-1].msg) msg = "\n"+(timers[idx-1].msg.length > 10 ? + timers[idx-1].msg.substring(0, 10)+"..." : timers[idx-1].msg); + else msg = ""; + return g.setColor(g.theme.bg2).fillRect({x:r.x+4,y:r.y+2,w:r.w-8, h:r.h-4, r:5}) + .setColor(g.theme.fg2).setFont("6x8:2").setFontAlign(-1,0).drawString(a+msg,r.x+12,r.y+(r.h/2)); + } + + if (idx == 0) { + drawMenuItem("+ New Timer"); + } + if (idx == timers.length+1) { + g.setColor(g.theme.bg).fillRect({x:r.x+4,y:r.y+2,w:r.w-8, h:r.h-4, r:5}) + .setColor(g.theme.fg).setFont("6x8:2").setFontAlign(0,0).drawString("< Swipe >",r.x+(r.w/2),r.y+(r.h/2)); + } + else if (idx > 0 && idx < timers.length+1) { + if (timers[idx-1].on == true) { + drawMenuItem(formatTime(timers[idx-1].t-getCurrentTime())); + updateTimers(idx-1); + } + else drawMenuItem(formatTime(timers[idx-1].timer)); + } + }, + select : (idx) => { + clearInt(); + if (idx == 0) editTimer(-1); + else if (idx > 0 && idx < timers.length+1) timerMenu(idx-1); + } + }); +} + +function timerMenu(idx) { + layer = -1; + var timers = require("sched").getAlarms(); + var timerIdx = []; + var j = 0; + for (let i = 0; i < timers.length; i++) { + if (timers[i].timer && timers[i].appid == "multitimer") { + a = i; + timerIdx.push(a); + j++; + } + } + var a = timers[timerIdx[idx]]; + var msg = ""; + + function updateTimer() { + if (timerInt1[0] == undefined) timerInt1[0] = setTimeout(function() { + s.drawItem(0); + if (timerInt2[0] == undefined) timerInt2[0] = setInterval(function(){ + s.drawItem(0); + }, 1000); + }, 1000 - (a.t % 1000)); + } + + var s = E.showScroller({ + h : 40, c : 5, + back : function() { + clearInt(); + drawTimers(); + }, + draw : (i, r) => { + + function drawMenuItem(b) { + return g.setClipRect(R.x,R.y,R.x2,R.y2).setColor(g.theme.bg2) + .fillRect({x:r.x+4,y:r.y+2,w:r.w-8, h:r.h-4, r:5}) + .setColor(g.theme.fg2).setFont("6x8:2").setFontAlign(-1,0).drawString(b,r.x+12,r.y+(r.h/2)); + } + + if (i == 0) { + if (a.msg) msg = "\n"+(a.msg.length > 10 ? a.msg.substring(0, 10)+"..." : a.msg); + if (a.on == true) { + drawMenuItem(formatTime(a.t-getCurrentTime())+msg); + updateTimer(); + } + else { + clearInt(); + drawMenuItem(formatTime(a.timer)+msg); + } + } + if (i == 1) { + if (a.on == true) drawMenuItem("Pause"); + else drawMenuItem("Start"); + } + if (i == 2) drawMenuItem("Reset"); + if (i == 3) drawMenuItem("Edit"); + if (i == 4) drawMenuItem("Delete"); + }, + select : (i) => { + + function saveAndReload() { + require("sched").setAlarms(timers); + require("sched").reload(); + s.draw(); + } + + //pause/start + if (i == 1) { + if (a.on == true) { + clearInt(); + a.timer = a.t-getCurrentTime(); + a.on = false; + timers[timerIdx[idx]] = a; + saveAndReload(); + } + else { + a.t = a.timer+getCurrentTime(); + a.on = true; + timers[timerIdx[idx]] = a; + saveAndReload(); + } + } + //reset + if (i == 2) { + clearInt(); + a.timer = a.data; + if (a.on == true) a.on = false; + saveAndReload(); + } + //edit + if (i == 3) { + clearInt(); + editTimer(idx); + } + //delete + if (i == 4) { + clearInt(); + timers.splice(timerIdx[idx], 1); + saveAndReload(); + drawTimers(); + } + } + }); +} + +function editTimer(idx, a) { + layer = -1; + var timers = require("sched").getAlarms().filter(a => a.timer && a.appid == "multitimer"); + var alarms = require("sched").getAlarms(); + var timerIdx = []; + var j = 0; + for (let i = 0; i < alarms.length; i++) { + if (alarms[i].timer && alarms[i].appid == "multitimer") { + b = i; + timerIdx.push(b); + j++; + } + } + if (!a) { + if (idx < 0) a = require("sched").newDefaultTimer(); + else a = timers[idx]; + } + var t = decodeTime(a.timer); + + function editMsg(idx, a) { + g.clear(); + idx < 0 ? msg = "" : msg = a.msg; + require("textinput").input({text:msg}).then(result => { + if (result != "") { + a.msg = result; + } + else delete a.msg; + editTimer(idx, a); + }); + } + + function kbAlert() { + E.showAlert("Must install keyboard app").then(function() { + editTimer(idx, a); + }); + } + + var menu = { + "": { "title": "Timer" }, + "< Back": () => { + a.t = getCurrentTime() + a.timer; + a.last = 0; + a.data = a.timer; + a.appid = "multitimer"; + a.js = "load('multitimer.alarm.js')"; + if (idx < 0) alarms.push(a); + else alarms[timerIdx[idx]] = a; + require("sched").setAlarms(alarms); + require("sched").reload(); + drawTimers(); + }, + "Enabled": { + value: a.on, + format: v => v ? "On" : "Off", + onchange: v => a.on = v + }, + "Hours": { + value: t.hrs, min: 0, max: 23, wrap: true, + onchange: v => { + t.hrs = v; + a.timer = encodeTime(t); + } + }, + "Minutes": { + value: t.mins, min: 0, max: 59, wrap: true, + onchange: v => { + t.mins = v; + a.timer = encodeTime(t); + } + }, + "Seconds": { + value: t.secs, min: 0, max: 59, wrap: true, + onchange: v => { + t.secs = v; + a.timer = encodeTime(t); + } + }, + "Vibrate": require("buzz_menu").pattern(a.vibrate, v => a.vibrate = v), + "Msg": { + value: !a.msg ? "" : a.msg.length > 6 ? a.msg.substring(0, 6)+"..." : a.msg, + //menu glitch? setTimeout required here + onchange: () => { + var kbapp = require("Storage").read("textinput"); + if (kbapp != undefined) setTimeout(editMsg, 0, idx, a); + else setTimeout(kbAlert, 0); + } + }, + "Cancel": () => { + if (idx >= 0) timerMenu(idx); + else drawTimers(); + }, + }; + + E.showMenu(menu); +} + +function drawSw() { + layer = 1; + var sw = require("Storage").readJSON("multitimer.json", true) || []; + + function updateTimers(idx) { + if (!timerInt1[idx]) timerInt1[idx] = setTimeout(function() { + s.drawItem(idx+1); + if (!timerInt2[idx]) timerInt2[idx] = setInterval(function(){ + s.drawItem(idx+1); + }, 1000); + }, 1000 - (sw[idx].t % 1000)); + } + + var s = E.showScroller({ + h : 40, c : sw.length+2, + back : function() {load();}, + draw : (idx, r) => { + + function drawMenuItem(a) { + g.setClipRect(R.x,R.y,R.x2,R.y2); + if (idx > 0 && sw[idx-1].msg) msg = "\n"+(sw[idx-1].msg.length > 10 ? + sw[idx-1].msg.substring(0, 10)+"..." : sw[idx-1].msg); + else msg = ""; + return g.setColor(g.theme.bg2).fillRect({x:r.x+4,y:r.y+2,w:r.w-8, h:r.h-4, r:5}) + .setColor(g.theme.fg2).setFont("6x8:2").setFontAlign(-1,0).drawString(a+msg,r.x+12,r.y+(r.h/2)); + } + + if (idx == 0) { + drawMenuItem("+ New Chrono"); + } + if (idx == sw.length+1) { + g.setColor(g.theme.bg).fillRect({x:r.x+4,y:r.y+2,w:r.w-8, h:r.h-4, r:5}) + .setColor(g.theme.fg).setFont("6x8:2").setFontAlign(0,0).drawString("< Swipe >",r.x+(r.w/2),r.y+(r.h/2)); + } + else if (idx > 0 && idx < sw.length+1) { + if (sw[idx-1].on == true) { + drawMenuItem(formatTime(Date.now()-sw[idx-1].t)); + updateTimers(idx-1); + } + else drawMenuItem(formatTime(sw[idx-1].t)); + } + }, + select : (idx) => { + clearInt(); + if (idx == 0) swMenu(sw.length); + else if (idx > 0 && idx < sw.length+1) swMenu(idx-1); + } + }); +} + +function swMenu(idx, a) { + layer = -1; + var sw = require("Storage").readJSON("multitimer.json", true) || []; + if (sw[idx]) a = sw[idx]; + else { + a = {"t" : 0, "on" : false, "msg" : ""}; + sw[idx] = a; + require("Storage").writeJSON("multitimer.json", sw); + } + + function updateTimer() { + if (timerInt1[0] == undefined) timerInt1[0] = setTimeout(function() { + s.drawItem(0); + if (timerInt2[0] == undefined) timerInt2[0] = setInterval(function(){ + s.drawItem(0); + }, 100); + }, 100 - (a.t % 100)); + } + + function editMsg(idx, a) { + g.clear(); + msg = a.msg; + require("textinput").input({text:msg}).then(result => { + if (result != "") { + a.msg = result; + } + else delete a.msg; + sw[idx] = a; + require("Storage").writeJSON("multitimer.json", sw); + swMenu(idx, a); + }); + } + + function kbAlert() { + E.showAlert("Must install keyboard app").then(function() { + swMenu(idx, a); + }); + } + + var s = E.showScroller({ + h : 40, c : 5, + back : function() { + clearInt(); + drawSw(); + }, + draw : (i, r) => { + + function drawMenuItem(b) { + return g.setClipRect(R.x,R.y,R.x2,R.y2).setColor(g.theme.bg2) + .fillRect({x:r.x+4,y:r.y+2,w:r.w-8, h:r.h-4, r:5}) + .setColor(g.theme.fg2).setFont("6x8:2").setFontAlign(-1,0).drawString(b,r.x+12,r.y+(r.h/2)); + } + + if (i == 0) { + if (a.msg) msg = "\n"+(a.msg.length > 10 ? a.msg.substring(0, 10)+"..." : a.msg); + else msg = ""; + if (a.on == true) { + drawMenuItem(formatTimeDecis(Date.now()-a.t)+msg); + updateTimer(); + } + else { + clearInt(); + drawMenuItem(formatTimeDecis(a.t)+msg); + } + } + if (i == 1) { + if (a.on == true) drawMenuItem("Pause"); + else drawMenuItem("Start"); + } + if (i == 2) drawMenuItem("Reset"); + if (i == 3) drawMenuItem("Msg"); + if (i == 4) drawMenuItem("Delete"); + }, + select : (i) => { + + function saveAndReload() { + require("Storage").writeJSON("multitimer.json", sw); + s.draw(); + } + + //pause/start + if (i == 1) { + if (a.on == true) { + clearInt(); + a.t = Date.now()-a.t; + a.on = false; + sw[idx] = a; + saveAndReload(); + } + else { + a.t == 0 ? a.t = Date.now() : a.t = Date.now()-a.t; + a.on = true; + sw[idx] = a; + saveAndReload(); + } + } + //reset + if (i == 2) { + clearInt(); + a.t = 0; + if (a.on == true) a.on = false; + saveAndReload(); + } + //edit message + if (i == 3) { + clearInt(); + var kbapp = require("Storage").read("textinput"); + if (kbapp != undefined) editMsg(idx, a); + else kbAlert(); + } + //delete + if (i == 4) { + clearInt(); + sw.splice(idx, 1); + saveAndReload(); + drawSw(); + } + } + }); +} + +function drawAlarms() { + layer = 2; + var alarms = require("sched").getAlarms().filter(a => !a.timer); + + var s = E.showScroller({ + h : 40, c : alarms.length+2, + back : function() {load();}, + draw : (idx, r) => { + + function drawMenuItem(a) { + g.setClipRect(R.x,R.y,R.x2,R.y2); + var on = ""; + var dow = ""; + if (idx > 0 && alarms[idx-1].on == true) on = " - on"; + else if (idx > 0 && alarms[idx-1].on == false) on = " - off"; + if (idx > 0 && idx < alarms.length+1) dow = "\n"+"SMTWTFS".split("").map((d,n)=>alarms[idx-1].dow&(1<",r.x+(r.w/2),r.y+(r.h/2)); + } + else if (idx > 0 && idx < alarms.length+1){ + var str = formatTime(alarms[idx-1].t); + drawMenuItem(str.slice(0, -3)); + } + }, + select : (idx) => { + clearInt(); + if (idx == 0) editAlarm(-1); + else if (idx > 0 && idx < alarms.length+1) editAlarm(idx-1); + } + }); +} + +function editDOW(dow, onchange) { + const menu = { + '': { 'title': 'Days of Week' }, + '< Back' : () => onchange(dow) + }; + for (var i = 0; i < 7; i++) (i => { + var dayOfWeek = require("locale").dow({ getDay: () => i }); + menu[dayOfWeek] = { + value: !!(dow&(1< v ? "Yes" : "No", + onchange: v => v ? dow |= 1<= 0) a = alarms[alarmIdx[idx]]; + else a = require("sched").newDefaultAlarm(); + } + var t = decodeTime(a.t); + + function editMsg(idx, a) { + g.clear(); + idx < 0 ? msg = "" : msg = a.msg; + require("textinput").input({text:msg}).then(result => { + if (result != "") { + a.msg = result; + } + else delete a.msg; + editAlarm(idx, a); + }); + } + + function kbAlert() { + E.showAlert("Must install keyboard app").then(function() { + editAlarm(idx, a); + }); + } + + var menu = { + "": { "title": "Alarm" }, + "< Back": () => { + if (idx >= 0) alarms[alarmIdx[idx]] = a; + else alarms.push(a); + require("sched").setAlarms(alarms); + require("sched").reload(); + drawAlarms(); + }, + "Enabled": { + value: a.on, + format: v => v ? "On" : "Off", + onchange: v => a.on = v + }, + "Hours": { + value: t.hrs, min: 0, max: 23, wrap: true, + onchange: v => { + t.hrs = v; + a.t = encodeTime(t); + } + }, + "Minutes": { + value: t.mins, min: 0, max: 59, wrap: true, + onchange: v => { + t.mins = v; + a.t = encodeTime(t); + } + }, + "Repeat": { + value: a.rp, + format: v => v ? "Yes" : "No", + onchange: v => a.rp = v + }, + "Days": { + value: "SMTWTFS".split("").map((d,n)=>a.dow&(1< editDOW(a.dow, d=>{a.dow=d;editAlarm(idx,a);}) + }, + "Vibrate": require("buzz_menu").pattern(a.vibrate, v => a.vibrate = v), + "Auto Snooze": { + value: a.as, + format: v => v ? "Yes" : "No", + onchange: v => a.as = v + }, + "Msg": { + value: !a.msg ? "" : a.msg.length > 6 ? a.msg.substring(0, 6)+"..." : a.msg, + //menu glitch? setTimeout required here + onchange: () => { + var kbapp = require("Storage").read("textinput"); + if (kbapp != undefined) setTimeout(editMsg, 0, idx, a); + else setTimeout(kbAlert, 0); + } + }, + "Delete": () => { + if (idx >= 0) { + alarms.splice(alarmIdx[idx], 1); + require("sched").setAlarms(alarms); + require("sched").reload(); + } + drawAlarms(); + }, + }; + + E.showMenu(menu); +} + +drawTimers(); + +Bangle.on("drag", e=>{ + if (layer < 0) return; + if (!drag) { // start dragging + drag = {x: e.x, y: e.y}; + } + else if (!e.b) { // released + const dx = e.x-drag.x, dy = e.y-drag.y; + drag = null; + if (dx == 0) return; + //horizontal swipes + if (Math.abs(dx)>Math.abs(dy)+10) { + //swipe left + if (dx<0) layer == 2 ? layer = 0 : layer++; + //swipe right + if (dx>0) layer == 0 ? layer = 2 : layer--; + clearInt(); + if (layer == 0) drawTimers(); + else if (layer == 1) drawSw(); + else if (layer == 2) drawAlarms(); + } + } +}); From 29354d6a51c615b03fc86a64d9b190325b832770 Mon Sep 17 00:00:00 2001 From: frigis1 <63980066+frigis1@users.noreply.github.com> Date: Sat, 14 May 2022 11:23:50 -0700 Subject: [PATCH 045/294] Add files via upload --- apps/multitimer/ChangeLog | 1 + apps/multitimer/README.md | 8 ++++ apps/multitimer/alarm.js | 77 ++++++++++++++++++++++++++++++++ apps/multitimer/app-icon.js | 1 + apps/multitimer/app.png | Bin 0 -> 971 bytes apps/multitimer/metadata.json | 22 +++++++++ apps/multitimer/screenshot1.png | Bin 0 -> 3337 bytes apps/multitimer/screenshot2.png | Bin 0 -> 2970 bytes apps/multitimer/screenshot3.png | Bin 0 -> 3476 bytes 9 files changed, 109 insertions(+) create mode 100644 apps/multitimer/ChangeLog create mode 100644 apps/multitimer/README.md create mode 100644 apps/multitimer/alarm.js create mode 100644 apps/multitimer/app-icon.js create mode 100644 apps/multitimer/app.png create mode 100644 apps/multitimer/metadata.json create mode 100644 apps/multitimer/screenshot1.png create mode 100644 apps/multitimer/screenshot2.png create mode 100644 apps/multitimer/screenshot3.png diff --git a/apps/multitimer/ChangeLog b/apps/multitimer/ChangeLog new file mode 100644 index 000000000..624f1b0fb --- /dev/null +++ b/apps/multitimer/ChangeLog @@ -0,0 +1 @@ +0.01: Initial version \ No newline at end of file diff --git a/apps/multitimer/README.md b/apps/multitimer/README.md new file mode 100644 index 000000000..0cc747c28 --- /dev/null +++ b/apps/multitimer/README.md @@ -0,0 +1,8 @@ +# Multi Timer +With this app, you can set timers and chronographs (stopwatches) and watch them count down/up in real time. You can also set alarms - swipe left or right to switch between the three functions. + +## WARNING +* Editing timers in another app (such as the default Alarm app) is not recommended. Editing alarms should not be a problem. +* This app uses the [Scheduler library](https://banglejs.com/apps/?id=sched). +* To avoid potential conflicts with other apps that uses sched (especially ones that make use of the data field), this app only lists timers that it created - all other timers will be ignored. +* A keyboard app is only used for adding messages to timers and is therefore not strictly needed. \ No newline at end of file diff --git a/apps/multitimer/alarm.js b/apps/multitimer/alarm.js new file mode 100644 index 000000000..96e5ade89 --- /dev/null +++ b/apps/multitimer/alarm.js @@ -0,0 +1,77 @@ +//sched.js, modified +// Chances are boot0.js got run already and scheduled *another* +// 'load(sched.js)' - so let's remove it first! +if (Bangle.SCHED) { + clearInterval(Bangle.SCHED); + delete Bangle.SCHED; +} + +function showAlarm(alarm) { + const settings = require("sched").getSettings(); + + let msg = ""; + msg += require("sched").formatTime(alarm.timer); + if (alarm.msg) { + msg += "\n"+alarm.msg; + } + else msg = atob("ACQswgD//33vRcGHIQAAABVVVAAAAAAAABVVVAAAAAAAABVVVAAAAAAAABVVVAAAAAAAABVVVAAAAAAAABVVVAAAAAAAAAP/wAAAAAAAAAP/wAAAAAAAAAqqoAPAAAAAAqqqqoP8AAAAKqqqqqv/AAACqqqqqqq/wAAKqqqlWqqvwAAqqqqlVaqrAACqqqqlVVqqAAKqqqqlVVaqgAKqaqqlVVWqgAqpWqqlVVVqoAqlWqqlVVVaoCqlV6qlVVVaqCqVVfqlVVVWqCqVVf6lVVVWqKpVVX/lVVVVqqpVVV/+VVVVqqpVVV//lVVVqqpVVVfr1VVVqqpVVVfr1VVVqqpVVVb/lVVVqqpVVVW+VVVVqqpVVVVVVVVVqiqVVVVVVVVWqCqVVVVVVVVWqCqlVVVVVVVaqAqlVVVVVVVaoAqpVVVVVVVqoAKqVVVVVVWqgAKqlVVVVVaqgACqpVVVVVqqAAAqqlVVVaqoAAAKqqVVWqqgAAACqqqqqqqAAAAAKqqqqqgAAAAAAqqqqoAAAAAAAAqqoAAAAA==")+" "+msg; + + Bangle.loadWidgets(); + Bangle.drawWidgets(); + + let buzzCount = settings.buzzCount; + + E.showPrompt(msg,{ + title: "TIMER!", + buttons : {"Snooze":true,"Ok":false} // default is sleep so it'll come back in 10 mins + }).then(function(sleep) { + buzzCount = 0; + if (sleep) { + if(alarm.ot===undefined) alarm.ot = alarm.t; + alarm.t += settings.defaultSnoozeMillis; + } else { + if (!alarm.timer) alarm.last = (new Date()).getDate(); + if (alarm.ot!==undefined) { + alarm.t = alarm.ot; + delete alarm.ot; + } + if (!alarm.rp) alarm.on = false; + } + //reset timer value + alarm.timer = alarm.data; + // alarm is still a member of 'alarms', so writing to array writes changes back directly + require("sched").setAlarms(alarms); + load(); + }); + + function buzz() { + if (settings.unlockAtBuzz) { + Bangle.setLocked(false); + } + + require("buzz").pattern(alarm.vibrate === undefined ? ".." : alarm.vibrate).then(() => { + if (buzzCount--) { + setTimeout(buzz, settings.buzzIntervalMillis); + } else if (alarm.as) { // auto-snooze + buzzCount = settings.buzzCount; + setTimeout(buzz, settings.defaultSnoozeMillis); + } + }); + } + + if ((require("Storage").readJSON("setting.json", 1) || {}).quiet > 1) + return; + + buzz(); +} + +// Check for alarms +let alarms = require("sched").getAlarms(); +let active = require("sched").getActiveAlarms(alarms); +if (active.length) { + // if there's an alarm, show it + showAlarm(active[0]); +} else { + // otherwise just go back to default app + setTimeout(load, 100); +} \ No newline at end of file diff --git a/apps/multitimer/app-icon.js b/apps/multitimer/app-icon.js new file mode 100644 index 000000000..6eac4ab31 --- /dev/null +++ b/apps/multitimer/app-icon.js @@ -0,0 +1 @@ +atob("MDCBAYAAAAAAfwAAAAAAPz//////Pz//////Pz//////Pz//////Pz//////PwAAAAAAPwAAAAAAPz//////Pz//////Pz//////Pz//////Pz//////Pz48AAAfPz4YAAAPPz//////Pz//////Pz//////Pz48AAAfPz4YAAAPPz//////Pz//////Pz//////Pz4YAAAPPz4YAAAfPz//////vz///////z///////z4YAAH4Pz48AAP4Dz////95hz////594z////x/8T////zP+T////nH+D////nj/AAAADnw/AAAABn4/P////n4/P////n//P////n/+f////z/+f////x/8/////4/4/////8Ph/////+AH//////gfw==") \ No newline at end of file diff --git a/apps/multitimer/app.png b/apps/multitimer/app.png new file mode 100644 index 0000000000000000000000000000000000000000..3006b0a2697673f59fba9fc1facff92f14be4112 GIT binary patch literal 971 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 BTc7{{ literal 0 HcmV?d00001 diff --git a/apps/multitimer/screenshot2.png b/apps/multitimer/screenshot2.png new file mode 100644 index 0000000000000000000000000000000000000000..23a0d4c222288b45c19532ae5e30b7798c26d971 GIT binary patch literal 2970 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 literal 0 HcmV?d00001 From 1b993fb09987043f6e124f794fa50c264d3a5b4c Mon Sep 17 00:00:00 2001 From: thyttan <97237430+thyttan@users.noreply.github.com> Date: Sun, 15 May 2022 00:24:18 +0200 Subject: [PATCH 046/294] Update lib.js --- apps/kbmulti/lib.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/kbmulti/lib.js b/apps/kbmulti/lib.js index 2d38539e8..d06e2bb7d 100644 --- a/apps/kbmulti/lib.js +++ b/apps/kbmulti/lib.js @@ -17,7 +17,7 @@ exports.input = function(options) { "4":"GHI4","5":"JKL5","6":"MNO6", "7":"PQRS7","8":"TUV80","9":"WXYZ9", }; - var helpMessage = 'swipe:\nRight: Space\nLeft:Backspace\nUp/Down: Caps lock\n'; + var helpMessage = 'Swipe:\nRight: Space\nLeft:Backspace\nUp/Down: Caps lock\n'; var charTimeout; // timeout after a key is pressed var charCurrent; // current character (index in letters) From 687eaaab4b3457d1cd227e0b0049a9a50ae772c3 Mon Sep 17 00:00:00 2001 From: frigis1 <63980066+frigis1@users.noreply.github.com> Date: Sat, 14 May 2022 22:16:15 -0700 Subject: [PATCH 047/294] Update app.js --- apps/multitimer/app.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/multitimer/app.js b/apps/multitimer/app.js index caf2637f0..faafc00a3 100644 --- a/apps/multitimer/app.js +++ b/apps/multitimer/app.js @@ -17,7 +17,7 @@ function getCurrentTime() { } function decodeTime(t) { - let hrs = 0 | Math.floor(t / 3600000 % 24); + let hrs = 0 | Math.floor(t / 3600000); let mins = 0 | Math.floor(t / 60000 % 60); let secs = 0 | Math.floor(t / 1000 % 60); return { hrs: hrs, mins: mins, secs: secs }; @@ -33,7 +33,7 @@ function formatTime(t) { } function decodeTimeDecis(t) { - let hrs = 0 | Math.floor(t / 3600000 % 24); + let hrs = 0 | Math.floor(t / 3600000); let mins = 0 | Math.floor(t / 60000 % 60); let secs = 0 | Math.floor(t / 1000 % 60); let decis = 0 | Math.floor(t / 100 % 100); From 1f175ecd9fa0662ac042f1fbbf59d9cef0f4da10 Mon Sep 17 00:00:00 2001 From: JuliusS123 <42714028+JuliusS123@users.noreply.github.com> Date: Sun, 15 May 2022 10:11:56 +0200 Subject: [PATCH 048/294] Create app.js --- apps/homework/app.js | 238 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 238 insertions(+) create mode 100644 apps/homework/app.js diff --git a/apps/homework/app.js b/apps/homework/app.js new file mode 100644 index 000000000..032560ec5 --- /dev/null +++ b/apps/homework/app.js @@ -0,0 +1,238 @@ +var Layout = require("Layout"); + +var homework = require("Storage").readJSON("homework.txt", "r"); +//var hwfile = require("Storage").open("homework.txt", "w"); +var mainCheckHomeworkMenu; +console.log(homework); +//subjects = require("Storage").open("subjects.txt", "r"); + +var mode = "mainmenu"; +var statusmsg; +var mainMenu = { + "": { + title: "--Main Menu--" + }, + "New Homework": function() { + E.showMenu(nhwmn); + mode = "newhomework"; + }, + "Check Homework": function() { + checkUnfinishedHomeworkAssembler(); + }, + "Reset Homework": function() { + E.showPrompt("Are you sure you want to delete homework.txt?", { + buttons: { + "No": false, + "Yes": true + } + }).then(function(v) { + if (v) { + require("Storage").write("homework.txt", '{"homework":[]}'); + homework = require("Storage").readJSON("homework.txt", "r"); + E.showMenu(mainMenu); + + }else{ + E.showMenu(mainMenu); + } + }); + }, +}; + + +var nhwmn = { // New homework Menu + "": { + "title": "New HW Subject:" + }, + "German": function() { + addNewHomework("German"); + }, + "English": function() { + addNewHomework("English"); + }, + "Maths": function() { + addNewHomework("Maths"); + }, + "French": function() { + addNewHomework("French"); + }, + "Chemistry": function() { + addNewHomework("Chemistry"); + }, + "Physics": function() { + addNewHomework("Physics"); + }, + "Religion": function() { + addNewHomework("Religion"); + }, + "Biology": function() { + addNewHomework("Biology"); + }, + "Music": function() { + addNewHomework("Music"); + }, + "History": function() { + addNewHomework("History"); + }, + "Arts": function() { + addNewHomework("Arts"); + }, + "Sports": function() { + addNewHomework("Sports"); + }, + + "Back": function() { + mode = "mainmenu"; + E.showMenu(mainMenu); + }, + + +}; + + +function checkUnfinishedHomeworkAssembler() { + homework = require("Storage").readJSON("homework.txt", "r"); + var hwcount = Object.keys(homework.homework).length; + mainCheckHomeworkMenu = { + '': { + 'title': 'Unfinished HW:' + } + }; + // This code snippet gets the unfinished HW and puts it in mainCheckHomeworkMenu + // btw mainCheckHomeworkMenu displays all the homework, when tapping on it you get more details with checkPreciseHomework function (currently being written) + for (var i = 0; i < hwcount; ++i) { + if (homework.homework[i].done === false) { + var currentsubject = i; //attempting to pass i + mainCheckHomeworkMenu[homework.homework[i].subject] = function() { + checkPreciseHomework(currentsubject); + }; + } + + } + mainCheckHomeworkMenu["See Archived HW"] = function() { + checkFinishedHomeworkAssembler(); + }; + mainCheckHomeworkMenu["Back to Main Menu"] = function() { + mode = "mainmenu"; + E.showMenu(mainMenu); + }; + E.showMenu(mainCheckHomeworkMenu); +} + +function checkFinishedHomeworkAssembler() { + homework = require("Storage").readJSON("homework.txt", "r"); + var hwcount = Object.keys(homework.homework).length; + mainCheckHomeworkMenu = { + '': { + 'title': 'Unfinished HW:' + } + }; + // This code snippet gets the unfinished HW and puts it in mainCheckHomeworkMenu + // btw mainCheckHomeworkMenu displays all the homework, when tapping on it you get more details with checkPreciseHomework function (currently being written) + for (var i = 0; i < hwcount; ++i) { + if (homework.homework[i].done === true) { + var currentsubject = i; //attempting to pass i + mainCheckHomeworkMenu[homework.homework[i].subject] = function() { + checkPreciseHomework(currentsubject); + }; + } + + } + mainCheckHomeworkMenu["Back"] = function() { + mode = "mainmenu"; + E.showMenu(mainMenu); + }; + E.showMenu(mainCheckHomeworkMenu); +} + +function checkPreciseHomework(subjectnum) { // P A I N + homework = require("Storage").read("homework.txt", "r"); + homework = JSON.parse(homework); + var subject = homework.homework[subjectnum].subject; + var task = homework.homework[subjectnum].task; + var taskmsg = "Task: " + homework.homework[subjectnum].task; + if (homework.homework[subjectnum].done === false) { + statusmsg = "Status: Unfinished"; + } else { + statusmsg = "Status: Finished"; + } + var datetimerecieved = homework.homework[subjectnum].datetimerecievehw; + var datetimerecievedmsg = "Recieved: " + homework.homework[subjectnum].datetimerecievehw; + var checkPreciseHomeworkMenu = { + '': { + 'title': subject + }, + }; + checkPreciseHomeworkMenu[subject] = function() {}, + checkPreciseHomeworkMenu[taskmsg] = function() {}, + checkPreciseHomeworkMenu[statusmsg] = function() { + status = "Status: Finished"; + var d = new Date(); + var currenttime = require("locale").time(d, 1); + var currentdate = require("locale").date(d); + var datetime = (currenttime + " " + currentdate); + delete homework.homework[subjectnum]; + homework.homework.push({ + subject: subject, + task: task, + done: true, + datetimerecievehw: datetimerecieved, + datetimehwdone: datetime + }); + require("Storage").write("homework.txt", JSON.stringify(homework)); + checkUnfinishedHomeworkAssembler(); + }, + checkPreciseHomeworkMenu[datetimerecievedmsg] = function() {}, + checkPreciseHomeworkMenu["Back"] = function() { + checkUnfinishedHomeworkAssembler(); + }, + + E.showMenu(checkPreciseHomeworkMenu); + + +} + +function pushHomework(subject, status, datetimehwdone) { + homework = require("Storage").readJSON("homework.txt", "r"); + +} + +function addNewHomework(subject) { // Pass subject + require("textinput").input().then(result => { + if (result === "") { + mode = "newhomework"; + E.showMenu(nhwmn); + } else { + var d = new Date(); + // update time and date + var currenttime = require("locale").time(d, 1); + var currentdate = require("locale").date(d); + var datetime = (currenttime + " " + currentdate); + homework.homework.push({ + subject: subject, + task: result, + done: false, + datetimerecievehw: datetime + }); // TODO: when HW is done, add datetimeendhw !!! + //homework.homework[subject] = result; + require("Storage").write("homework.txt", JSON.stringify(homework)); + E.showMenu(mainMenu); + + } + }); + +} + +function main() { // why does this still exist + if (mode === "mainmenu") { + E.showMenu(mainMenu); + + } else if (mode === "newhomework") { + E.showMenu(nhwmn); + + } +} +g.clear(); +Bangle.loadWidgets(); +Bangle.drawWidgets(); +main(); +//loop = setInterval(main, 1); From a6cdee8a40ac6348f8e7b9361025f1d20a283da9 Mon Sep 17 00:00:00 2001 From: JuliusS123 <42714028+JuliusS123@users.noreply.github.com> Date: Sun, 15 May 2022 10:16:41 +0200 Subject: [PATCH 049/294] Create app-icon.js --- apps/homework/app-icon.js | 1 + 1 file changed, 1 insertion(+) create mode 100644 apps/homework/app-icon.js diff --git a/apps/homework/app-icon.js b/apps/homework/app-icon.js new file mode 100644 index 000000000..7eeb41f50 --- /dev/null +++ b/apps/homework/app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEw4cA///43hg3ytVN/UF61hsvR2kEKf4AzgMgCJ9JkmACBsSCIOSCBkEyQRCpBELBwIRCpJKKEAYmDJRBEFJRQdHJRBEDIIgIIhJlIFgYRGKBQRFIgMN23YOgwREHYQRHJQIFDhADCCI5KBIA4RIAAsW7doCIsf5LHGCNMbkmQRwIRhGpy6BCMI1RCP4R9UITXOCKJZvAH4AoA=")) From bd69f2136195b99bb3ac4d96f92b354063995e93 Mon Sep 17 00:00:00 2001 From: JuliusS123 <42714028+JuliusS123@users.noreply.github.com> Date: Sun, 15 May 2022 10:22:52 +0200 Subject: [PATCH 050/294] Create metadata.json --- apps/homework/metadata.json | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 apps/homework/metadata.json diff --git a/apps/homework/metadata.json b/apps/homework/metadata.json new file mode 100644 index 000000000..a8f7909ea --- /dev/null +++ b/apps/homework/metadata.json @@ -0,0 +1,15 @@ + +{ "id": "homework", + "name": "Homework", + "shortName":"Homwork", + "version":"0.1", + "description": "A simple app to manage homework", + "icon": "app-icon.js", + "tags": "tool", + "supports" : ["BANGLEJS2"], + "readme": "README.md", + "storage": [ + {"name":"homework.app.js","url":"app.js"}, + {"name":"homework.img","url":"app-icon.js","evaluate":true} + ] +} From 35f7f3d630fbba02b78efdbd6ddaa1ed454f224e Mon Sep 17 00:00:00 2001 From: JuliusS123 <42714028+JuliusS123@users.noreply.github.com> Date: Sun, 15 May 2022 10:44:38 +0200 Subject: [PATCH 051/294] Create README.md --- apps/homework/README.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 apps/homework/README.md diff --git a/apps/homework/README.md b/apps/homework/README.md new file mode 100644 index 000000000..adad4ef39 --- /dev/null +++ b/apps/homework/README.md @@ -0,0 +1,4 @@ +# This is a simple homework app +Use the touchscreen to navigate. + +Requires the "textinput" library. (Tap keyboard) From 558f219ccf99796bf0e779395996bc353de9045e Mon Sep 17 00:00:00 2001 From: JuliusS123 <42714028+JuliusS123@users.noreply.github.com> Date: Sun, 15 May 2022 10:47:25 +0200 Subject: [PATCH 052/294] Update app-icon.js --- apps/homework/app-icon.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/homework/app-icon.js b/apps/homework/app-icon.js index 7eeb41f50..7fe731b3a 100644 --- a/apps/homework/app-icon.js +++ b/apps/homework/app-icon.js @@ -1 +1 @@ -require("heatshrink").decompress(atob("mEw4cA///43hg3ytVN/UF61hsvR2kEKf4AzgMgCJ9JkmACBsSCIOSCBkEyQRCpBELBwIRCpJKKEAYmDJRBEFJRQdHJRBEDIIgIIhJlIFgYRGKBQRFIgMN23YOgwREHYQRHJQIFDhADCCI5KBIA4RIAAsW7doCIsf5LHGCNMbkmQRwIRhGpy6BCMI1RCP4R9UITXOCKJZvAH4AoA=")) +require("heatshrink").decompress(atob("mEwxH+AH4A/AH4A/AG27y4ttAAYttGM4tJGMYsMGMCJLSsIhPGLodTGLIYI3ZFhFxQtOJJgURFqQxKCR4tGm83nAACGKQQNLZAvTGIjWMBRIvVERgAMFYOHAAQcWABUtltSAAQvRisVjgACF7KPPF/4AHrFYvgACF5OXy+7AAQHBFYNkAAQv/R6IvHX8/C4XJAAQv/R/4v/F/4v/F/4v/ABNYrF8AAQHBFYOHAAQHB4XC5IACA4IrBsgACF/6//F/4vRAH4A/AH4A/ACwA==")) From f69cd6e5ef91a16e07e303c174927116c06527ed Mon Sep 17 00:00:00 2001 From: JuliusS123 <42714028+JuliusS123@users.noreply.github.com> Date: Sun, 15 May 2022 10:49:53 +0200 Subject: [PATCH 053/294] Add files via upload --- apps/homework/app.png | Bin 0 -> 684 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 apps/homework/app.png diff --git a/apps/homework/app.png b/apps/homework/app.png new file mode 100644 index 0000000000000000000000000000000000000000..e6174d46bfdb46eaa36f1f742ff1c8fd390efc04 GIT binary patch literal 684 zcmV;d0#p5oP)UKDB{`}XjR+#5) z0JzBsjeJK!1%{@HV|TV+qEzNYftZR`+d!XQvp? zTzyb2n~dl_I3hvf2w23}L)~`Y1Uo8E)(8MHg^aJgeP>&ElhAF~0Z<>BMisz42#SaZ zgcd#za!$`i43SU)2JC^Mb^_<{tc^THs^NQ zognlM+_?Ch0HAm#>uY~z-;z_{)2-2tcVX4vzP`fEpJW%B;_&Ms0HBAyjC8Tk{`-iM z5t;$>auEQKJ%7^QVT%p2Un&s*6f(zs?WcC#(GnRioqFc9uYX4%_tBUE=ff8OK=E6a z6Pb|D`v8C)ta1XUk@6DrSXo{k{is~>ckH^;!7(`+OK4U;9UK4v3O@$Yb1(c1D1o$5 z0%@ZJ(niW*ZgLk6UTE6b1|aYyR);wbyu%#tLc{$M&v2Mq_!(Gu0fj=LNSEI_v-0fT SL+0E70000 Date: Sun, 15 May 2022 10:50:21 +0200 Subject: [PATCH 054/294] Update metadata.json --- apps/homework/metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/homework/metadata.json b/apps/homework/metadata.json index a8f7909ea..a6f9b1207 100644 --- a/apps/homework/metadata.json +++ b/apps/homework/metadata.json @@ -4,7 +4,7 @@ "shortName":"Homwork", "version":"0.1", "description": "A simple app to manage homework", - "icon": "app-icon.js", + "icon": "app.png", "tags": "tool", "supports" : ["BANGLEJS2"], "readme": "README.md", From 831a8635bf97467019d2452332fd480abddd2e57 Mon Sep 17 00:00:00 2001 From: JuliusS123 <42714028+JuliusS123@users.noreply.github.com> Date: Sun, 15 May 2022 10:52:54 +0200 Subject: [PATCH 055/294] Update app-icon.js --- apps/homework/app-icon.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/homework/app-icon.js b/apps/homework/app-icon.js index 7fe731b3a..7dab2103b 100644 --- a/apps/homework/app-icon.js +++ b/apps/homework/app-icon.js @@ -1 +1 @@ -require("heatshrink").decompress(atob("mEwxH+AH4A/AH4A/AG27y4ttAAYttGM4tJGMYsMGMCJLSsIhPGLodTGLIYI3ZFhFxQtOJJgURFqQxKCR4tGm83nAACGKQQNLZAvTGIjWMBRIvVERgAMFYOHAAQcWABUtltSAAQvRisVjgACF7KPPF/4AHrFYvgACF5OXy+7AAQHBFYNkAAQv/R6IvHX8/C4XJAAQv/R/4v/F/4v/F/4v/ABNYrF8AAQHBFYOHAAQHB4XC5IACA4IrBsgACF/6//F/4vRAH4A/AH4A/ACwA==")) +require("heatshrink").decompress(atob("mEwhH+AH4A/AH4A/AGu7y4ttAAYttGM4tJGMYsMGMCJLSsIhPGLodTGLIYI3ZFhFxQtOJJgURFqQxKCR4tGm83nAACGKQQNLZAvTGIjWMBRIvVERgAMFYOHAAQcWABUtltSAAQvRisVjgACF7KPPF/4AHrFYvgACF5OXy+7AAQHBFYNkAAQv/R6IvHX8/C4XJAAQv/R/4v/F/4v/F/4v/ABNYrF8AAQHBFYOHAAQHB4XC5IACA4IrBsgACF/6//F/4vRAH4A/AH4A/ACwA==")) From afbaf2b90e08a0f0bcefc27e725e89ef278cf190 Mon Sep 17 00:00:00 2001 From: JuliusS123 <42714028+JuliusS123@users.noreply.github.com> Date: Sun, 15 May 2022 10:56:27 +0200 Subject: [PATCH 056/294] Update app-icon.js --- apps/homework/app-icon.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/homework/app-icon.js b/apps/homework/app-icon.js index 7dab2103b..23a974ef3 100644 --- a/apps/homework/app-icon.js +++ b/apps/homework/app-icon.js @@ -1 +1 @@ -require("heatshrink").decompress(atob("mEwhH+AH4A/AH4A/AGu7y4ttAAYttGM4tJGMYsMGMCJLSsIhPGLodTGLIYI3ZFhFxQtOJJgURFqQxKCR4tGm83nAACGKQQNLZAvTGIjWMBRIvVERgAMFYOHAAQcWABUtltSAAQvRisVjgACF7KPPF/4AHrFYvgACF5OXy+7AAQHBFYNkAAQv/R6IvHX8/C4XJAAQv/R/4v/F/4v/F/4v/ABNYrF8AAQHBFYOHAAQHB4XC5IACA4IrBsgACF/6//F/4vRAH4A/AH4A/ACwA==")) +require("heatshrink").decompress(atob("mEwxH+AH4A/AH4AVvNPp95F1tPqujF9IuCvPO5wspAAXHF84uFp4uBL84xEvPN5q+rqtiCBl6F7tiAAY9LvQDBF86cDvQvCGLYvEGAr7EF4IwDF7c4GQwuERwIACqpecrlcF4lWLw4ACF7s3F58rGDIvEA4VcFwtWL4ovSCwwvHFoiOHGCQXHXYdcBwQuIDIwsMI5QwEGIKNERgh6JFpIuKAAOAGIYvCqpYJAwUyFxaNIGAovEXBheOF5pfCrl6RYjoTVAYvMRwYOKF76NDwAveGBaNEF8AwLFzgvHeRovoqtWFxtVDQbwSF44KBqouLDYzAYqz8OPg5gSD6K9FGCIvJVoIdLdoxgUDop9NF7gcEPZwvZJgwvnbiwTHF54bLMCEsAAIvVTRBEOF7zBSF7StPGDB1HPpyMVDAgZFbxztWAH4A/AGw")) From 38475eaa1191ed5c7ce2a384b8290481825b5f46 Mon Sep 17 00:00:00 2001 From: JuliusS123 <42714028+JuliusS123@users.noreply.github.com> Date: Sun, 15 May 2022 11:06:26 +0200 Subject: [PATCH 057/294] attempting to properly display app image --- apps/homework/app-icon.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/homework/app-icon.js b/apps/homework/app-icon.js index 23a974ef3..202b52b09 100644 --- a/apps/homework/app-icon.js +++ b/apps/homework/app-icon.js @@ -1 +1 @@ -require("heatshrink").decompress(atob("mEwxH+AH4A/AH4AVvNPp95F1tPqujF9IuCvPO5wspAAXHF84uFp4uBL84xEvPN5q+rqtiCBl6F7tiAAY9LvQDBF86cDvQvCGLYvEGAr7EF4IwDF7c4GQwuERwIACqpecrlcF4lWLw4ACF7s3F58rGDIvEA4VcFwtWL4ovSCwwvHFoiOHGCQXHXYdcBwQuIDIwsMI5QwEGIKNERgh6JFpIuKAAOAGIYvCqpYJAwUyFxaNIGAovEXBheOF5pfCrl6RYjoTVAYvMRwYOKF76NDwAveGBaNEF8AwLFzgvHeRovoqtWFxtVDQbwSF44KBqouLDYzAYqz8OPg5gSD6K9FGCIvJVoIdLdoxgUDop9NF7gcEPZwvZJgwvnbiwTHF54bLMCEsAAIvVTRBEOF7zBSF7StPGDB1HPpyMVDAgZFbxztWAH4A/AGw")) +require("heatshrink").decompress(atob("mEwwhC/AH4AbhvQCyvd7oYTCwQYTCwgYRCwwYPIgpKQCA4YOBxIYMBhYLLHhgYEC5BsKDAYXHCwUBiUikAYIC4wtDC5IYCA4pEEC5QYBYRUCkQXJAA8K1Wq0AXHhGIxGAC5ZHHC8ZDDC4cM5qaBC8ZHHC68N6czmAXrL94X/C/4XHgUiCYIDDa54XXO/4XHAH4A/ABY=")) From bd7d5cf7e4928e683e04b3b34c6b7e024ff53c9b Mon Sep 17 00:00:00 2001 From: JuliusS123 <42714028+JuliusS123@users.noreply.github.com> Date: Sun, 15 May 2022 11:12:19 +0200 Subject: [PATCH 058/294] Update metadata.json --- apps/homework/metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/homework/metadata.json b/apps/homework/metadata.json index a6f9b1207..07279c4ea 100644 --- a/apps/homework/metadata.json +++ b/apps/homework/metadata.json @@ -1,7 +1,7 @@ { "id": "homework", "name": "Homework", - "shortName":"Homwork", + "shortName":"Homework", "version":"0.1", "description": "A simple app to manage homework", "icon": "app.png", From 4415325703bdc111848d4e734169f37caa363a0c Mon Sep 17 00:00:00 2001 From: thyttan <97237430+thyttan@users.noreply.github.com> Date: Sun, 15 May 2022 11:52:07 +0200 Subject: [PATCH 059/294] Update lib.js --- apps/kbmulti/lib.js | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/apps/kbmulti/lib.js b/apps/kbmulti/lib.js index d06e2bb7d..db18948b8 100644 --- a/apps/kbmulti/lib.js +++ b/apps/kbmulti/lib.js @@ -25,18 +25,21 @@ exports.input = function(options) { var caps = true; var layout; - function displayText(charTimeout) { + function displayText(hideMarker) { layout.clear(layout.text); - layout.text.label = text.slice(settings.showHelpBtn ? -11 : -13) + (charTimeout ? " " : "_"); // Implemented marker here. + layout.text.label = text.slice(settings.showHelpBtn ? -11 : -13) + (!hideMarker ? "_" : " "); layout.render(layout.text); } - function backspace() { - // remove the timeout if we had one + function deactivateTimeout(charTimeout) { if (charTimeout!==undefined) { clearTimeout(charTimeout); charTimeout = undefined; } + } + + function backspace() { + deactivateTimeout(charTimeout); text = text.slice(0, -1); newCharacter(); } @@ -56,11 +59,7 @@ exports.input = function(options) { } function onKeyPad(key) { - // remove the timeout if we had one - if (charTimeout!==undefined) { - clearTimeout(charTimeout); - charTimeout = undefined; - } + deactivateTimeout(charTimeout); // work out which char was pressed if (key==charCurrent) { charIndex = (charIndex+1) % letters[charCurrent].length; @@ -124,7 +123,7 @@ exports.input = function(options) { ]}, ] },{back: ()=>{ - // charTimeout = undefined; // Tried this to see if it would stop the text from being drawn after closing keyboard when doing it too soon after pressing a key. It didn't help. This problem goes back to how I've implemented the marker above. + deactivateTimeout(charTimeout); Bangle.setUI(); Bangle.removeListener("swipe", onSwipe); g.clearRect(Bangle.appRect); @@ -134,13 +133,13 @@ exports.input = function(options) { return new Promise((resolve,reject) => { g.clearRect(Bangle.appRect); - if (settings.firstLaunch) { - onHelp(resolve,reject); + if (settings.firstLaunch) { + onHelp(resolve,reject); settings.firstLaunch = false; require('Storage').writeJSON("kbmulti.settings.json", settings); } else { generateLayout(resolve,reject); - displayText(true); + displayText(false); Bangle.on('swipe', onSwipe); layout.render(); } From 29be42c6063ecfc505c55bb8e987597d2ba24748 Mon Sep 17 00:00:00 2001 From: thyttan <97237430+thyttan@users.noreply.github.com> Date: Sun, 15 May 2022 11:53:51 +0200 Subject: [PATCH 060/294] Update lib.js --- apps/kbmulti/lib.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/kbmulti/lib.js b/apps/kbmulti/lib.js index db18948b8..c8abf98b4 100644 --- a/apps/kbmulti/lib.js +++ b/apps/kbmulti/lib.js @@ -27,7 +27,7 @@ exports.input = function(options) { function displayText(hideMarker) { layout.clear(layout.text); - layout.text.label = text.slice(settings.showHelpBtn ? -11 : -13) + (!hideMarker ? "_" : " "); + layout.text.label = text.slice(settings.showHelpBtn ? -11 : -13) + (hideMarker ? " " : "_"); layout.render(layout.text); } From 134a9e2369c0a5f82abed9208c58ef3ca3a21992 Mon Sep 17 00:00:00 2001 From: thyttan <97237430+thyttan@users.noreply.github.com> Date: Sun, 15 May 2022 12:19:29 +0200 Subject: [PATCH 061/294] Update README.md --- apps/kbmulti/README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/kbmulti/README.md b/apps/kbmulti/README.md index d40b2dd07..4c83d378e 100644 --- a/apps/kbmulti/README.md +++ b/apps/kbmulti/README.md @@ -10,7 +10,8 @@ Uses the multitap keypad logic originally from here: http://www.espruino.com/Mor ![](screenshot_1.png) ![](screenshot_2.png) +![](screenshot_3.png) Written by: [Sir Indy](https://github.com/sir-indy) and [Thyttan](https://github.com/thyttan) -For support and discussion please post in the [Bangle JS Forum](http://forum.espruino.com/microcosms/1424/) \ No newline at end of file +For support and discussion please post in the [Bangle JS Forum](http://forum.espruino.com/microcosms/1424/) From 5e564db73186325732b1a92859d8a6a6599641b8 Mon Sep 17 00:00:00 2001 From: thyttan <97237430+thyttan@users.noreply.github.com> Date: Sun, 15 May 2022 12:23:29 +0200 Subject: [PATCH 062/294] Add files via upload --- apps/kbmulti/screenshot_3.png | Bin 0 -> 3674 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 apps/kbmulti/screenshot_3.png diff --git a/apps/kbmulti/screenshot_3.png b/apps/kbmulti/screenshot_3.png new file mode 100644 index 0000000000000000000000000000000000000000..e0da184baa34c29285e7cd5b76d93638450a6cf4 GIT binary patch literal 3674 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 literal 0 HcmV?d00001 From f0a7ea0ee97f58f83a045a24f21a546aac95303d Mon Sep 17 00:00:00 2001 From: JuliusS123 <42714028+JuliusS123@users.noreply.github.com> Date: Sun, 15 May 2022 12:29:11 +0200 Subject: [PATCH 063/294] Update app.js --- apps/homework/app.js | 104 ++++++++++++++++--------------------------- 1 file changed, 39 insertions(+), 65 deletions(-) diff --git a/apps/homework/app.js b/apps/homework/app.js index 032560ec5..c7e04ba9f 100644 --- a/apps/homework/app.js +++ b/apps/homework/app.js @@ -1,11 +1,35 @@ var Layout = require("Layout"); var homework = require("Storage").readJSON("homework.txt", "r"); -//var hwfile = require("Storage").open("homework.txt", "w"); var mainCheckHomeworkMenu; -console.log(homework); -//subjects = require("Storage").open("subjects.txt", "r"); +var nhwmn = { // New homework Menu + "": { + "title": "New HW Subject:" + } + +}; + + + +function newHomeworkMenu() { + E.showMessage("Getting subjects..."); + var rawsubjects = require("Storage").read("subjects.txt"); // This code reads out the subjects list and removes the newline character at the end + var splitsubjects = rawsubjects.split(","); + var lastItem = splitsubjects[splitsubjects.length - 1]; + var thiscurrentsubject; + var command; + lastItem = lastItem.slice(0, -1); + splitsubjects[splitsubjects.length - 1] = lastItem; + for (let i = 0; i < splitsubjects.length; i++) { // loop through array and add to menu + thiscurrentsubject = splitsubjects[i]; + command = addNewHomework(thiscurrentsubject); + nhwmn[splitsubjects[i]] = addNewHomework.bind(null, thiscurrentsubject); + } + nhwmn["Back"] = function() {E.showMenu(mainMenu);}; + console.log(nhwmn); + E.showMenu(nhwmn); +} var mode = "mainmenu"; var statusmsg; var mainMenu = { @@ -13,7 +37,7 @@ var mainMenu = { title: "--Main Menu--" }, "New Homework": function() { - E.showMenu(nhwmn); + newHomeworkMenu(); mode = "newhomework"; }, "Check Homework": function() { @@ -38,73 +62,20 @@ var mainMenu = { }, }; - -var nhwmn = { // New homework Menu - "": { - "title": "New HW Subject:" - }, - "German": function() { - addNewHomework("German"); - }, - "English": function() { - addNewHomework("English"); - }, - "Maths": function() { - addNewHomework("Maths"); - }, - "French": function() { - addNewHomework("French"); - }, - "Chemistry": function() { - addNewHomework("Chemistry"); - }, - "Physics": function() { - addNewHomework("Physics"); - }, - "Religion": function() { - addNewHomework("Religion"); - }, - "Biology": function() { - addNewHomework("Biology"); - }, - "Music": function() { - addNewHomework("Music"); - }, - "History": function() { - addNewHomework("History"); - }, - "Arts": function() { - addNewHomework("Arts"); - }, - "Sports": function() { - addNewHomework("Sports"); - }, - - "Back": function() { - mode = "mainmenu"; - E.showMenu(mainMenu); - }, - - -}; - - function checkUnfinishedHomeworkAssembler() { homework = require("Storage").readJSON("homework.txt", "r"); var hwcount = Object.keys(homework.homework).length; mainCheckHomeworkMenu = { '': { - 'title': 'Unfinished HW:' + 'title': 'Archived HW:' } }; // This code snippet gets the unfinished HW and puts it in mainCheckHomeworkMenu - // btw mainCheckHomeworkMenu displays all the homework, when tapping on it you get more details with checkPreciseHomework function (currently being written) + // btw mainCheckHomeworkMenu displays all the homework, when tapping on it you get more details with checkPreciseHomework function for (var i = 0; i < hwcount; ++i) { if (homework.homework[i].done === false) { var currentsubject = i; //attempting to pass i - mainCheckHomeworkMenu[homework.homework[i].subject] = function() { - checkPreciseHomework(currentsubject); - }; + mainCheckHomeworkMenu[homework.homework[i].subject] = checkPreciseHomework.bind(null, currentsubject); } } @@ -115,6 +86,7 @@ function checkUnfinishedHomeworkAssembler() { mode = "mainmenu"; E.showMenu(mainMenu); }; + console.log(mainCheckHomeworkMenu); E.showMenu(mainCheckHomeworkMenu); } @@ -126,14 +98,13 @@ function checkFinishedHomeworkAssembler() { 'title': 'Unfinished HW:' } }; + // This code snippet gets the unfinished HW and puts it in mainCheckHomeworkMenu // btw mainCheckHomeworkMenu displays all the homework, when tapping on it you get more details with checkPreciseHomework function (currently being written) for (var i = 0; i < hwcount; ++i) { if (homework.homework[i].done === true) { var currentsubject = i; //attempting to pass i - mainCheckHomeworkMenu[homework.homework[i].subject] = function() { - checkPreciseHomework(currentsubject); - }; + mainCheckHomeworkMenu[homework.homework[i].subject] = checkPreciseHomework.bind(null, currentsubject); } } @@ -197,10 +168,11 @@ function pushHomework(subject, status, datetimehwdone) { } function addNewHomework(subject) { // Pass subject + console.log(subject); require("textinput").input().then(result => { if (result === "") { mode = "newhomework"; - E.showMenu(nhwmn); + newHomeworkMenu(); } else { var d = new Date(); // update time and date @@ -213,6 +185,8 @@ function addNewHomework(subject) { // Pass subject done: false, datetimerecievehw: datetime }); // TODO: when HW is done, add datetimeendhw !!! + console.log("subject is" + subject); + //homework.homework[subject] = result; require("Storage").write("homework.txt", JSON.stringify(homework)); E.showMenu(mainMenu); @@ -227,7 +201,7 @@ function main() { // why does this still exist E.showMenu(mainMenu); } else if (mode === "newhomework") { - E.showMenu(nhwmn); + newHomeworkMenu() } } From 6992c6f2f052f9108c209e3b0985bc5e3c6ed3e6 Mon Sep 17 00:00:00 2001 From: frigis1 <63980066+frigis1@users.noreply.github.com> Date: Sun, 15 May 2022 04:51:58 -0700 Subject: [PATCH 064/294] Update alarm.js --- apps/multitimer/alarm.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/multitimer/alarm.js b/apps/multitimer/alarm.js index 96e5ade89..208c374b6 100644 --- a/apps/multitimer/alarm.js +++ b/apps/multitimer/alarm.js @@ -38,7 +38,7 @@ function showAlarm(alarm) { if (!alarm.rp) alarm.on = false; } //reset timer value - alarm.timer = alarm.data; + alarm.timer = alarm.data.ot; // alarm is still a member of 'alarms', so writing to array writes changes back directly require("sched").setAlarms(alarms); load(); @@ -74,4 +74,4 @@ if (active.length) { } else { // otherwise just go back to default app setTimeout(load, 100); -} \ No newline at end of file +} From cfe8887b6ac5ad16006e26a1294ce32fa438029d Mon Sep 17 00:00:00 2001 From: frigis1 <63980066+frigis1@users.noreply.github.com> Date: Sun, 15 May 2022 04:52:11 -0700 Subject: [PATCH 065/294] Update app.js --- apps/multitimer/app.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/multitimer/app.js b/apps/multitimer/app.js index faafc00a3..b514126f0 100644 --- a/apps/multitimer/app.js +++ b/apps/multitimer/app.js @@ -190,7 +190,7 @@ function timerMenu(idx) { //reset if (i == 2) { clearInt(); - a.timer = a.data; + a.timer = a.data.ot; if (a.on == true) a.on = false; saveAndReload(); } @@ -252,7 +252,8 @@ function editTimer(idx, a) { "< Back": () => { a.t = getCurrentTime() + a.timer; a.last = 0; - a.data = a.timer; + if (!a.data) a.data = {}; + a.data.ot = a.timer; a.appid = "multitimer"; a.js = "load('multitimer.alarm.js')"; if (idx < 0) alarms.push(a); From 1f7178150afdd14feb8341557effaaca6648665c Mon Sep 17 00:00:00 2001 From: JuliusS123 <42714028+JuliusS123@users.noreply.github.com> Date: Sun, 15 May 2022 14:22:01 +0200 Subject: [PATCH 066/294] Add files via upload --- apps/homework/subjects.html | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 apps/homework/subjects.html diff --git a/apps/homework/subjects.html b/apps/homework/subjects.html new file mode 100644 index 000000000..622719e2d --- /dev/null +++ b/apps/homework/subjects.html @@ -0,0 +1,30 @@ + + + + + + +

Subjects:

+

Click

+ + + + + + From 27d63037837b9c7d9478d491b5d5d96b1e4dffe2 Mon Sep 17 00:00:00 2001 From: JuliusS123 <42714028+JuliusS123@users.noreply.github.com> Date: Sun, 15 May 2022 14:23:13 +0200 Subject: [PATCH 067/294] Update metadata.json --- apps/homework/metadata.json | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/homework/metadata.json b/apps/homework/metadata.json index 07279c4ea..2ba1e918f 100644 --- a/apps/homework/metadata.json +++ b/apps/homework/metadata.json @@ -8,6 +8,7 @@ "tags": "tool", "supports" : ["BANGLEJS2"], "readme": "README.md", + "custom": "subjects.html", "storage": [ {"name":"homework.app.js","url":"app.js"}, {"name":"homework.img","url":"app-icon.js","evaluate":true} From 60f4cd8f9d3b4f4dc645e5d6d8c5713bc79cb2c6 Mon Sep 17 00:00:00 2001 From: JuliusS123 <42714028+JuliusS123@users.noreply.github.com> Date: Sun, 15 May 2022 14:26:51 +0200 Subject: [PATCH 068/294] Update app.js --- apps/homework/app.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/homework/app.js b/apps/homework/app.js index c7e04ba9f..4ba786690 100644 --- a/apps/homework/app.js +++ b/apps/homework/app.js @@ -67,11 +67,11 @@ function checkUnfinishedHomeworkAssembler() { var hwcount = Object.keys(homework.homework).length; mainCheckHomeworkMenu = { '': { - 'title': 'Archived HW:' + 'title': 'Unfinished HW:' } }; // This code snippet gets the unfinished HW and puts it in mainCheckHomeworkMenu - // btw mainCheckHomeworkMenu displays all the homework, when tapping on it you get more details with checkPreciseHomework function + // btw mainCheckHomeworkMenu displays all the homework, when tapping on it you get more details with checkPreciseHomework function for (var i = 0; i < hwcount; ++i) { if (homework.homework[i].done === false) { var currentsubject = i; //attempting to pass i @@ -95,7 +95,7 @@ function checkFinishedHomeworkAssembler() { var hwcount = Object.keys(homework.homework).length; mainCheckHomeworkMenu = { '': { - 'title': 'Unfinished HW:' + 'title': 'Archived HW:' } }; From a1335bfe225419154009a4dcd5f7107fe59465e9 Mon Sep 17 00:00:00 2001 From: JuliusS123 <42714028+JuliusS123@users.noreply.github.com> Date: Sun, 15 May 2022 14:29:17 +0200 Subject: [PATCH 069/294] Update subjects.html --- apps/homework/subjects.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/homework/subjects.html b/apps/homework/subjects.html index 622719e2d..d3bf7a400 100644 --- a/apps/homework/subjects.html +++ b/apps/homework/subjects.html @@ -4,7 +4,7 @@ -

Subjects:

+

Subjects:

Click

From 117b52cc080eca4d621d4525bd70d8d96555901c Mon Sep 17 00:00:00 2001 From: frigis1 <63980066+frigis1@users.noreply.github.com> Date: Sun, 15 May 2022 07:40:13 -0700 Subject: [PATCH 070/294] Update alarm.js --- apps/multitimer/alarm.js | 117 ++++++++++++++++++++++++++++++++------- 1 file changed, 96 insertions(+), 21 deletions(-) diff --git a/apps/multitimer/alarm.js b/apps/multitimer/alarm.js index 208c374b6..7daa0d45a 100644 --- a/apps/multitimer/alarm.js +++ b/apps/multitimer/alarm.js @@ -6,6 +6,73 @@ if (Bangle.SCHED) { delete Bangle.SCHED; } +function hardMode(tries, max) { + var R = Bangle.appRect; + + function adv() { + tries++; + hardMode(tries, max); + } + + function random(min, max) { // min and max included + return Math.floor(Math.random() * (max - min + 1) + min); + } + + if (tries < max) { + g.clear(); + g.reset(); + g.setClipRect(R.x,R.y,R.x2,R.y2); + var code = Math.abs(E.hwRand()%4); + if (code == 0) dir = "up"; + else if (code == 1) dir = "right"; + else if (code == 2) dir = "down"; + else dir = "left"; + g.setFont("6x8:2").setFontAlign(0,0).drawString(tries+"/"+max+"\nSwipe "+dir, (R.x2-R.x)/2, (R.y2-R.y)/2); + var drag; + Bangle.setUI({ + mode : "custom", + drag : e=>{ + if (!drag) { // start dragging + drag = {x: e.x, y: e.y}; + } else if (!e.b) { // released + const dx = e.x-drag.x, dy = e.y-drag.y; + drag = null; + //horizontal swipes + if (Math.abs(dx)>Math.abs(dy)+10) { + //left + if (dx<0 && code == 3) adv(); + //right + else if (dx>0 && code == 1) adv(); + //wrong swipe - reset + else startHM(); + } + //vertical swipes + else if (Math.abs(dy)>Math.abs(dx)+10) { + //up + if (dy<0 && code == 0) adv(); + //down + else if (dy>0 && code == 2) adv(); + //wrong swipe - reset + else startHM(); + } + } + } + }); + } + else { + if (!active[0].timer) active[0].last = (new Date()).getDate(); + if (!active[0].rp) active[0].on = false; + if (active[0].timer) active[0].timer = active[0].data.ot; + require("sched").setAlarms(alarms); + load(); + } +} + +function startHM() { + //between 5-8 random swipes + hardMode(0, Math.abs(E.hwRand()%4)+5); +} + function showAlarm(alarm) { const settings = require("sched").getSettings(); @@ -21,28 +88,36 @@ function showAlarm(alarm) { let buzzCount = settings.buzzCount; - E.showPrompt(msg,{ - title: "TIMER!", - buttons : {"Snooze":true,"Ok":false} // default is sleep so it'll come back in 10 mins - }).then(function(sleep) { - buzzCount = 0; - if (sleep) { - if(alarm.ot===undefined) alarm.ot = alarm.t; - alarm.t += settings.defaultSnoozeMillis; - } else { - if (!alarm.timer) alarm.last = (new Date()).getDate(); - if (alarm.ot!==undefined) { - alarm.t = alarm.ot; - delete alarm.ot; + if (alarm.data.hm && alarm.data.hm == true) { + //hard mode extends auto-snooze time + buzzCount = buzzCount * 2; + startHM(); + } + + else { + E.showPrompt(msg,{ + title: "TIMER!", + buttons : {"Snooze":true,"Ok":false} // default is sleep so it'll come back in 10 mins + }).then(function(sleep) { + buzzCount = 0; + if (sleep) { + if(alarm.ot===undefined) alarm.ot = alarm.t; + alarm.t += settings.defaultSnoozeMillis; + } else { + if (!alarm.timer) alarm.last = (new Date()).getDate(); + if (alarm.ot!==undefined) { + alarm.t = alarm.ot; + delete alarm.ot; + } + if (!alarm.rp) alarm.on = false; } - if (!alarm.rp) alarm.on = false; - } - //reset timer value - alarm.timer = alarm.data.ot; - // alarm is still a member of 'alarms', so writing to array writes changes back directly - require("sched").setAlarms(alarms); - load(); - }); + //reset timer value + if (alarm.timer) alarm.timer = alarm.data.ot; + // alarm is still a member of 'alarms', so writing to array writes changes back directly + require("sched").setAlarms(alarms); + load(); + }); + } function buzz() { if (settings.unlockAtBuzz) { From 2e36770a706e4b8e7177bf1163c11ac87706b3c1 Mon Sep 17 00:00:00 2001 From: frigis1 <63980066+frigis1@users.noreply.github.com> Date: Sun, 15 May 2022 07:40:32 -0700 Subject: [PATCH 071/294] Update app.js --- apps/multitimer/app.js | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/apps/multitimer/app.js b/apps/multitimer/app.js index b514126f0..becaf6169 100644 --- a/apps/multitimer/app.js +++ b/apps/multitimer/app.js @@ -227,6 +227,10 @@ function editTimer(idx, a) { if (idx < 0) a = require("sched").newDefaultTimer(); else a = timers[idx]; } + if (!a.data) { + a.data = {}; + a.data.hm = false; + } var t = decodeTime(a.timer); function editMsg(idx, a) { @@ -252,7 +256,6 @@ function editTimer(idx, a) { "< Back": () => { a.t = getCurrentTime() + a.timer; a.last = 0; - if (!a.data) a.data = {}; a.data.ot = a.timer; a.appid = "multitimer"; a.js = "load('multitimer.alarm.js')"; @@ -288,6 +291,11 @@ function editTimer(idx, a) { a.timer = encodeTime(t); } }, + "Hard Mode": { + value: a.data.hm, + format: v => v ? "On" : "Off", + onchange: v => a.data.hm = v + }, "Vibrate": require("buzz_menu").pattern(a.vibrate, v => a.vibrate = v), "Msg": { value: !a.msg ? "" : a.msg.length > 6 ? a.msg.substring(0, 6)+"..." : a.msg, @@ -550,6 +558,10 @@ function editAlarm(idx, a) { if (idx >= 0) a = alarms[alarmIdx[idx]]; else a = require("sched").newDefaultAlarm(); } + if (!a.data) { + a.data = {}; + a.data.hm = false; + } var t = decodeTime(a.t); function editMsg(idx, a) { @@ -573,6 +585,8 @@ function editAlarm(idx, a) { var menu = { "": { "title": "Alarm" }, "< Back": () => { + if (a.data.hm == true) a.js = "load('multitimer.alarm.js')"; + if (a.data.hm == false && a.js) delete a.js; if (idx >= 0) alarms[alarmIdx[idx]] = a; else alarms.push(a); require("sched").setAlarms(alarms); @@ -607,6 +621,11 @@ function editAlarm(idx, a) { value: "SMTWTFS".split("").map((d,n)=>a.dow&(1< editDOW(a.dow, d=>{a.dow=d;editAlarm(idx,a);}) }, + "Hard Mode": { + value: a.data.hm, + format: v => v ? "On" : "Off", + onchange: v => a.data.hm = v + }, "Vibrate": require("buzz_menu").pattern(a.vibrate, v => a.vibrate = v), "Auto Snooze": { value: a.as, From 9cc825b93da6b47c918899d3ac4002bb9cbd5989 Mon Sep 17 00:00:00 2001 From: frigis1 <63980066+frigis1@users.noreply.github.com> Date: Sun, 15 May 2022 07:40:55 -0700 Subject: [PATCH 072/294] Update README.md --- apps/multitimer/README.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/apps/multitimer/README.md b/apps/multitimer/README.md index 0cc747c28..f8e14f518 100644 --- a/apps/multitimer/README.md +++ b/apps/multitimer/README.md @@ -1,8 +1,10 @@ # Multi Timer With this app, you can set timers and chronographs (stopwatches) and watch them count down/up in real time. You can also set alarms - swipe left or right to switch between the three functions. +"Hard mode" is also available for timers and alarms. It will double the number of buzz counts and you will have to swipe the screen five to eight times correctly - make a mistake, and you will need to start over. + ## WARNING -* Editing timers in another app (such as the default Alarm app) is not recommended. Editing alarms should not be a problem. +* Editing timers in another app (such as the default Alarm app) is not recommended. Editing alarms should not be a problem (in theory). * This app uses the [Scheduler library](https://banglejs.com/apps/?id=sched). -* To avoid potential conflicts with other apps that uses sched (especially ones that make use of the data field), this app only lists timers that it created - all other timers will be ignored. -* A keyboard app is only used for adding messages to timers and is therefore not strictly needed. \ No newline at end of file +* To avoid potential conflicts with other apps that uses sched (especially ones that make use of the data and js field), this app only lists timers and alarms that it created - any made outside the app will be ignored. +* A keyboard app is only used for adding messages to timers and is therefore not strictly needed. From fc164df525f3617a1315e23b9d959be462202b36 Mon Sep 17 00:00:00 2001 From: frigis1 <63980066+frigis1@users.noreply.github.com> Date: Sun, 15 May 2022 08:42:24 -0700 Subject: [PATCH 073/294] Update README.md --- apps/multitimer/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/multitimer/README.md b/apps/multitimer/README.md index f8e14f518..f1e2eb281 100644 --- a/apps/multitimer/README.md +++ b/apps/multitimer/README.md @@ -6,5 +6,5 @@ With this app, you can set timers and chronographs (stopwatches) and watch them ## WARNING * Editing timers in another app (such as the default Alarm app) is not recommended. Editing alarms should not be a problem (in theory). * This app uses the [Scheduler library](https://banglejs.com/apps/?id=sched). -* To avoid potential conflicts with other apps that uses sched (especially ones that make use of the data and js field), this app only lists timers and alarms that it created - any made outside the app will be ignored. +* To avoid potential conflicts with other apps that uses sched (especially ones that make use of the data and js field), this app only lists timers and alarms that it created - any made outside the app will be ignored. GB alarms are currently an exception as they do not make use of the data and js field. * A keyboard app is only used for adding messages to timers and is therefore not strictly needed. From 15f395f5768a5385d98537875858d299bf0b9eba Mon Sep 17 00:00:00 2001 From: frigis1 <63980066+frigis1@users.noreply.github.com> Date: Sun, 15 May 2022 08:49:06 -0700 Subject: [PATCH 074/294] Update alarm.js --- apps/multitimer/alarm.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/apps/multitimer/alarm.js b/apps/multitimer/alarm.js index 7daa0d45a..fc0195455 100644 --- a/apps/multitimer/alarm.js +++ b/apps/multitimer/alarm.js @@ -14,10 +14,6 @@ function hardMode(tries, max) { hardMode(tries, max); } - function random(min, max) { // min and max included - return Math.floor(Math.random() * (max - min + 1) + min); - } - if (tries < max) { g.clear(); g.reset(); From 12f84357caabca9855645299a8aaa48ed3213567 Mon Sep 17 00:00:00 2001 From: Richard de Boer Date: Thu, 12 May 2022 23:19:43 +0200 Subject: [PATCH 075/294] add ClockFace module --- modules/ClockFace.js | 103 ++++++++++++++++++++++++++++++++++++++++ modules/ClockFace.md | 110 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 213 insertions(+) create mode 100644 modules/ClockFace.js create mode 100644 modules/ClockFace.md diff --git a/modules/ClockFace.js b/modules/ClockFace.js new file mode 100644 index 000000000..9818ae4e3 --- /dev/null +++ b/modules/ClockFace.js @@ -0,0 +1,103 @@ +/* +Most of the boilerplate needed to run a clock. +See ClockFace.md for documentation +*/ +function ClockFace(options) { + if ("function"=== typeof options) options = {draw: options}; // simple usage + // some validation, in the hopes of at least catching typos/basic mistakes + Object.keys(options).forEach(k => { + if (![ + "precision", + "init", "draw", "update", + "pause", "resume", + "up", "down", "upDown" + ].includes(k)) throw `Invalid ClockFace option: ${k}`; + }); + if (!options.draw && !options.update) throw "ClockFace needs at least one of draw() or update() functions"; + this.draw = options.draw || (t=> { + options.update.apply(this, [t, {d: true, h: true, m: true, s: true}]); + }); + this.update = options.update || (t => { + g.clear(); + options.draw.apply(this, [t, {d: true, h: true, m: true, s: true}]); + }); + if (options.precision===1000||options.precision===60000) throw "ClockFace precision is in seconds, not ms"; + this.precision = (options.precision || 60); + if (options.init) this.init = options.init; + if (options.pause) this._pause = options.pause; + if (options.resume) this._resume = options.resume; + if ((options.up || options.down) && options.upDown) throw "ClockFace up/down and upDown cannot be used together"; + if (options.up || options.down) this._upDown = (dir) => { + if (dir<0 && options.up) options.up.apply(this); + if (dir>0 && options.down) options.down.apply(this); + }; + if (options.upDown) this._upDown = options.upDown; +} + +ClockFace.prototype.tick = function() { + const time = new Date(); + const now = { + d: `${time.getFullYear()}-${time.getMonth()}-${time.getDate()}`, + h: time.getHours(), + m: time.getMinutes(), + s: time.getSeconds(), + }; + if (!this._last) { + g.clear(true); + Bangle.drawWidgets(); + g.reset(); + this.draw.apply(this, [time, {d: true, h: true, m: true, s: true}]); + } else { + let c = {d: false, h: false, m: false, s: false}; // changed + if (now.d!==this._last.d) c.d = c.h = c.m = c.s = true; + else if (now.h!==this._last.h) c.h = c.m = c.s = true; + else if (now.m!==this._last.m) c.m = c.s = true; + else if (now.s!==this._last.s) c.s = true; + g.reset(); + this.update.apply(this, [time, c]); + } + this._last = now; + if (this.paused) return; // called redraw() while still paused + // figure out timeout: if e.g. precision=60s, update at the start of a new minute + const interval = this.precision*1000; + this._timeout = setTimeout(() => this.tick(), interval-(Date.now()%interval)); +}; + +ClockFace.prototype.start = function() { + Bangle.loadWidgets(); + if (this.init) this.init.apply(this); + if (this._upDown) Bangle.setUI("clockupdown", d=>this._upDown.apply(this,[d])); + else Bangle.setUI("clock"); + delete this._last; + this.tick(); + + Bangle.on("lcdPower", on => { + if (on) this.resume(); + else this.pause(); + }); +}; + +ClockFace.prototype.pause = function() { + if (!this._timeout) return; // already paused + clearTimeout(this._timeout); + delete this._timeout; + this.paused = true; // apps might want to check this + if (this._pause) this._pause.apply(this); +}; +ClockFace.prototype.resume = function() { + if (this._timeout) return; // not paused + delete this._last; + delete this.paused; + if (this._resume) this._resume.apply(this); + this.tick(true); +}; + +/** + * Force a complete redraw + */ +ClockFace.prototype.redraw = function() { + delete this._last; + this.tick(); +}; + +exports = ClockFace; \ No newline at end of file diff --git a/modules/ClockFace.md b/modules/ClockFace.md new file mode 100644 index 000000000..1da6e6020 --- /dev/null +++ b/modules/ClockFace.md @@ -0,0 +1,110 @@ +ClockFace +========= + +This module handles most of the tasks needed to set up a clock, so you can +concentrate on drawing the time. + +Example +------- +Tthe [tutorial clock](https://www.espruino.com/Bangle.js+Clock) converted to use +this module: + +```js + +// Load fonts +require("Font7x11Numeric7Seg").add(Graphics); +// position on screen +const X = 160, Y = 140; + +var ClockFace = require("ClockFace"); +var clock = new ClockFace({ + precision: 1, // update every second + draw: function(d) { + // work out how to display the current time + var h = d.getHours(), m = d.getMinutes(); + var time = (" "+h).substr(-2)+":"+("0"+m).substr(-2); + // draw the current time (4x size 7 segment) + g.setFont("7x11Numeric7Seg", 4); + g.setFontAlign(1, 1); // align right bottom + g.drawString(time, X, Y, true /*clear background*/); + // draw the seconds (2x size 7 segment) + g.setFont("7x11Numeric7Seg", 2); + g.drawString(("0"+d.getSeconds()).substr(-2), X+30, Y, true /*clear background*/); + // draw the date, in a normal font + g.setFont("6x8"); + g.setFontAlign(0, 1); // align center bottom + // pad the date - this clears the background if the date were to change length + var dateStr = " "+require("locale").date(d)+" "; + g.drawString(dateStr, g.getWidth()/2, Y+15, true /*clear background*/); + } +}); +clock.start(); + +``` + + + +Complete Usage +-------------- + +```js + +var ClockFace = require("ClockFace"); +var clock = new ClockFace({ + precision: 1, // optional, defaults to 60: how often to call update(), in seconds + init: function() { // optional + // called only once before starting the clock, but after setting up the + // screen/widgets, so you can use Bangle.appRect + }, + draw: function(time, changed) { // at least draw or update is required + // (re)draw entire clockface, time is a Date object + // `changed` is the same format as for update() below, but always all true + }, + // The difference between draw() and update() is that the screen is cleared + // before draw() is called, so it needs to always redraw the entire clock + update: function(time, changed) { // at least draw or update is required + // redraw date/time, time is a Date object + // if you want, you can only redraw the changed parts: + if (changed.d) // redraw date (changed.h/m/s will also all be true) + if (changed.h) // redraw hours + if (changed.m) // redraw minutes + if (changed.s) // redraw seconds + }, + pause: function() { // optional, called when the screen turns off + // for example: turn off GPS/compass if the watch used it + }, + resume: function() { // optional, called when the screen turns on + // for example: turn GPS/compass back on + }, + up: function() { // optional, up handler + }, + down: function() { // optional, down handler + }, + upDown: function(dir) { // optional, combined up/down handler + if (dir === -1) // Up + else // (dir === 1): Down + }, + }); +clock.start(); + +``` + + +Simple Usage +------------ +Basic clocks can pass just a function to redraw the entire screen every minute: + +```js + +var ClockFace = require("ClockFace"); +var clock = new ClockFace(function(time) { + // draw the current time at the center of the screen + g.setFont("Vector:50").setFontAlign(0, 0) + .drawString( + require("locale").time(time, true), + Bangle.appRect.w/2, Bangle.appRect.h/2 + ); +}); +clock.start(); + +``` \ No newline at end of file From 8f342e27cc172b3694edc5227dba724810395396 Mon Sep 17 00:00:00 2001 From: Richard de Boer Date: Sun, 15 May 2022 18:25:18 +0200 Subject: [PATCH 076/294] barclock: Use ClockFace library --- apps/barclock/ChangeLog | 1 + apps/barclock/clock-bar.js | 105 ++++++++++++++++-------------------- apps/barclock/metadata.json | 2 +- 3 files changed, 48 insertions(+), 60 deletions(-) diff --git a/apps/barclock/ChangeLog b/apps/barclock/ChangeLog index 316660fc6..0b8470b6a 100644 --- a/apps/barclock/ChangeLog +++ b/apps/barclock/ChangeLog @@ -7,3 +7,4 @@ 0.07: Update to use Bangle.setUI instead of setWatch 0.08: Use theme colors, Layout library 0.09: Fix time/date disappearing after fullscreen notification +0.10: Use ClockFace library diff --git a/apps/barclock/clock-bar.js b/apps/barclock/clock-bar.js index 5d46a1cb4..a465bb692 100644 --- a/apps/barclock/clock-bar.js +++ b/apps/barclock/clock-bar.js @@ -11,13 +11,9 @@ let locale = require("locale"); date.setMonth(1, 3); // februari: months are zero-indexed const localized = locale.date(date, true); locale.dayFirst = /3.*2/.test(localized); - - locale.hasMeridian = false; - if (typeof locale.meridian==="function") { // function does not exist if languages app is not installed - locale.hasMeridian = (locale.meridian(date)!==""); - } + locale.hasMeridian = (locale.meridian(date)!==""); } -Bangle.loadWidgets(); + function renderBar(l) { if (!this.fraction) { // zero-size fillRect stills draws one line of pixels, we don't want that @@ -27,32 +23,6 @@ function renderBar(l) { g.fillRect(l.x, l.y, l.x+width-1, l.y+l.height-1); } -const Layout = require("Layout"); -const layout = new Layout({ - type: "v", c: [ - { - type: "h", c: [ - {id: "time", label: "88:88", type: "txt", font: "6x8:5", bgCol: g.theme.bg}, // size updated below - {id: "ampm", label: " ", type: "txt", font: "6x8:2", bgCol: g.theme.bg}, - ], - }, - {id: "bar", type: "custom", fraction: 0, fillx: 1, height: 6, col: g.theme.fg2, render: renderBar}, - {height: 40}, - {id: "date", type: "txt", font: "10%", valign: 1}, - ], -}, {lazy: true}); -// adjustments based on screen size and whether we display am/pm -let thickness; // bar thickness, same as time font "pixel block" size -if (is12Hour) { - // Maximum font size = ( - ) / (5chars * 6px) - thickness = Math.floor((g.getWidth()-24)/(5*6)); -} else { - layout.ampm.label = ""; - thickness = Math.floor(g.getWidth()/(5*6)); -} -layout.bar.height = thickness+1; -layout.time.font = "6x8:"+thickness; -layout.update(); function timeText(date) { if (!is12Hour) { @@ -78,31 +48,48 @@ function dateText(date) { return `${dayName} ${dayMonth}`; } -draw = function draw(force) { - if (!Bangle.isLCDOn()) {return;} // no drawing, also no new update scheduled - const date = new Date(); - layout.time.label = timeText(date); - layout.ampm.label = ampmText(date); - layout.date.label = dateText(date); - const SECONDS_PER_MINUTE = 60; - layout.bar.fraction = date.getSeconds()/SECONDS_PER_MINUTE; - if (force) { - Bangle.drawWidgets(); - layout.forgetLazyState(); - } - layout.render(); - // schedule update at start of next second - const millis = date.getMilliseconds(); - setTimeout(draw, 1000-millis); -}; -// Show launcher when button pressed -Bangle.setUI("clock"); -Bangle.on("lcdPower", function(on) { - if (on) { - draw(true); - } -}); -g.reset().clear(); -Bangle.drawWidgets(); -draw(); +const ClockFace = require("ClockFace"), + clock = new ClockFace({ + precision:1, + init: function() { + const Layout = require("Layout"); + this.layout = new Layout({ + type: "v", c: [ + { + type: "h", c: [ + {id: "time", label: "88:88", type: "txt", font: "6x8:5", col:g.theme.fg, bgCol: g.theme.bg}, // size updated below + {id: "ampm", label: " ", type: "txt", font: "6x8:2", col:g.theme.fg, bgCol: g.theme.bg}, + ], + }, + {id: "bar", type: "custom", fraction: 0, fillx: 1, height: 6, col: g.theme.fg2, render: renderBar}, + {height: 40}, + {id: "date", type: "txt", font: "10%", valign: 1}, + ], + }, {lazy: true}); + // adjustments based on screen size and whether we display am/pm + let thickness; // bar thickness, same as time font "pixel block" size + if (is12Hour) { + // Maximum font size = ( - ) / (5chars * 6px) + thickness = Math.floor((Bangle.appRect.w-24)/(5*6)); + } else { + this.layout.ampm.label = ""; + thickness = Math.floor(Bangle.appRect.w/(5*6)); + } + this.layout.bar.height = thickness+1; + this.layout.time.font = "6x8:"+thickness; + this.layout.update(); + }, + update: function(date, c) { + if (c.m) this.layout.time.label = timeText(date); + if (c.h) this.layout.ampm.label = ampmText(date); + if (c.d) this.layout.date.label = dateText(date); + const SECONDS_PER_MINUTE = 60; + if (c.s) this.layout.bar.fraction = date.getSeconds()/SECONDS_PER_MINUTE; + this.layout.render(); + }, + resume: function() { + this.layout.forgetLazyState(); + }, + }); +clock.start(); diff --git a/apps/barclock/metadata.json b/apps/barclock/metadata.json index 2b7be355f..3ee7ccb3a 100644 --- a/apps/barclock/metadata.json +++ b/apps/barclock/metadata.json @@ -1,7 +1,7 @@ { "id": "barclock", "name": "Bar Clock", - "version": "0.09", + "version": "0.10", "description": "A simple digital clock showing seconds as a bar", "icon": "clock-bar.png", "screenshots": [{"url":"screenshot.png"},{"url":"screenshot_pm.png"}], From 6f68e07d665c82289680304aa2afc4804c21ff9c Mon Sep 17 00:00:00 2001 From: thyttan <97237430+thyttan@users.noreply.github.com> Date: Sun, 15 May 2022 19:27:40 +0200 Subject: [PATCH 077/294] Don't change page if doing swipe-to-exit --- apps/dtlaunch/app-b2.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/dtlaunch/app-b2.js b/apps/dtlaunch/app-b2.js index 8466a7414..46194ec5d 100644 --- a/apps/dtlaunch/app-b2.js +++ b/apps/dtlaunch/app-b2.js @@ -93,7 +93,7 @@ Bangle.on("swipe",(dirLeftRight, dirUpDown)=>{ if (dirUpDown==-1||dirLeftRight==-1){ ++page; if (page>maxPage) page=0; drawPage(page); - } else if (dirUpDown==1||dirLeftRight==1){ + } else if (dirUpDown==1||(dirLeftRight==1 && !settings.swipeExit)){ --page; if (page<0) page=maxPage; drawPage(page); } From 3f29aff90a59827226e56b659c506913ae68ac63 Mon Sep 17 00:00:00 2001 From: thyttan <97237430+thyttan@users.noreply.github.com> Date: Sun, 15 May 2022 19:32:37 +0200 Subject: [PATCH 078/294] Up and down also moves pages --- apps/dtlaunch/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/dtlaunch/README.md b/apps/dtlaunch/README.md index bea20ef65..55c9f53b8 100644 --- a/apps/dtlaunch/README.md +++ b/apps/dtlaunch/README.md @@ -29,6 +29,6 @@ Bangle 2: **Touch** - icon to select, scond touch launches app -**Swipe Left** - move to next page of app icons +**Swipe Left/Up** - move to next page of app icons -**Swipe Right** - move to previous page of app icons +**Swipe Right/Down** - move to previous page of app icons From 7a6aa8158b80c23778accd5e5e0bf34355ad5c2b Mon Sep 17 00:00:00 2001 From: thyttan <97237430+thyttan@users.noreply.github.com> Date: Sun, 15 May 2022 19:36:22 +0200 Subject: [PATCH 079/294] Don't change page if doing swipe-to-exit --- apps/dtlaunch/ChangeLog | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/dtlaunch/ChangeLog b/apps/dtlaunch/ChangeLog index 95952b9fe..09804b82e 100644 --- a/apps/dtlaunch/ChangeLog +++ b/apps/dtlaunch/ChangeLog @@ -11,3 +11,4 @@ 0.11: Fix bangle.js 1 white icons not displaying 0.12: On Bangle 2 change to swiping up/down to move between pages as to match page indicator. Swiping from left to right now loads the clock. 0.13: Added swipeExit setting so that left-right to exit is an option +0.14: Don't move pages when doing exit swipe. From f9af4b064010b9e361b6255a05969b6fe7e30e44 Mon Sep 17 00:00:00 2001 From: thyttan <97237430+thyttan@users.noreply.github.com> Date: Sun, 15 May 2022 19:36:46 +0200 Subject: [PATCH 080/294] Update metadata.json --- apps/dtlaunch/metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/dtlaunch/metadata.json b/apps/dtlaunch/metadata.json index 7784972ca..4a0b8067c 100644 --- a/apps/dtlaunch/metadata.json +++ b/apps/dtlaunch/metadata.json @@ -1,7 +1,7 @@ { "id": "dtlaunch", "name": "Desktop Launcher", - "version": "0.13", + "version": "0.14", "description": "Desktop style App Launcher with six (four for Bangle 2) apps per page - fast access if you have lots of apps installed.", "screenshots": [{"url":"shot1.png"},{"url":"shot2.png"},{"url":"shot3.png"}], "icon": "icon.png", From e3ff844215c068376460f2022b3052198d9aad1c Mon Sep 17 00:00:00 2001 From: David Peer Date: Sun, 15 May 2022 21:45:56 +0200 Subject: [PATCH 081/294] Improved positioning of BW clock. --- apps/bwclk/ChangeLog | 3 ++- apps/bwclk/app.js | 19 ++++++++++--------- apps/bwclk/metadata.json | 2 +- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/apps/bwclk/ChangeLog b/apps/bwclk/ChangeLog index 11569af0c..89fcea519 100644 --- a/apps/bwclk/ChangeLog +++ b/apps/bwclk/ChangeLog @@ -3,4 +3,5 @@ 0.03: Adapt colors based on the theme of the user. 0.04: Steps can be hidden now such that the time is even larger. 0.05: Included icons for information. -0.06: Design and usability improvements. \ No newline at end of file +0.06: Design and usability improvements. +0.07: Improved positioning. \ No newline at end of file diff --git a/apps/bwclk/app.js b/apps/bwclk/app.js index 5240e69ec..0fe71b240 100644 --- a/apps/bwclk/app.js +++ b/apps/bwclk/app.js @@ -259,11 +259,12 @@ function draw() { function drawDate(){ // Draw background - var y = H/5*2 + (settings.fullscreen ? 0 : 8); + var y = H/5*2; g.reset().clearRect(0,0,W,W); // Draw date - y -= settings.fullscreen ? 8 : 0; + y = parseInt(y/2); + y += settings.fullscreen ? 0 : 15; var date = new Date(); var dateStr = date.getDate(); dateStr = ("0" + dateStr).substr(-2); @@ -276,14 +277,14 @@ function drawDate(){ var dayW = Math.max(g.stringWidth(dayStr), g.stringWidth(monthStr)); var fullDateW = dateW + 10 + dayW; - g.setFontAlign(-1,1); + g.setFontAlign(-1,0); g.setMediumFont(); g.setColor(g.theme.fg); g.drawString(dateStr, W/2 - fullDateW / 2, y+5); g.setSmallFont(); - g.drawString(monthStr, W/2 - fullDateW/2 + 10 + dateW, y+3); - g.drawString(dayStr, W/2 - fullDateW/2 + 10 + dateW, y-23); + g.drawString(monthStr, W/2 - fullDateW/2 + 10 + dateW, y+14); + g.drawString(dayStr, W/2 - fullDateW/2 + 10 + dateW, y-10); } @@ -296,9 +297,9 @@ function drawTime(){ // Draw time g.setColor(g.theme.bg); - g.setFontAlign(0,-1); + g.setFontAlign(0,0); var timeStr = locale.time(date,1); - y += settings.fullscreen ? 14 : 10; + y += parseInt((H - y)/2) + 5; var infoEntry = getInfoEntry(); var infoStr = infoEntry[0]; @@ -307,9 +308,9 @@ function drawTime(){ // Show large or small time depending on info entry if(infoStr == null){ - y += 10; g.setLargeFont(); } else { + y -= 15; g.setMediumFont(); } g.drawString(timeStr, W/2, y); @@ -319,7 +320,7 @@ function drawTime(){ return; } - y += H/5*2-5; + y += 35; g.setFontAlign(0,0); g.setSmallFont(); var imgWidth = 0; diff --git a/apps/bwclk/metadata.json b/apps/bwclk/metadata.json index 8b13cd256..59d044eb3 100644 --- a/apps/bwclk/metadata.json +++ b/apps/bwclk/metadata.json @@ -1,7 +1,7 @@ { "id": "bwclk", "name": "BW Clock", - "version": "0.06", + "version": "0.07", "description": "BW Clock.", "readme": "README.md", "icon": "app.png", From 275f6a87d5e043a37baafb1644e96f3c9e33b318 Mon Sep 17 00:00:00 2001 From: thyttan <97237430+thyttan@users.noreply.github.com> Date: Mon, 16 May 2022 11:51:59 +0200 Subject: [PATCH 082/294] add fixed and equal button width for all buttons replaced fillx:1 with width:btnWidth --- apps/kbmulti/lib.js | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/apps/kbmulti/lib.js b/apps/kbmulti/lib.js index c8abf98b4..b099603cb 100644 --- a/apps/kbmulti/lib.js +++ b/apps/kbmulti/lib.js @@ -24,6 +24,7 @@ exports.input = function(options) { var charIndex; // index in letters[charCurrent] var caps = true; var layout; + var btnWidth = g.getWidth()/3 function displayText(hideMarker) { layout.clear(layout.text); @@ -107,19 +108,19 @@ exports.input = function(options) { (settings.showHelpBtn ? {type:"btn", font:'6x8', label:'?', cb: l=>onHelp(resolve,reject), filly:1 } : {}), ]}, {type:"h", c: [ - {type:"btn", font:fontSize, label:letters[1], cb: l=>onKeyPad(1), id:'1', fillx:1, filly:1 }, - {type:"btn", font:fontSize, label:letters[2], cb: l=>onKeyPad(2), id:'2', fillx:1, filly:1 }, - {type:"btn", font:fontSize, label:letters[3], cb: l=>onKeyPad(3), id:'3', fillx:1, filly:1 }, + {type:"btn", font:fontSize, label:letters[1], cb: l=>onKeyPad(1), id:'1', width:btnWidth, filly:1 }, + {type:"btn", font:fontSize, label:letters[2], cb: l=>onKeyPad(2), id:'2', width:btnWidth, filly:1 }, + {type:"btn", font:fontSize, label:letters[3], cb: l=>onKeyPad(3), id:'3', width:btnWidth, filly:1 }, ]}, {type:"h", filly:1, c: [ - {type:"btn", font:fontSize, label:letters[4], cb: l=>onKeyPad(4), id:'4', fillx:1, filly:1 }, - {type:"btn", font:fontSize, label:letters[5], cb: l=>onKeyPad(5), id:'5', fillx:1, filly:1 }, - {type:"btn", font:fontSize, label:letters[6], cb: l=>onKeyPad(6), id:'6', fillx:1, filly:1 }, + {type:"btn", font:fontSize, label:letters[4], cb: l=>onKeyPad(4), id:'4', width:btnWidth, filly:1 }, + {type:"btn", font:fontSize, label:letters[5], cb: l=>onKeyPad(5), id:'5', width:btnWidth, filly:1 }, + {type:"btn", font:fontSize, label:letters[6], cb: l=>onKeyPad(6), id:'6', width:btnWidth, filly:1 }, ]}, {type:"h", filly:1, c: [ - {type:"btn", font:fontSize, label:letters[7], cb: l=>onKeyPad(7), id:'7', fillx:1, filly:1 }, - {type:"btn", font:fontSize, label:letters[8], cb: l=>onKeyPad(8), id:'8', fillx:1, filly:1 }, - {type:"btn", font:fontSize, label:letters[9], cb: l=>onKeyPad(9), id:'9', fillx:1, filly:1 }, + {type:"btn", font:fontSize, label:letters[7], cb: l=>onKeyPad(7), id:'7', width:btnWidth, filly:1 }, + {type:"btn", font:fontSize, label:letters[8], cb: l=>onKeyPad(8), id:'8', width:btnWidth, filly:1 }, + {type:"btn", font:fontSize, label:letters[9], cb: l=>onKeyPad(9), id:'9', width:btnWidth, filly:1 }, ]}, ] },{back: ()=>{ From 9a98a518dea0f8ce6a36f37f632eb07d5e8000fb Mon Sep 17 00:00:00 2001 From: thyttan <97237430+thyttan@users.noreply.github.com> Date: Mon, 16 May 2022 11:52:59 +0200 Subject: [PATCH 083/294] Update lib.js --- apps/kbmulti/lib.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/kbmulti/lib.js b/apps/kbmulti/lib.js index b099603cb..5ccab4204 100644 --- a/apps/kbmulti/lib.js +++ b/apps/kbmulti/lib.js @@ -115,7 +115,7 @@ exports.input = function(options) { {type:"h", filly:1, c: [ {type:"btn", font:fontSize, label:letters[4], cb: l=>onKeyPad(4), id:'4', width:btnWidth, filly:1 }, {type:"btn", font:fontSize, label:letters[5], cb: l=>onKeyPad(5), id:'5', width:btnWidth, filly:1 }, - {type:"btn", font:fontSize, label:letters[6], cb: l=>onKeyPad(6), id:'6', width:btnWidth, filly:1 }, + {type:"btn", font:fontSize, label:letters[6], cb: l=>onKeyPad(6), id:'6', width:btnWidth, filly:1 }, ]}, {type:"h", filly:1, c: [ {type:"btn", font:fontSize, label:letters[7], cb: l=>onKeyPad(7), id:'7', width:btnWidth, filly:1 }, From fd35af1bd67cae273d1278961328e16db80346be Mon Sep 17 00:00:00 2001 From: thyttan <97237430+thyttan@users.noreply.github.com> Date: Mon, 16 May 2022 12:34:46 +0200 Subject: [PATCH 084/294] Update ChangeLog --- apps/kbmulti/ChangeLog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/kbmulti/ChangeLog b/apps/kbmulti/ChangeLog index c6c606bff..709aa3203 100644 --- a/apps/kbmulti/ChangeLog +++ b/apps/kbmulti/ChangeLog @@ -1,2 +1,2 @@ 0.01: New keyboard -0.02: Introduce setting "Show help button?". Make setting firstLaunch invisible by removing corresponding code from settings.js. Add marker that shows when character selection timeout has run out. Display opened text on launch when editing existing text string. +0.02: Introduce setting "Show help button?". Make setting firstLaunch invisible by removing corresponding code from settings.js. Add marker that shows when character selection timeout has run out. Display opened text on launch when editing existing text string. Perfect horizontal alignment of buttons. Tweak help message letter casing. From b4b6d424ecc18b85554cf84b88f23a341ac4fc86 Mon Sep 17 00:00:00 2001 From: thyttan <97237430+thyttan@users.noreply.github.com> Date: Mon, 16 May 2022 12:42:07 +0200 Subject: [PATCH 085/294] perfect horizontal button alignment --- apps/kbmulti/screenshot_3.png | Bin 3674 -> 3503 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/apps/kbmulti/screenshot_3.png b/apps/kbmulti/screenshot_3.png index e0da184baa34c29285e7cd5b76d93638450a6cf4..882ea73862fe0c46c8a984fbc9b6c63afe1dc4a9 100644 GIT binary patch delta 3489 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 From 7f9bf3a758c090b8d69839f2a5e871796cf6377e Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Mon, 16 May 2022 14:32:35 +0100 Subject: [PATCH 086/294] Add option to use lower write size for phones with potentially iffy Bluetooth stacks (fix #)1834 --- index.html | 4 ++++ loader.js | 11 +++++++++++ 2 files changed, 15 insertions(+) diff --git a/index.html b/index.html index de7facd5a..b141cffc9 100644 --- a/index.html +++ b/index.html @@ -147,6 +147,10 @@ Always update time when we connect +
+ +
+ +
+ + + + + + + +
+ + +
+ + + + + + + + + + + + + + + + + From fd9569ffa9a12346d83844cc1f25341c906970c2 Mon Sep 17 00:00:00 2001 From: Noah Howard <3317164+nh-99@users.noreply.github.com> Date: Mon, 23 May 2022 15:50:49 -0400 Subject: [PATCH 262/294] Add R2D2 clock --- apps/r2d2clk/ChangeLog | 1 + apps/r2d2clk/README.md | 7 ++++ apps/r2d2clk/app-icon.js | 1 + apps/r2d2clk/app.js | 67 +++++++++++++++++++++++++++++++++++++ apps/r2d2clk/app.png | Bin 0 -> 3143 bytes apps/r2d2clk/metadata.json | 14 ++++++++ 6 files changed, 90 insertions(+) create mode 100644 apps/r2d2clk/ChangeLog create mode 100644 apps/r2d2clk/README.md create mode 100644 apps/r2d2clk/app-icon.js create mode 100644 apps/r2d2clk/app.js create mode 100644 apps/r2d2clk/app.png create mode 100644 apps/r2d2clk/metadata.json diff --git a/apps/r2d2clk/ChangeLog b/apps/r2d2clk/ChangeLog new file mode 100644 index 000000000..5560f00bc --- /dev/null +++ b/apps/r2d2clk/ChangeLog @@ -0,0 +1 @@ +0.01: New App! diff --git a/apps/r2d2clk/README.md b/apps/r2d2clk/README.md new file mode 100644 index 000000000..24730a0bf --- /dev/null +++ b/apps/r2d2clk/README.md @@ -0,0 +1,7 @@ +# R2D2 Clock + +A clock with R2D2's shiny metal face on it. :) + +## Creator + +Made by [Noah Howard](https://github.com/nh-99) diff --git a/apps/r2d2clk/app-icon.js b/apps/r2d2clk/app-icon.js new file mode 100644 index 000000000..17ef6b709 --- /dev/null +++ b/apps/r2d2clk/app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("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")) \ No newline at end of file diff --git a/apps/r2d2clk/app.js b/apps/r2d2clk/app.js new file mode 100644 index 000000000..a7ead76f1 --- /dev/null +++ b/apps/r2d2clk/app.js @@ -0,0 +1,67 @@ +Graphics.prototype.setFontUndo = function(scale) { + // Actual height 19 (20 - 2) + this.setFontCustom(atob("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKqKAqooCqigKqKAAAACgAAKAAAoAACgAAAAAAAAACgAAKAAAoAACgAAAAAAKCgAoKAKqqAqqoCqqgKqqAKCgAoKAKqqAqqoCqqgKqqAKCgAoKAAAAAKgoAqCgKqKAqooKiioqKKiooqKiioKKqAoqoCgqAKCoAAAACoCgKgKAiCoCIKgKioAqKgACoAAKgACoAAKgACoqAKioCoIgKgiAoCoCgKgAAAAKqgAqqAKqqAqqoKiioqKKiooqKiioKAKAoAoCgCgKAKAAAACgAAKAAAoAACgAAAAAAKqgAqqAKqqAqqoCgCgKAKAAAACgCgKAKAqqoCqqgCqoAKqgAAAACigAKKAAqoACqgAqoACqgAKqAAqoAAqoACqgAKKAAooAAAAAAoAACgAAKAAAoAAqqACqoAKqgAqqAAKAAAoAACgAAKAAAAAAACoAAKgAAqAACoAAAAAoAACgAAKAAAoAACgAAKAAAoAACgAAKAAAoAACgAAKAAAAAAACgAAKAAAoAACgAAAAAAoAACgAAqAACoAAqAACoAAqAACoAAqAACoAAqAACoAAqAACoAAKAAAoAAAAAACqoAKqgCqqgKqqAoAoCgCgKAKAoAoCqqgKqqAKqgAqqAAAAAqqoCqqgKqqAqqoAAAAKCqAoKoCiqgKKqAoooCiigKKKAoooCqigKqKAKgoAqCgAAAAoAoCgCgKAKAoAoCiigKKKAoooCiigKqqAqqoAqqACqoAAAACqAAKoAAqoACqgAAKAAAoAACgAAKAAqqoCqqgKqqAqqoAAAAKoKAqgoCqigKqKAoooCiigKKKAoooCiqgKKqAoKgCgqAAAAAKqgAqqAKqqAqqoCiigKKKAoooCiigKKqAoqoCgqAKCoAAAACgAAKAAAoAACgAAKAAAoAACgAAKAAAqqoCqqgCqqAKqoAAAACqoAKqgCqqgKqqAoooCiigKKKAoooCqqgKqqAKqgAqqAAAAAKgAAqAAKqAAqoACigAKKAAooACigAKqqAqqoAqqgCqqAAAACgCgKAKAoAoCgCgAAAAoAqCgCoKAKgoAqAAAAAKAAAoAAKoAAqgAKqgAqqAKgqAqCoCgCgKAKAAAAAoKACgoAKCgAoKACgoAKCgAoKACgoAKCgAoKACgoAKCgAAAAKAKAoAoCoKgKgqAKqgAqqAAqgACqAACgAAKAAAAACgAAKAAAoAACgAAKKKAoooCiigKKKAqoACqgACoAAKgAAAAACqqAKqoCqqgKqqAoAACgAAKCoAoKgCiqgKKqAoooCiigKqqAqqoAqqACqoAAAAAqqgCqqAqqoCqqgKKAAooACigAKKAAqqoCqqgCqqAKqoAAAAKqqAqqoCqqgKqqAoooCiigKKKAoooCqqgKqqAKCgAoKAAAAAKqgAqqAKqqAqqoCgCgKAKAoAoCgCgKAKAoAoCgCgKAKAAAACqqgKqqAqqoCqqgKAKAoAoCoKgKgqAKqgAqqAAqgACqAAAAACqoAKqgCqqgKqqAoooCiigKKKAoooCgCgKAKAoAoCgCgAAAAKqoAqqgKqqAqqoCigAKKAAooACigAKAAAoAACgAAKAAAAAAAqqACqoAqqoCqqgKAKAoAoCiigKKKAoqoCiqgKKqAoqoAAAAKqqAqqoCqqgKqqAAoAACgAAKAAAoACqqgKqqAqqoCqqgAAAAoAoCgCgKAKAoAoCqqgKqqAqqoCqqgKAKAoAoCgCgKAKAAAAAAKAAAoAACoAAKgAAKAAAoAACgAAKAqqoCqqgKqoAqqgAAAAKqqAqqoCqqgKqqACqAAKoACqoAKqgCoKgKgqAoAoCgCgAAAAqqgCqqAKqqAqqoAACgAAKAAAoAACgAAKAAAoAACgAAKAAAACqqgKqqAqqoCqqgCoAAKgAAKgAAqAAKgAAqAAKqqAqqoCqqgKqqAAAACqqgKqqAqqoCqqgCoAAKgAAKgAAqAAqqoCqqgKqqAqqoAAAACqoAKqgCqqgKqqAoAoCgCgKAKAoAoCqqgKqqAKqgAqqAAAAAqqoCqqgKqqAqqoCigAKKAAooACigAKqAAqoAAqAACoAAAAAAqqACqoAqqoCqqgKAKAoAoCgKgKAqAqqoCqqgCqqAKqoAAAAKqqAqqoCqqgKqqAooACigAKKgAoqACqqgKqqAKioAqKgAAAAKgoAqCgKqKAqooCiigKKKAoooCiigKKqAoqoCgqAKCoAAAACgAAKAAAoAACgAAKqqAqqoCqqgKqqAoAACgAAKAAAoAAAAAAKqoAqqgCqqgKqqAAAoAACgAAKAAAoCqqgKqqAqqgCqqAAAAAqqACqoAKqoAqqgAAKgAAqAACoAAKgKqoAqqgCqoAKqgAAAACqqgKqqAqqoCqqgACoAAKgACoAAKgAAKgAAqAKqqAqqoCqqgKqqAAAACoKgKgqAqqoCqqgAqgACqAAKoAAqgAqqoCqqgKgqAqCoAAAAKoAAqgACqgAKqAAAqoACqgAKqAAqoCqgAKqAAqgACqAAAAAAoCoCgKgKCqAoKoCiqgKKqAqooCqigKoKAqgoCoCgKgKAAAACqqgKqqAqqoCqqgKAKAoAoAAAAKAAAoAACoAAKgAAKgAAqAAAqAACoAACoAAKgAAKgAAqAAAqAACoAACgAAKAAAACgCgKAKAqqoCqqgKqqAqqoAAA"), 32, atob("DQULDw0RDQUHBw0NBQ0FEQ0FDQ0NDQ0NDQ0FBQsNCw0RDQ0NDQ0NDQ0NDQ0NDw0NDQ0NDQ0NDQ8NDQ0HEQc="), 22+(scale<<8)+(1<<16)); + return this; +}; + +var IMAGEWIDTH = 117; +var IMAGEHEIGHT = 60; +var r2d2 = require("heatshrink").decompress(atob("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")); + +// timeout used to update every minute +var drawTimeout; + +// schedule a draw for the next minute +function queueDraw() { + if (drawTimeout) clearTimeout(drawTimeout); + drawTimeout = setTimeout(function() { + drawTimeout = undefined; + draw(); + }, 60000 - (Date.now() % 60000)); +} + +function draw() { + //reset().clearRect(0,24,g.getWidth(),g.getHeight()-IMAGEHEIGHT); + // draw r2d2 + g.drawImage(r2d2, (g.getWidth()/2)-(IMAGEWIDTH/2), g.getHeight()-IMAGEHEIGHT); + + var x = g.getWidth()/2; + var y = g.getHeight()/2 - 30; + g.reset(); + // work out locale-friendly date/time + var date = new Date(); + var timeStr = require("locale").time(date,1).trim(); + var dateStr = require("locale").date(date).toUpperCase(); + + + // draw time + g.setFontAlign(0,0).setFont("Undo:3"); + g.clearRect(0,y-30,g.getWidth(),y+30); // clear the background + g.drawString(timeStr,x,y); + // draw date + y += 40; + g.setFontAlign(0,0).setFont("Undo"); + g.clearRect(0,y-10,g.getWidth(),y+20); // clear the background + g.drawString(dateStr,x,y); + // queue draw in one minute + queueDraw(); +} + +// Clear the screen once, at startup +g.clear(); +// draw immediately at first, queue update +draw(); +// Stop updates when LCD is off, restart when on +Bangle.on('lcdPower',on=>{ + if (on) { + draw(); // draw immediately, queue redraw + } else { // stop draw timer + if (drawTimeout) clearTimeout(drawTimeout); + drawTimeout = undefined; + } +}); +// Show launcher when middle button pressed +Bangle.setUI("clock"); +// Load widgets +Bangle.loadWidgets(); +Bangle.drawWidgets(); \ No newline at end of file diff --git a/apps/r2d2clk/app.png b/apps/r2d2clk/app.png new file mode 100644 index 0000000000000000000000000000000000000000..94502501d69c4d629548302d7d8b3fa7b5126452 GIT binary patch literal 3143 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 literal 0 HcmV?d00001 diff --git a/apps/r2d2clk/metadata.json b/apps/r2d2clk/metadata.json new file mode 100644 index 000000000..3d521e1e6 --- /dev/null +++ b/apps/r2d2clk/metadata.json @@ -0,0 +1,14 @@ +{ "id": "r2d2clk", + "name": "R2D2 Clock", + "shortName":"R2D2 Clock", + "version":"0.01", + "description": "A clock with R2D2's shiny metal face on it. :)", + "icon": "app.png", + "tags": "", + "supports" : ["BANGLEJS2"], + "readme": "README.md", + "storage": [ + {"name":"r2d2clk.app.js","url":"app.js"}, + {"name":"r2d2clk.img","url":"app-icon.js","evaluate":true} + ] +} From 9973435b69f744bbdc420d02f20cd9f96f12b97e Mon Sep 17 00:00:00 2001 From: nujw Date: Tue, 24 May 2022 09:37:47 +1200 Subject: [PATCH 263/294] Update metadata.json --- apps/speedalt2/metadata.json | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/apps/speedalt2/metadata.json b/apps/speedalt2/metadata.json index 801d65fb0..0de0b28bb 100644 --- a/apps/speedalt2/metadata.json +++ b/apps/speedalt2/metadata.json @@ -15,5 +15,10 @@ {"name":"speedalt2.img","url":"app-icon.js","evaluate":true}, {"name":"speedalt2.settings.js","url":"settings.js"} ], - "data": [{"name":"speedalt2.json"}] + "data": [ + {"name":"speedalt2.json"}, + {"name":"waypoints1.json"}, + {"name":"waypoints2.json"}, + {"name":"waypoints3.json"} + ] } From a7c9c124eac162a76aa58dd3e58b6005c4d59403 Mon Sep 17 00:00:00 2001 From: frigis1 <63980066+frigis1@users.noreply.github.com> Date: Mon, 23 May 2022 17:05:34 -0700 Subject: [PATCH 264/294] Update ChangeLog --- apps/multitimer/ChangeLog | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/multitimer/ChangeLog b/apps/multitimer/ChangeLog index 624f1b0fb..9b60f403a 100644 --- a/apps/multitimer/ChangeLog +++ b/apps/multitimer/ChangeLog @@ -1 +1,2 @@ -0.01: Initial version \ No newline at end of file +0.01: Initial version +0.02: Update for time_utils module From 5330784b3fc0bef3d04b1b3e6b09bf91de148f42 Mon Sep 17 00:00:00 2001 From: frigis1 <63980066+frigis1@users.noreply.github.com> Date: Mon, 23 May 2022 17:05:59 -0700 Subject: [PATCH 265/294] Update alarm.js --- apps/multitimer/alarm.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/multitimer/alarm.js b/apps/multitimer/alarm.js index fc0195455..97cbaa5fa 100644 --- a/apps/multitimer/alarm.js +++ b/apps/multitimer/alarm.js @@ -73,7 +73,7 @@ function showAlarm(alarm) { const settings = require("sched").getSettings(); let msg = ""; - msg += require("sched").formatTime(alarm.timer); + if (alarm.timer) msg += require("time_utils").formatTime(alarm.timer); if (alarm.msg) { msg += "\n"+alarm.msg; } @@ -86,7 +86,7 @@ function showAlarm(alarm) { if (alarm.data.hm && alarm.data.hm == true) { //hard mode extends auto-snooze time - buzzCount = buzzCount * 2; + buzzCount = buzzCount * 3; startHM(); } From 5854217f1ccc166dcf2f64fe1f6ca40117a41a53 Mon Sep 17 00:00:00 2001 From: frigis1 <63980066+frigis1@users.noreply.github.com> Date: Mon, 23 May 2022 17:06:31 -0700 Subject: [PATCH 266/294] Update app.js --- apps/multitimer/app.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/multitimer/app.js b/apps/multitimer/app.js index becaf6169..e5d77d860 100644 --- a/apps/multitimer/app.js +++ b/apps/multitimer/app.js @@ -258,7 +258,7 @@ function editTimer(idx, a) { a.last = 0; a.data.ot = a.timer; a.appid = "multitimer"; - a.js = "load('multitimer.alarm.js')"; + a.js = "(require('Storage').read('multitimer.alarm.js') !== undefined) ? load('multitimer.alarm.js') : load('sched.js')"; if (idx < 0) alarms.push(a); else alarms[timerIdx[idx]] = a; require("sched").setAlarms(alarms); @@ -585,7 +585,7 @@ function editAlarm(idx, a) { var menu = { "": { "title": "Alarm" }, "< Back": () => { - if (a.data.hm == true) a.js = "load('multitimer.alarm.js')"; + if (a.data.hm == true) a.js = "(require('Storage').read('multitimer.alarm.js') !== undefined) ? load('multitimer.alarm.js') : load('sched.js')"; if (a.data.hm == false && a.js) delete a.js; if (idx >= 0) alarms[alarmIdx[idx]] = a; else alarms.push(a); From b56eff48c6e57e1f84b0675fba2ce59c14949244 Mon Sep 17 00:00:00 2001 From: frigis1 <63980066+frigis1@users.noreply.github.com> Date: Mon, 23 May 2022 17:06:55 -0700 Subject: [PATCH 267/294] Update metadata.json --- apps/multitimer/metadata.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/multitimer/metadata.json b/apps/multitimer/metadata.json index 6e53e2c8c..abb958b90 100644 --- a/apps/multitimer/metadata.json +++ b/apps/multitimer/metadata.json @@ -1,7 +1,7 @@ { "id": "multitimer", "name": "Multi Timer", - "version": "0.01", + "version": "0.02", "description": "Set timers and chronographs (stopwatches) and watch them count down in real time. Pause, create, edit, and delete timers and chronos, and add custom labels/messages. Also sets alarms.", "icon": "app.png", "screenshots": [ @@ -19,4 +19,4 @@ ], "data": [{"name":"multitimer.json"}], "dependencies": {"scheduler":"type"} -} \ No newline at end of file +} From 3bdcc55c9b40dfcc28125dfc033e7fd3c8ca970a Mon Sep 17 00:00:00 2001 From: Lubomir Date: Tue, 24 May 2022 10:18:26 +1000 Subject: [PATCH 268/294] iconlaunch: Release app --- apps/iconlaunch/ChangeLog | 1 + apps/iconlaunch/README.md | 12 ++ apps/iconlaunch/app.js | 201 ++++++++++++++++++++++++++++++++ apps/iconlaunch/app.png | Bin 0 -> 888 bytes apps/iconlaunch/metadata.json | 18 +++ apps/iconlaunch/screenshot1.png | Bin 0 -> 4689 bytes apps/iconlaunch/screenshot2.png | Bin 0 -> 4752 bytes apps/iconlaunch/settings.js | 28 +++++ 8 files changed, 260 insertions(+) create mode 100644 apps/iconlaunch/ChangeLog create mode 100644 apps/iconlaunch/README.md create mode 100644 apps/iconlaunch/app.js create mode 100644 apps/iconlaunch/app.png create mode 100644 apps/iconlaunch/metadata.json create mode 100644 apps/iconlaunch/screenshot1.png create mode 100644 apps/iconlaunch/screenshot2.png create mode 100644 apps/iconlaunch/settings.js diff --git a/apps/iconlaunch/ChangeLog b/apps/iconlaunch/ChangeLog new file mode 100644 index 000000000..af7f83942 --- /dev/null +++ b/apps/iconlaunch/ChangeLog @@ -0,0 +1 @@ +0.01: Initial release diff --git a/apps/iconlaunch/README.md b/apps/iconlaunch/README.md new file mode 100644 index 000000000..0d36fdeb4 --- /dev/null +++ b/apps/iconlaunch/README.md @@ -0,0 +1,12 @@ +# Icon launcher + +A launcher inspired by smartphones, with an icon-only scrollable menu. + +This launcher shows 9 apps per screen, making it much faster to navigate versus the default launcher. + +![A screenshot](screenshot1.png) +![Another screenshot](screenshot2.png) + +## Technical note + +The app uses `E.showScroller`'s code in the app but not the function itself because `E.showScroller` doesn't report the position of a press to the select function. diff --git a/apps/iconlaunch/app.js b/apps/iconlaunch/app.js new file mode 100644 index 000000000..5dec33284 --- /dev/null +++ b/apps/iconlaunch/app.js @@ -0,0 +1,201 @@ +const s = require("Storage"); +const settings = s.readJSON("launch.json", true) || { showClocks: true, fullscreen: false }; + +if (!settings.fullscreen) { + Bangle.loadWidgets(); + Bangle.drawWidgets(); +} + +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" && settings.showClocks) || + !app.type) + ); +apps.sort((a, b) => { + var n = (0 | a.sortorder) - (0 | b.sortorder); + if (n) return n; // do sortorder first + if (a.name < b.name) return -1; + if (a.name > b.name) return 1; + return 0; +}); +apps.forEach((app) => { + if (app.icon) app.icon = s.read(app.icon); // should just be a link to a memory area +}); + +let scroll = 0; +let selectedItem = -1; +const R = Bangle.appRect; + +const iconSize = 48; + +const appsN = Math.floor(R.w / iconSize); +const whitespace = (R.w - appsN * iconSize) / (appsN + 1); + +const itemSize = iconSize + whitespace; + +function drawItem(itemI, r) { + g.clearRect(r.x, r.y, r.x + r.w - 1, r.y + r.h - 1); + let x = 0; + for (let i = itemI * appsN; i < appsN * (itemI + 1); i++) { + if (!apps[i]) break; + x += whitespace; + if (!apps[i].icon) { + g.setFontAlign(0,0,0).setFont("12x20:2").drawString("?", x + r.x+iconSize/2, r.y + iconSize/2); + } else { + g.drawImage(apps[i].icon, x + r.x, r.y); + } + if (selectedItem == i) { + g.drawRect( + x + r.x - 1, + r.y - 1, + x + r.x + iconSize + 1, + r.y + iconSize + 1 + ); + } + x += iconSize; + } + drawText(itemI); +} + +function drawItemAuto(i) { + var y = idxToY(i); + g.reset().setClipRect(R.x, y, R.x2, y + itemSize); + drawItem(i, { + x: R.x, + y: y, + w: R.w, + h: itemSize + }); + g.setClipRect(0, 0, g.getWidth() - 1, g.getHeight() - 1); +} + +let lastIsDown = false; + +function drawText(i) { + const selectedApp = apps[selectedItem]; + const idy = (selectedItem - (selectedItem % 3)) / 3; + if (!selectedApp || i != idy) return; + const appY = idxToY(idy) + iconSize / 2; + g.setFontAlign(0, 0, 0); + g.setFont("12x20"); + const rect = g.stringMetrics(selectedApp.name); + g.clearRect( + R.w / 2 - rect.width / 2, + appY - rect.height / 2, + R.w / 2 + rect.width / 2, + appY + rect.height / 2 + ); + g.drawString(selectedApp.name, R.w / 2, appY); +} + +function selectItem(id, e) { + const iconN = E.clip(Math.floor((e.x - R.x) / itemSize), 0, appsN - 1); + const appId = id * appsN + iconN; + if (appId == selectedItem && apps[appId]) { + const app = apps[appId]; + if (!app.src || s.read(app.src) === undefined) { + E.showMessage( /*LANG*/ "App Source\nNot found"); + } else { + load(app.src); + } + } + selectedItem = appId; + drawItems(); +} + +function idxToY(i) { + return i * itemSize + R.y - (scroll & ~1); +} + +function YtoIdx(y) { + return Math.floor((y + (scroll & ~1) - R.y) / itemSize); +} + +function drawItems() { + g.reset().clearRect(R.x, R.y, R.x2, R.y2); + g.setClipRect(R.x, R.y, R.x2, R.y2); + var a = YtoIdx(R.y); + var b = Math.min(YtoIdx(R.y2), 99); + for (var i = a; i <= b; i++) + drawItem(i, { + x: R.x, + y: idxToY(i), + w: R.w, + h: itemSize, + }); + g.setClipRect(0, 0, g.getWidth() - 1, g.getHeight() - 1); +} + +drawItems(); +g.flip(); + +const itemsN = Math.ceil(apps.length / appsN); + +Bangle.setUI({ + mode: "custom", + drag: (e) => { + let dy = e.dy; + if (scroll + R.h - dy > itemsN * itemSize) { + dy = scroll + R.h - itemsN * itemSize; + } + if (scroll - dy < 0) { + dy = scroll; + } + scroll -= dy; + scroll = E.clip(scroll, 0, itemSize * (itemsN - 1)); + g.setClipRect(R.x, R.y, R.x2, R.y2); + g.scroll(0, dy); + if (dy < 0) { + g.setClipRect(R.x, R.y2 - (1 - dy), R.x2, R.y2); + let i = YtoIdx(R.y2 - (1 - dy)); + let y = idxToY(i); + while (y < R.y2) { + drawItem(i, { + x: R.x, + y: y, + w: R.w, + h: itemSize, + }); + i++; + y += itemSize; + } + } else { + // d>0 + g.setClipRect(R.x, R.y, R.x2, R.y + dy); + let i = YtoIdx(R.y + dy); + let y = idxToY(i); + while (y > R.y - itemSize) { + drawItem(i, { + x: R.x, + y: y, + w: R.w, + h: itemSize, + }); + y -= itemSize; + i--; + } + } + g.setClipRect(0, 0, g.getWidth() - 1, g.getHeight() - 1); + }, + touch: (_, e) => { + if (e.y < R.y - 4) return; + var i = YtoIdx(e.y); + selectItem(i, e); + }, +}); diff --git a/apps/iconlaunch/app.png b/apps/iconlaunch/app.png new file mode 100644 index 0000000000000000000000000000000000000000..6f498aa20f592305a7a0788fa67a46d7a12f0d6f GIT binary patch literal 888 zcmV-;1Bd*HP) zZzpt+A8*GQfBgk^aKE|P3BZfO@zVI9=EjxRI)G(s9l)}69YCKf$tdF%u8TlFTBCke-#!7@j;O-i{ff1$hzaIOB^;s0|EpzsVSg@_VQCFuaIpPWXA7 zxdX~crl=m$SH}S48P>t$SS`&ip_=->YU=xkhld?W zmHhenxx2rx_qK!5>i)vz=L$dIS>M-GegEj_sFftiKvKiZDtR*-Z*6V0Pft%vJbUk2 z1S5BU;AZ@dHkTiM!9Df|k|Y@bp=0s@O-bQsG@9)XY>evr12^L*<^F)(qP}m1`hLD_ zy!dXnJLxa%z3q^C_80bF-=80lv{UouoqWFLJ^5hm2UbGs0G6#s6TpM|0ZDP1rg!rb zvME2{S>M-GeZSl7F3d}c&d$!t{e}HEi;r(X#J7+4>jySBH*0xGF%X4eILA+Hw8>1B zdwf$w(s1~Jn)<$K>ic8aPQ~$Umsj2sTs+7eEsye{J=jkd15E9S~5)l O0000oY_o zvKvpt$QEKIWy$*W`2)V^^TX$!bMHO(ywADko_p@OulKo$7UssB5K#yK0N^yaZGb-Y z)&HaHtf#iBX%TzsSOU?;`T+75vDMSyOrXAr75k|~vb!Vz0K5k#26|SZ*p0lz>|*%2 zxYoIof`9tKhGzn5CGVFq)GR~nCz%oFc;C*ENTequonQQdd+CCEoVb%kieXU*#~CWV zi`1wKI4p}-5|se3fvUmBM+dvV4-O7)MRkEiFP+12ChwJAlnou*MqRG~?*+ym7xQW9 z(2&c2?OF%j_|%TBXc^9*KU>2~CGk4M_~#GXeE!E`!KCx+(a=J$GGL@Q*iYxAa#dqI zqLGBU4pA<;ZH)%uNHHPY0P{0?Xq!KlhyZREqxqv-ki%52h@USGFQ{Y=+A&Fsg`;X@9f+{Ee(d>ePk%G z#jTbHIeh-i;v>tHe%HVTr@ZJNTVaZOva|kc<5PLRdMoPlRyz&(#;;3T>Fsc6ySj1! zP7{**?k>Mrn+A;_-4_34a^`HAy5H)0sYhER-6jeRv+oT?v6rk;jtHO`6dgo2$kk2s zWRiOjQO-INL>MCj{`;-EGFXV*)-?T4q+r=4j-2(pYS~)l4HYfz(+PtNNI1dSzyjN@ zgUI>v$BpDxc(p-d1oIitG`^X{;F8;hWOx`$J(1GBlQG$<$VM!nzU8w#efE5o&E{|V zdPML|e@f==TOf^4m&~8l;Vqvcrd|EGkMY+ZY_z^9uTE14bHM+ynA&des+?c9QYhq+ zHSxRQ*;B8`PzD#jQz^e8%1QmuE#rDaF;R9qbasTG8lsEmTApv@sjdLvgd@!Z+KgXagxis{T{a|Q- z`M*m5{&jpMT_JkBtB%I7>K7Me zgr(au7bjPD0Pdmj$FMFgKdv(k_k5V3r#IgyL5VYZl8;M76^SJ7na5IIJKg@!-ir!C z=H){<;wZPMR~>Oc(+ZnUw<;G($S?#*ku}c4>IP-rP+x;O51R8b&)e0#pT$*pjRgI& zjMXTulIP63e|hI1*1;{-j!R91p=~8&^jgVbzrIe+&qJqS?G8jkjl@G$hnaa$?6r~3 zgWCq;t4Jut}YC-Tmg zy#EN$v{OpT>jKJlOTl1()cPF>GDjS(zsb-{08o^f6vSL#d07g<8QULltm$WjTHOQD zQJE>>4p(>ptwaRm{3ARdlu%M6E_Aw@6kT8F8{1s~h(B6=+uH+VseW!(G>j5t#~It* zSo5#Z1^j$4DH}up1ONXiB`SJ}wDdFEjuU$ac0z3x=ZBB$`|YAn#Mv1uXI4*G$TVB;N!lr$W+vI15A?Pw*+i4+~8v#+=!)E`N#14zWIRb z8r`BeL}Rh}oiW1T;5t|J?)knAKZT>5NTC3K7d7&m{&3)qC0a@XEby7=uGbYFTzK z+dh;hQeiG3!NY$hf@b@t =J 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 literal 0 HcmV?d00001 diff --git a/apps/iconlaunch/screenshot2.png b/apps/iconlaunch/screenshot2.png new file mode 100644 index 0000000000000000000000000000000000000000..b17efa78b87d432dac7a0c80be616cb7a1e74452 GIT binary patch literal 4752 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 S?|(lh!05W^wJJUQgZ}~Ti1d*F literal 0 HcmV?d00001 diff --git a/apps/iconlaunch/settings.js b/apps/iconlaunch/settings.js new file mode 100644 index 000000000..9fbc7ae6a --- /dev/null +++ b/apps/iconlaunch/settings.js @@ -0,0 +1,28 @@ +// make sure to enclose the function in parentheses +(function(back) { + let settings = Object.assign({ + showClocks: true, + fullscreen: false + }, require("Storage").readJSON("launch.json", true) || {}); + + let fonts = g.getFonts(); + function save(key, value) { + settings[key] = value; + require("Storage").write("launch.json",settings); + } + const appMenu = { + "": { "title": /*LANG*/"Launcher" }, + /*LANG*/"< Back": back, + /*LANG*/"Show Clocks": { + value: settings.showClocks == true, + format: v => v ? /*LANG*/"Yes" : /*LANG*/"No", + onchange: (m) => { save("showClocks", m) } + }, + /*LANG*/"Fullscreen": { + value: settings.fullscreen == true, + format: v => v ? /*LANG*/"Yes" : /*LANG*/"No", + onchange: (m) => { save("fullscreen", m) } + } + }; + E.showMenu(appMenu); +}); From 28eb907f57d7c4a44ba2bc00faf101f01a727725 Mon Sep 17 00:00:00 2001 From: Noah Howard <3317164+nh-99@users.noreply.github.com> Date: Mon, 23 May 2022 20:39:54 -0400 Subject: [PATCH 269/294] Add properly sized icon --- apps/r2d2clk/app-icon.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/r2d2clk/app-icon.js b/apps/r2d2clk/app-icon.js index 17ef6b709..246df9376 100644 --- a/apps/r2d2clk/app-icon.js +++ b/apps/r2d2clk/app-icon.js @@ -1 +1 @@ -require("heatshrink").decompress(atob("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")) \ No newline at end of file +require("heatshrink").decompress(atob("mEwyBC/AH4A/AH4A/AH4A/AH4AKqn5ol4416737nlXqnYAIJN/ABMsm80m8j60b60Lu0T22ty2920j+8DBIQPBlkXN4JZ9VIJLBI4IBBLoIHBJoIDBAIO16/Gi4JDBon2jZlCAINEzBbzqn5HoSrB+xJBAI5fNAI8r+7LBAIM8ZN0TywzBIpZfZDIrJDdoJblttagd1W5ZfhDoqTBpnYLsMDq0DmsL28T24DBAKGXgeX1pfCDYIHBDqQzCHYUVLruNzNMq1k69sAKgXBAIK/DBIYXNBZNUu1s+5fb3u271X6wBXm/mu4dD92Y+2YAYIBFBIYTCm4jH71Y4vW51ZLq+12wBB3vX3v3AKvOm69BYYapE+4BCA4Vc2+Fm/Oi/FE5mtuvW3S7U++1ywDB62a404LqZDBUoNEu8Dq0L20L/MMjUL/EMjIFC68Ly0Dy+VaoQrNMIJdR73bCoK7B51588cAYLDTXoOt28b60j+8svUr6sipkp9EylUriEsrIBBMILFBL5+12wDBL567BCoK5B737bYK9Ta4VXU4MT68kvMrqUYwMo0MgAIOAnMjmUJlk4if4qmXbILdBYJ6vBLpazBXoRDB3QVB40YXqYBBUYONq8UjMrykYoFi9QlB51ZoUokMEmHBlVrjlank3DoPGi4vOIYPXXpjRB64zBXoIDBLqpfDvs3hkZkPImMD/4AECIMIsMxssxokjucsvO1HYJfPYIStBLo/WzQNBW4IPBAIJbVL4tk/EL28hw0pgf3zxfD1tVL4WGmMCkWukl61u35zDCYLIJBX4K9d4v3IINMzET68x9EYsFS1SLB2uWmOmkMkL4cq98crWdu/Wq4zREYJfHBIINBYYPe7Y3BL67/Dmk3JIMqxk5kUY8kQ0QBBLoXHmNEmOFlf2hfYvsXboJfT515LoYFBBIJZBXoJhBLq5fCm+t28r+8knEsi6zDmNlAoQBBokw4MriEszUL21c26/TJoJVBL4a1F51ZXrLdCm+ly8b+8j+0srKvBmUJmMjAIRlClXwB4JxBie2pl3P4PFG6fXL4YZDAYRbC40XA4IBFDoZvBAI5fCq+Vq8Ly8jMIUkrIBBldSlXvLYMj6skvUki4RBhe3nk350XHYJfR2uW88bL4XWDoJ/BAJphD404aYIBFBII9DIoJJBjfXjfWY4McnMcrQBCjALC68T64VBvsXb4KRGFIIDDnBhG23vjd9rM8m1My4BMu9Eu+l3HWrF759jhlrpoBBrXrxlx4xlBm5jBzt3zuXAYQFDAJN31u3LoJ/DKoeU2WEiAtB3vXSIajBrm3JoMLyyBBie3AJaPBgY1BzHevFS1Uxw1ChABBlNFueO62aF4JFB71XAIIFBA4oLEvHOzInBA4JdG66RBLYOtuuc6dz121y3OrAVBlkXgd2ifWmgHCAJcj+71BX4a9BoUoqWKAIM58979/m3V0+4ZBnk3bYJLDolXnlXolWnl4mmYpk2mmZml4BYO165PBwkwLIP/AAmtqppBE4PGjAnBXYMb+xfj93aqmXRYMLy8bU4MX2v3GoLjBif4AoOClXBodytkD7AJB2vY5v3WoPe7ZfF+++GIO1uvOnBfp83ashTCC4IrBX4YjDhl6uXu+MA5OD9MgqcxBYJfF626L42eL4WVL/sUvVbqPhkBdB7NindzilZ1vXF4OMuIBBLIJfDznzwkQ40440YL4b1BGoI5BAJmXgd3zuY714LIMpspbBAIMhklzxvu/VUCoNWC4IvBL4O1+4jBgeXAYX4pXQxPoncRgfYie31u3L4J3BKoOEmBbBMoN75+123OrApBQ4IzBsn4rmWrm3AJpLB1vYboItBueOeYIBBtdNymy715ws3pl3C4LFBX4YnHosaAINNjIJD2oXCWIZdCqOc6YhBBYPF+4BBtnXqm3//c70V92YAJv2XoNX60382593a93ZAIX682ZBoV3+24C4IbB61XDYIhDE4WXFo4DBF4QXCeYIpB82YAYIHBB4vmq3/nWN3N8+ybBAJ99AKQZJF8oBCi+NvEDqsb+8T24B/AK3XgeWhYBD24B/AKxbCgEAqlVtnXtn3AP4BS69cu2N3RfB/9b4vV5v260XAP4BOi3N6vu/RdBAAvOrIBCvIB/AJVZ404LY4A/AH4A/AH4A/AH4A/AH4A9")) \ No newline at end of file From 6c28d94b76e0758157b837174dae2179b8a823bb Mon Sep 17 00:00:00 2001 From: Noah Howard <3317164+nh-99@users.noreply.github.com> Date: Mon, 23 May 2022 22:00:38 -0400 Subject: [PATCH 270/294] Add new metadata --- apps/r2d2clk/metadata.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/r2d2clk/metadata.json b/apps/r2d2clk/metadata.json index 3d521e1e6..f2cde76f4 100644 --- a/apps/r2d2clk/metadata.json +++ b/apps/r2d2clk/metadata.json @@ -4,7 +4,8 @@ "version":"0.01", "description": "A clock with R2D2's shiny metal face on it. :)", "icon": "app.png", - "tags": "", + "type": "clock", + "tags": "clock", "supports" : ["BANGLEJS2"], "readme": "README.md", "storage": [ From 2ef59c470fdd35c0559a2b648a5b0d050af27c70 Mon Sep 17 00:00:00 2001 From: Rarder44 Date: Tue, 24 May 2022 10:18:03 +0200 Subject: [PATCH 271/294] implemented "direct launch" and "one click exit" settings --- apps/iconlaunch/ChangeLog | 1 + apps/iconlaunch/app.js | 10 +++++++++- apps/iconlaunch/metadata.json | 2 +- apps/iconlaunch/settings.js | 10 ++++++++++ 4 files changed, 21 insertions(+), 2 deletions(-) diff --git a/apps/iconlaunch/ChangeLog b/apps/iconlaunch/ChangeLog index af7f83942..4a72a9f28 100644 --- a/apps/iconlaunch/ChangeLog +++ b/apps/iconlaunch/ChangeLog @@ -1 +1,2 @@ 0.01: Initial release +0.02: implemented "direct launch" and "one click exit" settings \ No newline at end of file diff --git a/apps/iconlaunch/app.js b/apps/iconlaunch/app.js index 5dec33284..4eeaff589 100644 --- a/apps/iconlaunch/app.js +++ b/apps/iconlaunch/app.js @@ -1,5 +1,8 @@ const s = require("Storage"); -const settings = s.readJSON("launch.json", true) || { showClocks: true, fullscreen: false }; +const settings = s.readJSON("launch.json", true) || { showClocks: true, fullscreen: false,direct:false,oneClickExit:false }; + +if( settings.oneClickExit) + setWatch(_=> load(), BTN1); if (!settings.fullscreen) { Bangle.loadWidgets(); @@ -107,6 +110,11 @@ function drawText(i) { function selectItem(id, e) { const iconN = E.clip(Math.floor((e.x - R.x) / itemSize), 0, appsN - 1); const appId = id * appsN + iconN; + if( settings.direct && apps[appId]) + { + load(apps[appId].src); + return; + } if (appId == selectedItem && apps[appId]) { const app = apps[appId]; if (!app.src || s.read(app.src) === undefined) { diff --git a/apps/iconlaunch/metadata.json b/apps/iconlaunch/metadata.json index 1dddb66b4..01e447672 100644 --- a/apps/iconlaunch/metadata.json +++ b/apps/iconlaunch/metadata.json @@ -2,7 +2,7 @@ "id": "iconlaunch", "name": "Icon Launcher", "shortName" : "Icon launcher", - "version": "0.01", + "version": "0.02", "icon": "app.png", "description": "A launcher inspired by smartphones, with an icon-only scrollable menu.", "tags": "tool,system,launcher", diff --git a/apps/iconlaunch/settings.js b/apps/iconlaunch/settings.js index 9fbc7ae6a..e9667047c 100644 --- a/apps/iconlaunch/settings.js +++ b/apps/iconlaunch/settings.js @@ -22,6 +22,16 @@ value: settings.fullscreen == true, format: v => v ? /*LANG*/"Yes" : /*LANG*/"No", onchange: (m) => { save("fullscreen", m) } + }, + /*LANG*/"Direct launch": { + value: settings.direct == true, + format: v => v ? /*LANG*/"Yes" : /*LANG*/"No", + onchange: (m) => { save("direct", m) } + }, + /*LANG*/"One click exit": { + value: settings.oneClickExit == true, + format: v => v ? /*LANG*/"Yes" : /*LANG*/"No", + onchange: (m) => { save("oneClickExit", m) } } }; E.showMenu(appMenu); From 9ef9137bc060757c491117d08a9effe26337029f Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Tue, 24 May 2022 09:50:10 +0100 Subject: [PATCH 272/294] update after https://github.com/espruino/BangleApps/pull/1868 since we use waypoints.json too --- apps/speedalt2/metadata.json | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/speedalt2/metadata.json b/apps/speedalt2/metadata.json index 0de0b28bb..2a111af28 100644 --- a/apps/speedalt2/metadata.json +++ b/apps/speedalt2/metadata.json @@ -17,6 +17,7 @@ ], "data": [ {"name":"speedalt2.json"}, + {"name":"waypoints.json"}, {"name":"waypoints1.json"}, {"name":"waypoints2.json"}, {"name":"waypoints3.json"} From 4ded6c844ac4e8ecbbf4ee1a5d85b57ddc1e0baa Mon Sep 17 00:00:00 2001 From: Lubomir Date: Tue, 24 May 2022 22:54:16 +1000 Subject: [PATCH 273/294] iconlaunch: Change icon to one by icons8 This doesn't bump the version, as it doesn't change anything on the watch, just the website --- apps/iconlaunch/app.png | Bin 888 -> 1395 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/apps/iconlaunch/app.png b/apps/iconlaunch/app.png index 6f498aa20f592305a7a0788fa67a46d7a12f0d6f..1c8068c50d528badf72b8b3355668c55feb377f7 100644 GIT binary patch delta 1376 zcmV-m1)uu(2J;G#B!32COGiWi{{a60|De66lK=n(C`m*?RA_nwDFa5?mTXX^@)+0xcR-V}wvKQR9P2jRsMOf|@9=zR&^@QZ>4T#At%m zN?WufUMK}&W7{mD*0xZMQp{M zA^zQ9w5A!h23Q#s09iXu+KRh+pi%%7zCU6s&i~x>7|xQNV7pMHFp3mTs_#o>U7UZy zOI_JHTXWbGkXH-KK8Ly66LwYPFbx%ZIa0ZsG&z*8|JLFjGMyS*OS)}Qa@gvfQw4H5 zo^a0kNIZaJcZO`ruLza~)R z8%JhlB`j%&C2cUX0>E-7-ur103mdE1e`XN?#FQLYz)-7-78pM&vJ+_z5!*N$P z8QA*{*hC`YQ}{1nLbBcU*(zI!e(%N>0jYPfQ6#(r0>NU}Dh%LUe+vea|Bxk%sDn-B z4kZ*Yf7S{fU9uAZO%L<)K%0F=d9{#J4TD}w6A0K!zhEI?ZOINi1)F0C7w42y?S7fl z{(oaM`|6Vya2H*ysg+n>P=z9=Q|ekxV4#t}KqIBDH7IgAo`OvYIj73SnhNOfdkJen zq+u@^-P_6N-i{bS^}XvtU*Q?m24!@C|*3xAPs-!BXvFEd@kzVW6E)&g{GS zY=u<2SV%&Efk9V)%WV_0gDDq#FJVGLPj!uRvhFvEq)Llvaww_tAWXi-8HFqylz$gi zvo!BvM1nF5Bq1Q0))Ez^qL^%r6C&ix^49ang6G-1xQ?Q1Pr?|>ER@O`=N9)XEOtG_ z`QN^|*;bUZoX3~GPKUqA)cu<7Kq_mTvT#u9T8$(m7S66@Z15wl^&etc-Ugg|<0FtTfqgp7O6T2le0JCMp6r)H?M_kM_b z&RTk|{y^E>7jObUUjBljY!9b;KejIb#@%84ihU?@*mUKixSbkjv#)_>Us(gCuGN&y zT@OHK|5qIE+HXZM@f`?hPM&UiHS&BHYn)MZ^?yxR8zZP*=hE+I6ZTK)5~tD~8W>y{ iJe9KfrZ9zj9sdBN)1W#sewIi80000A?Ru!uXiB+ox*s*S;K1kISuh3nqJ^=^>Wn0)pks|R1yn=&};t2b)u-n*4 zJkGRL6RMn@e?HG#d*nOkUiiZzpt+A8*GQfBgk^aKE|P3BZfO@zVI9=EjxR zI)G(s9l)}69e+TdEXgdY80Zy_@5ZO}ktZKyd@&Ob$&$<>ijba_&KRCNCEku1q6K*o z={VzyOQ;PDalgqJi1K@<^)S4MXioTfo4EtZNv5bC(pSd-DbM$ z_0XDGLWbK92)7?F+d2!iE;9m_VZU6Ukt$KH#ih}Iu(E?Pl^A1<@FmKhPxRbWP|(r0b}9^@@3=6Py9f1 zMMpkidU>haE|k{Q3F0yT7pawu92@{=((w3P0dk-`7-q z|LEwbl_bePQp3zDc{3YtZEdwrPftrcd+%BVBY$^);AZ@dHkTiM!9Df|k|Y@bp=0s@ zO-bQsG@9)XY>evr12^L*<^F)(qP}m1`hLD_y!dXnJLxa%z3q^C_80bF-=80lv{Uou zoqWFLJ^5hm2UbGs0G6#s6TpM|0ZDP1rg!rbvME2{S>M-GeZSl7F3d}c&d$!t{e}HE zi&~FwLBzL@_v;5XH#ci}Nih(GVK~Q6Y_!Qtm3w?sMAC5hftvchYU=xWhMmi&Y1+HE rxNz_1_g^1eC#f09dVKx#xctCBF?nJquv#)r00000NkvXXu0mjfF}Jb| From c3468fc0e91c4454d2e932deeeb5ce9dba7c8cf2 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Tue, 24 May 2022 16:28:22 +0100 Subject: [PATCH 274/294] bthrm 0.09: Misc Fixes and improvements (https://github.com/espruino/BangleApps/pull/1655) --- apps/bthrm/ChangeLog | 1 + apps/bthrm/metadata.json | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/bthrm/ChangeLog b/apps/bthrm/ChangeLog index 41eec666a..7ca8319b6 100644 --- a/apps/bthrm/ChangeLog +++ b/apps/bthrm/ChangeLog @@ -21,3 +21,4 @@ Adds some preset modes and a custom one Restructure the settings menu 0.08: Allow scanning for devices in settings +0.09: Misc Fixes and improvements (https://github.com/espruino/BangleApps/pull/1655) diff --git a/apps/bthrm/metadata.json b/apps/bthrm/metadata.json index 85c19ab33..39c1ff8bb 100644 --- a/apps/bthrm/metadata.json +++ b/apps/bthrm/metadata.json @@ -2,7 +2,7 @@ "id": "bthrm", "name": "Bluetooth Heart Rate Monitor", "shortName": "BT HRM", - "version": "0.08", + "version": "0.09", "description": "Overrides Bangle.js's build in heart rate monitor with an external Bluetooth one.", "icon": "app.png", "type": "app", From 4f512a15f4c23ade6788fd57628317dba178c97d Mon Sep 17 00:00:00 2001 From: Noah Howard <3317164+nh-99@users.noreply.github.com> Date: Tue, 24 May 2022 12:02:37 -0400 Subject: [PATCH 275/294] Remove new apps from master branch --- apps/discgolf/ChangeLog | 1 - apps/discgolf/README.md | 14 --- apps/discgolf/app-icon.js | 1 - apps/discgolf/app.js | 171 ------------------------------- apps/discgolf/app.png | Bin 10687 -> 0 bytes apps/discgolf/metadata.json | 14 --- apps/discgolf/summary_screen.png | Bin 3025 -> 0 bytes apps/discgolf/throw_screen.png | Bin 2459 -> 0 bytes apps/r2d2clk/ChangeLog | 1 - apps/r2d2clk/README.md | 7 -- apps/r2d2clk/app-icon.js | 1 - apps/r2d2clk/app.js | 67 ------------ apps/r2d2clk/app.png | Bin 3143 -> 0 bytes apps/r2d2clk/metadata.json | 15 --- 14 files changed, 292 deletions(-) delete mode 100644 apps/discgolf/ChangeLog delete mode 100644 apps/discgolf/README.md delete mode 100644 apps/discgolf/app-icon.js delete mode 100644 apps/discgolf/app.js delete mode 100644 apps/discgolf/app.png delete mode 100644 apps/discgolf/metadata.json delete mode 100644 apps/discgolf/summary_screen.png delete mode 100644 apps/discgolf/throw_screen.png delete mode 100644 apps/r2d2clk/ChangeLog delete mode 100644 apps/r2d2clk/README.md delete mode 100644 apps/r2d2clk/app-icon.js delete mode 100644 apps/r2d2clk/app.js delete mode 100644 apps/r2d2clk/app.png delete mode 100644 apps/r2d2clk/metadata.json diff --git a/apps/discgolf/ChangeLog b/apps/discgolf/ChangeLog deleted file mode 100644 index 220e1d1c2..000000000 --- a/apps/discgolf/ChangeLog +++ /dev/null @@ -1 +0,0 @@ -0.01: Initial version of disc golf app. Has throw and hole counter, along with summary screen. Uses buttons for holes & throws. \ No newline at end of file diff --git a/apps/discgolf/README.md b/apps/discgolf/README.md deleted file mode 100644 index 34a9dfe90..000000000 --- a/apps/discgolf/README.md +++ /dev/null @@ -1,14 +0,0 @@ -# Disc Golf - -Individual score tracking for disc golf on your wrist. - -![](throw_screen.png) -![](summary_screen.png) - -## Usage - -Press the side button once to increment throws. Double-tap the side button to increment holes. View your game summary with the button in the upper right of the screen. - -## Creator - -Made by [Noah Howard](https://github.com/nh-99) diff --git a/apps/discgolf/app-icon.js b/apps/discgolf/app-icon.js deleted file mode 100644 index cfc07a2fa..000000000 --- a/apps/discgolf/app-icon.js +++ /dev/null @@ -1 +0,0 @@ -require("heatshrink").decompress(atob("mEwxH+AH4A/ABFzudsAAImmABIppAAIQBFcYMBzwMDFbP+y5RJHYiHdLJYADG5AATzxaNFotszwuXFp5sFLq4tIVpANNF0D4FRqobFJ5peaFxKtJXgi9VzxdSLwwvUFyYvaFxIhKOYwvSFxoAEzyjJF7I/VFyzRjU5QICuYiNBxBJTQp7lFF7byQGQYwSOwovSOpJsFdpwvTao4voMQ4vQOQQwmX4oQCBAwwgCxAvWDIwvPGD4vIy4WJSSzcFMCCpGMC+eGChiUYJwjJPIRiTF5xULBxwvVEJgQQCIQOEF5X+zwfLSoY0HBYg9FF5a2QDSQvNWqJbBAQTaOMTY9PF6DFNAB4uRGLguUYygucfKwubGQgzLFsAAHFYV6Fc4A/AAw=")) \ No newline at end of file diff --git a/apps/discgolf/app.js b/apps/discgolf/app.js deleted file mode 100644 index 68bbd817d..000000000 --- a/apps/discgolf/app.js +++ /dev/null @@ -1,171 +0,0 @@ -Bangle.loadWidgets(); - -// -// App imports -// -var Layout = require("Layout"); - -// -// App variables -// -var holeCount = 1; -var throwCount = 0; -var drawTimeout; -var currentScreen = 'throw'; -var redraw = true; -var update = true; -var holeSummary = { - "< Back" : () => { update = true; redraw = true; currentScreen = 'throw'; E.showMenu(); createThrowLayout(); }, - "Hole #1": { value: 0 }, - "Hole #2": { value: 0 }, - "Hole #3": { value: 0 }, - "Hole #4": { value: 0 }, - "Hole #5": { value: 0 }, - "Hole #6": { value: 0 }, - "Hole #7": { value: 0 }, - "Hole #8": { value: 0 }, - "Hole #9": { value: 0 }, - "Front": { value: 0 }, - "Hole #10": { value: 0 }, - "Hole #11": { value: 0 }, - "Hole #12": { value: 0 }, - "Hole #13": { value: 0 }, - "Hole #14": { value: 0 }, - "Hole #15": { value: 0 }, - "Hole #16": { value: 0 }, - "Hole #17": { value: 0 }, - "Hole #18": { value: 0 }, - "Back": { value: 0 }, -}; - -// Images -function getBackImage() { - return atob("FhYBAAAAEAAAwAAHAAA//wH//wf//g///BwB+DAB4EAHwAAPAAA8AADwAAPAAB4AAHgAB+AH/wA/+AD/wAH8AA=="); -} -function getMenuImage() { - return { - width : 20, height : 20, bpp : 1, - buffer : require("heatshrink").decompress(atob("AAk///D//8CBcDBwITB4AiVA")) - }; -} -function getBasketIcon() { - return { - width : 20, height : 20, bpp : 1, - buffer : require("heatshrink").decompress(atob("gFggF/8EH/0AiWAgtogEW0EDt0Am3ggfsgEf4EB/EA//4j//wEChEP/8AgwnDAgw")) - }; -} -function getFrisbeeIcon() { - return { - width : 20, height : 20, bpp : 1, - buffer : require("heatshrink").decompress(atob("AAf+gF/wE+uEPx0B+PAn0cgf/4F3/0G/1g9/7g1/7AJB4+f/k+v3B/Hcg4WBj/4E4ItC")) - }; -} - -var throwLayout; - -function createThrowLayout() { - throwLayout = new Layout( { - type:"v", c: [ - // Title & menu button - { - type:"h", fillx:1, valign:-1, bgCol:g.theme.bg2, col: g.theme.fg2, c: [ - {type:"img", src:getBasketIcon()}, - {type:"txt", pad:4, font:"15%", label:holeCount, id: "holeCount"}, - {type:"txt", pad:4, font:"15%", label: '', fillx:1}, - {type:"btn", src:getMenuImage(), halign:1, cb: l=>{ currentScreen = 'summary'; update = true; redraw = true; }} - ] - }, - // Throw count - { - type:"h", filly:1, c: [ - {type:"img", pad:4, src:getFrisbeeIcon() }, - {type:"txt", fillx:1, font:"6x8:2", label:"Throws: "+throwCount, id:"throwCount"} - ] - } - ] - }, {lazy:true}); -} - -function incrementHole() { - if (holeCount > 18) return; - resetThrow(); - holeCount += 1; - holeSummary["Hole #" + holeCount] = {value: 0}; -} -function incrementThrow() { - throwCount += 1; - holeSummary["Hole #" + holeCount] = {value: throwCount}; -} -function decrementThrow() { - throwCount -= 1; - holeSummary["Hole #" + holeCount] = {value: throwCount}; -} -function resetThrow() { - throwCount = 0; -} -function computeFrontScore() { - var scoreSum = 0; - for (var i = 1; i < 10; i++) { - scoreSum += holeSummary["Hole #" + i].value; - } - holeSummary.Front = {value: scoreSum}; -} -function computeBackScore() { - var scoreSum = 0; - for (var i = 1; i < 19; i++) { - scoreSum += holeSummary["Hole #" + i].value; - } - holeSummary.Back = {value: scoreSum}; -} - -// update the app state/variables -function updateApp() { - throwLayout.holeCount.label = holeCount; - throwLayout.throwCount.label = "Throws: " + throwCount; -} - -// update the screen -function draw() { - updateApp(); - if (redraw) { - throwLayout.forgetLazyState(); - redraw = false; - } - if (update) { - if (currentScreen == 'throw') { - throwLayout.render(); - } else if (currentScreen == 'summary') { - E.showMenu(holeSummary); - } - update = false; - } - // schedule a draw for the next 500ms - if (drawTimeout) clearTimeout(drawTimeout); - drawTimeout = setTimeout(function() { - drawTimeout = undefined; - draw(); - }, 500 - (Date.now() % 500)); -} - -// -// button press events -// -setWatch((p) => { - if (p.time - p.lastTime < 0.2) { - decrementThrow(); - incrementHole(); - } else { - incrementThrow(); - } - computeFrontScore(); - computeBackScore(); - update = true; -}, BTN, {edge:"rising", debounce:50, repeat:true}); - -// -// main app function start -// -g.clear(); -Bangle.drawWidgets(); -createThrowLayout(); -draw(); \ No newline at end of file diff --git a/apps/discgolf/app.png b/apps/discgolf/app.png deleted file mode 100644 index 6aba5e54816571474aae74f0db98b39a7db7933a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10687 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 diff --git a/apps/discgolf/metadata.json b/apps/discgolf/metadata.json deleted file mode 100644 index 6d56f05e4..000000000 --- a/apps/discgolf/metadata.json +++ /dev/null @@ -1,14 +0,0 @@ -{ "id": "discgolf", - "name": "Disc Golf", - "shortName":"Disc Golf", - "version":"0.01", - "description": "A personal disc golf score tracker", - "icon": "app.png", - "tags": "", - "supports" : ["BANGLEJS2"], - "readme": "README.md", - "storage": [ - {"name":"discgolf.app.js","url":"app.js"}, - {"name":"discgolf.img","url":"app-icon.js","evaluate":true} - ] -} diff --git a/apps/discgolf/summary_screen.png b/apps/discgolf/summary_screen.png deleted file mode 100644 index 480d36eddfa8646b874e96458520979ac2de4ad6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3025 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 diff --git a/apps/r2d2clk/ChangeLog b/apps/r2d2clk/ChangeLog deleted file mode 100644 index 5560f00bc..000000000 --- a/apps/r2d2clk/ChangeLog +++ /dev/null @@ -1 +0,0 @@ -0.01: New App! diff --git a/apps/r2d2clk/README.md b/apps/r2d2clk/README.md deleted file mode 100644 index 24730a0bf..000000000 --- a/apps/r2d2clk/README.md +++ /dev/null @@ -1,7 +0,0 @@ -# R2D2 Clock - -A clock with R2D2's shiny metal face on it. :) - -## Creator - -Made by [Noah Howard](https://github.com/nh-99) diff --git a/apps/r2d2clk/app-icon.js b/apps/r2d2clk/app-icon.js deleted file mode 100644 index 246df9376..000000000 --- a/apps/r2d2clk/app-icon.js +++ /dev/null @@ -1 +0,0 @@ -require("heatshrink").decompress(atob("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")) \ No newline at end of file diff --git a/apps/r2d2clk/app.js b/apps/r2d2clk/app.js deleted file mode 100644 index a7ead76f1..000000000 --- a/apps/r2d2clk/app.js +++ /dev/null @@ -1,67 +0,0 @@ -Graphics.prototype.setFontUndo = function(scale) { - // Actual height 19 (20 - 2) - this.setFontCustom(atob("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKqKAqooCqigKqKAAAACgAAKAAAoAACgAAAAAAAAACgAAKAAAoAACgAAAAAAKCgAoKAKqqAqqoCqqgKqqAKCgAoKAKqqAqqoCqqgKqqAKCgAoKAAAAAKgoAqCgKqKAqooKiioqKKiooqKiioKKqAoqoCgqAKCoAAAACoCgKgKAiCoCIKgKioAqKgACoAAKgACoAAKgACoqAKioCoIgKgiAoCoCgKgAAAAKqgAqqAKqqAqqoKiioqKKiooqKiioKAKAoAoCgCgKAKAAAACgAAKAAAoAACgAAAAAAKqgAqqAKqqAqqoCgCgKAKAAAACgCgKAKAqqoCqqgCqoAKqgAAAACigAKKAAqoACqgAqoACqgAKqAAqoAAqoACqgAKKAAooAAAAAAoAACgAAKAAAoAAqqACqoAKqgAqqAAKAAAoAACgAAKAAAAAAACoAAKgAAqAACoAAAAAoAACgAAKAAAoAACgAAKAAAoAACgAAKAAAoAACgAAKAAAAAAACgAAKAAAoAACgAAAAAAoAACgAAqAACoAAqAACoAAqAACoAAqAACoAAqAACoAAqAACoAAKAAAoAAAAAACqoAKqgCqqgKqqAoAoCgCgKAKAoAoCqqgKqqAKqgAqqAAAAAqqoCqqgKqqAqqoAAAAKCqAoKoCiqgKKqAoooCiigKKKAoooCqigKqKAKgoAqCgAAAAoAoCgCgKAKAoAoCiigKKKAoooCiigKqqAqqoAqqACqoAAAACqAAKoAAqoACqgAAKAAAoAACgAAKAAqqoCqqgKqqAqqoAAAAKoKAqgoCqigKqKAoooCiigKKKAoooCiqgKKqAoKgCgqAAAAAKqgAqqAKqqAqqoCiigKKKAoooCiigKKqAoqoCgqAKCoAAAACgAAKAAAoAACgAAKAAAoAACgAAKAAAqqoCqqgCqqAKqoAAAACqoAKqgCqqgKqqAoooCiigKKKAoooCqqgKqqAKqgAqqAAAAAKgAAqAAKqAAqoACigAKKAAooACigAKqqAqqoAqqgCqqAAAACgCgKAKAoAoCgCgAAAAoAqCgCoKAKgoAqAAAAAKAAAoAAKoAAqgAKqgAqqAKgqAqCoCgCgKAKAAAAAoKACgoAKCgAoKACgoAKCgAoKACgoAKCgAoKACgoAKCgAAAAKAKAoAoCoKgKgqAKqgAqqAAqgACqAACgAAKAAAAACgAAKAAAoAACgAAKKKAoooCiigKKKAqoACqgACoAAKgAAAAACqqAKqoCqqgKqqAoAACgAAKCoAoKgCiqgKKqAoooCiigKqqAqqoAqqACqoAAAAAqqgCqqAqqoCqqgKKAAooACigAKKAAqqoCqqgCqqAKqoAAAAKqqAqqoCqqgKqqAoooCiigKKKAoooCqqgKqqAKCgAoKAAAAAKqgAqqAKqqAqqoCgCgKAKAoAoCgCgKAKAoAoCgCgKAKAAAACqqgKqqAqqoCqqgKAKAoAoCoKgKgqAKqgAqqAAqgACqAAAAACqoAKqgCqqgKqqAoooCiigKKKAoooCgCgKAKAoAoCgCgAAAAKqoAqqgKqqAqqoCigAKKAAooACigAKAAAoAACgAAKAAAAAAAqqACqoAqqoCqqgKAKAoAoCiigKKKAoqoCiqgKKqAoqoAAAAKqqAqqoCqqgKqqAAoAACgAAKAAAoACqqgKqqAqqoCqqgAAAAoAoCgCgKAKAoAoCqqgKqqAqqoCqqgKAKAoAoCgCgKAKAAAAAAKAAAoAACoAAKgAAKAAAoAACgAAKAqqoCqqgKqoAqqgAAAAKqqAqqoCqqgKqqACqAAKoACqoAKqgCoKgKgqAoAoCgCgAAAAqqgCqqAKqqAqqoAACgAAKAAAoAACgAAKAAAoAACgAAKAAAACqqgKqqAqqoCqqgCoAAKgAAKgAAqAAKgAAqAAKqqAqqoCqqgKqqAAAACqqgKqqAqqoCqqgCoAAKgAAKgAAqAAqqoCqqgKqqAqqoAAAACqoAKqgCqqgKqqAoAoCgCgKAKAoAoCqqgKqqAKqgAqqAAAAAqqoCqqgKqqAqqoCigAKKAAooACigAKqAAqoAAqAACoAAAAAAqqACqoAqqoCqqgKAKAoAoCgKgKAqAqqoCqqgCqqAKqoAAAAKqqAqqoCqqgKqqAooACigAKKgAoqACqqgKqqAKioAqKgAAAAKgoAqCgKqKAqooCiigKKKAoooCiigKKqAoqoCgqAKCoAAAACgAAKAAAoAACgAAKqqAqqoCqqgKqqAoAACgAAKAAAoAAAAAAKqoAqqgCqqgKqqAAAoAACgAAKAAAoCqqgKqqAqqgCqqAAAAAqqACqoAKqoAqqgAAKgAAqAACoAAKgKqoAqqgCqoAKqgAAAACqqgKqqAqqoCqqgACoAAKgACoAAKgAAKgAAqAKqqAqqoCqqgKqqAAAACoKgKgqAqqoCqqgAqgACqAAKoAAqgAqqoCqqgKgqAqCoAAAAKoAAqgACqgAKqAAAqoACqgAKqAAqoCqgAKqAAqgACqAAAAAAoCoCgKgKCqAoKoCiqgKKqAqooCqigKoKAqgoCoCgKgKAAAACqqgKqqAqqoCqqgKAKAoAoAAAAKAAAoAACoAAKgAAKgAAqAAAqAACoAACoAAKgAAKgAAqAAAqAACoAACgAAKAAAACgCgKAKAqqoCqqgKqqAqqoAAA"), 32, atob("DQULDw0RDQUHBw0NBQ0FEQ0FDQ0NDQ0NDQ0FBQsNCw0RDQ0NDQ0NDQ0NDQ0NDw0NDQ0NDQ0NDQ8NDQ0HEQc="), 22+(scale<<8)+(1<<16)); - return this; -}; - -var IMAGEWIDTH = 117; -var IMAGEHEIGHT = 60; -var r2d2 = require("heatshrink").decompress(atob("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")); - -// timeout used to update every minute -var drawTimeout; - -// schedule a draw for the next minute -function queueDraw() { - if (drawTimeout) clearTimeout(drawTimeout); - drawTimeout = setTimeout(function() { - drawTimeout = undefined; - draw(); - }, 60000 - (Date.now() % 60000)); -} - -function draw() { - //reset().clearRect(0,24,g.getWidth(),g.getHeight()-IMAGEHEIGHT); - // draw r2d2 - g.drawImage(r2d2, (g.getWidth()/2)-(IMAGEWIDTH/2), g.getHeight()-IMAGEHEIGHT); - - var x = g.getWidth()/2; - var y = g.getHeight()/2 - 30; - g.reset(); - // work out locale-friendly date/time - var date = new Date(); - var timeStr = require("locale").time(date,1).trim(); - var dateStr = require("locale").date(date).toUpperCase(); - - - // draw time - g.setFontAlign(0,0).setFont("Undo:3"); - g.clearRect(0,y-30,g.getWidth(),y+30); // clear the background - g.drawString(timeStr,x,y); - // draw date - y += 40; - g.setFontAlign(0,0).setFont("Undo"); - g.clearRect(0,y-10,g.getWidth(),y+20); // clear the background - g.drawString(dateStr,x,y); - // queue draw in one minute - queueDraw(); -} - -// Clear the screen once, at startup -g.clear(); -// draw immediately at first, queue update -draw(); -// Stop updates when LCD is off, restart when on -Bangle.on('lcdPower',on=>{ - if (on) { - draw(); // draw immediately, queue redraw - } else { // stop draw timer - if (drawTimeout) clearTimeout(drawTimeout); - drawTimeout = undefined; - } -}); -// Show launcher when middle button pressed -Bangle.setUI("clock"); -// Load widgets -Bangle.loadWidgets(); -Bangle.drawWidgets(); \ No newline at end of file diff --git a/apps/r2d2clk/app.png b/apps/r2d2clk/app.png deleted file mode 100644 index 94502501d69c4d629548302d7d8b3fa7b5126452..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3143 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 diff --git a/apps/r2d2clk/metadata.json b/apps/r2d2clk/metadata.json deleted file mode 100644 index f2cde76f4..000000000 --- a/apps/r2d2clk/metadata.json +++ /dev/null @@ -1,15 +0,0 @@ -{ "id": "r2d2clk", - "name": "R2D2 Clock", - "shortName":"R2D2 Clock", - "version":"0.01", - "description": "A clock with R2D2's shiny metal face on it. :)", - "icon": "app.png", - "type": "clock", - "tags": "clock", - "supports" : ["BANGLEJS2"], - "readme": "README.md", - "storage": [ - {"name":"r2d2clk.app.js","url":"app.js"}, - {"name":"r2d2clk.img","url":"app-icon.js","evaluate":true} - ] -} From f5b85299a3bc17b2ebf38d2cba94b11e6e2370ef Mon Sep 17 00:00:00 2001 From: Noah Howard <3317164+nh-99@users.noreply.github.com> Date: Tue, 24 May 2022 12:04:19 -0400 Subject: [PATCH 276/294] Revert patches to mandelbrot clock --- apps/mandelbrotclock/mandelbrotclock.js | 41 ++++--------------------- 1 file changed, 6 insertions(+), 35 deletions(-) diff --git a/apps/mandelbrotclock/mandelbrotclock.js b/apps/mandelbrotclock/mandelbrotclock.js index ffc50e9bd..94636056e 100644 --- a/apps/mandelbrotclock/mandelbrotclock.js +++ b/apps/mandelbrotclock/mandelbrotclock.js @@ -1,5 +1,4 @@ // MIT License - James Milner 2021 -const locale = require('locale'); const mandelbrotBmp = { width: 176, @@ -13,51 +12,23 @@ const mandelbrotBmp = { ), }; -// timeout used to update every minute -var drawTimeout; - -// schedule a draw for the next minute -function queueDraw() { - if (drawTimeout) clearTimeout(drawTimeout); - drawTimeout = setTimeout(function() { - drawTimeout = undefined; - draw(); - }, 60000 - (Date.now() % 60000)); -} - function draw() { g.drawImage(mandelbrotBmp); // work out how to display the current time - var date = new Date(); - var timeStr = locale.time(date,1); - var dateStr = locale.dow(date, true).toUpperCase() + ' ' + date.getDate(); + const d = new Date(); + const h = d.getHours(), + m = d.getMinutes(); + const time = h + ":" + ("0" + m).substr(-2); // Reset the state of the graphics library g.reset(); g.setColor(1, 1, 1); g.setFont("Vector", 30); - g.drawString(timeStr, 70, 58, false); - g.setFont("Vector", 20); - g.drawString(dateStr, 70, 88, false); - - queueDraw(); + g.drawString(time, 70, 68, false); } -// Clear the screen once, at startup g.clear(); // draw immediately at first draw(); - -// Stop updates when LCD is off, restart when on -Bangle.on('lcdPower',on=>{ - if (on) { - draw(); // draw immediately, queue redraw - } else { // stop draw timer - if (drawTimeout) clearTimeout(drawTimeout); - drawTimeout = undefined; - } -}); - -// Show launcher when middle button pressed -Bangle.setUI("clock"); +var secondInterval = setInterval(draw, 1000); From c64882a82feee1bdb4836d8e9a46170cd2fa31df Mon Sep 17 00:00:00 2001 From: Noah Howard <3317164+nh-99@users.noreply.github.com> Date: Tue, 24 May 2022 12:09:25 -0400 Subject: [PATCH 277/294] Add r2d2 clock --- apps/r2d2clk/ChangeLog | 1 + apps/r2d2clk/README.md | 11 ++++++ apps/r2d2clk/app-icon.js | 1 + apps/r2d2clk/app.js | 67 ++++++++++++++++++++++++++++++++++++ apps/r2d2clk/app.png | Bin 0 -> 3143 bytes apps/r2d2clk/metadata.json | 15 ++++++++ apps/r2d2clk/screenshot.png | Bin 0 -> 2885 bytes 7 files changed, 95 insertions(+) create mode 100644 apps/r2d2clk/ChangeLog create mode 100644 apps/r2d2clk/README.md create mode 100644 apps/r2d2clk/app-icon.js create mode 100644 apps/r2d2clk/app.js create mode 100644 apps/r2d2clk/app.png create mode 100644 apps/r2d2clk/metadata.json create mode 100644 apps/r2d2clk/screenshot.png diff --git a/apps/r2d2clk/ChangeLog b/apps/r2d2clk/ChangeLog new file mode 100644 index 000000000..5560f00bc --- /dev/null +++ b/apps/r2d2clk/ChangeLog @@ -0,0 +1 @@ +0.01: New App! diff --git a/apps/r2d2clk/README.md b/apps/r2d2clk/README.md new file mode 100644 index 000000000..cd98b9170 --- /dev/null +++ b/apps/r2d2clk/README.md @@ -0,0 +1,11 @@ +# R2D2 Clock + +A clock with R2D2's shiny metal face on it. :) + +![](screenshot.png) + +## Creator + +Made by [Noah Howard](https://github.com/nh-99) + +Based on [Interlaced Clock](https://github.com/espruino/BangleApps/tree/master/apps/intclock) \ No newline at end of file diff --git a/apps/r2d2clk/app-icon.js b/apps/r2d2clk/app-icon.js new file mode 100644 index 000000000..246df9376 --- /dev/null +++ b/apps/r2d2clk/app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("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")) \ No newline at end of file diff --git a/apps/r2d2clk/app.js b/apps/r2d2clk/app.js new file mode 100644 index 000000000..a7ead76f1 --- /dev/null +++ b/apps/r2d2clk/app.js @@ -0,0 +1,67 @@ +Graphics.prototype.setFontUndo = function(scale) { + // Actual height 19 (20 - 2) + this.setFontCustom(atob("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKqKAqooCqigKqKAAAACgAAKAAAoAACgAAAAAAAAACgAAKAAAoAACgAAAAAAKCgAoKAKqqAqqoCqqgKqqAKCgAoKAKqqAqqoCqqgKqqAKCgAoKAAAAAKgoAqCgKqKAqooKiioqKKiooqKiioKKqAoqoCgqAKCoAAAACoCgKgKAiCoCIKgKioAqKgACoAAKgACoAAKgACoqAKioCoIgKgiAoCoCgKgAAAAKqgAqqAKqqAqqoKiioqKKiooqKiioKAKAoAoCgCgKAKAAAACgAAKAAAoAACgAAAAAAKqgAqqAKqqAqqoCgCgKAKAAAACgCgKAKAqqoCqqgCqoAKqgAAAACigAKKAAqoACqgAqoACqgAKqAAqoAAqoACqgAKKAAooAAAAAAoAACgAAKAAAoAAqqACqoAKqgAqqAAKAAAoAACgAAKAAAAAAACoAAKgAAqAACoAAAAAoAACgAAKAAAoAACgAAKAAAoAACgAAKAAAoAACgAAKAAAAAAACgAAKAAAoAACgAAAAAAoAACgAAqAACoAAqAACoAAqAACoAAqAACoAAqAACoAAqAACoAAKAAAoAAAAAACqoAKqgCqqgKqqAoAoCgCgKAKAoAoCqqgKqqAKqgAqqAAAAAqqoCqqgKqqAqqoAAAAKCqAoKoCiqgKKqAoooCiigKKKAoooCqigKqKAKgoAqCgAAAAoAoCgCgKAKAoAoCiigKKKAoooCiigKqqAqqoAqqACqoAAAACqAAKoAAqoACqgAAKAAAoAACgAAKAAqqoCqqgKqqAqqoAAAAKoKAqgoCqigKqKAoooCiigKKKAoooCiqgKKqAoKgCgqAAAAAKqgAqqAKqqAqqoCiigKKKAoooCiigKKqAoqoCgqAKCoAAAACgAAKAAAoAACgAAKAAAoAACgAAKAAAqqoCqqgCqqAKqoAAAACqoAKqgCqqgKqqAoooCiigKKKAoooCqqgKqqAKqgAqqAAAAAKgAAqAAKqAAqoACigAKKAAooACigAKqqAqqoAqqgCqqAAAACgCgKAKAoAoCgCgAAAAoAqCgCoKAKgoAqAAAAAKAAAoAAKoAAqgAKqgAqqAKgqAqCoCgCgKAKAAAAAoKACgoAKCgAoKACgoAKCgAoKACgoAKCgAoKACgoAKCgAAAAKAKAoAoCoKgKgqAKqgAqqAAqgACqAACgAAKAAAAACgAAKAAAoAACgAAKKKAoooCiigKKKAqoACqgACoAAKgAAAAACqqAKqoCqqgKqqAoAACgAAKCoAoKgCiqgKKqAoooCiigKqqAqqoAqqACqoAAAAAqqgCqqAqqoCqqgKKAAooACigAKKAAqqoCqqgCqqAKqoAAAAKqqAqqoCqqgKqqAoooCiigKKKAoooCqqgKqqAKCgAoKAAAAAKqgAqqAKqqAqqoCgCgKAKAoAoCgCgKAKAoAoCgCgKAKAAAACqqgKqqAqqoCqqgKAKAoAoCoKgKgqAKqgAqqAAqgACqAAAAACqoAKqgCqqgKqqAoooCiigKKKAoooCgCgKAKAoAoCgCgAAAAKqoAqqgKqqAqqoCigAKKAAooACigAKAAAoAACgAAKAAAAAAAqqACqoAqqoCqqgKAKAoAoCiigKKKAoqoCiqgKKqAoqoAAAAKqqAqqoCqqgKqqAAoAACgAAKAAAoACqqgKqqAqqoCqqgAAAAoAoCgCgKAKAoAoCqqgKqqAqqoCqqgKAKAoAoCgCgKAKAAAAAAKAAAoAACoAAKgAAKAAAoAACgAAKAqqoCqqgKqoAqqgAAAAKqqAqqoCqqgKqqACqAAKoACqoAKqgCoKgKgqAoAoCgCgAAAAqqgCqqAKqqAqqoAACgAAKAAAoAACgAAKAAAoAACgAAKAAAACqqgKqqAqqoCqqgCoAAKgAAKgAAqAAKgAAqAAKqqAqqoCqqgKqqAAAACqqgKqqAqqoCqqgCoAAKgAAKgAAqAAqqoCqqgKqqAqqoAAAACqoAKqgCqqgKqqAoAoCgCgKAKAoAoCqqgKqqAKqgAqqAAAAAqqoCqqgKqqAqqoCigAKKAAooACigAKqAAqoAAqAACoAAAAAAqqACqoAqqoCqqgKAKAoAoCgKgKAqAqqoCqqgCqqAKqoAAAAKqqAqqoCqqgKqqAooACigAKKgAoqACqqgKqqAKioAqKgAAAAKgoAqCgKqKAqooCiigKKKAoooCiigKKqAoqoCgqAKCoAAAACgAAKAAAoAACgAAKqqAqqoCqqgKqqAoAACgAAKAAAoAAAAAAKqoAqqgCqqgKqqAAAoAACgAAKAAAoCqqgKqqAqqgCqqAAAAAqqACqoAKqoAqqgAAKgAAqAACoAAKgKqoAqqgCqoAKqgAAAACqqgKqqAqqoCqqgACoAAKgACoAAKgAAKgAAqAKqqAqqoCqqgKqqAAAACoKgKgqAqqoCqqgAqgACqAAKoAAqgAqqoCqqgKgqAqCoAAAAKoAAqgACqgAKqAAAqoACqgAKqAAqoCqgAKqAAqgACqAAAAAAoCoCgKgKCqAoKoCiqgKKqAqooCqigKoKAqgoCoCgKgKAAAACqqgKqqAqqoCqqgKAKAoAoAAAAKAAAoAACoAAKgAAKgAAqAAAqAACoAACoAAKgAAKgAAqAAAqAACoAACgAAKAAAACgCgKAKAqqoCqqgKqqAqqoAAA"), 32, atob("DQULDw0RDQUHBw0NBQ0FEQ0FDQ0NDQ0NDQ0FBQsNCw0RDQ0NDQ0NDQ0NDQ0NDw0NDQ0NDQ0NDQ8NDQ0HEQc="), 22+(scale<<8)+(1<<16)); + return this; +}; + +var IMAGEWIDTH = 117; +var IMAGEHEIGHT = 60; +var r2d2 = require("heatshrink").decompress(atob("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")); + +// timeout used to update every minute +var drawTimeout; + +// schedule a draw for the next minute +function queueDraw() { + if (drawTimeout) clearTimeout(drawTimeout); + drawTimeout = setTimeout(function() { + drawTimeout = undefined; + draw(); + }, 60000 - (Date.now() % 60000)); +} + +function draw() { + //reset().clearRect(0,24,g.getWidth(),g.getHeight()-IMAGEHEIGHT); + // draw r2d2 + g.drawImage(r2d2, (g.getWidth()/2)-(IMAGEWIDTH/2), g.getHeight()-IMAGEHEIGHT); + + var x = g.getWidth()/2; + var y = g.getHeight()/2 - 30; + g.reset(); + // work out locale-friendly date/time + var date = new Date(); + var timeStr = require("locale").time(date,1).trim(); + var dateStr = require("locale").date(date).toUpperCase(); + + + // draw time + g.setFontAlign(0,0).setFont("Undo:3"); + g.clearRect(0,y-30,g.getWidth(),y+30); // clear the background + g.drawString(timeStr,x,y); + // draw date + y += 40; + g.setFontAlign(0,0).setFont("Undo"); + g.clearRect(0,y-10,g.getWidth(),y+20); // clear the background + g.drawString(dateStr,x,y); + // queue draw in one minute + queueDraw(); +} + +// Clear the screen once, at startup +g.clear(); +// draw immediately at first, queue update +draw(); +// Stop updates when LCD is off, restart when on +Bangle.on('lcdPower',on=>{ + if (on) { + draw(); // draw immediately, queue redraw + } else { // stop draw timer + if (drawTimeout) clearTimeout(drawTimeout); + drawTimeout = undefined; + } +}); +// Show launcher when middle button pressed +Bangle.setUI("clock"); +// Load widgets +Bangle.loadWidgets(); +Bangle.drawWidgets(); \ No newline at end of file diff --git a/apps/r2d2clk/app.png b/apps/r2d2clk/app.png new file mode 100644 index 0000000000000000000000000000000000000000..94502501d69c4d629548302d7d8b3fa7b5126452 GIT binary patch literal 3143 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 literal 0 HcmV?d00001 diff --git a/apps/r2d2clk/metadata.json b/apps/r2d2clk/metadata.json new file mode 100644 index 000000000..f2cde76f4 --- /dev/null +++ b/apps/r2d2clk/metadata.json @@ -0,0 +1,15 @@ +{ "id": "r2d2clk", + "name": "R2D2 Clock", + "shortName":"R2D2 Clock", + "version":"0.01", + "description": "A clock with R2D2's shiny metal face on it. :)", + "icon": "app.png", + "type": "clock", + "tags": "clock", + "supports" : ["BANGLEJS2"], + "readme": "README.md", + "storage": [ + {"name":"r2d2clk.app.js","url":"app.js"}, + {"name":"r2d2clk.img","url":"app-icon.js","evaluate":true} + ] +} diff --git a/apps/r2d2clk/screenshot.png b/apps/r2d2clk/screenshot.png new file mode 100644 index 0000000000000000000000000000000000000000..f0b3ca84f82f68f44b89a9c46a66fbe09adf0422 GIT binary patch literal 2885 zcmbtWhf~wb7XBp>5?TP24uT*SBoHo_UPYw^1OY{g5ET?d3xX8EkWfV_3JTIiI+6fV zB>{q>;8jBpC?&aqv=E3OMe57Ff54kJ^JZsvXU^_9=R5m-XJ(V^FIWiiOY;K&AY^5E z&Vjqv{xe~`+_k28+5-Rt1g*}UaSHcf=d*K)6$InUH=_H=jdbx!$@D|8@7X4+i!eUf z$pZ78(e94fUis+Olbp@SsFj^hI#^_OYErMSDFK3DuSLW9H&ZG z3HmP|z`C+a+#sbLs5>)#N6y&bmBl)zCIR)I+F`tjWeaM09Pn*8du938vP@4;`-t$+ zc)UHaxK#t>(K%^KJ7dT5Og0N%{XuvcD}ncn{Ps2BqiD-5phhD#OzsL~N;OAuoR8U- zi^~uDy?t5R5-1l5mUtVN7g+ukpbcAvDI3~-$1v}A(xgWvMhn^H(<^ny9dFAZwvH_c zqQC55zFA9Xz_2L~(YXeC$dkh)1G!O0TV$sA_mEswMtf^4WR|mHEem@Qwjn!Le}Cc? z#65VR$>jHxTAWVc(od3L?YhHjUi1=#TueXCtOn%SX0mJ{`AXN|x0wNT{u(U;{R#bp z74=|>I?uW@)0pa=mDd}WE}Kmj0dd;T^)}J})WY^X_H^#aEF6pswj*`90HmsvH^Src zNm3xvo9tT%(7Mj>b+J^Wup=hy=;I(1 z=QXeS5YH9{;2ju$d0I{voy}KUICo&w4rR`7j|ZR+XistcB4`tY)G1RCSXM#baqE;R zez(D^1mJ;T@pCrwOf*X)xb10rTYWN$ zToKWr(bl!rqSBCj-T>!6N&hKor1ZfYA8{}dNoJw&LhzZ=b~+y_!cF};Yx6;Y=#5xe z$!yha2aqritTypsvS=9qf@c&Y86Cz0=9nY?o@pP|G$@#>bZQ5`&&bdX1gv)C#FSk5 znqpIGT8}6fWpefC83z5)sJ^ix7bdrkkFV9mI9x^}D|#fa@ry8#^Vy?kK`?a5%$cow zHk3=r^i_wmEMjI8@3L>#*5L)pYxH_ZgPG-h^A<0g2KB5*P09J$4H)DYb_ z^LfnoU#kuNVt~o6I<$7|v(y8ANin?a=<|$;3VbeClD5{o54qJ_RM7GQxEXX#Nu4y~ z>bXcixRtBti4w0DFs`2C7Cz5&pE@)nouGIa52DqyKUEVhXv`on^Crq4&%TmNJJxjA zLSOAYBNY|Q_$D{6ver1xAgovBH#-|hqH739xLEB;0OEd!z|M#Yb-(jC$_!=m@ps8o zqoP$%$rRntp+iZ?d_gJY{kE=P?FL>ljo*ixh~DbsI%uU98Ztg$p=4R9?SIJ^b%Rw( zC}H*MBJP*`#-zOid=I@g65}`lyrYAJ(j*s_$*F)8vZY2}ZoTi_bG?v1Bdi(b$_RU* zV=2NT^Vz=&OO>|m38IIwVa%wFq6Qg4YvuGYk3!TbJJ&%s@u7pBRYtxGGtv@`$zNWA z2B5r>R^cr$3typ>^f=f7gZxLtj`VfBX82qLrR1Nk?DE&D}gFN5KDv%5Yn># z`d(HVNHC23LHlE9{-Q$T?lpWP-`4{EaBk-s4SQ8Dah180u31#hrOeUx!vYBaEve}p zy7zw{pB{=b+}q2v@XTUFe^RRb*wNfk+z}SUxUG^9x_$h>6;pKE#7|rQS%y~H?sz^L z9A##@K&g1AxVsFW|GLA6ExS-MWqrZUV()x5a3ZInI!F{s>ppL>#|6f4OM!uU+#Ssmbq=CVze9n%fq@Ud;W1aTD@CFi)J5kSMoC(SbA~FF~o@(3ZyOMc}y+z&_pT&pd68^ zV37d+abC1~BH3D2$Bb7vLdrJ1(L_@-XlUp?Npl_av}wT-Aom*2Wx z{v|oKs8MWjj?YZVFftZiAX|MAo*P9@c8T?a&66>2G`x=4@n)pc+YdZA?D+ zQJ4C?w_}2SrB{QN6Y=dlvh*}BCFbZwGh-0=B|#l>~()lI{}WO zo92VUy1`p9pCahxiKuQO>Q#Q0RoO&Ryol z`?N1b4XFGa;DL3tJ=ke0ho+bCcAJxA?Kt+F+F1j)j9>m%jDzj__Y zZ*mgwl?(UZ&s9&WZ#39z)2qXchoFf(@Bxo0r_An98ix5}ai8o=F*`Bb(zyLTCn8AV zx`<@syV^V=iY(kshI(7L=Lg1)EKsWny>#4P87=)7rh3=itgzDi*Y%OUOp+G%D&lIS zj;t?p=*esd(<=qh$j*KzH~duE!lt_z@kn)>=2qz9IcKa)WqEsTUTc1-EWR9HvD-i~ z;hBj%idm(M1xdWch%H+1NS{U$Av*Mwzo8fLfbeS(*#uj{Cve`RP{L3+iWr6C@mri~ z^4@Rz%8)+M%J2qx*bN!)w~a0FCAnVo>=o{iSG-&x@rDvEtk>(F5HR8Lm;|FQ=$Mf| zffwhgjm}JS-`UkKH}(}o(DtDDhnM`ryZDsy$)UK?P>-#mDbuY)J?y=jnDG z^|nbA)EF08>J;o2GNxMukulNun6y6|o!FdUCfAh{mWivtg)pZJ0K{Prty=A6RrWlU zYJHD=_9Yx_bL}Ci0+$Q181ASET)ibHmL6Rqy;kW>+|(R(v3LHbI>GJqE1KUpPlHL&y9F4>xUI literal 0 HcmV?d00001 From 43b07419b92a8ce1ee4759fac15f5b3f1fc2bf1a Mon Sep 17 00:00:00 2001 From: Gabriele Monaco Date: Wed, 25 May 2022 08:59:24 +0200 Subject: [PATCH 278/294] messages 0.38: using Telegram icon on Telegram FOSS --- apps/messages/app.js | 1 + apps/messages/metadata.json | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/messages/app.js b/apps/messages/app.js index aac59e246..ee9afc041 100644 --- a/apps/messages/app.js +++ b/apps/messages/app.js @@ -112,6 +112,7 @@ function getMessageImage(msg) { if (s=="snapchat") return atob("GBgBAAAAAAAAAH4AAf+AAf+AA//AA//AA//AA//AA//AH//4D//wB//gA//AB//gD//wH//4f//+P//8D//wAf+AAH4AAAAAAAAA"); if (s=="teams") return atob("GBgBAAAAAAAAAAQAAB4AAD8IAA8cP/M+f/scf/gIeDgAfvvefvvffvvffvvffvvff/vff/veP/PeAA/cAH/AAD+AAD8AAAQAAAAA"); if (s=="telegram") return atob("GBiBAAAAAAAAAAAAAAAAAwAAHwAA/wAD/wAf3gD/Pgf+fh/4/v/z/P/H/D8P/Acf/AM//AF/+AF/+AH/+ADz+ADh+ADAcAAAMAAAAA=="); + if (s=="telegram foss") return atob("GBiBAAAAAAAAAAAAAAAAAwAAHwAA/wAD/wAf3gD/Pgf+fh/4/v/z/P/H/D8P/Acf/AM//AF/+AF/+AH/+ADz+ADh+ADAcAAAMAAAAA=="); if (s=="threema") return atob("GBjB/4Yx//8AAAAAAAAAAAAAfgAB/4AD/8AH/+AH/+AP//AP2/APw/APw/AHw+AH/+AH/8AH/4AH/gAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="); if (s=="to do") return atob("GBgBAAAAAAAAAAAwAAB4AAD8AAH+AAP/DAf/Hg//Px/+f7/8///4///wf//gP//AH/+AD/8AB/4AA/wAAfgAAPAAAGAAAAAAAAAA"); if (s=="twitch") return atob("GBgBH//+P//+P//+eAAGeAAGeAAGeDGGeDOGeDOGeDOGeDOGeDOGeDOGeAAOeAAOeAAcf4/4f5/wf7/gf//Af/+AA/AAA+AAAcAA"); diff --git a/apps/messages/metadata.json b/apps/messages/metadata.json index ab9b03273..fd09fdfe4 100644 --- a/apps/messages/metadata.json +++ b/apps/messages/metadata.json @@ -1,7 +1,7 @@ { "id": "messages", "name": "Messages", - "version": "0.37", + "version": "0.38", "description": "App to display notifications from iOS and Gadgetbridge/Android", "icon": "app.png", "type": "app", From 8e4063004c86e06249d9c215ffc1d56d078defb2 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Wed, 25 May 2022 08:24:20 +0100 Subject: [PATCH 279/294] changelog and duplicate fix --- apps/messages/ChangeLog | 2 +- apps/messages/app.js | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/apps/messages/ChangeLog b/apps/messages/ChangeLog index d6ad393d6..53157f0d8 100644 --- a/apps/messages/ChangeLog +++ b/apps/messages/ChangeLog @@ -50,4 +50,4 @@ 0.35: Reset graphics colors before rendering a message (possibly fix #1752) 0.36: Ensure a new message plus an almost immediate deletion of that message doesn't load the messages app (fix #1362) 0.37: Now use the setUI 'back' icon in the top left rather than specific buttons/menu items - +0.38: Add telegram foss handling diff --git a/apps/messages/app.js b/apps/messages/app.js index ee9afc041..93c8ebf3e 100644 --- a/apps/messages/app.js +++ b/apps/messages/app.js @@ -111,8 +111,7 @@ function getMessageImage(msg) { if (s=="sms message") return getNotificationImage(); if (s=="snapchat") return atob("GBgBAAAAAAAAAH4AAf+AAf+AA//AA//AA//AA//AA//AH//4D//wB//gA//AB//gD//wH//4f//+P//8D//wAf+AAH4AAAAAAAAA"); if (s=="teams") return atob("GBgBAAAAAAAAAAQAAB4AAD8IAA8cP/M+f/scf/gIeDgAfvvefvvffvvffvvffvvff/vff/veP/PeAA/cAH/AAD+AAD8AAAQAAAAA"); - if (s=="telegram") return atob("GBiBAAAAAAAAAAAAAAAAAwAAHwAA/wAD/wAf3gD/Pgf+fh/4/v/z/P/H/D8P/Acf/AM//AF/+AF/+AH/+ADz+ADh+ADAcAAAMAAAAA=="); - if (s=="telegram foss") return atob("GBiBAAAAAAAAAAAAAAAAAwAAHwAA/wAD/wAf3gD/Pgf+fh/4/v/z/P/H/D8P/Acf/AM//AF/+AF/+AH/+ADz+ADh+ADAcAAAMAAAAA=="); + if (s=="telegram" || s=="telegram foss") return atob("GBiBAAAAAAAAAAAAAAAAAwAAHwAA/wAD/wAf3gD/Pgf+fh/4/v/z/P/H/D8P/Acf/AM//AF/+AF/+AH/+ADz+ADh+ADAcAAAMAAAAA=="); if (s=="threema") return atob("GBjB/4Yx//8AAAAAAAAAAAAAfgAB/4AD/8AH/+AH/+AP//AP2/APw/APw/AHw+AH/+AH/8AH/4AH/gAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="); if (s=="to do") return atob("GBgBAAAAAAAAAAAwAAB4AAD8AAH+AAP/DAf/Hg//Px/+f7/8///4///wf//gP//AH/+AD/8AB/4AA/wAAfgAAPAAAGAAAAAAAAAA"); if (s=="twitch") return atob("GBgBH//+P//+P//+eAAGeAAGeAAGeDGGeDOGeDOGeDOGeDOGeDOGeDOGeAAOeAAOeAAcf4/4f5/wf7/gf//Af/+AA/AAA+AAAcAA"); From cb890e6fc586e5efc5a26f1019c7384482d4ff12 Mon Sep 17 00:00:00 2001 From: Lubomir Date: Tue, 24 May 2022 22:08:43 +1000 Subject: [PATCH 280/294] android: Fix SMS bug --- apps/android/ChangeLog | 1 + apps/android/boot.js | 13 ++++++++++++- apps/android/metadata.json | 2 +- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/apps/android/ChangeLog b/apps/android/ChangeLog index 55f456795..f13ccd95c 100644 --- a/apps/android/ChangeLog +++ b/apps/android/ChangeLog @@ -8,3 +8,4 @@ 0.07: Include charging state in battery updates to phone 0.08: Handling of alarms 0.09: Alarm vibration, repeat, and auto-snooze now handled by sched +0.10: Fix SMS bug diff --git a/apps/android/boot.js b/apps/android/boot.js index fb2101aa4..efd7e7e46 100644 --- a/apps/android/boot.js +++ b/apps/android/boot.js @@ -3,6 +3,7 @@ Bluetooth.println(""); Bluetooth.println(JSON.stringify(message)); } + var lastMsg; var settings = require("Storage").readJSON("android.settings.json",1)||{}; //default alarm settings @@ -18,7 +19,17 @@ /* TODO: Call handling, fitness */ var HANDLERS = { // {t:"notify",id:int, src,title,subject,body,sender,tel:string} add - "notify" : function() { Object.assign(event,{t:"add",positive:true, negative:true});require("messages").pushMessage(event); }, + "notify" : function() { + Object.assign(event,{t:"add",positive:true, negative:true}); + // Detect a weird GadgetBridge bug and fix it + // For some reason SMS messages send two GB notifications, with different sets of info + if (lastMsg && event.body == lastMsg.body && lastMsg.src == undefined && event.src == "Messages") { + // Mutate the other message + event.id = lastMsg.id; + } + lastMsg = event; + require("messages").pushMessage(event); + }, // {t:"notify~",id:int, title:string} // modified "notify~" : function() { event.t="modify";require("messages").pushMessage(event); }, // {t:"notify-",id:int} // remove diff --git a/apps/android/metadata.json b/apps/android/metadata.json index 4051a344b..bf37b8407 100644 --- a/apps/android/metadata.json +++ b/apps/android/metadata.json @@ -2,7 +2,7 @@ "id": "android", "name": "Android Integration", "shortName": "Android", - "version": "0.09", + "version": "0.10", "description": "Display notifications/music/etc sent from the Gadgetbridge app on Android. This replaces the old 'Gadgetbridge' Bangle.js widget.", "icon": "app.png", "tags": "tool,system,messages,notifications,gadgetbridge", From 68edab1a18ef817bfd47f3531c5c51adf0b1b4e9 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Wed, 25 May 2022 09:58:02 +0100 Subject: [PATCH 281/294] Move getMessageImage/getMessageImageCol to the library as per https://github.com/espruino/BangleApps/pull/1872 No version bump as no functionality changes --- apps/messages/app.js | 95 +++----------------------------------------- apps/messages/lib.js | 81 +++++++++++++++++++++++++++++++++++++ 2 files changed, 86 insertions(+), 90 deletions(-) diff --git a/apps/messages/app.js b/apps/messages/app.js index 93c8ebf3e..63154c4b4 100644 --- a/apps/messages/app.js +++ b/apps/messages/app.js @@ -67,99 +67,14 @@ function saveMessages() { require("Storage").writeJSON("messages.json",MESSAGES) } -function getNotificationImage() { - return atob("HBKBAD///8H///iP//8cf//j4//8f5//j/x/8//j/H//H4//4PB//EYj/44HH/Hw+P4//8fH//44///xH///g////A=="); -} -function getFBIcon() { - return atob("GBiBAAAAAAAAAAAYAAD/AAP/wAf/4A/48A/g8B/g+B/j+B/n+D/n/D8A/B8A+B+B+B/n+A/n8A/n8Afn4APnwADnAAAAAAAAAAAAAA=="); -} function getPosImage() { return atob("GRSBAAAAAYAAAcAAAeAAAfAAAfAAAfAAAfAAAfAAAfBgAfA4AfAeAfAPgfAD4fAA+fAAP/AAD/AAA/AAAPAAADAAAA=="); } function getNegImage() { return atob("FhaBADAAMeAB78AP/4B/fwP4/h/B/P4D//AH/4AP/AAf4AB/gAP/AB/+AP/8B/P4P4fx/A/v4B//AD94AHjAAMA="); } -/* -* icons should be 24x24px with 1bpp colors and 'Transparency to Color' -* http://www.espruino.com/Image+Converter -*/ -function getMessageImage(msg) { - if (msg.img) return atob(msg.img); - var s = (msg.src||"").toLowerCase(); - if (s=="alarm" || s =="alarmclockreceiver") return atob("GBjBAP////8AAAAAAAACAEAHAOAefng5/5wTgcgHAOAOGHAMGDAYGBgYGBgYGBgYGBgYDhgYBxgMATAOAHAHAOADgcAB/4AAfgAAAAAAAAA="); - if (s=="bibel") return atob("GBgBAAAAA//wD//4D//4H//4H/f4H/f4H+P4H4D4H4D4H/f4H/f4H/f4H/f4H/f4H//4H//4H//4GAAAEAAAEAAACAAAB//4AAAA"); - if (s=="calendar") return atob("GBiBAAAAAAAAAAAAAA//8B//+BgAGBgAGBgAGB//+B//+B//+B9m2B//+B//+Btm2B//+B//+Btm+B//+B//+A//8AAAAAAAAAAAAA=="); - if (s=="corona-warn") return atob("GBgBAAAAABwAAP+AAf/gA//wB/PwD/PgDzvAHzuAP8EAP8AAPAAAPMAAP8AAH8AAHzsADzuAB/PAB/PgA//wAP/gAH+AAAwAAAAA"); - if (s=="discord") return atob("GBgBAAAAAAAAAAAAAIEABwDgDP8wH//4H//4P//8P//8P//8Pjx8fhh+fzz+f//+f//+e//ePH48HwD4AgBAAAAAAAAAAAAAAAAA"); - if (s=="facebook") return getFBIcon(); - if (s=="gmail") return getNotificationImage(); - if (s=="google home") return atob("GBiCAAAAAAAAAAAAAAAAAAAAAoAAAAAACqAAAAAAKqwAAAAAqroAAAACquqAAAAKq+qgAAAqr/qoAACqv/6qAAKq//+qgA6r///qsAqr///6sAqv///6sAqv///6sAqv///6sA6v///6sA6v///qsA6qqqqqsA6qqqqqsA6qqqqqsAP7///vwAAAAAAAAAAAAAAAAA=="); - if (s=="hangouts") return atob("FBaBAAH4AH/gD/8B//g//8P//H5n58Y+fGPnxj5+d+fmfj//4//8H//B//gH/4A/8AA+AAHAABgAAAA="); - if (s=="home assistant") return atob("FhaBAAAAAADAAAeAAD8AAf4AD/3AfP8D7fwft/D/P8ec572zbzbNsOEhw+AfD8D8P4fw/z/D/P8P8/w/z/AAAAA="); - if (s=="instagram") return atob("GBiBAAAAAAAAAAAAAAAAAAP/wAYAYAwAMAgAkAh+EAjDEAiBEAiBEAiBEAiBEAjDEAh+EAgAEAwAMAYAYAP/wAAAAAAAAAAAAAAAAA=="); - if (s=="kalender") return atob("GBgBBgBgBQCgff++RQCiRgBiQAACf//+QAACQAACR//iRJkiRIEiR//iRNsiRIEiRJkiR//iRIEiRIEiR//iQAACQAACf//+AAAA"); - if (s=="lieferando") return atob("GBgBABgAAH5wAP9wAf/4A//4B//4D//4H//4P/88fV8+fV4//V4//Vw/HVw4HVw4HBg4HBg4HBg4HDg4Hjw4Hj84Hj44Hj44Hj44"); - if (s=="mail") return getNotificationImage(); - if (s=="messenger") return getFBIcon(); - if (s=="nina") return atob("GBgBAAAABAAQCAAICAAIEAAEEgAkJAgSJBwSKRxKSj4pUn8lVP+VVP+VUgAlSgApKQBKJAASJAASEgAkEAAECAAICAAIBAAQAAAA"); - if (s=="outlook mail") return atob("HBwBAAAAAAAAAAAIAAAfwAAP/gAB/+AAP/5/A//v/D/+/8P/7/g+Pv8Dye/gPd74w5znHDnOB8Oc4Pw8nv/Dwe/8Pj7/w//v/D/+/8P/7/gf/gAA/+AAAfwAAACAAAAAAAAAAAA="); - if (s=="phone") return atob("FxeBABgAAPgAAfAAB/AAD+AAH+AAP8AAP4AAfgAA/AAA+AAA+AAA+AAB+AAB+AAB+OAB//AB//gB//gA//AA/8AAf4AAPAA="); - if (s=="post & dhl") return atob("GBgBAPgAE/5wMwZ8NgN8NgP4NgP4HgP4HgPwDwfgD//AB/+AAf8AAAAABs7AHcdgG4MwAAAAGESAFESAEkSAEnyAEkSAFESAGETw"); - if (s=="signal") return atob("GBgBAAAAAGwAAQGAAhggCP8QE//AB//oJ//kL//wD//0D//wT//wD//wL//0J//kB//oA//ICf8ABfxgBYBAADoABMAABAAAAAAA"); - if (s=="skype") return atob("GhoBB8AAB//AA//+Af//wH//+D///w/8D+P8Afz/DD8/j4/H4fP5/A/+f4B/n/gP5//B+fj8fj4/H8+DB/PwA/x/A/8P///B///gP//4B//8AD/+AAA+AA=="); - if (s=="slack") return atob("GBiBAAAAAAAAAABAAAHvAAHvAADvAAAPAB/PMB/veD/veB/mcAAAABzH8B3v+B3v+B3n8AHgAAHuAAHvAAHvAADGAAAAAAAAAAAAAA=="); - if (s=="sms message") return getNotificationImage(); - if (s=="snapchat") return atob("GBgBAAAAAAAAAH4AAf+AAf+AA//AA//AA//AA//AA//AH//4D//wB//gA//AB//gD//wH//4f//+P//8D//wAf+AAH4AAAAAAAAA"); - if (s=="teams") return atob("GBgBAAAAAAAAAAQAAB4AAD8IAA8cP/M+f/scf/gIeDgAfvvefvvffvvffvvffvvff/vff/veP/PeAA/cAH/AAD+AAD8AAAQAAAAA"); - if (s=="telegram" || s=="telegram foss") return atob("GBiBAAAAAAAAAAAAAAAAAwAAHwAA/wAD/wAf3gD/Pgf+fh/4/v/z/P/H/D8P/Acf/AM//AF/+AF/+AH/+ADz+ADh+ADAcAAAMAAAAA=="); - if (s=="threema") return atob("GBjB/4Yx//8AAAAAAAAAAAAAfgAB/4AD/8AH/+AH/+AP//AP2/APw/APw/AHw+AH/+AH/8AH/4AH/gAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="); - if (s=="to do") return atob("GBgBAAAAAAAAAAAwAAB4AAD8AAH+AAP/DAf/Hg//Px/+f7/8///4///wf//gP//AH/+AD/8AB/4AA/wAAfgAAPAAAGAAAAAAAAAA"); - if (s=="twitch") return atob("GBgBH//+P//+P//+eAAGeAAGeAAGeDGGeDOGeDOGeDOGeDOGeDOGeDOGeAAOeAAOeAAcf4/4f5/wf7/gf//Af/+AA/AAA+AAAcAA"); - if (s=="twitter") return atob("GhYBAABgAAB+JgA/8cAf/ngH/5+B/8P8f+D///h///4f//+D///g///wD//8B//+AP//gD//wAP/8AB/+AB/+AH//AAf/AAAYAAA"); - if (s=="whatsapp") return atob("GBiBAAB+AAP/wAf/4A//8B//+D///H9//n5//nw//vw///x///5///4///8e//+EP3/APn/wPn/+/j///H//+H//8H//4H//wMB+AA=="); - if (s=="wordfeud") return atob("GBgCWqqqqqqlf//////9v//////+v/////++v/////++v8///Lu+v8///L++v8///P/+v8v//P/+v9v//P/+v+fx/P/+v+Pk+P/+v/PN+f/+v/POuv/+v/Ofdv/+v/NvM//+v/I/Y//+v/k/k//+v/i/w//+v/7/6//+v//////+v//////+f//////9Wqqqqqql"); - if (s=="youtube") return atob("GBgBAAAAAAAAAAAAAAAAAf8AH//4P//4P//8P//8P5/8P4/8f4P8f4P8P4/8P5/8P//8P//8P//4H//4Af8AAAAAAAAAAAAAAAAA"); - if (msg.id=="music") return atob("FhaBAH//+/////////////h/+AH/4Af/gB/+H3/7/f/v9/+/3/7+f/vB/w8H+Dwf4PD/x/////////////3//+A="); - return getNotificationImage(); -} -function getMessageImageCol(msg,def) { - return { - // generic colors, using B2-safe colors - "alarm": "#fff", - "mail": "#ff0", - "music": "#f0f", - "phone": "#0f0", - "sms message": "#0ff", - // brands, according to https://www.schemecolor.com/?s (picking one for multicolored logos) - // all dithered on B2, but we only use the color for the icons. (Could maybe pick the closest 3-bit color for B2?) - "bibel": "#54342c", - "discord": "#738adb", - "facebook": "#4267b2", - "gmail": "#ea4335", - "google home": "#fbbc05", - "hangouts": "#1ba261", - "home assistant": "#fff", // ha-blue is #41bdf5, but that's the background - "instagram": "#dd2a7b", - "liferando": "#ee5c00", - "messenger": "#0078ff", - "nina": "#e57004", - "outlook mail": "#0072c6", - "post & dhl": "#f2c101", - "signal": "#00f", - "skype": "#00aff0", - "slack": "#e51670", - "snapchat": "#ff0", - "teams": "#464eb8", - "telegram": "#0088cc", - "threema": "#000", - "to do": "#3999e5", - "twitch": "#6441A4", - "twitter": "#1da1f2", - "whatsapp": "#4fce5d", - "wordfeud": "#e7d3c7", - "youtube": "#f00", - }[(msg.src||"").toLowerCase()]||(def !== undefined?def:g.theme.fg); -} + + function showMapMessage(msg) { active = "map"; @@ -411,7 +326,7 @@ function showMessage(msgid) { {type:"txt", font:fontSmall, label:msg.src||/*LANG*/"Message", bgCol:g.theme.bg2, col: g.theme.fg2, fillx:1, pad:2, halign:1 }, title?{type:"txt", font:titleFont, label:title, bgCol:g.theme.bg2, col: g.theme.fg2, fillx:1, pad:2 }:{}, ]}, - { type:"btn", src:getMessageImage(msg), col:getMessageImageCol(msg), pad: 3, cb:()=>{ + { type:"btn", src:require("messages").getMessageImage(msg), col:require("messages").getMessageImageCol(msg), pad: 3, cb:()=>{ cancelReloadTimeout(); // don't auto-reload to clock now showMessageSettings(msg); }}, @@ -467,14 +382,14 @@ function checkMessages(options) { g.clearRect(r.x,r.y,r.x+r.w, r.y+r.h); if (!msg) return; var x = r.x+2, title = msg.title, body = msg.body; - var img = getMessageImage(msg); + var img = require("messages").getMessageImage(msg); if (msg.id=="music") { title = msg.artist || /*LANG*/"Music"; body = msg.track; } if (img) { var fg = g.getColor(); - g.setColor(getMessageImageCol(msg,fg)).drawImage(img, x+24, r.y+24, {rotate:0}) // force centering + g.setColor(require("messages").getMessageImageCol(msg,fg)).drawImage(img, x+24, r.y+24, {rotate:0}) // force centering .setColor(fg); // only color the icon x += 50; } diff --git a/apps/messages/lib.js b/apps/messages/lib.js index c39c8886c..3f801e101 100644 --- a/apps/messages/lib.js +++ b/apps/messages/lib.js @@ -104,3 +104,84 @@ exports.clearAll = function(event) { if (global.WIDGETS && WIDGETS.messages) WIDGETS.messages.hide(); } + +exports.getMessageImage = function(msg) { + /* + * icons should be 24x24px with 1bpp colors and 'Transparency to Color' + * http://www.espruino.com/Image+Converter + */ + if (msg.img) return atob(msg.img); + var s = (msg.src||"").toLowerCase(); + if (s=="alarm" || s =="alarmclockreceiver") return atob("GBjBAP////8AAAAAAAACAEAHAOAefng5/5wTgcgHAOAOGHAMGDAYGBgYGBgYGBgYGBgYDhgYBxgMATAOAHAHAOADgcAB/4AAfgAAAAAAAAA="); + if (s=="bibel") return atob("GBgBAAAAA//wD//4D//4H//4H/f4H/f4H+P4H4D4H4D4H/f4H/f4H/f4H/f4H/f4H//4H//4H//4GAAAEAAAEAAACAAAB//4AAAA"); + if (s=="calendar") return atob("GBiBAAAAAAAAAAAAAA//8B//+BgAGBgAGBgAGB//+B//+B//+B9m2B//+B//+Btm2B//+B//+Btm+B//+B//+A//8AAAAAAAAAAAAA=="); + if (s=="corona-warn") return atob("GBgBAAAAABwAAP+AAf/gA//wB/PwD/PgDzvAHzuAP8EAP8AAPAAAPMAAP8AAH8AAHzsADzuAB/PAB/PgA//wAP/gAH+AAAwAAAAA"); + if (s=="discord") return atob("GBgBAAAAAAAAAAAAAIEABwDgDP8wH//4H//4P//8P//8P//8Pjx8fhh+fzz+f//+f//+e//ePH48HwD4AgBAAAAAAAAAAAAAAAAA"); + if (s=="facebook" || s=="messenger") return atob("GBiBAAAAAAAAAAAYAAD/AAP/wAf/4A/48A/g8B/g+B/j+B/n+D/n/D8A/B8A+B+B+B/n+A/n8A/n8Afn4APnwADnAAAAAAAAAAAAAA=="); + if (s=="google home") return atob("GBiCAAAAAAAAAAAAAAAAAAAAAoAAAAAACqAAAAAAKqwAAAAAqroAAAACquqAAAAKq+qgAAAqr/qoAACqv/6qAAKq//+qgA6r///qsAqr///6sAqv///6sAqv///6sAqv///6sA6v///6sA6v///qsA6qqqqqsA6qqqqqsA6qqqqqsAP7///vwAAAAAAAAAAAAAAAAA=="); + if (s=="hangouts") return atob("FBaBAAH4AH/gD/8B//g//8P//H5n58Y+fGPnxj5+d+fmfj//4//8H//B//gH/4A/8AA+AAHAABgAAAA="); + if (s=="home assistant") return atob("FhaBAAAAAADAAAeAAD8AAf4AD/3AfP8D7fwft/D/P8ec572zbzbNsOEhw+AfD8D8P4fw/z/D/P8P8/w/z/AAAAA="); + if (s=="instagram") return atob("GBiBAAAAAAAAAAAAAAAAAAP/wAYAYAwAMAgAkAh+EAjDEAiBEAiBEAiBEAiBEAjDEAh+EAgAEAwAMAYAYAP/wAAAAAAAAAAAAAAAAA=="); + if (s=="kalender") return atob("GBgBBgBgBQCgff++RQCiRgBiQAACf//+QAACQAACR//iRJkiRIEiR//iRNsiRIEiRJkiR//iRIEiRIEiR//iQAACQAACf//+AAAA"); + if (s=="lieferando") return atob("GBgBABgAAH5wAP9wAf/4A//4B//4D//4H//4P/88fV8+fV4//V4//Vw/HVw4HVw4HBg4HBg4HBg4HDg4Hjw4Hj84Hj44Hj44Hj44"); + if (s=="nina") return atob("GBgBAAAABAAQCAAICAAIEAAEEgAkJAgSJBwSKRxKSj4pUn8lVP+VVP+VUgAlSgApKQBKJAASJAASEgAkEAAECAAICAAIBAAQAAAA"); + if (s=="outlook mail") return atob("HBwBAAAAAAAAAAAIAAAfwAAP/gAB/+AAP/5/A//v/D/+/8P/7/g+Pv8Dye/gPd74w5znHDnOB8Oc4Pw8nv/Dwe/8Pj7/w//v/D/+/8P/7/gf/gAA/+AAAfwAAACAAAAAAAAAAAA="); + if (s=="phone") return atob("FxeBABgAAPgAAfAAB/AAD+AAH+AAP8AAP4AAfgAA/AAA+AAA+AAA+AAB+AAB+AAB+OAB//AB//gB//gA//AA/8AAf4AAPAA="); + if (s=="post & dhl") return atob("GBgBAPgAE/5wMwZ8NgN8NgP4NgP4HgP4HgPwDwfgD//AB/+AAf8AAAAABs7AHcdgG4MwAAAAGESAFESAEkSAEnyAEkSAFESAGETw"); + if (s=="signal") return atob("GBgBAAAAAGwAAQGAAhggCP8QE//AB//oJ//kL//wD//0D//wT//wD//wL//0J//kB//oA//ICf8ABfxgBYBAADoABMAABAAAAAAA"); + if (s=="skype") return atob("GhoBB8AAB//AA//+Af//wH//+D///w/8D+P8Afz/DD8/j4/H4fP5/A/+f4B/n/gP5//B+fj8fj4/H8+DB/PwA/x/A/8P///B///gP//4B//8AD/+AAA+AA=="); + if (s=="slack") return atob("GBiBAAAAAAAAAABAAAHvAAHvAADvAAAPAB/PMB/veD/veB/mcAAAABzH8B3v+B3v+B3n8AHgAAHuAAHvAAHvAADGAAAAAAAAAAAAAA=="); + if (s=="snapchat") return atob("GBgBAAAAAAAAAH4AAf+AAf+AA//AA//AA//AA//AA//AH//4D//wB//gA//AB//gD//wH//4f//+P//8D//wAf+AAH4AAAAAAAAA"); + if (s=="teams") return atob("GBgBAAAAAAAAAAQAAB4AAD8IAA8cP/M+f/scf/gIeDgAfvvefvvffvvffvvffvvff/vff/veP/PeAA/cAH/AAD+AAD8AAAQAAAAA"); + if (s=="telegram" || s=="telegram foss") return atob("GBiBAAAAAAAAAAAAAAAAAwAAHwAA/wAD/wAf3gD/Pgf+fh/4/v/z/P/H/D8P/Acf/AM//AF/+AF/+AH/+ADz+ADh+ADAcAAAMAAAAA=="); + if (s=="threema") return atob("GBjB/4Yx//8AAAAAAAAAAAAAfgAB/4AD/8AH/+AH/+AP//AP2/APw/APw/AHw+AH/+AH/8AH/4AH/gAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="); + if (s=="to do") return atob("GBgBAAAAAAAAAAAwAAB4AAD8AAH+AAP/DAf/Hg//Px/+f7/8///4///wf//gP//AH/+AD/8AB/4AA/wAAfgAAPAAAGAAAAAAAAAA"); + if (s=="twitch") return atob("GBgBH//+P//+P//+eAAGeAAGeAAGeDGGeDOGeDOGeDOGeDOGeDOGeDOGeAAOeAAOeAAcf4/4f5/wf7/gf//Af/+AA/AAA+AAAcAA"); + if (s=="twitter") return atob("GhYBAABgAAB+JgA/8cAf/ngH/5+B/8P8f+D///h///4f//+D///g///wD//8B//+AP//gD//wAP/8AB/+AB/+AH//AAf/AAAYAAA"); + if (s=="whatsapp") return atob("GBiBAAB+AAP/wAf/4A//8B//+D///H9//n5//nw//vw///x///5///4///8e//+EP3/APn/wPn/+/j///H//+H//8H//4H//wMB+AA=="); + if (s=="wordfeud") return atob("GBgCWqqqqqqlf//////9v//////+v/////++v/////++v8///Lu+v8///L++v8///P/+v8v//P/+v9v//P/+v+fx/P/+v+Pk+P/+v/PN+f/+v/POuv/+v/Ofdv/+v/NvM//+v/I/Y//+v/k/k//+v/i/w//+v/7/6//+v//////+v//////+f//////9Wqqqqqql"); + if (s=="youtube") return atob("GBgBAAAAAAAAAAAAAAAAAf8AH//4P//4P//8P//8P5/8P4/8f4P8f4P8P4/8P5/8P//8P//8P//4H//4Af8AAAAAAAAAAAAAAAAA"); + if (msg.id=="music") return atob("FhaBAH//+/////////////h/+AH/4Af/gB/+H3/7/f/v9/+/3/7+f/vB/w8H+Dwf4PD/x/////////////3//+A="); + // if (s=="sms message" || s=="mail" || s=="gmail") // .. default icon (below) + return atob("HBKBAD///8H///iP//8cf//j4//8f5//j/x/8//j/H//H4//4PB//EYj/44HH/Hw+P4//8fH//44///xH///g////A=="); +}; + +exports.getMessageImageCol = function(msg,def) { + return { + // generic colors, using B2-safe colors + "alarm": "#fff", + "mail": "#ff0", + "music": "#f0f", + "phone": "#0f0", + "sms message": "#0ff", + // brands, according to https://www.schemecolor.com/?s (picking one for multicolored logos) + // all dithered on B2, but we only use the color for the icons. (Could maybe pick the closest 3-bit color for B2?) + "bibel": "#54342c", + "discord": "#738adb", + "facebook": "#4267b2", + "gmail": "#ea4335", + "google home": "#fbbc05", + "hangouts": "#1ba261", + "home assistant": "#fff", // ha-blue is #41bdf5, but that's the background + "instagram": "#dd2a7b", + "liferando": "#ee5c00", + "messenger": "#0078ff", + "nina": "#e57004", + "outlook mail": "#0072c6", + "post & dhl": "#f2c101", + "signal": "#00f", + "skype": "#00aff0", + "slack": "#e51670", + "snapchat": "#ff0", + "teams": "#464eb8", + "telegram": "#0088cc", + "telegram foss": "#0088cc", + "threema": "#000", + "to do": "#3999e5", + "twitch": "#6441A4", + "twitter": "#1da1f2", + "whatsapp": "#4fce5d", + "wordfeud": "#e7d3c7", + "youtube": "#f00", + }[(msg.src||"").toLowerCase()]||(def !== undefined?def:g.theme.fg); +}; From a6d92c11151b4e0127bdc9fcccea7fa13098ba05 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Wed, 25 May 2022 10:00:27 +0100 Subject: [PATCH 282/294] inline tick/cross images to save some space --- apps/messages/app.js | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/apps/messages/app.js b/apps/messages/app.js index 63154c4b4..745f7d208 100644 --- a/apps/messages/app.js +++ b/apps/messages/app.js @@ -67,15 +67,6 @@ function saveMessages() { require("Storage").writeJSON("messages.json",MESSAGES) } -function getPosImage() { - return atob("GRSBAAAAAYAAAcAAAeAAAfAAAfAAAfAAAfAAAfAAAfBgAfA4AfAeAfAPgfAD4fAA+fAAP/AAD/AAA/AAAPAAADAAAA=="); -} -function getNegImage() { - return atob("FhaBADAAMeAB78AP/4B/fwP4/h/B/P4D//AH/4AP/AAf4AB/gAP/AB/+AP/8B/P4P4fx/A/v4B//AD94AHjAAMA="); -} - - - function showMapMessage(msg) { active = "map"; var m; @@ -302,7 +293,7 @@ function showMessage(msgid) { var buttons = [ ]; if (msg.positive) { - buttons.push({type:"btn", src:getPosImage(), cb:()=>{ + buttons.push({type:"btn", src:atob("GRSBAAAAAYAAAcAAAeAAAfAAAfAAAfAAAfAAAfAAAfBgAfA4AfAeAfAPgfAD4fAA+fAAP/AAD/AAA/AAAPAAADAAAA=="), cb:()=>{ msg.new = false; saveMessages(); cancelReloadTimeout(); // don't auto-reload to clock now Bangle.messageResponse(msg,true); @@ -311,7 +302,7 @@ function showMessage(msgid) { } if (msg.negative) { if (buttons.length) buttons.push({width:32}); // nasty hack... - buttons.push({type:"btn", src:getNegImage(), cb:()=>{ + buttons.push({type:"btn", src:atob("FhaBADAAMeAB78AP/4B/fwP4/h/B/P4D//AH/4AP/AAf4AB/gAP/AB/+AP/8B/P4P4fx/A/v4B//AD94AHjAAMA="), cb:()=>{ msg.new = false; saveMessages(); cancelReloadTimeout(); // don't auto-reload to clock now Bangle.messageResponse(msg,false); From f0e262757109e83bb3b6bf77e4aba3c2658fd067 Mon Sep 17 00:00:00 2001 From: Alessandro Cocco Date: Tue, 24 May 2022 22:25:44 +0200 Subject: [PATCH 283/294] Move Layout docs to a separate file --- modules/Layout.js | 70 +--------------------------------------- modules/Layout.md | 81 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+), 69 deletions(-) create mode 100644 modules/Layout.md diff --git a/modules/Layout.js b/modules/Layout.js index 43419a397..19cfabe11 100644 --- a/modules/Layout.js +++ b/modules/Layout.js @@ -1,74 +1,6 @@ /* Copyright (c) 2022 Bangle.js contributors. See the file LICENSE for copying permission. */ -/* -Take a look at README.md for hints on developing with this library. -Usage: -``` -var Layout = require("Layout"); -var layout = new Layout( layoutObject, options ) -layout.render(optionalObject); -``` -For example: -``` -var Layout = require("Layout"); -var layout = new Layout( { - type:"v", c: [ - {type:"txt", font:"20%", label:"12:00" }, - {type:"txt", font:"6x8", label:"The Date" } - ] -}); -g.clear(); -layout.render(); -``` -layoutObject has: -* A `type` field of: - * `undefined` - blank, can be used for padding - * `"txt"` - a text label, with value `label`. 'font' is required - * `"btn"` - a button, with value `label` and callback `cb` - optional `src` specifies an image (like img) in which case label is ignored - Default font is `6x8`, scale 2. This can be overridden with the `font` or `scale` fields. - * `"img"` - an image where `src` is an image, or a function which is called to return an image to draw. - * `"custom"` - a custom block where `render(layoutObj)` is called to render - * `"h"` - Horizontal layout, `c` is an array of more `layoutObject` - * `"v"` - Vertical layout, `c` is an array of more `layoutObject` -* A `id` field. If specified the object is added with this name to the - returned `layout` object, so can be referenced as `layout.foo` -* A `font` field, eg `6x8` or `30%` to use a percentage of screen height. Set scale with :, e.g. `6x8:2`. -* A `scale` field, eg `2` to set scale of an image -* A `r` field to set rotation of text or images (0: 0°, 1: 90°, 2: 180°, 3: 270°). -* A `wrap` field to enable line wrapping. Requires some combination of `width`/`height` - and `fillx`/`filly` to be set. Not compatible with text rotation. -* A `col` field, eg `#f00` for red -* A `bgCol` field for background color (will automatically fill on render) -* A `halign` field to set horizontal alignment WITHIN a `v` container. `-1`=left, `1`=right, `0`=center -* A `valign` field to set vertical alignment WITHIN a `h` container. `-1`=top, `1`=bottom, `0`=center -* A `pad` integer field to set pixels padding -* A `fillx` int to choose if the object should fill available space in x. 0=no, 1=yes, 2=2x more space -* A `filly` int to choose if the object should fill available space in y. 0=no, 1=yes, 2=2x more space -* `width` and `height` fields to optionally specify minimum size -options is an object containing: -* `lazy` - a boolean specifying whether to enable automatic lazy rendering -* `btns` - array of objects containing: - * `label` - the text on the button - * `cb` - a callback function - * `cbl` - a callback function for long presses -* `back` - a callback function, passed as `back` into Bangle.setUI (which usually adds an icon in the top left) - -If automatic lazy rendering is enabled, calls to `layout.render()` will attempt to automatically -determine what objects have changed or moved, clear their previous locations, and re-render just those objects. -Once `layout.update()` is called, the following fields are added -to each object: -* `x` and `y` for the top left position -* `w` and `h` for the width and height -* `_w` and `_h` for the **minimum** width and height -Other functions: -* `layout.update()` - update positions of everything if contents have changed -* `layout.debug(obj)` - draw outlines for objects on screen -* `layout.clear(obj)` - clear the given object (you can also just specify `bgCol` to clear before each render) -* `layout.forgetLazyState()` - if lazy rendering is enabled, makes the next call to `render()` perform a full re-render -* `layout.setUI()` - (called when module initialised) This sets up input (buttons, touch, etc) with Bangle._setUI - This can be useful if you called E.showMenu/showPrompt/etc and those grabbed input away from layour -*/ +// See Layout.md for documentation function Layout(layout, options) { this._l = this.l = layout; diff --git a/modules/Layout.md b/modules/Layout.md new file mode 100644 index 000000000..7a4177957 --- /dev/null +++ b/modules/Layout.md @@ -0,0 +1,81 @@ +Bangle.js Layout Library +======================== + +> Take a look at README.md for hints on developing with this library. + +Usage +----- + +```JS +var Layout = require("Layout"); +var layout = new Layout(layoutObject, options) + +layout.render(optionalObject); +``` + +For example: + +```JS +var Layout = require("Layout"); +var layout = new Layout({ + type:"v", + c: [ + { type: "txt", font: "20%", label: "12:00" }, + { type: "txt", font: "6x8", label: "The Date" } + ] +}); + +g.clear(); + +layout.render(); +``` + +`layoutObject` has: + +- A `type` field of: + - `undefined` - blank, can be used for padding + - `"txt"` - a text label, with value `label`. `font` is required + - `"btn"` - a button, with value `label` and callback `cb`. Optional `src` specifies an image (like img) in which case label is ignored. Default font is `6x8`, scale 2. This can be overridden with the `font` or `scale` fields. + - `"img"` - an image where `src` is an image, or a function which is called to return an image to draw + - `"custom"` - a custom block where `render(layoutObj)` is called to render + - `"h"` - Horizontal layout, `c` is an array of more `layoutObject` + - `"v"` - Vertical layout, `c` is an array of more `layoutObject` +- A `id` field. If specified the object is added with this name to the returned `layout` object, so can be referenced as `layout.foo` +- A `font` field, eg `6x8` or `30%` to use a percentage of screen height. Set scale with :, e.g. `6x8:2`. +- A `scale` field, eg `2` to set scale of an image +- A `r` field to set rotation of text or images (0: 0°, 1: 90°, 2: 180°, 3: 270°). +- A `wrap` field to enable line wrapping. Requires some combination of `width`/`height` and `fillx`/`filly` to be set. Not compatible with text rotation. +- A `col` field, eg `#f00` for red +- A `bgCol` field for background color (will automatically fill on render) +- A `halign` field to set horizontal alignment WITHIN a `v` container. `-1`=left, `1`=right, `0`=center +- A `valign` field to set vertical alignment WITHIN a `h` container. `-1`=top, `1`=bottom, `0`=center +- A `pad` integer field to set pixels padding +- A `fillx` int to choose if the object should fill available space in x. 0=no, 1=yes, 2=2x more space +- A `filly` int to choose if the object should fill available space in y. 0=no, 1=yes, 2=2x more space +- `width` and `height` fields to optionally specify minimum size options is an object containing: +- `lazy` - a boolean specifying whether to enable automatic lazy rendering +- `btns` - array of objects containing: + - `label` - the text on the button + - `cb` - a callback function + - `cbl` - a callback function for long presses +- `back` - a callback function, passed as `back` into Bangle.setUI (which usually adds an icon in the top left) + +If automatic lazy rendering is enabled, calls to `layout.render()` will attempt to automatically determine what objects have changed or moved, clear their previous locations, and re-render just those objects. + +Once `layout.update()` is called, the following fields are added to each object: + +- `x` and `y` for the top left position +- `w` and `h` for the width and height +- `_w` and `_h` for the **minimum** width and height + +Other functions: + +- `layout.update()` - update positions of everything if contents have changed +- `layout.debug(obj)` - draw outlines for objects on screen +- `layout.clear(obj)` - clear the given object (you can also just specify `bgCol` to clear before each render) +- `layout.forgetLazyState()` - if lazy rendering is enabled, makes the next call to `render()` perform a full re-render + +Links +----- + +- [Official tutorial](https://www.espruino.com/Bangle.js+Layout) From 4cbc80ddbb4e065e0aa7a5f1b4f28a54a9bcadb4 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Wed, 25 May 2022 14:12:55 +0100 Subject: [PATCH 284/294] oops - disable battery calibration for Bangle.js 1 --- apps/setting/settings.js | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/apps/setting/settings.js b/apps/setting/settings.js index 5c14e914d..73cb4b497 100644 --- a/apps/setting/settings.js +++ b/apps/setting/settings.js @@ -545,8 +545,10 @@ function showUtilMenu() { setInterval(function() { var i=1000;while (i--); }, 1); - }, - /*LANG*/'Calibrate Battery': () => { + } + }; + if (BANGLEJS2) + menu[/*LANG*/'Calibrate Battery'] = () => { E.showPrompt(/*LANG*/"Is the battery fully charged?",{title:/*LANG*/"Calibrate"}).then(ok => { if (ok) { var s=require("Storage").readJSON("setting.json"); @@ -558,7 +560,7 @@ function showUtilMenu() { } }); }, - /*LANG*/'Reset Settings': () => { + menu[/*LANG*/'Reset Settings'] = () => { E.showPrompt(/*LANG*/'Reset to Defaults?',{title:/*LANG*/"Settings"}).then((v) => { if (v) { E.showMessage('Resetting'); @@ -567,8 +569,8 @@ function showUtilMenu() { } else showUtilMenu(); }); }, - /*LANG*/'Turn Off': ()=>{ if (Bangle.softOff) Bangle.softOff(); else Bangle.off() } - }; + menu[/*LANG*/'Turn Off'] = ()=>{ if (Bangle.softOff) Bangle.softOff(); else Bangle.off() } + if (Bangle.factoryReset) { menu[/*LANG*/'Factory Reset'] = ()=>{ E.showPrompt(/*LANG*/'This will remove everything!',{title:/*LANG*/"Factory Reset"}).then((v) => { From 280fd5e665249ea92256c30a36ed25d74bffaee6 Mon Sep 17 00:00:00 2001 From: Alessandro Cocco Date: Wed, 25 May 2022 23:13:37 +0200 Subject: [PATCH 285/294] [Alarms & Timers] Fix dow handling for timers --- apps/alarm/app.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/alarm/app.js b/apps/alarm/app.js index 8e2e2b0a6..fe0f67dbb 100644 --- a/apps/alarm/app.js +++ b/apps/alarm/app.js @@ -37,8 +37,8 @@ function handleFirstDayOfWeek(dow) { return dow; } -// Check the first day of week and update the dow field accordingly. -alarms.forEach(alarm => alarm.dow = handleFirstDayOfWeek(alarm.dow)); +// Check the first day of week and update the dow field accordingly (alarms only!) +alarms.filter(e => e.timer === undefined).forEach(a => a.dow = handleFirstDayOfWeek(a.dow)); function showMainMenu() { const menu = { @@ -158,14 +158,14 @@ function saveAlarm(alarm, alarmIndex, time) { } function saveAndReload() { - // Before saving revert the dow to the standard format - alarms.forEach(a => a.dow = handleFirstDayOfWeek(a.dow, firstDayOfWeek)); + // Before saving revert the dow to the standard format (alarms only!) + alarms.filter(e => e.timer === undefined).forEach(a => a.dow = handleFirstDayOfWeek(a.dow)); require("sched").setAlarms(alarms); require("sched").reload(); // Fix after save - alarms.forEach(a => a.dow = handleFirstDayOfWeek(a.dow, firstDayOfWeek)); + alarms.filter(e => e.timer === undefined).forEach(a => a.dow = handleFirstDayOfWeek(a.dow)); } function decodeDOW(alarm) { From 2fd5ec8f37dd860db57da2e98d373b2f6ceedb3b Mon Sep 17 00:00:00 2001 From: Alessandro Cocco Date: Wed, 25 May 2022 23:20:00 +0200 Subject: [PATCH 286/294] [Alarms & Timers] Update metadata and changelog --- apps/alarm/ChangeLog | 1 + apps/alarm/metadata.json | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/alarm/ChangeLog b/apps/alarm/ChangeLog index 3d75e1209..b00055334 100644 --- a/apps/alarm/ChangeLog +++ b/apps/alarm/ChangeLog @@ -28,3 +28,4 @@ 0.26: Add support for Monday as first day of the week (#1780) 0.27: New UI! 0.28: Fix bug with alarms not firing when configured to fire only once +0.29: Fix wrong 'dow' handling in new timer if first day of week is Monday diff --git a/apps/alarm/metadata.json b/apps/alarm/metadata.json index b38ab1ef1..cac837b5e 100644 --- a/apps/alarm/metadata.json +++ b/apps/alarm/metadata.json @@ -2,7 +2,7 @@ "id": "alarm", "name": "Alarms & Timers", "shortName": "Alarms", - "version": "0.28", + "version": "0.29", "description": "Set alarms and timers on your Bangle", "icon": "app.png", "tags": "tool,alarm,widget", From 182743a0e3649a311cb0beaf485103bfd6798d4b Mon Sep 17 00:00:00 2001 From: Noah Howard <3317164+nh-99@users.noreply.github.com> Date: Wed, 25 May 2022 17:33:40 -0400 Subject: [PATCH 287/294] Add screenshot of R2D2 clock to metadata for app store --- apps/r2d2clk/metadata.json | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/r2d2clk/metadata.json b/apps/r2d2clk/metadata.json index f2cde76f4..249180ac8 100644 --- a/apps/r2d2clk/metadata.json +++ b/apps/r2d2clk/metadata.json @@ -4,6 +4,7 @@ "version":"0.01", "description": "A clock with R2D2's shiny metal face on it. :)", "icon": "app.png", + "screenshots": [{"url":"screenshot.png"}], "type": "clock", "tags": "clock", "supports" : ["BANGLEJS2"], From 211af92a41a5d167f9a42d5c73b4c3f09004234d Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Thu, 26 May 2022 09:58:59 +0100 Subject: [PATCH 288/294] bangle.js 2 compat --- apps/rndmclk/metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/rndmclk/metadata.json b/apps/rndmclk/metadata.json index e837c4bce..bb8e92f95 100644 --- a/apps/rndmclk/metadata.json +++ b/apps/rndmclk/metadata.json @@ -6,7 +6,7 @@ "icon": "rndmclk.png", "type": "widget", "tags": "widget,clock", - "supports": ["BANGLEJS"], + "supports": ["BANGLEJS","BANGLEJS2"], "readme": "README.md", "storage": [ {"name":"rndmclk.wid.js","url":"widget.js"} From 6f202bc9254a96de7bccba21fe75ce75d00cf95b Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Thu, 26 May 2022 09:59:11 +0100 Subject: [PATCH 289/294] fix locale errors after recent PRs --- apps/locale/locales.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/locale/locales.js b/apps/locale/locales.js index d1ac7687f..de56503fd 100644 --- a/apps/locale/locales.js +++ b/apps/locale/locales.js @@ -11,6 +11,8 @@ const speedUnits = { // how many kph per X? "kmh": 1, "kph": 1, "km/h": 1, + "kmt": 1, + "km/tim": 1, "mph": 1.60934, "kts": 1.852 }; From ed56c9142742eb3e7a132c730a4769a028396dde Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Thu, 26 May 2022 09:59:18 +0100 Subject: [PATCH 290/294] add relevant interface code to customize.js, and add checks to ensure the right file is used --- core | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core b/core index 404e98183..2054537a9 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit 404e981834f2e8df9c505a8fab12ae12fe3bd562 +Subproject commit 2054537a9958f9812ae2cad908b6597ff01e449d From 6b8cf13f6c635efc1392c82c8a95f2927ba65e4f Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Thu, 26 May 2022 10:07:04 +0100 Subject: [PATCH 291/294] 0.46: Fix regression after making 'calibrate battery' only for Bangle.js 2 --- apps/setting/ChangeLog | 1 + apps/setting/metadata.json | 2 +- apps/setting/settings.js | 6 +++--- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/apps/setting/ChangeLog b/apps/setting/ChangeLog index 6d3bbb468..eca2b7938 100644 --- a/apps/setting/ChangeLog +++ b/apps/setting/ChangeLog @@ -49,3 +49,4 @@ 0.44: Add "Start Week On X" option (#1780) UI improvements to Locale and Date & Time menu 0.45: Add calibrate battery option +0.46: Fix regression after making 'calibrate battery' only for Bangle.js 2 diff --git a/apps/setting/metadata.json b/apps/setting/metadata.json index c5c368fae..183290a85 100644 --- a/apps/setting/metadata.json +++ b/apps/setting/metadata.json @@ -1,7 +1,7 @@ { "id": "setting", "name": "Settings", - "version": "0.45", + "version": "0.46", "description": "A menu for setting up Bangle.js", "icon": "settings.png", "tags": "tool,system", diff --git a/apps/setting/settings.js b/apps/setting/settings.js index 73cb4b497..150251e7d 100644 --- a/apps/setting/settings.js +++ b/apps/setting/settings.js @@ -559,7 +559,7 @@ function showUtilMenu() { E.showAlert(/*LANG*/"Please charge Bangle.js for 3 hours and try again").then(() => load("settings.app.js")); } }); - }, + }; menu[/*LANG*/'Reset Settings'] = () => { E.showPrompt(/*LANG*/'Reset to Defaults?',{title:/*LANG*/"Settings"}).then((v) => { if (v) { @@ -568,8 +568,8 @@ function showUtilMenu() { setTimeout(showMainMenu, 50); } else showUtilMenu(); }); - }, - menu[/*LANG*/'Turn Off'] = ()=>{ if (Bangle.softOff) Bangle.softOff(); else Bangle.off() } + }; + menu[/*LANG*/'Turn Off'] = ()=>{ if (Bangle.softOff) Bangle.softOff(); else Bangle.off() }; if (Bangle.factoryReset) { menu[/*LANG*/'Factory Reset'] = ()=>{ From 3a3a01136b018fc2a9ea2b0069d9442c228f9b1d Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Thu, 26 May 2022 12:50:44 +0100 Subject: [PATCH 292/294] mylocation 0.07: Move mylocation app into 'Settings -> Apps' --- README.md | 1 + apps/mylocation/ChangeLog | 1 + apps/mylocation/README.md | 2 ++ apps/mylocation/icon.js | 1 - apps/mylocation/metadata.json | 7 +++--- apps/mylocation/{app.js => settings.js} | 30 ++++++++++++------------- bin/sanitycheck.js | 4 ++-- 7 files changed, 24 insertions(+), 22 deletions(-) delete mode 100644 apps/mylocation/icon.js rename apps/mylocation/{app.js => settings.js} (73%) diff --git a/README.md b/README.md index ee555cad2..b3da9f685 100644 --- a/README.md +++ b/README.md @@ -256,6 +256,7 @@ and which gives information about the app for the Launcher. // 'clock' - a clock - required for clocks to automatically start // 'widget' - a widget // 'bootloader' - an app that at startup (app.boot.js) but doesn't have a launcher entry for 'app.js' + // 'settings' - apps that appear in Settings->Apps (with appname.settings.js) but that have no 'app.js' // 'RAM' - code that runs and doesn't upload anything to storage // 'launch' - replacement 'Launcher' // 'textinput' - provides a 'textinput' library that allows text to be input on the Bangle diff --git a/apps/mylocation/ChangeLog b/apps/mylocation/ChangeLog index 1239554f0..c14e64ba9 100644 --- a/apps/mylocation/ChangeLog +++ b/apps/mylocation/ChangeLog @@ -4,3 +4,4 @@ 0.04: Fixed issue selecting Frankfurt not saved 0.05: Fixed issue with back option 0.06: renamed source files to match standard +0.07: Move mylocation app into 'Settings -> Apps' diff --git a/apps/mylocation/README.md b/apps/mylocation/README.md index fd597397a..a6a16ce83 100644 --- a/apps/mylocation/README.md +++ b/apps/mylocation/README.md @@ -2,6 +2,8 @@ *Sets and stores GPS lat and lon of your preferred city* +To access, go to `Settings -> Apps -> My Location` + * Select one of the preset Cities or setup through the GPS * Other Apps can read this information to do calculations based on location * When the City shows ??? it means the location has been set through the GPS diff --git a/apps/mylocation/icon.js b/apps/mylocation/icon.js deleted file mode 100644 index b79f5875f..000000000 --- a/apps/mylocation/icon.js +++ /dev/null @@ -1 +0,0 @@ -require("heatshrink").decompress(atob("mEw4UA///gH4AYPO/QPDgNVqtADY/1BYNfBQ0PBQIAB+ALFmoLDrgLF6oLDq4KEgYKDBYPABYcNBYlVuAuIGAwuEAANUBYYKFHgg6Bq4ZCr4DBHgQLBvWq2te1WlBYZGBBYOr1Wq1qSDBYNqBIILDKgQLLgoLHqBqDBfJHLBZBrOgKPCBYiPCU4NaBYe1WYrABBQLCCfgYGCrwVBa4kAirvKNgIAErgLDKgIAEKQQ8EAAY6DBZhIDIww8GHQg8GHQgwGFwowEFwx5EOog8GHQ0AlWpBYNq1AKFWIILBAYOgBYbICytWAgQKCgTgDcwYXGAAgvGAAY8EEgYWGBgoVEA==")) diff --git a/apps/mylocation/metadata.json b/apps/mylocation/metadata.json index 16549b2ba..4ab9aa37e 100644 --- a/apps/mylocation/metadata.json +++ b/apps/mylocation/metadata.json @@ -2,16 +2,15 @@ "name": "My Location", "shortName":"My Location", "icon": "app.png", - "type": "app", + "type": "settings", "screenshots": [{"url":"screenshot_1.png"}], - "version":"0.06", + "version":"0.07", "description": "Sets and stores the lat and long of your preferred City or it can be set from the GPS. mylocation.json can be used by other apps that need your main location lat and lon. See README", "readme": "README.md", "tags": "tool,utility", "supports": ["BANGLEJS", "BANGLEJS2"], "storage": [ - {"name":"mylocation.app.js","url":"app.js"}, - {"name":"mylocation.img","url":"icon.js","evaluate": true } + {"name":"mylocation.settings.js","url":"settings.js"} ], "data": [ {"name":"mylocation.json"} diff --git a/apps/mylocation/app.js b/apps/mylocation/settings.js similarity index 73% rename from apps/mylocation/app.js rename to apps/mylocation/settings.js index fd5c9cc6d..7033500fa 100644 --- a/apps/mylocation/app.js +++ b/apps/mylocation/settings.js @@ -1,5 +1,4 @@ -Bangle.loadWidgets(); -Bangle.drawWidgets(); +(function(back) { const SETTINGS_FILE = "mylocation.json"; let settings; @@ -18,7 +17,7 @@ function loadSettings() { } } -function save() { +function saveSettings() { settings = s; require('Storage').write(SETTINGS_FILE, settings); } @@ -34,29 +33,29 @@ function setFromGPS() { //console.log("fix from GPS"); s = {'lat': gps.lat, 'lon': gps.lon, 'location': '???' }; Bangle.buzz(1500); // buzz on first position - Bangle.setGPSPower(0); - save(); + Bangle.setGPSPower(0, "mylocation"); + saveSettings(); Bangle.setUI("updown", ()=>{ load(); }); - E.showPrompt("Location has been saved from the GPS fix",{ - title:"Location Saved", - buttons : {"OK":1} + E.showPrompt(/*LANG*/"Location has been saved from the GPS fix",{ + title:/*LANG*/"Location Saved", + buttons : {/*LANG*/"OK":1} }).then(function(v) { load(); // load default clock }); }); - Bangle.setGPSPower(1); - E.showMessage("Waiting for GPS fix. Place watch in the open. Could take 10 minutes. Long press to abort", "GPS Running"); + Bangle.setGPSPower(1, "mylocation"); + E.showMessage(/*LANG*/"Waiting for GPS fix. Place watch in the open. Could take 10 minutes. Long press to abort", "GPS Running"); Bangle.setUI("updown", undefined); } function showMainMenu() { //console.log("showMainMenu"); const mainmenu = { - '': { 'title': 'My Location' }, - '< Back': ()=>{ load(); }, - 'City': { + '': { 'title': /*LANG*/'My Location' }, + '< Back': ()=>{ back(); }, + /*LANG*/'City': { value: 0 | locations.indexOf(s.location), min: 0, max: locations.length - 1, format: v => locations[v], @@ -65,14 +64,15 @@ function showMainMenu() { s.location = locations[v]; s.lat = lats[v]; s.lon = lons[v]; - save(); + saveSettings(); } } }, - 'Set From GPS': ()=>{ setFromGPS(); } + /*LANG*/'Set From GPS': ()=>{ setFromGPS(); } }; return E.showMenu(mainmenu); } loadSettings(); showMainMenu(); +}) diff --git a/bin/sanitycheck.js b/bin/sanitycheck.js index 850b793f4..81c0f75ac 100755 --- a/bin/sanitycheck.js +++ b/bin/sanitycheck.js @@ -65,7 +65,7 @@ const APP_KEYS = [ const STORAGE_KEYS = ['name', 'url', 'content', 'evaluate', 'noOverwite', 'supports']; const DATA_KEYS = ['name', 'wildcard', 'storageFile', 'url', 'content', 'evaluate']; const SUPPORTS_DEVICES = ["BANGLEJS","BANGLEJS2"]; // device IDs allowed for 'supports' -const METADATA_TYPES = ["app","clock","widget","bootloader","RAM","launch","textinput","scheduler","notify","locale"]; // values allowed for "type" field +const METADATA_TYPES = ["app","clock","widget","bootloader","RAM","launch","textinput","scheduler","notify","locale","settings"]; // values allowed for "type" field const FORBIDDEN_FILE_NAME_CHARS = /[,;]/; // used as separators in appid.info const VALID_DUPLICATES = [ '.tfmodel', '.tfnames' ]; const GRANDFATHERED_ICONS = ["s7clk", "snek", "astral", "alpinenav", "slomoclock", "arrow", "pebble", "rebble"]; @@ -140,7 +140,7 @@ apps.forEach((app,appIdx) => { ERROR(`App ${app.id} 'dependencies' must all be tagged 'type' or 'app' right now`); if (app.dependencies[dependency]=="type" && !METADATA_TYPES.includes(dependency)) ERROR(`App ${app.id} 'type' dependency must be one of `+METADATA_TYPES); - + }); } else ERROR(`App ${app.id} 'dependencies' must be an object`); From 95bf53e68d9bbe40f7879f743568e59d71b198be Mon Sep 17 00:00:00 2001 From: Stiralbios Date: Thu, 26 May 2022 16:44:56 +0200 Subject: [PATCH 293/294] [TerminalClock] Add power related settings to control sensors --- apps/terminalclock/ChangeLog | 1 + apps/terminalclock/README.md | 5 +++ apps/terminalclock/app.js | 65 +++++++++++++++++++++++++------- apps/terminalclock/metadata.json | 2 +- apps/terminalclock/settings.js | 23 ++++++++++- 5 files changed, 81 insertions(+), 15 deletions(-) diff --git a/apps/terminalclock/ChangeLog b/apps/terminalclock/ChangeLog index b752c829d..ce31583e9 100644 --- a/apps/terminalclock/ChangeLog +++ b/apps/terminalclock/ChangeLog @@ -3,3 +3,4 @@ 0.03: Add Banglejs 1 compatibility 0.04: Fix settings bug 0.05: Add altitude display (only Bangle.js 2) +0.06: Add power related settings to control the HR and pressure(altitude) sensor from the watchface diff --git a/apps/terminalclock/README.md b/apps/terminalclock/README.md index c7452397d..93967e8a7 100644 --- a/apps/terminalclock/README.md +++ b/apps/terminalclock/README.md @@ -8,3 +8,8 @@ It can display : - hrm - motion - steps + + +"Power saving" setting control the HR and pressure (altitude) sensors. +If "Off" they will always be on. +If "On" the sensors will be turned on every "Power on interval" minutes for 45 secondes diff --git a/apps/terminalclock/app.js b/apps/terminalclock/app.js index 61861f745..833ed7694 100644 --- a/apps/terminalclock/app.js +++ b/apps/terminalclock/app.js @@ -3,15 +3,14 @@ var fontColor = g.theme.dark ? "#0f0" : "#000"; var heartRate = 0; var altitude = -9001; -// handling the differents versions of the Banglejs smartwatch +// handling the differents versions of the Banglejs smartwatch screen sizes if (process.env.HWVERSION == 1){ var paddingY = 3; var font6x8At4Size = 48; var font6x8At2Size = 27; var font6x8FirstTextSize = 6; var font6x8DefaultTextSize = 3; -} -else{ +} else{ var paddingY = 2; var font6x8At4Size = 32; var font6x8At2Size = 18; @@ -66,7 +65,7 @@ function drawDate(now, pos){ drawLine(locale_date, pos); } -function drawInput(now, pos){ +function drawInput(pos){ clearField(pos); drawLine(">", pos); } @@ -129,17 +128,55 @@ function draw(){ drawStepCount(curPos); curPos++; } - drawInput(now, curPos); + drawInput(curPos); } +function turnOnServices(){ + if(settings.showHRM){ + Bangle.setHRMPower(true, "terminalclock"); + } + if(settings.showAltitude && process.env.HWVERSION != 1){ + Bangle.setBarometerPower(true, "terminalclock"); + } + if(settings.powerSaving){ + setTimeout(function () { + turnOffServices(); + }, 45000); + } +} + +function turnOffServices(){ + if(settings.showHRM){ + Bangle.setHRMPower(false, "terminalclock"); + } + if(settings.showAltitude && process.env.HWVERSION != 1){ + Bangle.setBarometerPower(false, "terminalclock"); + } +} + +var unlockDrawIntervalID = -1; +Bangle.on('lock', function(on){ + if(!on){ // unclock + if(settings.powerSaving){ + turnOnServices(); + } + unlockDrawIntervalID = setInterval(draw, 1000); // every second + } + if(on && unlockDrawIntervalID != -1){ // lock + clearInterval(unlockDrawIntervalID); + } +}); + Bangle.on('HRM',function(hrmInfo) { + console.log('in hrm'); if(hrmInfo.confidence >= settings.HRMinConfidence) heartRate = hrmInfo.bpm; }); -var MEDIANLENGTH = 20; -var avr = [], median; +var MEDIANLENGTH = 20; // technical +var avr = [], median; // technical Bangle.on('pressure', function(e) { + console.log('in pressure'); while (avr.length>MEDIANLENGTH) avr.pop(); avr.unshift(e.altitude); median = avr.slice().sort(); @@ -161,18 +198,20 @@ var settings = Object.assign({ showActivity: true, showStepCount: true, showAltitude: process.env.HWVERSION != 1 ? true : false, + powerSaving: true, + PowerOnInterval: 15, }, require('Storage').readJSON("terminalclock.json", true) || {}); -if(settings.showAltitude && process.env.HWVERSION != 1){ - Bangle.setBarometerPower(true, "app"); +// turn the services before drawing anything +turnOnServices(); +if(settings.powerSaving){ + setInterval(turnOnServices, settings.PowerOnInterval*60000); // every PowerOnInterval min } - // Show launcher when middle button pressed Bangle.setUI("clock"); -// Load widgets +// Load and draw widgets Bangle.loadWidgets(); Bangle.drawWidgets(); // draw immediately at first draw(); - -var secondInterval = setInterval(draw, 10000); +setInterval(draw, 10000); // every 10 seconds diff --git a/apps/terminalclock/metadata.json b/apps/terminalclock/metadata.json index 7bc00bca4..9f76ed8f2 100644 --- a/apps/terminalclock/metadata.json +++ b/apps/terminalclock/metadata.json @@ -3,7 +3,7 @@ "name": "Terminal Clock", "shortName":"Terminal Clock", "description": "A terminal cli like clock displaying multiple sensor data", - "version":"0.05", + "version":"0.06", "icon": "app.png", "type": "clock", "tags": "clock", diff --git a/apps/terminalclock/settings.js b/apps/terminalclock/settings.js index 4b09aad6a..bd860b491 100644 --- a/apps/terminalclock/settings.js +++ b/apps/terminalclock/settings.js @@ -8,6 +8,8 @@ showHRM: true, showActivity: true, showStepCount: true, + powerSaving: true, + PowerOnInterval: 15, }, require('Storage').readJSON(FILE, true) || {}); function writeSettings() { @@ -65,10 +67,29 @@ settings.showStepCount = v; writeSettings(); } + }, + 'Power saving': { + value: settings.powerSaving, + format: v => v?"On":"Off", + onchange: v => { + settings.powerSaving = v; + writeSettings(); + } + }, + 'Power on interval': { + value: settings.PowerOnInterval, + min: 3, max: 60, + onchange: v => { + settings.PowerOnInterval = v; + writeSettings(); + }, + format: x => { + return x + " min"; + } } } if (process.env.HWVERSION == 1) { delete menu['Show Altitude'] } E.showMenu(menu); -}) +}) \ No newline at end of file From 76c40f94a259737f0dadbe6929d819147d4b84cc Mon Sep 17 00:00:00 2001 From: Stiralbios Date: Thu, 26 May 2022 16:53:50 +0200 Subject: [PATCH 294/294] [TerminalClock] Remove logs --- apps/terminalclock/app.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/apps/terminalclock/app.js b/apps/terminalclock/app.js index 833ed7694..7dc3bf1d1 100644 --- a/apps/terminalclock/app.js +++ b/apps/terminalclock/app.js @@ -168,7 +168,6 @@ Bangle.on('lock', function(on){ }); Bangle.on('HRM',function(hrmInfo) { - console.log('in hrm'); if(hrmInfo.confidence >= settings.HRMinConfidence) heartRate = hrmInfo.bpm; }); @@ -176,7 +175,6 @@ Bangle.on('HRM',function(hrmInfo) { var MEDIANLENGTH = 20; // technical var avr = [], median; // technical Bangle.on('pressure', function(e) { - console.log('in pressure'); while (avr.length>MEDIANLENGTH) avr.pop(); avr.unshift(e.altitude); median = avr.slice().sort();