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 01/82] 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 02/82] 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 03/82] 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 04/82] 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 05/82] 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 06/82] 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 07/82] 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 08/82] 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 09/82] 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 10/82] 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 11/82] 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 12/82] 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 13/82] 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 14/82] 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 15/82] 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 16/82] 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 17/82] 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 18/82] 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 19/82] 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 20/82] 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 21/82] [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 22/82] [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 23/82] [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 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 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 zcmai#dpy&N8^`4~#C)k3EtwYO(rF>HWiGR#<5EbuavQ~Q&g=Di{a)v<-yhHOyq-Uve?Fh*{XD4`Y|hC@DN6|n3CUPm znA`2vn!iIrcsHx^gC&K8KpabRQ-_G0uel?XB2@raJMd%Y7hPHP&dM}lhSwtbCGWZF z*>4i&<%)|tq$H~22*j6Jh@Gi}_-0llcOlAz zL6B*KHv(Hsm3tedr0$|W^m4ByC)-+m8z>vxT7#%-VonAz;rl79(K$j+e;EJk_~Z*L z={i<1x+^~@e>l%9=yrNtfp*!YvkL&x(s=>J#&C@U+P405(;c5^uBNM&!Q@dZgAm4e z)uGrg?On@~`UW$0)S+b`zLuj3Z^1G|3_T_JTV!?G&y}_9K_~Gu>8$FwOm6hMvfLRY zGu@+u)&~ENBu?KhFy)o>jWGSCR|Pl4)KqZ3k8@-M4^8u4fu@e}hBerRNd>lL_!OF& zZo9rXMJ=S*5J$H4Fzsf+j9a8odMy@OtqE2nr{eOpEF#mCjBo2!8nY&lX?PRVuYWlJ^=f$M^kfh*yo!0e>guHD3lBikH z`|YDC?~dZBFV?%FWbeo)j=464k9|Qb9DGNWJt$5#iN{{vgcdRg4?AvFv6_$h`xmK@ zQ*J)L*YBWUWc77^7T~ev!9-B8BgFeqHg^9b1?XhJ9ID|@6jQ?)g3X*z@(OCinmeD3 z!|=AObNAYQDbSb+g3q{fE)(X~^W%m%l3A|j zS)mPHQenF@TbDXuV}(R81?h5!o@^@zojf$Zs=E)oBrbC!54v+~Usn&ffI}pvpaa*= z6KGOOv+`GKX?DD@71hw(ky5B|Kv&5+How6EjT8+@#O5PKJ12l+;6101qG{M$(%^(i zK-K;oB9uIq_H0o`3n>cENCL~x02!?iVe4zsdn7Bc`Kh)OK*p_q%?>XDo83DRoFv!p zuI-K`-+oZ+6pW@h^))ZC6QT`MD_&@RI2T>^Wi+k=n^C#!yf6ct=)P)J&(>X?Ka*uG zk`i6Gq70tuKa<55;09B9xZ;5sVwCkW_FbJvGGLh{4~HOutv^ zwnxE4d!6qNanp)J3_OVJZ4*pP>7uI4B~Zzs6ggknk(Z+>L>ZpnifZL&s&q%ZU);xd zwNNxu!=c&yBQQ`nh+SMJbU@4mxw<{)k2jr_y`*u2Drj^RDP1h0rpsTC4x=hL7_@4?RPzgk>qty@8Ec8Or#l&jqGDE)V9uGTj*GAelG0t0ExqQe1a@k%HRgKnaUh z*afJtN1()hvXD}cRe|K+LQ;VLDRbn*H6ReYm~{=22!^f_IB$qr;NsGe2|3Fk2H8+%yy_R>N(uUJ9ogb+S^lQTlBC&vNz^og|SV4=+u_e?@h34XYPJ@DSeza z>Xxc~N+T_=3WFz6&K(E5_TCeGuJo^)_W>7(T0FQ53(>wG_xR>4bQV}T@N4G_XF*6L z<97QCSM6ehwHyLdf2|5TXz!qJEhZebU6wF!rv*Zhn);`&x|4_kdW1_>4P#4)d<-8b zkpx1SU(vaQ5~N46g|JRB$~kI+YAS3f?w3)dlAfAu_kp(8F5!s9 z5nG?{Ae}oPSrjSARJqwP$yZPp4B0w0#SZua5R%z7?H4`-aIBx=G$T)PUz{%@X?B02 zzddAszhiRWn&anmYKLE+#$C79x3LWJRdIJDGdjc{t{5Ulz9kA3X2DE$VJAvty!pq$ zPDGOW?zWpan_1*zO@#3hdI<|6S2LFULD;3g+$!_tCrse(g5t>$`v(<(x@o=HCf)_-RIz9>Z zYPtByrk8Vp-h$PoaoSmDB45k(7}Z*3@+D!>#`E!-E@?k|GS;kz$fsxx$)4Tod_C5El@{JdfbSQhP?X~$IMBqo zfi{*x#Oyt;G`0nOJ6UZHM#KkLRwo*eY#iU8WXMJqpK_~>y#w;Ws9g@7Dn^*cT-rNL zI33mN_hbmP5vC{0&$dM|?-#nU^A)BRMS zb7U6i3YSj8xb$%oYaL3kt!Rlu*Yk;V{9Mvzf_BJB*?&3qzr$zvym!}p`E8Lm?(j#w 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 24/82] [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 25/82] 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 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 26/82] 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 27/82] 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 28/82] 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 29/82] 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 30/82] 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 31/82] 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 32/82] 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 33/82] 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 34/82] 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 35/82] 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 36/82] 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 37/82] 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 38/82] 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 39/82] 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 40/82] 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 41/82] 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 42/82] 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 43/82] 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 44/82] 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 45/82] 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 46/82] 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 47/82] 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 48/82] 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 49/82] 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 50/82] 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 51/82] 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 52/82] 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 53/82] 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 54/82] 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 55/82] 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 56/82] 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 57/82] 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 58/82] 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 59/82] 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 60/82] 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 61/82] 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 62/82] 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 63/82] 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 64/82] 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 65/82] 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 66/82] 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 67/82] 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 cff3c77f0805ca51f691a0f637e3b9c45161e211 Mon Sep 17 00:00:00 2001 From: marko Date: Mon, 16 May 2022 13:50:25 -0400 Subject: [PATCH 68/82] First commit for f9lander --- apps/f9lander/ChangeLog | 1 + apps/f9lander/README.md | 30 +++++ apps/f9lander/app-icon.js | 1 + apps/f9lander/app.js | 150 +++++++++++++++++++++++++ apps/f9lander/f9lander_screenshot1.png | Bin 0 -> 1340 bytes apps/f9lander/f9lander_screenshot2.png | Bin 0 -> 722 bytes apps/f9lander/metadata.json | 15 +++ 7 files changed, 197 insertions(+) create mode 100644 apps/f9lander/ChangeLog create mode 100644 apps/f9lander/README.md create mode 100644 apps/f9lander/app-icon.js create mode 100644 apps/f9lander/app.js create mode 100644 apps/f9lander/f9lander_screenshot1.png create mode 100644 apps/f9lander/f9lander_screenshot2.png create mode 100644 apps/f9lander/metadata.json diff --git a/apps/f9lander/ChangeLog b/apps/f9lander/ChangeLog new file mode 100644 index 000000000..5560f00bc --- /dev/null +++ b/apps/f9lander/ChangeLog @@ -0,0 +1 @@ +0.01: New App! diff --git a/apps/f9lander/README.md b/apps/f9lander/README.md new file mode 100644 index 000000000..ce0e56903 --- /dev/null +++ b/apps/f9lander/README.md @@ -0,0 +1,30 @@ +# F9 Lander + +Land a Falcon 9 booster on a drone ship. + +## Game play + +Attempt to land your Falcon 9 booster on a drone ship before running out of fuel. +A successful landing requires: + * setting down on the ship + * the booster has to be mostly vertical + * the landing speed cannot be too high + +## Controls + +The angle of the booster is controlled by tilting the watch side-to-side. The +throttle level is controlled by tilting the watch forward and back: + * screen horizontal (face up) means no throttle + * screen vertical corresponds to full throttle + +The fuel burn rate is proportional to the throttle level. + +## Creators +Liam Kl. B. +Marko Kl. B. + +## Screenshots + +![](f9lander_screenshot1.png) + +![](f9lander_screenshot2.png) diff --git a/apps/f9lander/app-icon.js b/apps/f9lander/app-icon.js new file mode 100644 index 000000000..d08b4ce9a --- /dev/null +++ b/apps/f9lander/app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("sFgwcA/4AL/1JkmSARMntu27YCEEbUk9ojT+QjiEBYCCzojS/gjOyYjS8gjOyV2EcVOEcVJEccnEcTaFEbySEEb4CDEf4j/EbYgUEf4jV/Ij/AA3JEf4AF/wgVEZnyEcQgWEZf8EcXkEbMnEQ35EC4CDz7UeAQlPRjoC/AX4C/AX4C3n4jgyf//n/5JHgngmCEcJHhn4jjR8Qjj//+fb4j/Ef4j/Ef4jgp4jk+Qjfyf/EcP+I4P/5Ijdk/yp3Y+V/R74jBSQPkEb127cSa8Aj/Ef4COye2a4Ij/Ef6zN4gjhpwgfAX4C/AX4C/AX4C/AX4CIk//ACnJEd8kESn+NxufEafyEeIC/AX4C/ASA")) diff --git a/apps/f9lander/app.js b/apps/f9lander/app.js new file mode 100644 index 000000000..41f3b7666 --- /dev/null +++ b/apps/f9lander/app.js @@ -0,0 +1,150 @@ +const falcon9 = Graphics.createImage(` + xxxxx + xxxxx xxxxx + x x + x x + xxxxx + xxxxx + xxxxx + xxxxx + xxxxx + xxxxx + xxxxx + xxxxx + xxxxx + xxxxx + xxxxx + xxxxx + xxxxx + xxxxx + xxxxxxxxx + xx xxxxx xx +xx xx`); + +const droneShip = Graphics.createImage(` +xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx +xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx +`); + +const droneX = Math.floor(Math.random()*(g.getWidth()-droneShip.width-40) + 20) +const cloudOffs = Math.floor(Math.random()*g.getWidth()/2); + +const oceanHeight = g.getHeight()*0.1; + +const targetY = g.getHeight()-oceanHeight-falcon9.height/2; + +var booster = { x : g.getWidth()/4 + Math.random()*g.getWidth()/2, + y : 20, + vx : 0, + vy : 0, + mass : 100, + fuel : 100 }; + +var exploded = false; +var nExplosions = 0; +var landed = false; + +const gravity = 4; +const dt = 0.1; +const fuelBurnRate = 20; +const maxV = 12; + +function flameImageGen (throttle) { + var str = " xxx \n xxx \n"; + str += "xxxxx\n".repeat(throttle); + str += " xxx \n x \n"; + return Graphics.createImage(str); +} + +function drawFalcon(x, y, throttle, angle) { + g.setColor(1, 1, 1).drawImage(falcon9, x, y, {rotate:angle}); + if (throttle>0) { + var flameImg = flameImageGen(throttle); + var r = falcon9.height/2 + flameImg.height/2-1; + var xoffs = -Math.sin(angle)*r; + var yoffs = Math.cos(angle)*r; + if (Math.random()>0.7) g.setColor(1, 0.5, 0); + else g.setColor(1, 1, 0); + g.drawImage(flameImg, x+xoffs, y+yoffs, {rotate:angle}); + } +} + +function drawBG() { + g.setBgColor(0.2, 0.2, 1).clear(); + g.setColor(0, 0, 1).fillRect(0, g.getHeight()-oceanHeight, g.getWidth()-1, g.getHeight()-1); + g.setColor(0.5, 0.5, 1).fillCircle(cloudOffs+34, 30, 15).fillCircle(cloudOffs+60, 35, 20).fillCircle(cloudOffs+75, 20, 10); + g.setColor(1, 1, 0).fillCircle(g.getWidth(), 0, 20); + g.setColor(1, 1, 1).drawImage(droneShip, droneX, g.getHeight()-oceanHeight-1); +} + +function showFuel() { + g.setColor(0, 0, 0).setFont("4x6:2").setFontAlign(-1, -1, 0).drawString("Fuel: "+Math.abs(booster.fuel).toFixed(0), 4, 4); +} + +function renderScreen(input) { + drawBG(); + showFuel(); + drawFalcon(booster.x, booster.y, Math.floor(input.throttle*12), input.angle); +} + +function getInputs() { + var accel = Bangle.getAccel(); + var a = Math.PI/2 + Math.atan2(accel.y, accel.x); + var t = (1+accel.z); + if (t > 1) t = 1; + if (t < 0) t = 0; + if (booster.fuel<=0) t = 0; + return {throttle: t, angle: a}; +} + +function epilogue(str) { + g.setFont("Vector", 24).setFontAlign(0, 0, 0).setColor(0, 0, 0).drawString(str, g.getWidth()/2, g.getHeight()/2).flip(); + g.setFont("Vector", 16).drawString("<= again exit =>", g.getWidth()/2, g.getHeight()/2+20); + clearInterval(stepInterval); + Bangle.on("swipe", (d) => { if (d>0) load(); else load('falcon.app.js'); }); +} + +function gameStep() { + if (exploded) { + if (nExplosions++ < 15) { + var r = Math.random()*25; + var x = Math.random()*30 - 15; + var y = Math.random()*30 - 15; + g.setColor(1, Math.random()*0.5+0.5, 0).fillCircle(booster.x+x, booster.y+y, r); + if (nExplosions==1) Bangle.buzz(600); + } + else epilogue("You crashed!"); + } + else { + var input = getInputs(); + if (booster.y >= targetY) { +// console.log(booster.x + " " + booster.y + " " + booster.vy + " " + droneX + " " + input.angle); + if (Math.abs(booster.x-droneX-droneShip.width/2) { + stepInterval = setInterval(gameStep, Math.floor(1000*dt)); + Bangle.removeListener("swipe"); +}); diff --git a/apps/f9lander/f9lander_screenshot1.png b/apps/f9lander/f9lander_screenshot1.png new file mode 100644 index 0000000000000000000000000000000000000000..a2f13d6c7278538af255e6c267cd11e0bfca517e GIT binary patch literal 1340 zcmZ{ke>l^76vsbYGuwzR*CZunidw!1-I0Eo$dAMlB__Yhucl#JevNUdT*|MgZoAb} zD?f+2jZxO_C0bHp)+}>rQDj%eSBZB2xPSD={o|b1^FHUipXWT!d7g9H*JqCo+87N0 z(D870^;1##Z)p6W%A(YdS5?r6-s!y)fQBN>LKs4&*Mz(Kc>{3D0sv+X0H0MQ<~RV! z5CCt<01zqwz)~)^>~~f*tbDylL;Y1vcNLb@KVJ4y7HQ_^h-Qpf;F zaYGl>v}LvH8z~Wl!SRbY#|^uCVlZ3Tu`d(tG~|CTjQ&%ePznf;l7m!o=;sFO-v?i(~eR z0<2lIN+ovWbWJbr_2bZsDXt@F()U0y({Ig8)e0Hcd}w=rvEupL zR>YQRALJge{XKRuRNaBG_CkK*tA~6eZB3Sd41Eu=!J%7h>YQKKu@CkeC+DfOmY9lF z;R&4jl_8D$*6{S$8pYRZSC!Rw!|3k%ylg=lHvVyO6ZRfy^b$9aC^5FWfSwQBq`Wat z>A)yD9m&mApKhC5_AiLA7Ds71is~~3>>t-j)cdi0SDI4s8BvBc0YAlDU5wlogxARN zaN<9js@Wc+hAs~u%Ed+)dKIi46;$Q@twgL;+{b&4h+e zxA6$wsWRQsdb7B%9TU}7x#ZKt$?TXK%f2hM6kYcC`ZUwbdA?D5Gsn{Czf+t(pI%ZV zpZpqPPHawvuT9$ecW}em57wfIh zc}!P!^iNbkiH0T(V%;uz_iMMD>bGx{TAe0id%Nm;mG%C@jBQyDb+r`}xl6N=R}v>4 zGnS`SmN1oU64ZR0UY@0Nh5JSq^HB$@v#rZg&wZ8AP`Y!39h^Kl)sM~{Yxw{G literal 0 HcmV?d00001 diff --git a/apps/f9lander/f9lander_screenshot2.png b/apps/f9lander/f9lander_screenshot2.png new file mode 100644 index 0000000000000000000000000000000000000000..ea7d8a834d4fb8c60a13722957ff42be49e8010d GIT binary patch literal 722 zcmeAS@N?(olHy`uVBq!ia0vp^A3&Ie8AzU~{<08Av7|ftIx;Y9?C1WI$O_~uBzpw; zGB8xBF)%c=FfjZA3N^f7U???UV0e|lz+g3lfkC`r&aOZkpoBz#Pl&65!H*w*fEc#S%MS13By^p1!W^&sYUGH8flJ+Ghf#w|lxc zhE&{od*g2IAp?=NL}hE{5>|f!P3|X3%mtH0cm3z!ZCqfo&@VQ*o^`*z(*0I9e+#dk{rU0h-}x-(!}s5b*jlZy^YZ_OzoOsjx__tdwz^>xwKaa* z?xM#}^Hzx-h!vmaFa2ZJ`>VUA`?~M?##Mgw;cRIM%k%Efj6UeQ`K4{!EO$^%HZK2a z-krzO!#7z=TYvu{J9XRh+fm>1ILtCXNWFZNFqz3-;?wsJPi^cIAJ`w@T=`(JZ#YMK z5x@UNp1jZkz3&|7%svRtIm^0^VcUVF3BmF?p#=p`%+zy2H%vUpXt{p(pQtTQAI?|H zzc0IOk?(sqJ<|_)Pmu(vvx)j-ek=iMK z_KjMU(dO54QxYDtU0m(W#&5NQU2l@`A))O~J9cgVxS(;lX?8+-%;H<6#!{SjdKOQt z5uA~D^n`fCBp$ia50X1PdIhHKu)1;L!RJU8VL?=I@wX{UxAnDjpG1pS0fig5ch Date: Mon, 16 May 2022 13:53:27 -0400 Subject: [PATCH 69/82] Add icon --- apps/f9lander/f9lander.png | Bin 0 -> 542 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 apps/f9lander/f9lander.png diff --git a/apps/f9lander/f9lander.png b/apps/f9lander/f9lander.png new file mode 100644 index 0000000000000000000000000000000000000000..9ecf155411021db6cba17a262d80a24446c7e732 GIT binary patch literal 542 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeE3?v1%WpM*3mUKs7M+SzC{oH>NS%G|oWRD45bDP46hOx7_4S6Fo+k-*%fF5ln@Q@32|*`_+eo1rlDl0^$SkL4-#TD%s zn8?b^?ZAA2!KC8;!G>@@&JETVtP*WA&aP)W+j~H)L6;$#VH*SAof@VE&(s@Mm;RRw zc$rZBfSGkqhxn#MCzXW!gvJf#8yr+h3LGBnXGn0EwcMfVwv(;hK?&O-T>}#<1B0zgj(9nO2Eg!;zo$9zYEYp00i_>zopr0F|q_761SM literal 0 HcmV?d00001 From 2430cefbbfe905c650bb56eeaddd472073f2c290 Mon Sep 17 00:00:00 2001 From: marko Date: Mon, 16 May 2022 14:00:46 -0400 Subject: [PATCH 70/82] Fix icon size --- apps/f9lander/app-icon.js | 2 +- apps/f9lander/f9lander.png | Bin 542 -> 1229 bytes 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/f9lander/app-icon.js b/apps/f9lander/app-icon.js index d08b4ce9a..572768a28 100644 --- a/apps/f9lander/app-icon.js +++ b/apps/f9lander/app-icon.js @@ -1 +1 @@ -require("heatshrink").decompress(atob("sFgwcA/4AL/1JkmSARMntu27YCEEbUk9ojT+QjiEBYCCzojS/gjOyYjS8gjOyV2EcVOEcVJEccnEcTaFEbySEEb4CDEf4j/EbYgUEf4jV/Ij/AA3JEf4AF/wgVEZnyEcQgWEZf8EcXkEbMnEQ35EC4CDz7UeAQlPRjoC/AX4C/AX4C3n4jgyf//n/5JHgngmCEcJHhn4jjR8Qjj//+fb4j/Ef4j/Ef4jgp4jk+Qjfyf/EcP+I4P/5Ijdk/yp3Y+V/R74jBSQPkEb127cSa8Aj/Ef4COye2a4Ij/Ef6zN4gjhpwgfAX4C/AX4C/AX4C/AX4CIk//ACnJEd8kESn+NxufEafyEeIC/AX4C/ASA")) +require("heatshrink").decompress(atob("mEwwcA/4AD/P8yVJkgCCye27dt2wRE//kCIuSuwRIBwgCCpwRQpIRRnYRQkmdCIvPCJICBEZ4RG/IRP/15CJ/z5IRPz4RM/gQB/n+BxICCn/z/P/BxQCDz7mIAX4Cq31/CJ+ebpiYE/IR/CNP/5IROnn//4jP5DFQ5sJCKAjPk3oCMMk4QRQAX4Ckn7jBAA/5CK8nCJPJNHA")) diff --git a/apps/f9lander/f9lander.png b/apps/f9lander/f9lander.png index 9ecf155411021db6cba17a262d80a24446c7e732..f03cc1645264e4bbbff1fbcb774a8c5c890bbd7d 100644 GIT binary patch delta 1093 zcmYL{eK6Yx7{`Bk@ls>7*;Xr4FV~v4BqjCURw5xv39^-HOSDlG+c2SC63n}uxkzYx z-g?%Sq26gsXGhO%=jCR_Ij`}uZmLzIm**FW?6m%!A1YsDrx5Y(y5)l^;H^#PG3t*YL!&qsgh>d3++`I8Q|#&PEL@W4Zgl`^CqOH zLrMx{WdWNF4i4aX4%mK>m;|@tz?%saX#!|^2xZ?wY8tq@f~_qSmx3SzO3EOL z2P_siIznwd>?vUKH()Tp+Z*PW;7|iBA6WYX)EW>=z|KwxYnxCd1$%p7GC{rxw-aDz z4^TCfmV=u+@S+t%!%CG#we=dJZzv?yiugojU7l=5R`j%QJ1-yHXxlRW#kY5KQUY5k zXATk)A>t}HkWrTF(z?Jzorg%mvh2tzGDR8aIlY;FTq#1zxP|s)RXMjnnTvd0{#n67 z>M4ecoJ>I}6ttCh{cHaR&W>+wY(Ps3h(sWfptA=M1n_w9qQm$UEX!eW6|}X%*cePq zK%>!&F9n%ko#LYXeVJl8VWqFK%u+~lbewOzgkhr_yudWf)Bh6#bNWJv_z{*^@?+Au z?6I~PG~yWDbZnP*7qvCN{XDvnU(Lcj=;fP9s+!{pqH1(%)8dN?@qRjK#=kaBM=rLT zP7y}BoTf$&p!Gx-o<;YZ=AywDe#gJ+q)IV9m-Zaa2XXd3hIQ@(@y+C>qT4Q_i=k=Kt(nj+B z^u&mZue-SZ9IBfR%^4|KDP7TkTHbO9)NXFIF z-H+7mCZwx2{_1{7p~euSu4SQH@9tOj=LpAj7sWeL>534b8fmaHmhCoWM!@MQ$sLAD;GDA3*w)0%7$^H6BjItO}*5|8x;oXqp>v6U76&`d#GNb zpPWN&3Z{M_?JM=(@8`s4T5}%NzUF>aJpJ5pe(_D6&*0O9hdp-r`#Fd8F{s**W?;Oo zt-;xNuQMzLu6l?&a8~cTxu2yvP-*T|>gay{o>-2vI`Kd1ZT1MlUIX!C1v1+iQF;FW D;shQr delta 402 zcmX@hIgdrLGr-TCmrII^fq{Y7)59eQNGE_W3p0=u*p|gTQPEC^K{UW8#I>Q}hk?P5 zAAcBr{Q2>t0Vw_B|NsAriyc1#nT$!^?k;SJX*+5s8!;)>3+XO9HTNgTgyclOG9di{ zid%qm(~LgP-$44Rr;B4q#NoGBE^;0=;9&_UZ;qS8xvTLa3+ws|f5TT^o^(q<`SmQJ zNmstFJ?@$C=8lrMPSNQ?HG>rlDl0^$SkL4-#TD%sn8?b^?ZAA2!KC8;!G>@@&JETV ztm+eOGtRDOJKK9etU;F{nqeCQ-<=w!1<%wQR+s*l40xGP{eYQuPlx!XL?@Mm{Dj60 z<{KPTN(vkv>}N=Dn6=!Y>b8@u-9ZW4BYYDap2}Zv=qZ2o!nncEO-6P>+2(&H4ooE% z4w^Y!N%=5iar5~Iwz%2+q6^-{xS6S864_INt$Y(4o^+LPm1l=&>IOiXnROsotH gwk|pTW%2|TWhsQvk)QP*z<^-zboFyt=akR{0PP}|hyVZp From c83c82bd0990f39980e9e8957a331970f7822570 Mon Sep 17 00:00:00 2001 From: marko Date: Mon, 16 May 2022 14:08:26 -0400 Subject: [PATCH 71/82] Swap screen shots, fix README --- apps/f9lander/README.md | 1 + apps/f9lander/metadata.json | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/f9lander/README.md b/apps/f9lander/README.md index ce0e56903..30136fe58 100644 --- a/apps/f9lander/README.md +++ b/apps/f9lander/README.md @@ -21,6 +21,7 @@ The fuel burn rate is proportional to the throttle level. ## Creators Liam Kl. B. + Marko Kl. B. ## Screenshots diff --git a/apps/f9lander/metadata.json b/apps/f9lander/metadata.json index 65831351b..7d2ee9dce 100644 --- a/apps/f9lander/metadata.json +++ b/apps/f9lander/metadata.json @@ -1,10 +1,10 @@ { "id": "f9lander", - "name": "Falcon9 lander", + "name": "Falcon9 Lander", "shortName":"F9lander", "version":"0.01", "description": "Land a rocket booster", "icon": "f9lander.png", - "screenshots" : [ { "url":"f9lander_screenshot1.png" }, { "url":"f9lander_screenshot2.png" }], + "screenshots" : [ { "url":"f9lander_screenshot2.png" }, { "url":"f9lander_screenshot1.png" }], "readme": "README.md", "tags": "game", "supports" : ["BANGLEJS", "BANGLEJS2"], From fec2074764e6a6913b4b7f417c2dc9ecb94cfac0 Mon Sep 17 00:00:00 2001 From: marko Date: Mon, 16 May 2022 14:12:04 -0400 Subject: [PATCH 72/82] Fix app name on reload --- apps/f9lander/app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/f9lander/app.js b/apps/f9lander/app.js index 41f3b7666..62d88df6d 100644 --- a/apps/f9lander/app.js +++ b/apps/f9lander/app.js @@ -104,7 +104,7 @@ function epilogue(str) { g.setFont("Vector", 24).setFontAlign(0, 0, 0).setColor(0, 0, 0).drawString(str, g.getWidth()/2, g.getHeight()/2).flip(); g.setFont("Vector", 16).drawString("<= again exit =>", g.getWidth()/2, g.getHeight()/2+20); clearInterval(stepInterval); - Bangle.on("swipe", (d) => { if (d>0) load(); else load('falcon.app.js'); }); + Bangle.on("swipe", (d) => { if (d>0) load(); else load('f9lander.app.js'); }); } function gameStep() { From 8e2fdffd20a2515d18369b2de3845ec6ff395378 Mon Sep 17 00:00:00 2001 From: marko Date: Mon, 16 May 2022 14:14:17 -0400 Subject: [PATCH 73/82] Fix fuel burn rate on Bangle 1 --- apps/f9lander/app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/f9lander/app.js b/apps/f9lander/app.js index 62d88df6d..7e52104c0 100644 --- a/apps/f9lander/app.js +++ b/apps/f9lander/app.js @@ -49,7 +49,7 @@ var landed = false; const gravity = 4; const dt = 0.1; -const fuelBurnRate = 20; +const fuelBurnRate = 20*(176/g.getHeight()); const maxV = 12; function flameImageGen (throttle) { From f7efc338f172ccc3a0468ce8ffcacb4a6e44d702 Mon Sep 17 00:00:00 2001 From: Richard de Boer Date: Mon, 16 May 2022 20:21:24 +0200 Subject: [PATCH 74/82] ClockFace: add `is12Hour` property, document `paused` --- modules/ClockFace.js | 5 ++++- modules/ClockFace.md | 26 ++++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/modules/ClockFace.js b/modules/ClockFace.js index 9818ae4e3..25e2430bf 100644 --- a/modules/ClockFace.js +++ b/modules/ClockFace.js @@ -32,6 +32,8 @@ function ClockFace(options) { if (dir>0 && options.down) options.down.apply(this); }; if (options.upDown) this._upDown = options.upDown; + + this.is12Hour = !!(require("Storage").readJSON("setting.json", 1) || {})["12hour"]; } ClockFace.prototype.tick = function() { @@ -69,6 +71,7 @@ ClockFace.prototype.start = function() { if (this._upDown) Bangle.setUI("clockupdown", d=>this._upDown.apply(this,[d])); else Bangle.setUI("clock"); delete this._last; + this.paused = false; this.tick(); Bangle.on("lcdPower", on => { @@ -87,7 +90,7 @@ ClockFace.prototype.pause = function() { ClockFace.prototype.resume = function() { if (this._timeout) return; // not paused delete this._last; - delete this.paused; + this.paused = false; if (this._resume) this._resume.apply(this); this.tick(true); }; diff --git a/modules/ClockFace.md b/modules/ClockFace.md index 1da6e6020..e760c3e74 100644 --- a/modules/ClockFace.md +++ b/modules/ClockFace.md @@ -59,6 +59,7 @@ var clock = new ClockFace({ 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 + // You can use `this.is12Hour` to test if the 'Time Format' setting is set to "12h" or "24h" }, // 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 @@ -107,4 +108,29 @@ var clock = new ClockFace(function(time) { }); clock.start(); +``` + +Properties +---------- +The following properties are automatically set on the clock: +* `is12Hour`: `true` if the "Time Format" setting is set to "12h", `false` for "24h". +* `paused`: `true` while the clock is paused. (You don't need to check this inside your `draw()` code) + +Inside the `draw()`/`update()` function you can access these using `this`: + +```js + +var ClockFace = require("ClockFace"); +var clock = new ClockFace({ + draw: function (time) { + if (this.is12Hour) // draw 12h time + else // use 24h format + } +}); +clock.start(); + +Bangle.on('step', function(steps) { + if (clock.paused === false) // draw step count +}); + ``` \ No newline at end of file From 0059e8ec92131625eaff63d6d7b6b5ca7613a7b1 Mon Sep 17 00:00:00 2001 From: marko Date: Mon, 16 May 2022 14:49:02 -0400 Subject: [PATCH 75/82] Add "landed" screenshot --- apps/f9lander/README.md | 2 ++ apps/f9lander/f9lander_screenshot1.png | Bin 1340 -> 722 bytes apps/f9lander/f9lander_screenshot2.png | Bin 722 -> 1340 bytes apps/f9lander/f9lander_screenshot3.png | Bin 0 -> 3241 bytes apps/f9lander/metadata.json | 2 +- 5 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 apps/f9lander/f9lander_screenshot3.png diff --git a/apps/f9lander/README.md b/apps/f9lander/README.md index 30136fe58..16202f166 100644 --- a/apps/f9lander/README.md +++ b/apps/f9lander/README.md @@ -29,3 +29,5 @@ Marko Kl. B. ![](f9lander_screenshot1.png) ![](f9lander_screenshot2.png) + +![](f9lander_screenshot3.png) diff --git a/apps/f9lander/f9lander_screenshot1.png b/apps/f9lander/f9lander_screenshot1.png index a2f13d6c7278538af255e6c267cd11e0bfca517e..ea7d8a834d4fb8c60a13722957ff42be49e8010d 100644 GIT binary patch delta 579 zcmdnPb%}LCLcK(QPl&65!H*w*7=WOm0m%6AqXEeL@&Et-&*!^CflS6EZ+91VvBZwo zKn{C}r>`sfGgbjk4b2w5_L)HG?Vc`_F8yA=?^ovcdXWg&w^vM0x;$kKagJl`=-|J89+Islj@880!XMcYD`gcCd`SAUB zBDPj5?7aNH;jieoy6)fUyRB~6L~V`Vw!7%@)4Wxp2V%vi`Ah%U_5SLv>Avo}zHyZw zeK=cM!t%WPGougsZhmRoHp?AUla0&2ns?{%^zcpA($?R9$WGn%{C3p$JPxzW4^l55 zB}`_rm-zJk!_#^j`@{$K2RK(gSnM0lkzT~_zmX>|v_S7W$2qePf^*KYu4CACU}-|I zd`@UV!4os}oX`yu4>DS=-~A_Q%hQMR)$;GlZd>I0-c8T+L*A35cWF7G+ew`SskCgvV?bS9`PZTkT-in=(n&;aL=E<|Vf6q200(qQO+^Rh1rP}*AIvNc&j0`f4@pEp zRCwC$+dXdEFcb%HMhc9qy@9|J81Mx;*yx%iHz-_m>(D?$_kTtOx(D7m_XGxfgyv9{ z_#u8sqCQAI#@72IAC_e4r}ro^b^sFsnh$MY-L=D%(sqOPuwKxCR8f)~IZ zNd=E}dWCQ#cXWu8!P``DEO!i!R`3`c%|&q(Ox6eIsbFWx+n8{k3MR>5haA_H z?-p}-c&PI2t;2buPIpR%D!5ZJm}`{`SFlwwplkkL0)IAnBA1A9-om>W3S(uZM!cd>3uYlCu}LRO6elSVh?yDwhiRSS;|R`EbSy=EpZ+xvKT4Bq`PW%oiqN zcMayNihqos5+m6H)fd#BvwJOmW)`eg6>6dWWj$Ff1cXUDyU6XVKWYIAmSfz77i1Pp zj3VQ~s)yq61smqRElc6dxKW5&B@QYV^dj54+2^Xx)UBz*g$WyD%-ik@Yo}kdTjXRW z7SzneVZWIRgIPzW-WpWC2Duv8|8#XYn_gI9On+1!FgwoV$xBT7?XJxl_8N#+cEE*fD_wXynSD1eF4xq+3ue8U z|9?)ir+>!n!EhzpE>y{#g7^E!RPYlB+;#T{2)U==y5z^`?y=5iczAQ<>A;bD zE!~cMh+J~(+TD%}ACE)wA#SgS;kbjm(SPBi4L`yZY?pkKu-R#=*G~}#d3~_unuCmR zY`ARl9UT5tiZpXIAl$lT2?~EHwIqX|Q^6(RTy41Jb1Jw@27ikN6W0(Ygv)sF#?|SV zFmV4pFHWu9^A%XtxenSYaj z@SjvLxoLQof$&85)Z_k$30JFvFO_?c{oQv75BEAir-$HkQh2b}0o)De9_(CZ*~3!Q{C_- zrhEAh5N)~2@3K}O0000bbVXQnWRq=(n&;aL=E<|Vf6q200(qQO+^Rh1rP}*AIvNc&j0`f4@pEp zRCwC$+dXdEFcb%HMhc9qy@9|J81Mx;*yx%iHz-_m>(D?$_kTtOx(D7m_XGxfgyv9{ z_#u8sqCQAI#@72IAC_e4r}ro^b^sFsnh$MY-L=D%(sqOPuwKxCR8f)~IZ zNd=E}dWCQ#cXWu8!P``DEO!i!R`3`c%|&q(Ox6eIsbFWx+n8{k3MR>5haA_H z?-p}-c&PI2t;2buPIpR%D!5ZJm}`{`SFlwwplkkL0)IAnBA1A9-om>W3S(uZM!cd>3uYlCu}LRO6elSVh?yDwhiRSS;|R`EbSy=EpZ+xvKT4Bq`PW%oiqN zcMayNihqos5+m6H)fd#BvwJOmW)`eg6>6dWWj$Ff1cXUDyU6XVKWYIAmSfz77i1Pp zj3VQ~s)yq61smqRElc6dxKW5&B@QYV^dj54+2^Xx)UBz*g$WyD%-ik@Yo}kdTjXRW z7SzneVZWIRgIPzW-WpWC2Duv8|8#XYn_gI9On+1!FgwoV$xBT7?XJxl_8N#+cEE*fD_wXynSD1eF4xq+3ue8U z|9?)ir+>!n!EhzpE>y{#g7^E!RPYlB+;#T{2)U==y5z^`?y=5iczAQ<>A;bD zE!~cMh+J~(+TD%}ACE)wA#SgS;kbjm(SPBi4L`yZY?pkKu-R#=*G~}#d3~_unuCmR zY`ARl9UT5tiZpXIAl$lT2?~EHwIqX|Q^6(RTy41Jb1Jw@27ikN6W0(Ygv)sF#?|SV zFmV4pFHWu9^A%XtxenSYaj z@SjvLxoLQof$&85)Z_k$30JFvFO_?c{oQv75BEAir-$HkQh2b}0o)De9_(CZ*~3!Q{C_- zrhEAh5N)~2@3K}O0000bbVXQnWRq`sfGgbjk4b2w5_L)HG?Vc`_F8yA=?^ovcdXWg&w^vM0x;$kKagJl`=-|J89+Islj@880!XMcYD`gcCd`SAUB zBDPj5?7aNH;jieoy6)fUyRB~6L~V`Vw!7%@)4Wxp2V%vi`Ah%U_5SLv>Avo}zHyZw zeK=cM!t%WPGougsZhmRoHp?AUla0&2ns?{%^zcpA($?R9$WGn%{C3p$JPxzW4^l55 zB}`_rm-zJk!_#^j`@{$K2RK(gSnM0lkzT~_zmX>|v_S7W$2qePf^*KYu4CACU}-|I zd`@UV!4os}oX`yu4>DS=-~A_Q%hQMR)$;GlZd>I0-c8T+L*A35cWF7G+ew`SskCgvV?bS9`PZTkT-incq6{*sQ2}EE7=$p- zDry*_G6b2fuL@EyP=x>`Kq`|8fq*g;h`#Bk{(-Ld{n8K5bIx9Cul?biv(B?0y1T2R zk~~@-fj}rZ9k%n3M)6+<+AO`Ty*_40gG_{nqb;JEr~VOvPz-dkBmNZQFDi7&5SS`D z40|2#z7WT>Py3^MP1Qffs3X_@QGrL}#K+zYC4NC1g2-PYR$eW0uDS_f-2KXyCjoD7W z9HJi|=vS_9Z>VNhT_3lWOOWJMEQm;#-^lAD&EMIxbNEsEiY_$~oSXUl=q*hAF2hmU zJB;y4Wx-d$nngsFZ{zB{@Q3kAk{@HwO^oy;M$u8LPw^vdkRVO&(oXLe(>I| zEWW*i{<#-r-gD;Gc9l~n!kr8(aO65Z=GdJ}-Mz*ysO?ySLtni!o&!{!FeX zhV4KBy)SiY6<7QeLW!B8noo9Mz)|z8BMeyMoel$~#b>Ld7Vu($y|6ILD+pZ9F+9dN z+-OR~jW^()<-^`g6gTRLT}S$!Y~Z<{?B&z(wffo|${IRC;5VwI321IZ0cOA6Ggqgf zRzrD6-&5p6TPGy4>6jc0msox|1-B0faM84++L*cIqH;!d&|Drd8lc#r#0byMtp(bB z3)4{dT)vtO$U}Wv{oJI`{R?|TtVJz4*0BAOifZinz!ccj)z5pxi#$=6t_BPr@AScO z)c=f>L&XSLT4MOk&b!8-#$A--Y3$zs+HkrWLSA>raSFY%vn~meP=nTIq0o^2(>lPV z=hiMBphmM7WEFG$V0H>zs77|WVn%OFsz3Uw#^f*7c`56VO#%hfXti&XZ@%+#7G5s3 zBU`fP^yjfgi>%b0K=#6?);MXKxS=nRT*d&B?ZZ-~bvY=~x?+^-;!K##hJLg{0GWx(cItK{Ns+18#kO#2q>VVgHr*|I~uDeN`e6 znQ^8+Yb(@5CYqAP*O)V2{n0GPEF12t`{FM7=E9abCO>L-S(&}|K;>f1e?JUlBNnS!k}*r$ne zw)gC=*HVf|N?ATNe_MW&mQ{{p2Q;%r8xZ~y1<$#f6#*A)p%4qNw*W#p_=w7y8 zux2KkBxZt!RV!Z41cB|p#imgeEyd!2!ZpA-pQIi5#^_#1B&&S)N@1Gbq}AFQNd$j1 zJQ=qh+TvA>DvNXv-m&^Ap{n79iQ*B9^i~bp0n8)jaMahy_T3mV?K$vAVNO@}R)5Jl`-a7%A_$78?_5xnFF zr>8li4jNfGYHtO-@w3u4aVOqSz1rW=KDemI8gUisJ+oyZ_etL!ZCw_TYzIJA6rTrj zfCB)9g0J>NjKc_;a(0~e8PIayy1lpV#f{g+R%P*t42U_ zm6CKLe^&DsR?%kt&ns6(M}D!ta6ebgTUZ|cE;FI&OkL?@g0)Q_(eD?SB! zZ+e>0Fcg?-FU-(V|2d}m?BkOUc!TPGwRo`lR7FwOTXeXdIO`{tep^RgIjweX*F6{S zng;R6xnJepuIqSLTbm3UkL?3U=o1$ef`%}AeB$O!TDEu?QGF7ht%-Kc^pq9T8k3@P zGG1rrS}c9i+**knOHx88oL-*CD%?GF65) z5*S4G(eGct`@3UC&Wd6$_H^nigto|5#nPj`JeW+R`MfD{EE<+i*d5U6Xcy8WstL~` zCHIv-#|NGqxm6^3tKzSB37i|6Bu0?JO1BskJ_)lE@+~=&E>X{>cs}cDu|{tm;;8q% z4zw@}fdr{yU&Q$B-meJK-p3hb4E{cN9skD z{`R6$wCSHhw_zstK_#k^V4Kb?T$Zd;jrYF%91(8w;HtzU0#Td{Bk z=UycKS(y(H7k?lPjABiDI++ve-)A$rrJRhW)6m$YKBmk*j%PK+kA_-)rkS7G} z4Fr%v*3kuxrPKT(cMlShdIc?CIe8f+=`>S!D}c5TmI`@avn3ot{4XTFZc3Q0s9zyu SSxWyN2q$}2yJ}nVwf_Q8wo>u{ literal 0 HcmV?d00001 diff --git a/apps/f9lander/metadata.json b/apps/f9lander/metadata.json index 7d2ee9dce..75c6a0164 100644 --- a/apps/f9lander/metadata.json +++ b/apps/f9lander/metadata.json @@ -4,7 +4,7 @@ "version":"0.01", "description": "Land a rocket booster", "icon": "f9lander.png", - "screenshots" : [ { "url":"f9lander_screenshot2.png" }, { "url":"f9lander_screenshot1.png" }], + "screenshots" : [ { "url":"f9lander_screenshot1.png" }, { "url":"f9lander_screenshot2.png" }, { "url":"f9lander_screenshot3.png" }], "readme": "README.md", "tags": "game", "supports" : ["BANGLEJS", "BANGLEJS2"], From 33d25e4b0755288d5f9e77ba1c15bf72006bc7af Mon Sep 17 00:00:00 2001 From: Richard de Boer Date: Mon, 16 May 2022 21:28:08 +0200 Subject: [PATCH 76/82] barclock: use ClockFace.is12Hour instead of reading the setting --- apps/barclock/ChangeLog | 1 + apps/barclock/clock-bar.js | 7 +++---- apps/barclock/metadata.json | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/barclock/ChangeLog b/apps/barclock/ChangeLog index 0b8470b6a..5df032c4d 100644 --- a/apps/barclock/ChangeLog +++ b/apps/barclock/ChangeLog @@ -8,3 +8,4 @@ 0.08: Use theme colors, Layout library 0.09: Fix time/date disappearing after fullscreen notification 0.10: Use ClockFace library +0.11: Use ClockFace.is12Hour diff --git a/apps/barclock/clock-bar.js b/apps/barclock/clock-bar.js index a465bb692..987d41cc6 100644 --- a/apps/barclock/clock-bar.js +++ b/apps/barclock/clock-bar.js @@ -3,7 +3,6 @@ * A simple digital clock showing seconds as a bar **/ // Check settings for what type our clock should be -const is12Hour = (require("Storage").readJSON("setting.json", 1) || {})["12hour"]; let locale = require("locale"); { // add some more info to locale let date = new Date(); @@ -25,7 +24,7 @@ function renderBar(l) { function timeText(date) { - if (!is12Hour) { + if (!clock.is12Hour) { return locale.time(date, true); } const date12 = new Date(date.getTime()); @@ -38,7 +37,7 @@ function timeText(date) { return locale.time(date12, true); } function ampmText(date) { - return (is12Hour && locale.hasMeridian)? locale.meridian(date) : ""; + return (clock.is12Hour && locale.hasMeridian) ? locale.meridian(date) : ""; } function dateText(date) { const dayName = locale.dow(date, true), @@ -69,7 +68,7 @@ const ClockFace = require("ClockFace"), }, {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) { + if (this.is12Hour) { // Maximum font size = ( - ) / (5chars * 6px) thickness = Math.floor((Bangle.appRect.w-24)/(5*6)); } else { diff --git a/apps/barclock/metadata.json b/apps/barclock/metadata.json index 3ee7ccb3a..7bc61096d 100644 --- a/apps/barclock/metadata.json +++ b/apps/barclock/metadata.json @@ -1,7 +1,7 @@ { "id": "barclock", "name": "Bar Clock", - "version": "0.10", + "version": "0.11", "description": "A simple digital clock showing seconds as a bar", "icon": "clock-bar.png", "screenshots": [{"url":"screenshot.png"},{"url":"screenshot_pm.png"}], From 9750be3fa50fc38dae49d249a737b73a89f488f0 Mon Sep 17 00:00:00 2001 From: Alessandro Cocco Date: Sat, 14 May 2022 16:44:32 +0200 Subject: [PATCH 77/82] [lang] Update Italian translations --- lang/it_IT.json | 70 ++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 64 insertions(+), 6 deletions(-) diff --git a/lang/it_IT.json b/lang/it_IT.json index 07545e1e7..4bc36ee48 100644 --- a/lang/it_IT.json +++ b/lang/it_IT.json @@ -45,6 +45,7 @@ "Messages": "Messaggi", "No Messages": "Nessun messaggio", "Keep Msgs": "Tieni i messaggi", + "Mark all read": "Segna tutto come letto", "Mark Unread": "Segna come non letto", "Vibrate": "Vibrazione", "Are you sure": "Sei sicuro/a", @@ -83,8 +84,8 @@ "Background": "Sfondo", "Foreground 2": "Primo piano 2", "Background 2": "Sfondo 2", - "Highlight FG": "Selezione PP", - "Highlight BG": "Selezione Sf", + "Highlight FG": "Primo piano selezione", + "Highlight BG": "Sfondo selezione", "Utilities": "Utilità", "Storage": "Memoria", "Compact Storage": "Compatta memoria", @@ -110,7 +111,7 @@ "Loading": "Caricamento", "Launcher Settings": "Impostazioni Launcher", "Font": "Font", - "Show clocks": "Mostra orologi", + "Show Clocks": "Mostra orologi", "Log": "Log", "Steps": "Passi", "steps": "passi", @@ -151,19 +152,76 @@ "start&lap/reset, BTN1: EXIT": "start&lap/reset, BTN1: EXIT", "back": "indietro", "color": "colore", - "BACK": "INDIETRO" + "BACK": "INDIETRO", + "Select App": "Seleziona app", + "No Apps Found": "Nessuna app trovata", + "Edit Alarm": "Modifica sveglia", + "Auto Snooze": "Ripeti automaticamente", + "Delete Alarm": "Cancella sveglia", + "Repeat Alarm": "Ripeti sveglia", + "Once": "Una volta", + "Workdays": "Giorni lavorativi", + "Weekends": "Weekend", + "Every Day": "Ogni giorno", + "Custom": "Personalizza", + "Edit Timer": "Modifica timer", + "Delete Timer": "Cancella timer", + "Scheduler Settings": "Impostazioni schedulatore", + "Nothing to Enable": "Niente da attivare", + "Nothing to Disable": "Niente da disattivare", + "Enable All": "Attiva tutto", + "Disable All": "Disattiva tutto", + "Delete All": "Cancella tutto", + "Updating boot0": "Aggiornamento boot0 in corso", + "Reloading": "Ricaricamento in corso", + "Date & Time": "Data & ora", + "Small": "Piccolo", + "Medium": "Medio", + "Big": "Grande", + "Text size": "Dimensione testo", + "Find Phone": "Trova telefono", + "Movement": "Movimento", + "Heart Rate": "Frequenza cardiaca", + "Step Counting": "Conteggio passi", + "Daily Step Goal": "Obiettivo passi giornalieri", + "Fullscreen": "Schermo intero", + "Unlock Watch": "Sblocca orologio", + "Flash Icon": "Icona lampeggiante", + "Auto-Open Music": "Apri modalità musica automaticamente", + "Colour": "Colore", + "Notifications": "Notifiche", + "Scheduler": "Schedulatore", + "Stop": "Stop", + "Min Font": "Dimensione minima del font" }, "//2": "App-specific overrides", + "alarm": { + "//": "'Crea' instead of 'Nuovo' because 'Nuovo sveglia' would be weird (and wrong)", + "New": "Crea", + "Custom Days": "Personalizza i giorni", + "Advanced": "Altre funzionalità" + }, + "health": { + "Health Tracking": "Monitoraggio salute", + "HRM Interval": "Intervallo monitoraggio cardiaco", + "3 min": "3 min", + "10 min": "10 min", + "Always": "Sempre" + }, "launch": { - "Vector font size": "Dim. font vett.", + "Vector Font Size": "Dim. font vett.", "App Source\nNot found": "Codice app\nnon trovato" }, "messages": { - "Unread timer": "Timer msg non letti" + "Unread timer": "Timer messaggi non letti" }, "run": { "Record Run": "Registra corsa" }, + "sched": { + "Unlock at Buzz": "Sblocca quando vibra", + "s": "s" + }, "setting": { "Clock Style": "Formato ora", "Compacting...\nTakes approx\n1 minute": "Compattamento in corso...\nCi vorrà circa un minuto", From 92ac8ee3f0c283a22d5710fc39dd0452cc85361d Mon Sep 17 00:00:00 2001 From: storm64 Date: Tue, 17 May 2022 09:18:39 +0200 Subject: [PATCH 78/82] sleeplog: Fix LOW_MEMORY,MEMORY error #1835 Check and if neccessary reduce logsize to 1500 entries in writeLog() to prevent low mem error. --- apps/sleeplog/ChangeLog | 1 + apps/sleeplog/README.md | 3 ++- apps/sleeplog/lib.js | 3 +++ apps/sleeplog/metadata.json | 2 +- 4 files changed, 7 insertions(+), 2 deletions(-) diff --git a/apps/sleeplog/ChangeLog b/apps/sleeplog/ChangeLog index d12c565ac..e21f12757 100644 --- a/apps/sleeplog/ChangeLog +++ b/apps/sleeplog/ChangeLog @@ -2,3 +2,4 @@ 0.02: Fix crash on start #1423 0.03: Added power saving mode, move all read/write log actions into lib/module 0.04: Fix #1445, display loading info, add icons to display service states +0.05: Fix LOW_MEMORY,MEMORY error on to big log size diff --git a/apps/sleeplog/README.md b/apps/sleeplog/README.md index 4b10438ef..b1618c5bf 100644 --- a/apps/sleeplog/README.md +++ b/apps/sleeplog/README.md @@ -21,7 +21,8 @@ also provides a power saving mode using the built in movement calculation. The i * __Logging__ To minimize the log size only a changed state is logged. The logged timestamp is matching the beginning of its measurement period. When not on power saving mode a movement is detected nearly instantaneous and the detection of a no movement period is delayed by the minimal no movement duration. To match the beginning of the measurement period a cached timestamp (_sleeplog.firstnomodate_) is logged. - On power saving mode the measurement period is fixed to 10 minutes and all logged timestamps are also set back 10 minutes. + On power saving mode the measurement period is fixed to 10 minutes and all logged timestamps are also set back 10 minutes. + To prevent a LOW_MEMORY,MEMORY error the log size is limited to 1500 entries, older entries will be overwritten. --- ### Control diff --git a/apps/sleeplog/lib.js b/apps/sleeplog/lib.js index 7b35d8a85..7e3ec7451 100644 --- a/apps/sleeplog/lib.js +++ b/apps/sleeplog/lib.js @@ -98,6 +98,9 @@ exports = { input = log; } + // check and if neccessary reduce logsize to prevent low mem + if (input.length > 1500) input = input.slice(-1500); + // simple check for log plausibility if (input[0].length > 1 && input[0][0] * 1 > 9E11) { // write log to storage diff --git a/apps/sleeplog/metadata.json b/apps/sleeplog/metadata.json index 8cf6979d6..17eab2d1d 100644 --- a/apps/sleeplog/metadata.json +++ b/apps/sleeplog/metadata.json @@ -2,7 +2,7 @@ "id":"sleeplog", "name":"Sleep Log", "shortName": "SleepLog", - "version": "0.04", + "version": "0.05", "description": "Log and view your sleeping habits. This app derived from SleepPhaseAlarm and uses also the principe of Estimation of Stationary Sleep-segments (ESS). It also provides a power saving mode using the built in movement calculation.", "icon": "app.png", "type": "app", From 8102fd4e72f7dd34679709305cea2fb2a974a48c Mon Sep 17 00:00:00 2001 From: storm64 Date: Tue, 17 May 2022 17:51:10 +0200 Subject: [PATCH 79/82] [sleeplog] Reduced log size further, see #1835 Reduced log size further to 750 entries --- apps/sleeplog/ChangeLog | 1 + apps/sleeplog/README.md | 2 +- apps/sleeplog/lib.js | 2 +- apps/sleeplog/metadata.json | 2 +- 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/apps/sleeplog/ChangeLog b/apps/sleeplog/ChangeLog index e21f12757..8a3da6362 100644 --- a/apps/sleeplog/ChangeLog +++ b/apps/sleeplog/ChangeLog @@ -3,3 +3,4 @@ 0.03: Added power saving mode, move all read/write log actions into lib/module 0.04: Fix #1445, display loading info, add icons to display service states 0.05: Fix LOW_MEMORY,MEMORY error on to big log size +0.06: Reduced log size further to 750 entries diff --git a/apps/sleeplog/README.md b/apps/sleeplog/README.md index b1618c5bf..ebbcdde54 100644 --- a/apps/sleeplog/README.md +++ b/apps/sleeplog/README.md @@ -22,7 +22,7 @@ also provides a power saving mode using the built in movement calculation. The i To minimize the log size only a changed state is logged. The logged timestamp is matching the beginning of its measurement period. When not on power saving mode a movement is detected nearly instantaneous and the detection of a no movement period is delayed by the minimal no movement duration. To match the beginning of the measurement period a cached timestamp (_sleeplog.firstnomodate_) is logged. On power saving mode the measurement period is fixed to 10 minutes and all logged timestamps are also set back 10 minutes. - To prevent a LOW_MEMORY,MEMORY error the log size is limited to 1500 entries, older entries will be overwritten. + To prevent a LOW_MEMORY,MEMORY error the log size is limited to 750 entries, older entries will be overwritten. --- ### Control diff --git a/apps/sleeplog/lib.js b/apps/sleeplog/lib.js index 7e3ec7451..752139e27 100644 --- a/apps/sleeplog/lib.js +++ b/apps/sleeplog/lib.js @@ -99,7 +99,7 @@ exports = { } // check and if neccessary reduce logsize to prevent low mem - if (input.length > 1500) input = input.slice(-1500); + if (input.length > 750) input = input.slice(-750); // simple check for log plausibility if (input[0].length > 1 && input[0][0] * 1 > 9E11) { diff --git a/apps/sleeplog/metadata.json b/apps/sleeplog/metadata.json index 17eab2d1d..c4dbe8631 100644 --- a/apps/sleeplog/metadata.json +++ b/apps/sleeplog/metadata.json @@ -2,7 +2,7 @@ "id":"sleeplog", "name":"Sleep Log", "shortName": "SleepLog", - "version": "0.05", + "version": "0.06", "description": "Log and view your sleeping habits. This app derived from SleepPhaseAlarm and uses also the principe of Estimation of Stationary Sleep-segments (ESS). It also provides a power saving mode using the built in movement calculation.", "icon": "app.png", "type": "app", From 1d3428321ce41f34ad0e99b7536d8bfcb329ff9c Mon Sep 17 00:00:00 2001 From: Alessandro Cocco Date: Tue, 17 May 2022 23:18:44 +0200 Subject: [PATCH 80/82] [Health] Use var instead of let --- apps/health/app.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/apps/health/app.js b/apps/health/app.js index a1fe1a4f7..30f57af19 100644 --- a/apps/health/app.js +++ b/apps/health/app.js @@ -46,7 +46,7 @@ function menuHRM() { function stepsPerHour() { E.showMessage(/*LANG*/"Loading..."); - let data = new Uint16Array(24); + var data = new Uint16Array(24); require("health").readDay(new Date(), h=>data[h.hr]+=h.steps); g.clear(1); Bangle.drawWidgets(); @@ -57,7 +57,7 @@ function stepsPerHour() { function stepsPerDay() { E.showMessage(/*LANG*/"Loading..."); - let data = new Uint16Array(31); + var data = new Uint16Array(31); require("health").readDailySummaries(new Date(), h=>data[h.day]+=h.steps); g.clear(1); Bangle.drawWidgets(); @@ -68,8 +68,8 @@ function stepsPerDay() { function hrmPerHour() { E.showMessage(/*LANG*/"Loading..."); - let data = new Uint16Array(24); - let cnt = new Uint8Array(23); + var data = new Uint16Array(24); + var cnt = new Uint8Array(23); require("health").readDay(new Date(), h=>{ data[h.hr]+=h.bpm; if (h.bpm) cnt[h.hr]++; @@ -84,8 +84,8 @@ function hrmPerHour() { function hrmPerDay() { E.showMessage(/*LANG*/"Loading..."); - let data = new Uint16Array(31); - let cnt = new Uint8Array(31); + var data = new Uint16Array(31); + var cnt = new Uint8Array(31); require("health").readDailySummaries(new Date(), h=>{ data[h.day]+=h.bpm; if (h.bpm) cnt[h.day]++; @@ -100,7 +100,7 @@ function hrmPerDay() { function movementPerHour() { E.showMessage(/*LANG*/"Loading..."); - let data = new Uint16Array(24); + var data = new Uint16Array(24); require("health").readDay(new Date(), h=>data[h.hr]+=h.movement); g.clear(1); Bangle.drawWidgets(); @@ -111,7 +111,7 @@ function movementPerHour() { function movementPerDay() { E.showMessage(/*LANG*/"Loading..."); - let data = new Uint16Array(31); + var data = new Uint16Array(31); require("health").readDailySummaries(new Date(), h=>data[h.day]+=h.movement); g.clear(1); Bangle.drawWidgets(); From 5b37bdca63850a1e12ab1cba010de65842ed081b Mon Sep 17 00:00:00 2001 From: Alessandro Cocco Date: Tue, 17 May 2022 23:19:42 +0200 Subject: [PATCH 81/82] [Health] Avoid division by zero --- apps/health/app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/health/app.js b/apps/health/app.js index 30f57af19..c0a40bd93 100644 --- a/apps/health/app.js +++ b/apps/health/app.js @@ -183,7 +183,7 @@ function drawBarChart() { } // draw a fake 0 height bar if chart_index is outside the bounds of the array - if ((chart_index + bar - 1) >= 0 && (chart_index + bar - 1) < data_len) + if ((chart_index + bar - 1) >= 0 && (chart_index + bar - 1) < data_len && chart_max_datum > 0) bar_top = bar_bot - 100 * (chart_data[chart_index + bar - 1]) / chart_max_datum; else bar_top = bar_bot; From 774aa169ebe5432c6f1a212a282f90077e91342c Mon Sep 17 00:00:00 2001 From: Alessandro Cocco Date: Tue, 17 May 2022 23:27:13 +0200 Subject: [PATCH 82/82] [Health] Update metadata and changelog --- apps/health/ChangeLog | 1 + apps/health/metadata.json | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/health/ChangeLog b/apps/health/ChangeLog index 74be2faec..62d93e606 100644 --- a/apps/health/ChangeLog +++ b/apps/health/ChangeLog @@ -13,3 +13,4 @@ 0.12: Add setting for Daily Step Goal 0.13: Add support for internationalization 0.14: Move settings +0.15: Fix charts (fix #1366) diff --git a/apps/health/metadata.json b/apps/health/metadata.json index 58762c77a..a038f67b5 100644 --- a/apps/health/metadata.json +++ b/apps/health/metadata.json @@ -1,7 +1,7 @@ { "id": "health", "name": "Health Tracking", - "version": "0.14", + "version": "0.15", "description": "Logs health data and provides an app to view it", "icon": "app.png", "tags": "tool,system,health",