From 8dc3e8f8fcad22e379c7d8b59959c0c55d3fc6ed Mon Sep 17 00:00:00 2001 From: Joseph Paul Date: Fri, 4 Mar 2022 10:16:32 +0100 Subject: [PATCH 01/61] Ratchet Launcher: Initial version --- apps/ratchet_launch/ChangeLog | 1 + apps/ratchet_launch/README.md | 15 ++++ apps/ratchet_launch/app.js | 123 ++++++++++++++++++++++++++++++ apps/ratchet_launch/app.png | Bin 0 -> 9788 bytes apps/ratchet_launch/metadata.json | 16 ++++ 5 files changed, 155 insertions(+) create mode 100644 apps/ratchet_launch/ChangeLog create mode 100644 apps/ratchet_launch/README.md create mode 100644 apps/ratchet_launch/app.js create mode 100644 apps/ratchet_launch/app.png create mode 100644 apps/ratchet_launch/metadata.json diff --git a/apps/ratchet_launch/ChangeLog b/apps/ratchet_launch/ChangeLog new file mode 100644 index 000000000..af7f83942 --- /dev/null +++ b/apps/ratchet_launch/ChangeLog @@ -0,0 +1 @@ +0.01: Initial release diff --git a/apps/ratchet_launch/README.md b/apps/ratchet_launch/README.md new file mode 100644 index 000000000..15df463d0 --- /dev/null +++ b/apps/ratchet_launch/README.md @@ -0,0 +1,15 @@ +# Rachet Launcher + +Ratchet Launcher is a fork of the default Launcher with modified user interaction. Instead of free scrolling, apps are selected by swiping up and down, but in discrete "ticks", just like in the settings menus. + +**WARNING: Untested on Bangle.js v1! Please test and give feedback.** + +## Usage +- Choose app: Swipe up/down (top/bottom button on Bangle.js v1) +- Launch app: Tap screen (center button on Bangle.js v1) +- Return to clock: Swipe three ticks beyond first/last app in list + +## Installation +1. Install Ratchet Launcher using App Loader +2. Uninstall default Launcher +3. Reload diff --git a/apps/ratchet_launch/app.js b/apps/ratchet_launch/app.js new file mode 100644 index 000000000..626b8e4f8 --- /dev/null +++ b/apps/ratchet_launch/app.js @@ -0,0 +1,123 @@ +var Storage = require("Storage"); +var Layout = require("Layout"); + +var font = "6x15"; +var largeFont = "12x20"; +var currentApp = 0; +var overscroll = 0; +var blankImage = Graphics.createImage(` `); +var rowHeight = g.getHeight()/3; + +// Load apps list +var apps = Storage.list(/\.info$/).map(app=>{ + var a=Storage.readJSON(app,1); + return a&&{ + name:a.name, + type:a.type, + icon:a.icon ? Storage.read(a.icon) : a.icon, + sortorder:a.sortorder, + src:a.src + }; +}).filter(app=>app && ( + app.type=="app" +// || (app.type=="clock" && settings.showClocks) + || !app.type +)); +apps.sort((a,b)=>{ + var n=(0|a.sortorder)-(0|b.sortorder); + if (n) return n; // do sortorder first + if (a.nameb.name) return 1; + return 0; +}); + +// Initialize layout +var layout = new Layout({ + type:"v", c:[ + // A row for the previous app + { type:"h", height:rowHeight, c:[ + {type: "img", id:"prev_icon", src:blankImage, width:48, height:48, scale:0.8, pad:8}, + {type: "txt", id:"prev_name", label:"", font:font, fillx:1, wrap:1}, + ]}, + // A row for the current app + { type:"h", height:rowHeight, c:[ + {type: "img", id:"cur_icon", src:apps[currentApp].icon, width:48, height:48}, + {type: "txt", id:"cur_name", label:apps[currentApp].name, font:largeFont, fillx:1, wrap:1}, + ]}, + // A row for the next app + { type:"h", height:rowHeight, c:[ + {type: "img", id:"next_icon", src:blankImage, width:48, height:48, scale:0.8, pad:8}, + {type: "txt", id:"next_name", label:"", font:font, fillx:1, wrap:1}, + ]}, + ] +}); + +// Drawing logic +function render() { + // Previous app + if (currentApp > 0) { + layout.prev_icon.src = apps[currentApp-1].icon; + layout.prev_name.label = apps[currentApp-1].name; + } else { + layout.prev_icon.src = blankImage; + layout.prev_name.label = ""; + } + + // Current app + layout.cur_icon.src = apps[currentApp].icon; + layout.cur_name.label = apps[currentApp].name; + + // Next app + if (currentApp < apps.length-1) { + layout.next_icon.src = apps[currentApp+1].icon; + layout.next_name.label = apps[currentApp+1].name; + } else { + layout.next_icon.src = blankImage; + layout.next_name.label = ""; + } + + g.clear(); + layout.render(); +} + +// Launch the currently selected app +function launch() { + var app = apps[currentApp]; + if (!app) return; + if (!app.src || Storage.read(app.src)===undefined) { + E.showMessage(/*LANG*/"App Source\nNot found"); + setTimeout(drawMenu, 2000); + } else { + E.showMessage(/*LANG*/"Loading..."); + load(app.src); + } +} + +// Select previous/next app +function move(step) { + if ((currentApp == 0 && step < 0) || (currentApp >= apps.length-1 && step > 0)) { + // When we hit the end of the list (top or bottom), the step is + // counted towards the overscroll value. When the overscroll + // threshold is exceeded, we return to the clock face. + overscroll += step; + } else { + // This is the default case: the step is countedf towards the currentApp index + currentApp += step; + overscroll = 0; + return render(); + } + + // Overscroll threshold reached, return to clock + if (Math.abs(overscroll) > 3) { + Bangle.buzz(500, 1); + return load(); + } +} + +// Wire up user input +Bangle.setUI('updown', dir => { + if (dir) move(-1*dir); + else launch(); +}); + +render(); diff --git a/apps/ratchet_launch/app.png b/apps/ratchet_launch/app.png new file mode 100644 index 0000000000000000000000000000000000000000..a27ab48eda4d78d88a5d958e540b9bc822e2131c GIT binary patch literal 9788 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 cggb Date: Fri, 4 Mar 2022 12:31:30 +0100 Subject: [PATCH 02/61] Ratchet Launcher: Fix fonts and scrolling behaviour on Bangle.js 1 --- apps/ratchet_launch/app.js | 40 +++++++++++++++++++++++++++++++------- 1 file changed, 33 insertions(+), 7 deletions(-) diff --git a/apps/ratchet_launch/app.js b/apps/ratchet_launch/app.js index 626b8e4f8..11018080a 100644 --- a/apps/ratchet_launch/app.js +++ b/apps/ratchet_launch/app.js @@ -1,8 +1,8 @@ var Storage = require("Storage"); var Layout = require("Layout"); -var font = "6x15"; -var largeFont = "12x20"; +var font = g.getFonts().includes("6x15") ? "6x15" : "6x8:2"; +var largeFont = g.getFonts().includes("12x20") ? "12x20" : "6x8:3"; var currentApp = 0; var overscroll = 0; var blankImage = Graphics.createImage(` `); @@ -31,6 +31,24 @@ apps.sort((a,b)=>{ return 0; }); +// Uncomment for testing in the emulator without apps: +// apps = [ +// { +// name:"Test", +// type:"app", +// icon:blankImage, +// sortorder:undefined, +// src:"" +// }, +// { +// name:"Test 2", +// type:"app", +// icon:blankImage, +// sortorder:undefined, +// src:"" +// }, +// ]; + // Initialize layout var layout = new Layout({ type:"v", c:[ @@ -41,8 +59,8 @@ var layout = new Layout({ ]}, // A row for the current app { type:"h", height:rowHeight, c:[ - {type: "img", id:"cur_icon", src:apps[currentApp].icon, width:48, height:48}, - {type: "txt", id:"cur_name", label:apps[currentApp].name, font:largeFont, fillx:1, wrap:1}, + {type: "img", id:"cur_icon", src:blankImage, width:48, height:48}, + {type: "txt", id:"cur_name", label:"", font:largeFont, fillx:1, wrap:1}, ]}, // A row for the next app { type:"h", height:rowHeight, c:[ @@ -54,6 +72,11 @@ var layout = new Layout({ // Drawing logic function render() { + if (!apps.length) { + E.showMessage(/*LANG*/"No apps"); + return load(); + } + // Previous app if (currentApp > 0) { layout.prev_icon.src = apps[currentApp-1].icon; @@ -86,7 +109,7 @@ function launch() { if (!app) return; if (!app.src || Storage.read(app.src)===undefined) { E.showMessage(/*LANG*/"App Source\nNot found"); - setTimeout(drawMenu, 2000); + setTimeout(render, 2000); } else { E.showMessage(/*LANG*/"Loading..."); load(app.src); @@ -116,8 +139,11 @@ function move(step) { // Wire up user input Bangle.setUI('updown', dir => { - if (dir) move(-1*dir); - else launch(); + if (!dir) launch(); + else { + if (process.env.HWVERSION==2) dir *= -1; // "natural scrolling" on touch screen + move(dir); + } }); render(); From 371d78c49b18ac0e09c3734735f1c3dd97db8103 Mon Sep 17 00:00:00 2001 From: foostuff <97034053+foostuff@users.noreply.github.com> Date: Sat, 5 Mar 2022 09:24:59 +0100 Subject: [PATCH 03/61] Create ChangeLog --- apps/clockcal/ChangeLog | 1 + 1 file changed, 1 insertion(+) create mode 100644 apps/clockcal/ChangeLog diff --git a/apps/clockcal/ChangeLog b/apps/clockcal/ChangeLog new file mode 100644 index 000000000..5560f00bc --- /dev/null +++ b/apps/clockcal/ChangeLog @@ -0,0 +1 @@ +0.01: New App! From 9ed37056234a169ed85aff0cf25891ae713b3807 Mon Sep 17 00:00:00 2001 From: foostuff <97034053+foostuff@users.noreply.github.com> Date: Sat, 5 Mar 2022 09:26:40 +0100 Subject: [PATCH 04/61] Add files via upload --- apps/clockcal/ChangeLog | 10 ++ apps/clockcal/README.md | 79 ++++++++++++ apps/clockcal/app-icon.js | 1 + apps/clockcal/app.js | 230 +++++++++++++++++++++++++++++++++++ apps/clockcal/app.png | Bin 0 -> 1989 bytes apps/clockcal/metadata.json | 19 +++ apps/clockcal/screenshot.png | Bin 0 -> 1617 bytes apps/clockcal/settings.js | 107 ++++++++++++++++ 8 files changed, 446 insertions(+) create mode 100644 apps/clockcal/README.md create mode 100644 apps/clockcal/app-icon.js create mode 100644 apps/clockcal/app.js create mode 100644 apps/clockcal/app.png create mode 100644 apps/clockcal/metadata.json create mode 100644 apps/clockcal/screenshot.png create mode 100644 apps/clockcal/settings.js diff --git a/apps/clockcal/ChangeLog b/apps/clockcal/ChangeLog index 5560f00bc..ac49dcbd7 100644 --- a/apps/clockcal/ChangeLog +++ b/apps/clockcal/ChangeLog @@ -1 +1,11 @@ 0.01: New App! +0.02: Load widgets after setUI so widclk knows when to hide +0.03: Clock now shows day of week under date. +0.04: Clock can optionally show seconds, date optionally in ISO-8601 format, weekdays and uppercase configurable, too. +0.05: Clock can optionally show ISO-8601 calendar weeknumber (default: Off) + when weekday name "Off": week #: + when weekday name "On": weekday name is cut at 6th position and .# is added +0.06: fixes #1271 - wrong settings name + when weekday name and calendar weeknumber are on then display is # + week is buffered until date or timezone changes +0.07: align default settings with app.js (otherwise the initial displayed settings will be confusing to users) \ No newline at end of file diff --git a/apps/clockcal/README.md b/apps/clockcal/README.md new file mode 100644 index 000000000..28a38f5fd --- /dev/null +++ b/apps/clockcal/README.md @@ -0,0 +1,79 @@ +# Anton Clock - Large font digital watch with seconds and date + +Anton clock uses the "Anton" bold font to show the time in a clear, easily readable manner. On the Bangle.js 2, the time can be read easily even if the screen is locked and unlit. + +## Features + +The basic time representation only shows hours and minutes of the current time. However, Anton clock can show additional information: + +* Seconds can be shown, either always or only if the screen is unlocked. +* To help easy recognition, the seconds can be coloured in blue on the Bangle.js 2. +* Date can be shown in three different formats: + * ISO-8601: 2021-12-19 + * short local format: 19/12/2021, 19.12.2021 + * long local format: DEC 19 2021 +* Weekday can be shown (on seconds screen only instead of year) + +## Usage + +Install Anton clock through the Bangle.js app loader. +Configure it through the default Bangle.js configuration mechanism +(Settings app, "Apps" menu, "Anton clock" submenu). +If you like it, make it your default watch face +(Settings app, "System" menu, "Clock" submenu, select "Anton clock"). + +## Configuration + +Anton clock is configured by the standard settings mechanism of Bangle.js's operating system: +Open the "Settings" app, then the "Apps" submenu and below it the "Anton clock" menu. +You configure Anton clock through several "on/off" switches in two menus. + +### The main menu + +The main menu contains several settings covering Anton clock in general. + +* **Seconds...** - Opens the submenu for configuring the presentation of the current time's seconds. +* **Date** - Format of the date representation. Possible values are + * **Long** - "Long" date format in the current locale. Usually with the month as name, not number. + * **Short** - "Short" date format in the current locale. Usually with the month as number. + * **ISO8601** - Show the date in ISO-8601 format (YYYY-MM-DD), irrespective of the current locale. +* **Show Weekday** - Weekday is shown in the time presentation without seconds. +Weekday name depends on the current locale. +If seconds are shown, the weekday is never shown as there is not enough space on the watch face. +* **Show CalWeek** - Week-number (ISO-8601) is shown. (default: Off) +If "Show Weekday" is "Off" displays the week-number as "week #". +If "Show Weekday" is "On" displays "weekday name short" with " #" . +If seconds are shown, the week number is never shown as there is not enough space on the watch face. +* **Vector font** - Use the built-in vector font for dates and weekday. +This can improve readability. +Otherwise, a scaled version of the built-in 6x8 pixels font is used. + +### The "Seconds" submenu + +The "Seconds" submenu configures how (and if) seconds are shown on the "Anton" watch face. + +* **Show** - Configure when the seconds should be shown at all: + * **Never** - Seconds are never shown. +In this case, hour and minute are a bit more centered on the screen and the clock will always only update every minute. +This saves battery power. + * **Unlocked** - Seconds are shown if the display is unlocked. +On locked displays, only hour, minutes, date and optionally the weekday are shown. +_This option is highly recommended on the Bangle.js 2!_ + * **Always** - Seconds are _always_ shown, irrespective of the display's unlock state. +_Enabling this option increases power consumption as the watch face will update once per second instead of once per minute._ +* **With ":"** - If enabled, a colon ":" is prepended to the seconds. +This resembles the usual time representation "hh:mm:ss", even though the seconds are printed on a separate line. +* **Color** - If enabled, seconds are shown in blue instead of black. +If the date is shown on the seconds screen, it is colored read instead of black. +This make the visual orientation much easier on the watch face. +* **Date** - It is possible to show the date together with the seconds: + * **No** - Date is _not_ shown in the seconds screen. +In this case, the seconds are centered below hour and minute. + * **Year** - Date is shown with day, month, and year. If "Date" in the main settings is configured to _ISO8601_, this is used here, too. Otherwise, the short local format is used. + * **Weekday** - Date is shown with day, month, and weekday. + +The date is coloured in red if the "Coloured" option is chosen. + +## Compatibility + +Anton clock makes use of core Bangle.js 2 features (coloured display, display lock state). It also runs on the Bangle.js 1 but these features are not available there due to hardware restrictions. diff --git a/apps/clockcal/app-icon.js b/apps/clockcal/app-icon.js new file mode 100644 index 000000000..fad03d50f --- /dev/null +++ b/apps/clockcal/app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwgX/AH4A/AAf+14BBAoPq/Wq1QFB+EP+kLAoNA+CdB3//yEP6ALB/sABYf8gEMgALB6ALJqoLB+tVgH//kQhkQhUABYImCIwPwh3whcA94UCgJHD+AXB/4LCcQQLCKYQLB+EDBZQFCBY/Qh4LJ4ALLl4LFioLCgE/KZMAv4XFBYimBC4/+BYw7DRwQLIV4ILWTQQLDOIUA/ALDAC+t1uv/263/6/Pq/YLC3vv//vM4Oq33rBYP6/u//2/C4Pr1YXC12vBwO+BYO69XmJDQA/ACIA==")) diff --git a/apps/clockcal/app.js b/apps/clockcal/app.js new file mode 100644 index 000000000..356e067f2 --- /dev/null +++ b/apps/clockcal/app.js @@ -0,0 +1,230 @@ +// Clock with large digits using the "Anton" bold font + +const SETTINGSFILE = "clockcal.json"; + +Graphics.prototype.setFontAnton = function(scale) { + // Actual height 69 (68 - 0) + g.setFontCustom(atob("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADgAAAAAAAAAAA/gAAAAAAAAAAP/gAAAAAAAAAH//gAAAAAAAAB///gAAAAAAAAf///gAAAAAAAP////gAAAAAAD/////gAAAAAA//////gAAAAAP//////gAAAAH///////gAAAB////////gAAAf////////gAAP/////////gAD//////////AA//////////gAA/////////4AAA////////+AAAA////////gAAAA///////wAAAAA//////8AAAAAA//////AAAAAAA/////gAAAAAAA////4AAAAAAAA///+AAAAAAAAA///gAAAAAAAAA//wAAAAAAAAAA/8AAAAAAAAAAA/AAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD//////AAAAAB///////8AAAAH////////AAAAf////////wAAA/////////4AAB/////////8AAD/////////+AAH//////////AAP//////////gAP//////////gAP//////////gAf//////////wAf//////////wAf//////////wAf//////////wA//8AAAAAB//4A//wAAAAAAf/4A//gAAAAAAP/4A//gAAAAAAP/4A//gAAAAAAP/4A//wAAAAAAf/4A///////////4Af//////////wAf//////////wAf//////////wAf//////////wAP//////////gAP//////////gAH//////////AAH//////////AAD/////////+AAB/////////8AAA/////////4AAAP////////gAAAD///////+AAAAAf//////4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP/gAAAAAAAAAAP/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/AAAAAAAAAAA//AAAAAAAAAAA/+AAAAAAAAAAB/8AAAAAAAAAAD//////////gAH//////////gAP//////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH/4AAAAB/gAAD//4AAAAf/gAAP//4AAAB//gAA///4AAAH//gAB///4AAAf//gAD///4AAA///gAH///4AAD///gAP///4AAH///gAP///4AAP///gAf///4AAf///gAf///4AB////gAf///4AD////gA////4AH////gA////4Af////gA////4A/////gA//wAAB/////gA//gAAH/////gA//gAAP/////gA//gAA///8//gA//gAD///w//gA//wA////g//gA////////A//gA///////8A//gA///////4A//gAf//////wA//gAf//////gA//gAf/////+AA//gAP/////8AA//gAP/////4AA//gAH/////gAA//gAD/////AAA//gAB////8AAA//gAA////wAAA//gAAP///AAAA//gAAD//8AAAA//gAAAP+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB/+AAAAAD/wAAB//8AAAAP/wAAB///AAAA//wAAB///wAAB//wAAB///4AAD//wAAB///8AAH//wAAB///+AAP//wAAB///+AAP//wAAB////AAf//wAAB////AAf//wAAB////gAf//wAAB////gA///wAAB////gA///wAAB////gA///w//AAf//wA//4A//AAA//wA//gA//AAAf/wA//gB//gAAf/wA//gB//gAAf/wA//gD//wAA//wA//wH//8AB//wA///////////gA///////////gA///////////gA///////////gAf//////////AAf//////////AAP//////////AAP/////////+AAH/////////8AAH///+/////4AAD///+f////wAAA///8P////gAAAf//4H///+AAAAH//gB///wAAAAAP4AAH/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/wAAAAAAAAAA//wAAAAAAAAAP//wAAAAAAAAB///wAAAAAAAAf///wAAAAAAAH////wAAAAAAA/////wAAAAAAP/////wAAAAAB//////wAAAAAf//////wAAAAH///////wAAAA////////wAAAP////////wAAA///////H/wAAA//////wH/wAAA/////8AH/wAAA/////AAH/wAAA////gAAH/wAAA///4AAAH/wAAA//+AAAAH/wAAA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gAAAAAAAAH/4AAAAAAAAAAH/wAAAAAAAAAAH/wAAAAAAAAAAH/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB//8AAA/////+B///AAA/////+B///wAA/////+B///4AA/////+B///8AA/////+B///8AA/////+B///+AA/////+B////AA/////+B////AA/////+B////AA/////+B////gA/////+B////gA/////+B////gA/////+A////gA//gP/gAAB//wA//gf/AAAA//wA//gf/AAAAf/wA//g//AAAAf/wA//g//AAAA//wA//g//gAAA//wA//g//+AAP//wA//g////////gA//g////////gA//g////////gA//g////////gA//g////////AA//gf///////AA//gf//////+AA//gP//////+AA//gH//////8AA//gD//////4AA//gB//////wAA//gA//////AAAAAAAH////8AAAAAAAA////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD//////gAAAAB///////+AAAAH////////gAAAf////////4AAB/////////8AAD/////////+AAH//////////AAH//////////gAP//////////gAP//////////gAf//////////wAf//////////wAf//////////wAf//////////wAf//////////4A//wAD/4AAf/4A//gAH/wAAP/4A//gAH/wAAP/4A//gAP/wAAP/4A//gAP/4AAf/4A//wAP/+AD//4A///wP//////4Af//4P//////wAf//4P//////wAf//4P//////wAf//4P//////wAP//4P//////gAP//4H//////gAH//4H//////AAH//4D/////+AAD//4D/////8AAB//4B/////4AAA//4A/////wAAAP/4AP////AAAAB/4AD///4AAAAAAAAAH/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//AAAAAAAAAAA//gAAAAAAAAAA//gAAAAAAAAAA//gAAAAAAADgA//gAAAAAAP/gA//gAAAAAH//gA//gAAAAB///gA//gAAAAP///gA//gAAAD////gA//gAAAf////gA//gAAB/////gA//gAAP/////gA//gAB//////gA//gAH//////gA//gA///////gA//gD///////gA//gf///////gA//h////////gA//n////////gA//////////gAA/////////AAAA////////wAAAA///////4AAAAA///////AAAAAA//////4AAAAAA//////AAAAAAA/////4AAAAAAA/////AAAAAAAA////8AAAAAAAA////gAAAAAAAA///+AAAAAAAAA///4AAAAAAAAA///AAAAAAAAAA//4AAAAAAAAAA/+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD//gB///wAAAAP//4H///+AAAA///8P////gAAB///+f////4AAD///+/////8AAH/////////+AAH//////////AAP//////////gAP//////////gAf//////////gAf//////////wAf//////////wAf//////////wA///////////wA//4D//wAB//4A//wB//gAA//4A//gA//gAAf/4A//gA//AAAf/4A//gA//gAAf/4A//wB//gAA//4A///P//8AH//4Af//////////wAf//////////wAf//////////wAf//////////wAf//////////gAP//////////gAP//////////AAH//////////AAD/////////+AAD///+/////8AAB///8f////wAAAf//4P////AAAAH//wD///8AAAAA/+AAf//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH//gAAAAAAAAB///+AA/+AAAAP////gA//wAAAf////wA//4AAB/////4A//8AAD/////8A//+AAD/////+A///AAH/////+A///AAP//////A///gAP//////A///gAf//////A///wAf//////A///wAf//////A///wAf//////A///wA///////AB//4A//4AD//AAP/4A//gAB//AAP/4A//gAA//AAP/4A//gAA/+AAP/4A//gAB/8AAP/4A//wAB/8AAf/4Af//////////wAf//////////wAf//////////wAf//////////wAf//////////wAP//////////gAP//////////gAH//////////AAH/////////+AAD/////////8AAB/////////4AAAf////////wAAAP////////AAAAB///////4AAAAAD/////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAf/AAB/8AAAAAA//AAD/8AAAAAA//AAD/8AAAAAA//AAD/8AAAAAA//AAD/8AAAAAA//AAD/8AAAAAA//AAD/8AAAAAA//AAD/8AAAAAA//AAD/8AAAAAA//AAD/8AAAAAA//AAD/8AAAAAA//AAD/8AAAAAA//AAD/8AAAAAA//AAD/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=="), 46, atob("EiAnGicnJycnJycnEw=="), 78 + (scale << 8) + (1 << 16)); +}; + +Graphics.prototype.setFontAntonSmall = function(scale) { + // Actual height 53 (52 - 0) + g.setFontCustom(atob("AAAAAAAAAAAAAAAAAAAAAAAAAAf8AAAAAAAAf8AAAAAAAAf8AAAAAAAAf8AAAAAAAAf8AAAAAAAAf8AAAAAAAAf8AAAAAAAAf8AAAAAAAAf8AAAAAAAAf8AAAAAAAAf8AAAAAAAAAAAAAAAAAAAAMAAAAAAAAD8AAAAAAAA/8AAAAAAAf/8AAAAAAH//8AAAAAB///8AAAAA////8AAAAP////8AAAD/////8AAB//////8AAf//////8AH///////4A///////+AA///////AAA//////wAAA/////8AAAA////+AAAAA////gAAAAA///4AAAAAA//8AAAAAAA//AAAAAAAA/wAAAAAAAA4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH/////wAAA//////8AAB//////+AAH///////gAH///////gAP///////wAf///////4Af///////4A////////8A////////8A////////8A//AAAAD/8A/8AAAAA/8A/8AAAAA/8A/8AAAAA/8A/+AAAAB/8A////////8A////////8A////////8Af///////4Af///////4AP///////wAP///////wAH///////gAD///////AAA//////8AAAP/////wAAAAAAAAAAAAAAAAAAAAAAAfwAAAAAAAA/4AAAAAAAA/4AAAAAAAB/wAAAAAAAB/wAAAAAAAD/wAAAAAAAD/gAAAAAAAH///////8AP///////8A////////8A////////8A////////8A////////8A////////8A////////8A////////8A////////8A////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH/4AAAP8AA//4AAA/8AB//4AAH/8AH//4AAP/8AP//4AA//8AP//4AB//8Af//4AD//8Af//4AP//8A///4Af//8A///4A///8A///4D///8A//AAH///8A/8AAP///8A/8AA//+/8A/8AD//8/8A/+Af//w/8A//////g/8A/////+A/8A/////8A/8Af////4A/8Af////wA/8AP////AA/8AP///+AA/8AH///8AA/8AD///wAA/8AA///AAA/8AAP/4AAA/8AAAAAAAAAAAAAAAAAAAAAAH4AAf/gAAA/4AAf/8AAD/4AAf//AAH/4AAf//gAP/4AAf//wAP/4AAf//wAf/4AAf//4Af/4AAf//4A//4AAf//8A//4AAf//8A//4AAP//8A//A/8AB/8A/8A/8AA/8A/8B/8AA/8A/8B/8AA/8A/+D//AB/8A////////8A////////8A////////8Af///////4Af///////4Af///////wAP///////gAH//9////gAD//4///+AAB//wf//4AAAP/AH//gAAAAAAAAAAAAAAAAAAAAAAAAAAAH/wAAAAAAB//wAAAAAAP//wAAAAAD///wAAAAA////wAAAAH////wAAAB/////wAAAf/////wAAD//////wAA///////wAA/////h/wAA////wB/wAA///8AB/wAA///AAB/wAA//gAAB/wAA////////8A////////8A////////8A////////8A////////8A////////8A////////8A////////8A////////8A////////8A////////8AAAAAAB/wAAAAAAAB/wAAAAAAAB/wAAAAAAAAAAAAAAAAAAAAAAAAAAAP/4AA////4P/+AA////4P//AA////4P//gA////4P//wA////4P//wA////4P//4A////4P//4A////4P//8A////4P//8A////4P//8A/8H/AAB/8A/8H+AAA/8A/8P+AAA/8A/8P+AAA/8A/8P/gAD/8A/8P/////8A/8P/////8A/8P/////8A/8P/////4A/8H/////4A/8H/////wA/8D/////wA/8B/////gA/8A////+AA/8AP///4AAAAAB///AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/////wAAAf/////8AAB///////AAH///////gAP///////wAP///////wAf///////4Af///////4A////////8A////////8A////////8A/+AH/AB/8A/8AP+AA/8A/4Af+AA/8A/8Af+AA/8A/8Af/gH/8A//4f////8A//4f////8A//4f////8Af/4f////4Af/4f////4AP/4P////wAP/4P////gAH/4H////AAD/4D///+AAB/4B///4AAAP4AP//gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/8AAAAAAAA/8AAAAAAAA/8AAAAAB8A/8AAAAB/8A/8AAAAf/8A/8AAAH//8A/8AAA///8A/8AAH///8A/8AA////8A/8AD////8A/8Af////8A/8B/////8A/8P/////8A/8//////8A////////AA///////AAA//////gAAA/////4AAAA/////AAAAA////4AAAAA////AAAAAA///8AAAAAA///gAAAAAA//+AAAAAAA//wAAAAAAA/+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH/gD//gAAA//4P//8AAD//8f///AAH//+////gAH///////wAP///////4AP///////8Af///////8Af///////+Af///////+A////////+A//B//AB/+A/+A/+AA/+A/8Af+AA/+A/+Af+AA/+A//A//AB/+A////////+Af///////+Af///////+Af///////8Af///////8AP///////4AH///////4AH//+////wAD//+////AAA//4P//+AAAP/gH//wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH//gAfgAAA///8A/8AAB///+A//AAH////A//gAH////g//wAP////g//wAf////w//4Af////w//4A/////w//8A/////w//8A/////w//8A//gP/wA/8A/8AD/wA/8A/8AD/wAf8A/8AD/gA/8A/+AH/AB/8A////////8A////////8A////////8Af///////4Af///////4Af///////wAP///////wAH///////gAD//////+AAA//////4AAAP/////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP+AA/4AAAAP+AA/4AAAAP+AA/4AAAAP+AA/4AAAAP+AA/4AAAAP+AA/4AAAAP+AA/4AAAAP+AA/4AAAAP+AA/4AAAAP+AA/4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=="), 46, atob("DhgeFB4eHh4eHh4eDw=="), 60 + (scale << 8) + (1 << 16)); +}; + +// variables defined from settings +var secondsMode; +var secondsColoured; +var secondsWithColon; +var dateOnMain; +var dateOnSecs; +var weekDay; +var calWeek; +var upperCase; +var vectorFont; + +// dynamic variables +var drawTimeout; +var queueMillis = 1000; +var secondsScreen = true; + +var isBangle1 = (process.env.HWVERSION == 1); + +//For development purposes +/* +require('Storage').writeJSON(SETTINGSFILE, { + secondsMode: "Unlocked", // "Never", "Unlocked", "Always" + secondsColoured: true, + secondsWithColon: true, + dateOnMain: "Long", // "Short", "Long", "ISO8601" + dateOnSecs: "Year", // "No", "Year", "Weekday", LEGACY: true/false + weekDay: true, + calWeek: true, + upperCase: true, + vectorFont: true, +}); +*/ + +// OR (also for development purposes) +/* +require('Storage').erase(SETTINGSFILE); +*/ + +// Load settings +function loadSettings() { + // Helper function default setting + function def (value, def) {return value !== undefined ? value : def;} + + var settings = require('Storage').readJSON(SETTINGSFILE, true) || {}; + secondsMode = def(settings.secondsMode, "Never"); + secondsColoured = def(settings.secondsColoured, true); + secondsWithColon = def(settings.secondsWithColon, true); + dateOnMain = def(settings.dateOnMain, "Long"); + dateOnSecs = def(settings.dateOnSecs, "Year"); + weekDay = def(settings.weekDay, true); + calWeek = def(settings.calWeek, false); + upperCase = def(settings.upperCase, true); + vectorFont = def(settings.vectorFont, false); + + // Legacy + if (dateOnSecs === true) + dateOnSecs = "Year"; + if (dateOnSecs === false) + dateOnSecs = "No"; +} + +// schedule a draw for the next second or minute +function queueDraw() { + if (drawTimeout) clearTimeout(drawTimeout); + drawTimeout = setTimeout(function() { + drawTimeout = undefined; + draw(); + }, queueMillis - (Date.now() % queueMillis)); +} + +function updateState() { + if (Bangle.isLCDOn()) { + if ((secondsMode === "Unlocked" && !Bangle.isLocked()) || secondsMode === "Always") { + secondsScreen = true; + queueMillis = 1000; + } else { + secondsScreen = false; + queueMillis = 60000; + } + draw(); // draw immediately, queue redraw + } else { // stop draw timer + if (drawTimeout) clearTimeout(drawTimeout); + drawTimeout = undefined; + } +} + +function isoStr(date) { + return date.getFullYear() + "-" + ("0" + (date.getMonth() + 1)).substr(-2) + "-" + ("0" + date.getDate()).substr(-2); +} + +var calWeekBuffer = [false,false,false]; //buffer tz, date, week no (once calculated until other tz or date is requested) +function ISO8601calWeek(date) { //copied from: https://gist.github.com/IamSilviu/5899269#gistcomment-3035480 + dateNoTime = date; dateNoTime.setHours(0,0,0,0); + if (calWeekBuffer[0] === date.getTimezoneOffset() && calWeekBuffer[1] === dateNoTime) return calWeekBuffer[2]; + calWeekBuffer[0] = date.getTimezoneOffset(); + calWeekBuffer[1] = dateNoTime; + var tdt = new Date(date.valueOf()); + var dayn = (date.getDay() + 6) % 7; + tdt.setDate(tdt.getDate() - dayn + 3); + var firstThursday = tdt.valueOf(); + tdt.setMonth(0, 1); + if (tdt.getDay() !== 4) { + tdt.setMonth(0, 1 + ((4 - tdt.getDay()) + 7) % 7); + } + calWeekBuffer[2] = 1 + Math.ceil((firstThursday - tdt) / 604800000); + return calWeekBuffer[2]; +} + +function doColor() { + return !isBangle1 && !Bangle.isLocked() && secondsColoured; +} + +// Actually draw the watch face +function draw() { + var x = g.getWidth() / 2; + var y = g.getHeight() / 2 - (secondsMode !== "Never" ? 24 : (vectorFont ? 12 : 0)); + g.reset(); + /* This is to mark the widget areas during development. + g.setColor("#888") + .fillRect(0, 0, g.getWidth(), 23) + .fillRect(0, g.getHeight() - 23, g.getWidth(), g.getHeight()).reset(); + /* */ + g.clearRect(0, 24, g.getWidth(), g.getHeight() - 24); // clear whole background (w/o widgets) + var date = new Date(); // Actually the current date, this one is shown + var timeStr = require("locale").time(date, 1); // Hour and minute + g.setFontAlign(0, 0).setFont("Anton").drawString(timeStr, x, y); // draw time + if (secondsScreen) { + y += 65; + var secStr = (secondsWithColon ? ":" : "") + ("0" + date.getSeconds()).substr(-2); + if (doColor()) + g.setColor(0, 0, 1); + g.setFont("AntonSmall"); + if (dateOnSecs !== "No") { // A bit of a complex drawing with seconds on the right and date on the left + g.setFontAlign(1, 0).drawString(secStr, g.getWidth() - (isBangle1 ? 32 : 2), y); // seconds + y -= (vectorFont ? 15 : 13); + x = g.getWidth() / 4 + (isBangle1 ? 12 : 4) + (secondsWithColon ? 0 : g.stringWidth(":") / 2); + var dateStr2 = (dateOnMain === "ISO8601" ? isoStr(date) : require("locale").date(date, 1)); + var year; + var md; + var yearfirst; + if (dateStr2.match(/\d\d\d\d$/)) { // formatted date ends with year + year = (dateOnSecs === "Year" ? dateStr2.slice(-4) : require("locale").dow(date, 1)); + md = dateStr2.slice(0, -4); + if (!md.endsWith(".")) // keep separator before the year only if it is a dot (31.12. but 31/12) + md = md.slice(0, -1); + yearfirst = false; + } else { // formatted date begins with year + if (!dateStr2.match(/^\d\d\d\d/)) // if year position cannot be detected... + dateStr2 = isoStr(date); // ...use ISO date format instead + year = (dateOnSecs === "Year" ? dateStr2.slice(0, 4) : require("locale").dow(date, 1)); + md = dateStr2.slice(5); // never keep separator directly after year + yearfirst = true; + } + if (dateOnSecs === "Weekday" && upperCase) + year = year.toUpperCase(); + g.setFontAlign(0, 0); + if (vectorFont) + g.setFont("Vector", 24); + else + g.setFont("6x8", 2); + if (doColor()) + g.setColor(1, 0, 0); + g.drawString(md, x, (yearfirst ? y + (vectorFont ? 26 : 16) : y)); + g.drawString(year, x, (yearfirst ? y : y + (vectorFont ? 26 : 16))); + } else { + g.setFontAlign(0, 0).drawString(secStr, x, y); // Just the seconds centered + } + } else { // No seconds screen: Show date and optionally day of week + y += (vectorFont ? 50 : (secondsMode !== "Never") ? 52 : 40); + var dateStr = (dateOnMain === "ISO8601" ? isoStr(date) : require("locale").date(date, (dateOnMain === "Long" ? 0 : 1))); + if (upperCase) + dateStr = dateStr.toUpperCase(); + g.setFontAlign(0, 0); + if (vectorFont) + g.setFont("Vector", 24); + else + g.setFont("6x8", 2); + g.drawString(dateStr, x, y); + if (calWeek || weekDay) { + var dowcwStr = ""; + if (calWeek) + dowcwStr = " #" + ("0" + ISO8601calWeek(date)).substring(-2); + if (weekDay) + dowcwStr = require("locale").dow(date, calWeek ? 1 : 0) + dowcwStr; //weekDay e.g. Monday or weekDayShort # e.g. Mon #01 + else //week #01 + dowcwStr = /*LANG*/"week" + dowcwStr; + if (upperCase) + dowcwStr = dowcwStr.toUpperCase(); + g.drawString(dowcwStr, x, y + (vectorFont ? 26 : 16)); + } + } + + // queue next draw + queueDraw(); +} + +// Init the settings of the app +loadSettings(); +// Clear the screen once, at startup +g.clear(); +// Set dynamic state and perform initial drawing +updateState(); +// Register hooks for LCD on/off event and screen lock on/off event +Bangle.on('lcdPower', on => { + updateState(); +}); +Bangle.on('lock', on => { + updateState(); +}); +// Show launcher when middle button pressed +Bangle.setUI("clock"); +// Load widgets +Bangle.loadWidgets(); +Bangle.drawWidgets(); + +// end of file \ No newline at end of file diff --git a/apps/clockcal/app.png b/apps/clockcal/app.png new file mode 100644 index 0000000000000000000000000000000000000000..a38093c5f3b6f88dbc9b75017422dbe237d4407f GIT binary patch literal 1989 zcmV;$2RitPP)jLx_$n|!#a_+a7!4?Zj*KoBI+mq8Z8#{*+o z7DHwNZgKLU(NGK;MJHm2(2Z3wlN9^G$Dl3PLZR*L$JxWF_g-#q5pXO%?4OgH|2gM( z&iUPY&i~`w2to*6Cz0Salm7|*Pv});Rk#kH&o?nKVKf?JV`CKxgR&1SYr2-&`UyG$k%PDI4SU@#m$e3%a_DJdBl84(40z238D&kClk zs;Y82oqX8o)29U(i^UQ;n+PGB&6b*)8u|?i3JT`t=0fr3&YhD;M7F-UxtYZ<46||L z#$^(^di83!ed+D(C4@{&Ojs-yi^VcGH|KCTl9H16n23l7R(HGIbWWX4$8TSNkjR^L zcXzY8Ua#-%?PaT@qoV@@0~H&dOV(ykrCQkT3X65OnG@Zi=UX7pvt31 zj}{pcL)2{nR~LU?!AoakWJE?r@;{iv;h@Tm8#ky@Q&Y1{D-)+L zk?;ux0)h4G*YjJ(#>Q^nzRiCh09LE@!i5U}3JVKgYOOCJ6uR+Sw{CU2-NC`D<_&Lc zZ7nJ)ve|63T3A>ZA0H23aBz^e?A^OJbi$<(>ged0o}Lzbr0D2qQLxA3VcF#5df&c%%k%pC z_wR3NYGVEE(W6Hhh8Y?fqAfC+OyD3EODH`({lS9=J9q8`AeBm6T3YzMGcz-7ZEYHj zMx)V~&1Q$gG4w*>jhws#}m#f8yXryC+C~U z`1tsuqP^K{Rw|XD3shHEi{?XpeSM+eoSYo1)w(dD#ik#GkY~@Hm6eqVUYB7Q5=Ndr zeOgynw`b2D8Znxin?>0WLatxGUQtm|QBiU7#}wE{v` zE79qQ-%ki34hQ+;590L_Ldfha>Fp)d!~y~G@F9PBpO089!Qyrkhl5){BH^9@$<8K( zknwSGHUObsMZ!iMoIj7rNmN(E>qSis+-{VX!tckAKO!Om1qJYW@$I*me+7H^5OR62 z3=ZN&Qctf5g8}2?{1^qN6CZvUtlqoFPd{WbR8}H06H+N04!rjsKKcl1 zHT-^*mm?zsDJcj9aOMowuALuH=N;9*{^ImQhp>7z6pDG^{(i2SkbpPdKwMlnD;pTV zci*9=hFgSsgt0MHSEIZfVy=i!h!F4{kf=Wi^-z~Cfu=;}wcszLg7?YD27=Y7B$L-n$w>wz2ZCjda2n2$gD3L&|#yjuu z2}MPrp#d%zrl%1bi`-l|95{0Zk&&pa4elc$u-j2t3A-JBKOHBPB04%)Buo62QdtSL z8t=akwHjq*n3-7tKg75Bwl+ctsi@#u^m@|L64uIo{WZ*0`actu3LkvHRe$=4-LlzP zG&h4@(OoVyHR0!>Q z7SEqkLVx}VyB!`6&AgGFjjSwOzRV5%{dYK>@c97X&K-RDB~&Whx&>fx5P5mX%|&i5 zES9AaijKycZ{po|gH^j7J|8vvUAr(f#a_qZa-p>qnVHb*(cO)YKgK7YfW2`_r7##U zGXuN*KZ*8JQ)q0&kt0Y?hs%Wn2Ovn)Km8PaeXKu8NC11$U9)D%%lmw+13^*}qN6FH z-+sfTOGr$_fdjDHVKCt4O^lA>^Up#50d{oY$`u$4$j*jDf}1ztbmFV80BqTUEnC3* z|HA1lEy&D-(a5<(Lh$z69KdWwOblM!|B#xBHEXEZd%eW%CT=(JdO4k+urdq>AVk>9 z6Q`5N<>FSIpHBh-Vlss_`<9lKNk2L}#ngwjPIdq7ye|T3ar}q0{vjtPwx88zODg-bLj7E4oP%5!@EeCk*lKg)F X^{k9p7{Urq00000NkvXXu0mjf6Vk;2 literal 0 HcmV?d00001 diff --git a/apps/clockcal/metadata.json b/apps/clockcal/metadata.json new file mode 100644 index 000000000..9c20dca22 --- /dev/null +++ b/apps/clockcal/metadata.json @@ -0,0 +1,19 @@ +{ + "id": "clockcal", + "name": "clockcal Clock", + "version": "0.07", + "description": "A clockcal.", + "readme":"README.md", + "icon": "app.png", + "screenshots": [{"url":"screenshot.png"}], + "type": "clock", + "tags": "clock", + "supports": ["BANGLEJS","BANGLEJS2"], + "allow_emulator": true, + "storage": [ + {"name":"clockcal.app.js","url":"app.js"}, + {"name":"clockcal.settings.js","url":"settings.js"}, + {"name":"clockcal.img","url":"app-icon.js","evaluate":true} + ], + "data": [{"name":"clockcal.json"}] +} diff --git a/apps/clockcal/screenshot.png b/apps/clockcal/screenshot.png new file mode 100644 index 0000000000000000000000000000000000000000..e949b8a24a4eac5cbd8f8a01ffdd57b3660b939c GIT binary patch literal 1617 zcmV-X2Cn&uP)Q+S zK~#9!?VZUMqaYAPh2#JKvc1UZv~4tDs0p}l)q??3Tx$R!={SxJp})$Q0G+jC0!O8^ zZQJ(gqtoj@Omqnmc!(%iMD!3(V3KEOKA>AlTS_;6Lfh=O!<|dqR0_rLj7-Gw6Z=mp zp~2Trq^-sN$JXdw$RVuLh2YN@K!k`6Pvr(ctjI(h8vf-F??mA#V@N4cYlvqI5okD% z_;DP$JZ&Vq6!#OKe-2k=TnY^!SWV;*Zso@9p8;ZB8eWb#)U4Ef$av?E#0za2E;*)4 zGQr|jEE>MgPlWIg$fmf6shtWlvgg=3Rwde#%EB2ZCZ_CZaPtrhc0d|j{4_}=iN*gE z;u{bi0>vmhZ-Zhq7gZR!WpBGPT@bvP-QB*I3%vNK9g^4e^95YR9HNJMOGEc3^PP9= zeghUcMCX@GDcKZVBE6X1?T|^OpmnsZEZhDZOytNWR<$zI^OT+HG&D3DjmtcxmFGik zJRnpJL9i!eED?_aqL~>jBoBmvl^IAI?bAQ&EayfCLS!S5jl)pgvlP?kIp+`qJ-$`9 zI&Of=#-z_m07)eU0ze=`xV`)nKp=oXp~_BD#mLDJ9wK5fE z#1PK_NhKK)K)?h*keQkSK^pPXNsQt-Sls%7_-cz=S=@s2k+GEj%NkD=(Y+yF1hHNY zWjJb$33G_!II4DCYVYQgVzm5w4K066RQR$vmhmvwd4`4jP#6?u^o~J0xM5rioBqe!IzMMdoTw=&lVajkJ9GY z9%3vj6NW58##mMs+_FIqF^QG?w{A|BqPlI=31#Jm8=kdPNzu*-4r1ur+g_nwO_pDB zSt|nsBB?|GfdB#l1Of;I5C{PT`Vi+s2Euz_W#>-KgN-VUDq z#UUT`_r2FnJ@tTi{%rF%-L<}@?8QSJM06gQ<1o7S3rWrW=F(^C@-1(NO7CJ^d6bax zGyqiu-d<&OgG88Z zc)oUMn41Z;kO2*Z3{U_Fzw*!ML@7qRGi00};%0N+<~AZNBToysfdB#l1d`Ps5P#0|K}m9Y P00000NkvXXu0mjfUbx{% literal 0 HcmV?d00001 diff --git a/apps/clockcal/settings.js b/apps/clockcal/settings.js new file mode 100644 index 000000000..a69cab556 --- /dev/null +++ b/apps/clockcal/settings.js @@ -0,0 +1,107 @@ +// Settings menu for the enhanced Anton clock + +(function(back) { + var FILE = "clockcal.json"; + // Load settings + var settings = Object.assign({ + secondsOnUnlock: false, + }, require('Storage').readJSON(FILE, true) || {}); + + function writeSettings() { + require('Storage').writeJSON(FILE, settings); + } + + // Helper method which uses int-based menu item for set of string values + function stringItems(startvalue, writer, values) { + return { + value: (startvalue === undefined ? 0 : values.indexOf(startvalue)), + format: v => values[v], + min: 0, + max: values.length - 1, + wrap: true, + step: 1, + onchange: v => { + writer(values[v]); + writeSettings(); + } + }; + } + + // Helper method which breaks string set settings down to local settings object + function stringInSettings(name, values) { + return stringItems(settings[name], v => settings[name] = v, values); + } + + var mainmenu = { + "": { + "title": "clockcal clock" + }, + "< Back": () => back(), + "Seconds...": () => E.showMenu(secmenu), + "Date": stringInSettings("dateOnMain", ["Long", "Short", "ISO8601"]), + "Show Weekday": { + value: (settings.weekDay !== undefined ? settings.weekDay : true), + format: v => v ? "On" : "Off", + onchange: v => { + settings.weekDay = v; + writeSettings(); + } + }, + "Show CalWeek": { + value: (settings.calWeek !== undefined ? settings.calWeek : false), + format: v => v ? "On" : "Off", + onchange: v => { + settings.calWeek = v; + writeSettings(); + } + }, + "Uppercase": { + value: (settings.upperCase !== undefined ? settings.upperCase : true), + format: v => v ? "On" : "Off", + onchange: v => { + settings.upperCase = v; + writeSettings(); + } + }, + "Vector font": { + value: (settings.vectorFont !== undefined ? settings.vectorFont : false), + format: v => v ? "On" : "Off", + onchange: v => { + settings.vectorFont = v; + writeSettings(); + } + }, + }; + + // Submenu + var secmenu = { + "": { + "title": "Show seconds..." + }, + "< Back": () => E.showMenu(mainmenu), + "Show": stringInSettings("secondsMode", ["Never", "Unlocked", "Always"]), + "With \":\"": { + value: (settings.secondsWithColon !== undefined ? settings.secondsWithColon : true), + format: v => v ? "On" : "Off", + onchange: v => { + settings.secondsWithColon = v; + writeSettings(); + } + }, + "Color": { + value: (settings.secondsColoured !== undefined ? settings.secondsColoured : true), + format: v => v ? "On" : "Off", + onchange: v => { + settings.secondsColoured = v; + writeSettings(); + } + }, + "Date": stringInSettings("dateOnSecs", ["Year", "Weekday", "No"]) + }; + + // Actually display the menu + E.showMenu(mainmenu); + +}); + +// end of file From a9f857cd7f9b80729562d9af5f1b191bfe87b3eb Mon Sep 17 00:00:00 2001 From: foostuff <97034053+foostuff@users.noreply.github.com> Date: Sat, 5 Mar 2022 11:37:35 +0100 Subject: [PATCH 05/61] Update app.js --- apps/clockcal/app.js | 345 +++++++++++++++---------------------------- 1 file changed, 117 insertions(+), 228 deletions(-) diff --git a/apps/clockcal/app.js b/apps/clockcal/app.js index 356e067f2..fc299912f 100644 --- a/apps/clockcal/app.js +++ b/apps/clockcal/app.js @@ -1,230 +1,119 @@ -// Clock with large digits using the "Anton" bold font - -const SETTINGSFILE = "clockcal.json"; - -Graphics.prototype.setFontAnton = function(scale) { - // Actual height 69 (68 - 0) - g.setFontCustom(atob("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADgAAAAAAAAAAA/gAAAAAAAAAAP/gAAAAAAAAAH//gAAAAAAAAB///gAAAAAAAAf///gAAAAAAAP////gAAAAAAD/////gAAAAAA//////gAAAAAP//////gAAAAH///////gAAAB////////gAAAf////////gAAP/////////gAD//////////AA//////////gAA/////////4AAA////////+AAAA////////gAAAA///////wAAAAA//////8AAAAAA//////AAAAAAA/////gAAAAAAA////4AAAAAAAA///+AAAAAAAAA///gAAAAAAAAA//wAAAAAAAAAA/8AAAAAAAAAAA/AAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD//////AAAAAB///////8AAAAH////////AAAAf////////wAAA/////////4AAB/////////8AAD/////////+AAH//////////AAP//////////gAP//////////gAP//////////gAf//////////wAf//////////wAf//////////wAf//////////wA//8AAAAAB//4A//wAAAAAAf/4A//gAAAAAAP/4A//gAAAAAAP/4A//gAAAAAAP/4A//wAAAAAAf/4A///////////4Af//////////wAf//////////wAf//////////wAf//////////wAP//////////gAP//////////gAH//////////AAH//////////AAD/////////+AAB/////////8AAA/////////4AAAP////////gAAAD///////+AAAAAf//////4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP/gAAAAAAAAAAP/gAAAAAAAAAAf/gAAAAAAAAAAf/gAAAAAAAAAAf/AAAAAAAAAAA//AAAAAAAAAAA/+AAAAAAAAAAB/8AAAAAAAAAAD//////////gAH//////////gAP//////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH/4AAAAB/gAAD//4AAAAf/gAAP//4AAAB//gAA///4AAAH//gAB///4AAAf//gAD///4AAA///gAH///4AAD///gAP///4AAH///gAP///4AAP///gAf///4AAf///gAf///4AB////gAf///4AD////gA////4AH////gA////4Af////gA////4A/////gA//wAAB/////gA//gAAH/////gA//gAAP/////gA//gAA///8//gA//gAD///w//gA//wA////g//gA////////A//gA///////8A//gA///////4A//gAf//////wA//gAf//////gA//gAf/////+AA//gAP/////8AA//gAP/////4AA//gAH/////gAA//gAD/////AAA//gAB////8AAA//gAA////wAAA//gAAP///AAAA//gAAD//8AAAA//gAAAP+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB/+AAAAAD/wAAB//8AAAAP/wAAB///AAAA//wAAB///wAAB//wAAB///4AAD//wAAB///8AAH//wAAB///+AAP//wAAB///+AAP//wAAB////AAf//wAAB////AAf//wAAB////gAf//wAAB////gA///wAAB////gA///wAAB////gA///w//AAf//wA//4A//AAA//wA//gA//AAAf/wA//gB//gAAf/wA//gB//gAAf/wA//gD//wAA//wA//wH//8AB//wA///////////gA///////////gA///////////gA///////////gAf//////////AAf//////////AAP//////////AAP/////////+AAH/////////8AAH///+/////4AAD///+f////wAAA///8P////gAAAf//4H///+AAAAH//gB///wAAAAAP4AAH/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/wAAAAAAAAAA//wAAAAAAAAAP//wAAAAAAAAB///wAAAAAAAAf///wAAAAAAAH////wAAAAAAA/////wAAAAAAP/////wAAAAAB//////wAAAAAf//////wAAAAH///////wAAAA////////wAAAP////////wAAA///////H/wAAA//////wH/wAAA/////8AH/wAAA/////AAH/wAAA////gAAH/wAAA///4AAAH/wAAA//+AAAAH/wAAA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gA///////////gAAAAAAAAH/4AAAAAAAAAAH/wAAAAAAAAAAH/wAAAAAAAAAAH/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB//8AAA/////+B///AAA/////+B///wAA/////+B///4AA/////+B///8AA/////+B///8AA/////+B///+AA/////+B////AA/////+B////AA/////+B////AA/////+B////gA/////+B////gA/////+B////gA/////+A////gA//gP/gAAB//wA//gf/AAAA//wA//gf/AAAAf/wA//g//AAAAf/wA//g//AAAA//wA//g//gAAA//wA//g//+AAP//wA//g////////gA//g////////gA//g////////gA//g////////gA//g////////AA//gf///////AA//gf//////+AA//gP//////+AA//gH//////8AA//gD//////4AA//gB//////wAA//gA//////AAAAAAAH////8AAAAAAAA////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD//////gAAAAB///////+AAAAH////////gAAAf////////4AAB/////////8AAD/////////+AAH//////////AAH//////////gAP//////////gAP//////////gAf//////////wAf//////////wAf//////////wAf//////////wAf//////////4A//wAD/4AAf/4A//gAH/wAAP/4A//gAH/wAAP/4A//gAP/wAAP/4A//gAP/4AAf/4A//wAP/+AD//4A///wP//////4Af//4P//////wAf//4P//////wAf//4P//////wAf//4P//////wAP//4P//////gAP//4H//////gAH//4H//////AAH//4D/////+AAD//4D/////8AAB//4B/////4AAA//4A/////wAAAP/4AP////AAAAB/4AD///4AAAAAAAAAH/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//AAAAAAAAAAA//gAAAAAAAAAA//gAAAAAAAAAA//gAAAAAAADgA//gAAAAAAP/gA//gAAAAAH//gA//gAAAAB///gA//gAAAAP///gA//gAAAD////gA//gAAAf////gA//gAAB/////gA//gAAP/////gA//gAB//////gA//gAH//////gA//gA///////gA//gD///////gA//gf///////gA//h////////gA//n////////gA//////////gAA/////////AAAA////////wAAAA///////4AAAAA///////AAAAAA//////4AAAAAA//////AAAAAAA/////4AAAAAAA/////AAAAAAAA////8AAAAAAAA////gAAAAAAAA///+AAAAAAAAA///4AAAAAAAAA///AAAAAAAAAA//4AAAAAAAAAA/+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD//gB///wAAAAP//4H///+AAAA///8P////gAAB///+f////4AAD///+/////8AAH/////////+AAH//////////AAP//////////gAP//////////gAf//////////gAf//////////wAf//////////wAf//////////wA///////////wA//4D//wAB//4A//wB//gAA//4A//gA//gAAf/4A//gA//AAAf/4A//gA//gAAf/4A//wB//gAA//4A///P//8AH//4Af//////////wAf//////////wAf//////////wAf//////////wAf//////////gAP//////////gAP//////////AAH//////////AAD/////////+AAD///+/////8AAB///8f////wAAAf//4P////AAAAH//wD///8AAAAA/+AAf//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH//gAAAAAAAAB///+AA/+AAAAP////gA//wAAAf////wA//4AAB/////4A//8AAD/////8A//+AAD/////+A///AAH/////+A///AAP//////A///gAP//////A///gAf//////A///wAf//////A///wAf//////A///wAf//////A///wA///////AB//4A//4AD//AAP/4A//gAB//AAP/4A//gAA//AAP/4A//gAA/+AAP/4A//gAB/8AAP/4A//wAB/8AAf/4Af//////////wAf//////////wAf//////////wAf//////////wAf//////////wAP//////////gAP//////////gAH//////////AAH/////////+AAD/////////8AAB/////////4AAAf////////wAAAP////////AAAAB///////4AAAAAD/////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAf/AAB/8AAAAAA//AAD/8AAAAAA//AAD/8AAAAAA//AAD/8AAAAAA//AAD/8AAAAAA//AAD/8AAAAAA//AAD/8AAAAAA//AAD/8AAAAAA//AAD/8AAAAAA//AAD/8AAAAAA//AAD/8AAAAAA//AAD/8AAAAAA//AAD/8AAAAAA//AAD/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=="), 46, atob("EiAnGicnJycnJycnEw=="), 78 + (scale << 8) + (1 << 16)); -}; - -Graphics.prototype.setFontAntonSmall = function(scale) { - // Actual height 53 (52 - 0) - g.setFontCustom(atob("AAAAAAAAAAAAAAAAAAAAAAAAAAf8AAAAAAAAf8AAAAAAAAf8AAAAAAAAf8AAAAAAAAf8AAAAAAAAf8AAAAAAAAf8AAAAAAAAf8AAAAAAAAf8AAAAAAAAf8AAAAAAAAf8AAAAAAAAAAAAAAAAAAAAMAAAAAAAAD8AAAAAAAA/8AAAAAAAf/8AAAAAAH//8AAAAAB///8AAAAA////8AAAAP////8AAAD/////8AAB//////8AAf//////8AH///////4A///////+AA///////AAA//////wAAA/////8AAAA////+AAAAA////gAAAAA///4AAAAAA//8AAAAAAA//AAAAAAAA/wAAAAAAAA4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH/////wAAA//////8AAB//////+AAH///////gAH///////gAP///////wAf///////4Af///////4A////////8A////////8A////////8A//AAAAD/8A/8AAAAA/8A/8AAAAA/8A/8AAAAA/8A/+AAAAB/8A////////8A////////8A////////8Af///////4Af///////4AP///////wAP///////wAH///////gAD///////AAA//////8AAAP/////wAAAAAAAAAAAAAAAAAAAAAAAfwAAAAAAAA/4AAAAAAAA/4AAAAAAAB/wAAAAAAAB/wAAAAAAAD/wAAAAAAAD/gAAAAAAAH///////8AP///////8A////////8A////////8A////////8A////////8A////////8A////////8A////////8A////////8A////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH/4AAAP8AA//4AAA/8AB//4AAH/8AH//4AAP/8AP//4AA//8AP//4AB//8Af//4AD//8Af//4AP//8A///4Af//8A///4A///8A///4D///8A//AAH///8A/8AAP///8A/8AA//+/8A/8AD//8/8A/+Af//w/8A//////g/8A/////+A/8A/////8A/8Af////4A/8Af////wA/8AP////AA/8AP///+AA/8AH///8AA/8AD///wAA/8AA///AAA/8AAP/4AAA/8AAAAAAAAAAAAAAAAAAAAAAH4AAf/gAAA/4AAf/8AAD/4AAf//AAH/4AAf//gAP/4AAf//wAP/4AAf//wAf/4AAf//4Af/4AAf//4A//4AAf//8A//4AAf//8A//4AAP//8A//A/8AB/8A/8A/8AA/8A/8B/8AA/8A/8B/8AA/8A/+D//AB/8A////////8A////////8A////////8Af///////4Af///////4Af///////wAP///////gAH//9////gAD//4///+AAB//wf//4AAAP/AH//gAAAAAAAAAAAAAAAAAAAAAAAAAAAH/wAAAAAAB//wAAAAAAP//wAAAAAD///wAAAAA////wAAAAH////wAAAB/////wAAAf/////wAAD//////wAA///////wAA/////h/wAA////wB/wAA///8AB/wAA///AAB/wAA//gAAB/wAA////////8A////////8A////////8A////////8A////////8A////////8A////////8A////////8A////////8A////////8A////////8AAAAAAB/wAAAAAAAB/wAAAAAAAB/wAAAAAAAAAAAAAAAAAAAAAAAAAAAP/4AA////4P/+AA////4P//AA////4P//gA////4P//wA////4P//wA////4P//4A////4P//4A////4P//8A////4P//8A////4P//8A/8H/AAB/8A/8H+AAA/8A/8P+AAA/8A/8P+AAA/8A/8P/gAD/8A/8P/////8A/8P/////8A/8P/////8A/8P/////4A/8H/////4A/8H/////wA/8D/////wA/8B/////gA/8A////+AA/8AP///4AAAAAB///AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/////wAAAf/////8AAB///////AAH///////gAP///////wAP///////wAf///////4Af///////4A////////8A////////8A////////8A/+AH/AB/8A/8AP+AA/8A/4Af+AA/8A/8Af+AA/8A/8Af/gH/8A//4f////8A//4f////8A//4f////8Af/4f////4Af/4f////4AP/4P////wAP/4P////gAH/4H////AAD/4D///+AAB/4B///4AAAP4AP//gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/8AAAAAAAA/8AAAAAAAA/8AAAAAB8A/8AAAAB/8A/8AAAAf/8A/8AAAH//8A/8AAA///8A/8AAH///8A/8AA////8A/8AD////8A/8Af////8A/8B/////8A/8P/////8A/8//////8A////////AA///////AAA//////gAAA/////4AAAA/////AAAAA////4AAAAA////AAAAAA///8AAAAAA///gAAAAAA//+AAAAAAA//wAAAAAAA/+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH/gD//gAAA//4P//8AAD//8f///AAH//+////gAH///////wAP///////4AP///////8Af///////8Af///////+Af///////+A////////+A//B//AB/+A/+A/+AA/+A/8Af+AA/+A/+Af+AA/+A//A//AB/+A////////+Af///////+Af///////+Af///////8Af///////8AP///////4AH///////4AH//+////wAD//+////AAA//4P//+AAAP/gH//wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH//gAfgAAA///8A/8AAB///+A//AAH////A//gAH////g//wAP////g//wAf////w//4Af////w//4A/////w//8A/////w//8A/////w//8A//gP/wA/8A/8AD/wA/8A/8AD/wAf8A/8AD/gA/8A/+AH/AB/8A////////8A////////8A////////8Af///////4Af///////4Af///////wAP///////wAH///////gAD//////+AAA//////4AAAP/////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP+AA/4AAAAP+AA/4AAAAP+AA/4AAAAP+AA/4AAAAP+AA/4AAAAP+AA/4AAAAP+AA/4AAAAP+AA/4AAAAP+AA/4AAAAP+AA/4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=="), 46, atob("DhgeFB4eHh4eHh4eDw=="), 60 + (scale << 8) + (1 << 16)); -}; - -// variables defined from settings -var secondsMode; -var secondsColoured; -var secondsWithColon; -var dateOnMain; -var dateOnSecs; -var weekDay; -var calWeek; -var upperCase; -var vectorFont; - -// dynamic variables -var drawTimeout; -var queueMillis = 1000; -var secondsScreen = true; - -var isBangle1 = (process.env.HWVERSION == 1); - -//For development purposes -/* -require('Storage').writeJSON(SETTINGSFILE, { - secondsMode: "Unlocked", // "Never", "Unlocked", "Always" - secondsColoured: true, - secondsWithColon: true, - dateOnMain: "Long", // "Short", "Long", "ISO8601" - dateOnSecs: "Year", // "No", "Year", "Weekday", LEGACY: true/false - weekDay: true, - calWeek: true, - upperCase: true, - vectorFont: true, -}); -*/ - -// OR (also for development purposes) -/* -require('Storage').erase(SETTINGSFILE); -*/ - -// Load settings -function loadSettings() { - // Helper function default setting - function def (value, def) {return value !== undefined ? value : def;} - - var settings = require('Storage').readJSON(SETTINGSFILE, true) || {}; - secondsMode = def(settings.secondsMode, "Never"); - secondsColoured = def(settings.secondsColoured, true); - secondsWithColon = def(settings.secondsWithColon, true); - dateOnMain = def(settings.dateOnMain, "Long"); - dateOnSecs = def(settings.dateOnSecs, "Year"); - weekDay = def(settings.weekDay, true); - calWeek = def(settings.calWeek, false); - upperCase = def(settings.upperCase, true); - vectorFont = def(settings.vectorFont, false); - - // Legacy - if (dateOnSecs === true) - dateOnSecs = "Year"; - if (dateOnSecs === false) - dateOnSecs = "No"; -} - -// schedule a draw for the next second or minute -function queueDraw() { - if (drawTimeout) clearTimeout(drawTimeout); - drawTimeout = setTimeout(function() { - drawTimeout = undefined; - draw(); - }, queueMillis - (Date.now() % queueMillis)); -} - -function updateState() { - if (Bangle.isLCDOn()) { - if ((secondsMode === "Unlocked" && !Bangle.isLocked()) || secondsMode === "Always") { - secondsScreen = true; - queueMillis = 1000; - } else { - secondsScreen = false; - queueMillis = 60000; - } - draw(); // draw immediately, queue redraw - } else { // stop draw timer - if (drawTimeout) clearTimeout(drawTimeout); - drawTimeout = undefined; - } -} - -function isoStr(date) { - return date.getFullYear() + "-" + ("0" + (date.getMonth() + 1)).substr(-2) + "-" + ("0" + date.getDate()).substr(-2); -} - -var calWeekBuffer = [false,false,false]; //buffer tz, date, week no (once calculated until other tz or date is requested) -function ISO8601calWeek(date) { //copied from: https://gist.github.com/IamSilviu/5899269#gistcomment-3035480 - dateNoTime = date; dateNoTime.setHours(0,0,0,0); - if (calWeekBuffer[0] === date.getTimezoneOffset() && calWeekBuffer[1] === dateNoTime) return calWeekBuffer[2]; - calWeekBuffer[0] = date.getTimezoneOffset(); - calWeekBuffer[1] = dateNoTime; - var tdt = new Date(date.valueOf()); - var dayn = (date.getDay() + 6) % 7; - tdt.setDate(tdt.getDate() - dayn + 3); - var firstThursday = tdt.valueOf(); - tdt.setMonth(0, 1); - if (tdt.getDay() !== 4) { - tdt.setMonth(0, 1 + ((4 - tdt.getDay()) + 7) % 7); - } - calWeekBuffer[2] = 1 + Math.ceil((firstThursday - tdt) / 604800000); - return calWeekBuffer[2]; -} - -function doColor() { - return !isBangle1 && !Bangle.isLocked() && secondsColoured; -} - -// Actually draw the watch face -function draw() { - var x = g.getWidth() / 2; - var y = g.getHeight() / 2 - (secondsMode !== "Never" ? 24 : (vectorFont ? 12 : 0)); - g.reset(); - /* This is to mark the widget areas during development. - g.setColor("#888") - .fillRect(0, 0, g.getWidth(), 23) - .fillRect(0, g.getHeight() - 23, g.getWidth(), g.getHeight()).reset(); - /* */ - g.clearRect(0, 24, g.getWidth(), g.getHeight() - 24); // clear whole background (w/o widgets) - var date = new Date(); // Actually the current date, this one is shown - var timeStr = require("locale").time(date, 1); // Hour and minute - g.setFontAlign(0, 0).setFont("Anton").drawString(timeStr, x, y); // draw time - if (secondsScreen) { - y += 65; - var secStr = (secondsWithColon ? ":" : "") + ("0" + date.getSeconds()).substr(-2); - if (doColor()) - g.setColor(0, 0, 1); - g.setFont("AntonSmall"); - if (dateOnSecs !== "No") { // A bit of a complex drawing with seconds on the right and date on the left - g.setFontAlign(1, 0).drawString(secStr, g.getWidth() - (isBangle1 ? 32 : 2), y); // seconds - y -= (vectorFont ? 15 : 13); - x = g.getWidth() / 4 + (isBangle1 ? 12 : 4) + (secondsWithColon ? 0 : g.stringWidth(":") / 2); - var dateStr2 = (dateOnMain === "ISO8601" ? isoStr(date) : require("locale").date(date, 1)); - var year; - var md; - var yearfirst; - if (dateStr2.match(/\d\d\d\d$/)) { // formatted date ends with year - year = (dateOnSecs === "Year" ? dateStr2.slice(-4) : require("locale").dow(date, 1)); - md = dateStr2.slice(0, -4); - if (!md.endsWith(".")) // keep separator before the year only if it is a dot (31.12. but 31/12) - md = md.slice(0, -1); - yearfirst = false; - } else { // formatted date begins with year - if (!dateStr2.match(/^\d\d\d\d/)) // if year position cannot be detected... - dateStr2 = isoStr(date); // ...use ISO date format instead - year = (dateOnSecs === "Year" ? dateStr2.slice(0, 4) : require("locale").dow(date, 1)); - md = dateStr2.slice(5); // never keep separator directly after year - yearfirst = true; - } - if (dateOnSecs === "Weekday" && upperCase) - year = year.toUpperCase(); - g.setFontAlign(0, 0); - if (vectorFont) - g.setFont("Vector", 24); - else - g.setFont("6x8", 2); - if (doColor()) - g.setColor(1, 0, 0); - g.drawString(md, x, (yearfirst ? y + (vectorFont ? 26 : 16) : y)); - g.drawString(year, x, (yearfirst ? y : y + (vectorFont ? 26 : 16))); - } else { - g.setFontAlign(0, 0).drawString(secStr, x, y); // Just the seconds centered - } - } else { // No seconds screen: Show date and optionally day of week - y += (vectorFont ? 50 : (secondsMode !== "Never") ? 52 : 40); - var dateStr = (dateOnMain === "ISO8601" ? isoStr(date) : require("locale").date(date, (dateOnMain === "Long" ? 0 : 1))); - if (upperCase) - dateStr = dateStr.toUpperCase(); - g.setFontAlign(0, 0); - if (vectorFont) - g.setFont("Vector", 24); - else - g.setFont("6x8", 2); - g.drawString(dateStr, x, y); - if (calWeek || weekDay) { - var dowcwStr = ""; - if (calWeek) - dowcwStr = " #" + ("0" + ISO8601calWeek(date)).substring(-2); - if (weekDay) - dowcwStr = require("locale").dow(date, calWeek ? 1 : 0) + dowcwStr; //weekDay e.g. Monday or weekDayShort # e.g. Mon #01 - else //week #01 - dowcwStr = /*LANG*/"week" + dowcwStr; - if (upperCase) - dowcwStr = dowcwStr.toUpperCase(); - g.drawString(dowcwStr, x, y + (vectorFont ? 26 : 16)); - } - } - - // queue next draw - queueDraw(); -} - -// Init the settings of the app -loadSettings(); -// Clear the screen once, at startup -g.clear(); -// Set dynamic state and perform initial drawing -updateState(); -// Register hooks for LCD on/off event and screen lock on/off event -Bangle.on('lcdPower', on => { - updateState(); -}); -Bangle.on('lock', on => { - updateState(); -}); -// Show launcher when middle button pressed -Bangle.setUI("clock"); -// Load widgets Bangle.loadWidgets(); -Bangle.drawWidgets(); -// end of file \ No newline at end of file +var s = Object.assign({ + CAL_ROWS: 4, //number of calendar rows.(weeks) Shouldn't exceed 5 when using widgets. + BUZZ_ON_BT: true, //2x slow buzz on disconnect, 2x fast buzz on connect. Will be extra widget eventually + MODE24: true, //24h mode vs 12h mode + FIRSTDAYOFFSET: 6, //First day of the week: 0-6: Sun, Sat, Fri, Thu, Wed, Tue, Mon + REDSUN: true, // Use red color for sunday? + REDSAT: true, // Use red color for saturday? +}, require('Storage').readJSON("clockcal.json", true) || {}); + +const h = g.getHeight(); +const w = g.getWidth(); +const CELL_W = w / 7; +const CELL_H = 15; +const CAL_Y = h - s.CAL_ROWS * CELL_H; +const DEBUG = false; + +function drawMinutes() { + if (DEBUG) console.log("|-->minutes"); + var d = new Date(); + var hours = s.MODE24 ? d.getHours().toString().padStart(2, ' ') : ((d.getHours() + 24) % 12 || 12).toString().padStart(2, ' '); + var minutes = d.getMinutes().toString().padStart(2, '0'); + var textColor = NRF.getSecurityStatus().connected ? '#fff' : '#f00'; + var size = 50; + var clock_x = (w - 20) / 2; + if (dimSeconds) { + size = 65; + clock_x = 4 + (w / 2); + } + g.setBgColor(0); + g.setColor(textColor); + g.setFont("Vector", size); + g.setFontAlign(0, 1); + g.drawString(hours + ":" + minutes, clock_x, CAL_Y - 10, 1); + var nextminute = (61 - d.getSeconds()); + if (typeof minuteInterval !== "undefined") clearTimeout(minuteInterval); + minuteInterval = setTimeout(drawMinutes, nextminute * 1000); +} + +function drawSeconds() { + if (DEBUG) console.log("|--->seconds"); + var d = new Date(); + g.setColor(); + g.fillRect(w - 31, CAL_Y - 36, w - 3, CAL_Y - 19); + g.setBgColor(0); + g.setColor('#fff'); + g.setFont("Vector", 24); + g.setFontAlign(1, 1); + g.drawString(" " + d.getSeconds().toString().padStart(2, '0'), w, CAL_Y - 13); + if (typeof secondInterval !== "undefined") clearTimeout(secondInterval); + if (!dimSeconds) secondInterval = setTimeout(drawSeconds, 1000); +} + +function drawCalendar() { + if (DEBUG) console.log("CALENDAR"); + var d = new Date(); + g.reset(); + g.setBgColor(0); + g.clear(); + drawMinutes(); + if (!dimSeconds) drawSeconds(); + const dow = (s.FIRSTDAYOFFSET + d.getDay()) % 7; //MO=0, SU=6 + const today = d.getDate(); + var rD = new Date(d.getTime()); + rD.setDate(rD.getDate() - dow); + var rDate = rD.getDate(); + g.setFontAlign(1, 1); + for (var y = 1; y <= s.CAL_ROWS; y++) { + for (var x = 1; x <= 7; x++) { + bottomrightX = x * CELL_W - 2; + bottomrightY = y * CELL_H + CAL_Y; + g.setFont("Vector", 16); + var fg = ((s.REDSUN && rD.getDay() == 0) || (s.REDSAT && rD.getDay() == 6)) ? '#f00' : '#fff'; + if (y == 1 && today == rDate) { + g.setColor('#0f0'); + g.fillRect(bottomrightX - CELL_W + 1, bottomrightY - CELL_H - 1, bottomrightX, bottomrightY - 2); + g.setColor('#000'); + g.drawString(rDate, bottomrightX, bottomrightY); + } + else { + g.setColor(fg); + g.drawString(rDate, bottomrightX, bottomrightY); + } + rD.setDate(rDate + 1); + rDate = rD.getDate(); + } + } + Bangle.drawWidgets(); + + var nextday = (3600 * 24) - (d.getHours() * 3600 + d.getMinutes() * 60 + d.getSeconds() + 1); + if (DEBUG) console.log("Next Day:" + (nextday / 3600)); + if (typeof dayInterval !== "undefined") clearTimeout(dayInterval); + dayInterval = setTimeout(drawCalendar, nextday * 1000); +} + +function BTevent() { + drawMinutes(); + if (s.BUZZ_ON_BT) { + var interval = (NRF.getSecurityStatus().connected) ? 100 : 500; + Bangle.buzz(interval); + setTimeout(function () { Bangle.buzz(interval); }, interval * 3); + } +} + +//register events +Bangle.on('lock', locked => { + if (typeof secondInterval !== "undefined") clearTimeout(secondInterval); + dimSeconds = locked; //dim seconds if lock=on + drawCalendar(); +}); +NRF.on('connect', BTevent); +NRF.on('disconnect', BTevent); + + +dimSeconds = Bangle.isLocked(); +drawCalendar(); + +Bangle.setUI("clock"); From d1c6f59c28a1008ea0a62c9c5e54e798af2a635a Mon Sep 17 00:00:00 2001 From: foostuff <97034053+foostuff@users.noreply.github.com> Date: Sat, 5 Mar 2022 11:39:09 +0100 Subject: [PATCH 06/61] Add files via upload --- apps/clockcal/app.png | Bin 1989 -> 3396 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/apps/clockcal/app.png b/apps/clockcal/app.png index a38093c5f3b6f88dbc9b75017422dbe237d4407f..2e2e4461e0ed2e9c7052ab5347e8cc771792b650 100644 GIT binary patch literal 3396 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 KMNUMnLSTaLT**rS From 6ccbe2e030d7ba58bce6019772dce0903a03b42e Mon Sep 17 00:00:00 2001 From: foostuff <97034053+foostuff@users.noreply.github.com> Date: Sat, 5 Mar 2022 11:42:07 +0100 Subject: [PATCH 07/61] Add files via upload --- apps/clockcal/screenshot.png | Bin 1617 -> 2826 bytes apps/clockcal/screenshot2.png | Bin 0 -> 2811 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 apps/clockcal/screenshot2.png diff --git a/apps/clockcal/screenshot.png b/apps/clockcal/screenshot.png index e949b8a24a4eac5cbd8f8a01ffdd57b3660b939c..fcfde0c4abced61bbca0643cedfb597925db3b34 100644 GIT binary patch literal 2826 zcmb`J_gfNb8^xK*aS+Pc0I_Q#~wXXLM-NG1PBSAy{N8Uc+82jJGW}iVzdN5 zw7vv@m%>tmjo$XY?=Tt-0F_0_7K?m7c=UNtxbo@j70K$hgh;n^faMWUXiH@C;SOV= zt3~Kf?#R}|JY~^kA$?=jHF)0#Lfmc5$uigELm9w}{2;#t0+|X3q`vxnc=i9?vJdcF zs!?3?C z?5NEBD={xWzhJZ#9uY~c{T6Vh(O_{fR?UC8=tlGd>4Dyfdt3tiM?Y$xYfG;&~YpQR43>=r_8eUTr=twbe2(qhpP;l{F zrUB>3ZEP{y{pK~LZG~$eLG>c-a%p z8@^H!4N_6WFSc*KA(?rlV|f8s>bV#_)nu5N^sJu?5uHqeFr<0DI-5DSC=xCSz-A4F z!Wdok&2#kfSP=-pv2FTc_I|^%oT)@%{w%I1J6ni%VubP7n(Z?x3V#@f#LhNo5hpMdYelbFk(~(~Q|jj{|_h ze1(KJ1pZGr|5G_p;+mKFJn4`={=;tL@druknD?QAwHm8$7hN_|hj8?0iPUQQ&uepN ze9*!Pw(5R3(MrHJ8zb2t-zycf?z6H$pKmL~_*%2ds8=^`UGs~&m%O|>n*_5W6+ih; z9k2hC&QDbyS@m*BYXr(*oPb#2L~>3$96SWt^xKfDY|GjycO)XLE%xgC?l8%nAG^S_ zr#tR1SBtiwU%%R8YpM)`>AXCjF6Q9ZAl!_9>2xiWwp*UlSG7M^*q!~ke=X65ByR6C zx+my7To9QheD%eBwCP4nX)H2JQp?P_j;s>~f0RJ^cFTwJPO)BdW7n1SdJa;(UcnZ# zbJVN-iUG|PjXlbw3}4)_E@R>>JwXQfHauL*pW@4MByHVq&1GMwm_v>Kv8t9UuDa>K zF0D7*=r{}~V^&uE1V_aNsJ(@1}74&$ab6tl6slOROp?w)9XVRqq{30Y0Y*&u+ycCH`PX#H&q{1bn9^5 z%^8g0Na#K(y4Z?JpWX2M5*~pHd645S)GpkR{wPB0G--i5_6m|o^1r}E?z@Qxd?9{6 zl_Hxj4bjMc;4$VtkWX^E@*Y}9Hm&-^9Mhh(J3c%yq&Pkz9Ml$x0gWNO{wOf0HN5cG z7;pzS(|&j~Jwl&gx5+D z8}gJPMRPtMH$1*djmlyoIp-a-PJ4tJN&$jVHCpNbCH`A(yLaT=;;Fz%+?$;+ln;j_ zQa*3_v~phH*4R~px85{|7F%7Ec$5~eS&c|m#R<MY zsdOkSRzp3M)^Rwf33sgzQ&&2D?_es{eSZo!)al1=@|Def`zFiR=%$Uw$204Mx(WU& zO+~e(I1ZGtP>sTp##+5DW_X)2m*<)d_Wim!->VLuE#VJ5LG%l*7GUf4U}*H~FWv~V zp4^wK(z^wHE?q`t zzdpM}fsRHSc6f5$u@oa+uqpZdq%G?NoZ=1hsd9mU-^cP(cg+d@i`FNt$qUikzhZYK#K3#6&8W}xxZxcebL&16|WoY(NffDJ} z9-IaBS{#1%tMc&Yl+vCmKZIFbH#rTVucy^=Ri$&rqM-mHO-ThE6sHQnD6SI9y{h}4 zn6JOEu;B;cYZd46c$u?5h|aLL_D3h>Ek~TTqeA+`w3sJ%dx{lM(6iqcU<9#s1GC|- zKT;b}amxx0q&)6}57XP(UwNK^%T#VqZ{`jtA+y-xSV*5#cVITNp~{5kyIQH6|7}=z z;0vJ)hm{ZvWox2IdCvlw4iqF+7uqnu#flc@=KeZV(qPKk?WDl?|5pIg+z!!TicR@1x`9ZN delta 1611 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 T<=j3=!wNvyyV}**;%@v0LX%Et literal 0 HcmV?d00001 From 9a451d2b5521492d565f0fb708a610de56aefb45 Mon Sep 17 00:00:00 2001 From: foostuff <97034053+foostuff@users.noreply.github.com> Date: Sat, 5 Mar 2022 11:43:48 +0100 Subject: [PATCH 08/61] Add files via upload --- apps/clockcal/app-icon.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/clockcal/app-icon.js b/apps/clockcal/app-icon.js index fad03d50f..5bab7853e 100644 --- a/apps/clockcal/app-icon.js +++ b/apps/clockcal/app-icon.js @@ -1 +1 @@ -require("heatshrink").decompress(atob("mEwgX/AH4A/AAf+14BBAoPq/Wq1QFB+EP+kLAoNA+CdB3//yEP6ALB/sABYf8gEMgALB6ALJqoLB+tVgH//kQhkQhUABYImCIwPwh3whcA94UCgJHD+AXB/4LCcQQLCKYQLB+EDBZQFCBY/Qh4LJ4ALLl4LFioLCgE/KZMAv4XFBYimBC4/+BYw7DRwQLIV4ILWTQQLDOIUA/ALDAC+t1uv/263/6/Pq/YLC3vv//vM4Oq33rBYP6/u//2/C4Pr1YXC12vBwO+BYO69XmJDQA/ACIA==")) +require("heatshrink").decompress(atob("mEwwkECqMCkQACiEDkIXQuUnkUBkESiYXPgN/u8jgEx/8vC6E3k9xiH//8/C6BHCPQMSL6EDO4cgaf4A/ACEC+YFDl4FEAAM/+ISHbIIECh4FB+QWEA4PwCQsfC4gVBkYGDgP/mQ4CCQk/iAXEAQTiCgMiDQQSFiATDBgQXCgILBEQkQBwYrEC4sPLQRpCBwoXECgUCC4oSBAggXHNQRfDV4X/JgQXJBIIXFgYuDC5QKBiE/C4f/bwgXJmanGJgoSDiTQBmQMBE4JYBfwJ5BBYMiYQISEB4IAB+KdCAgfwAwTrCn4SDiczAAMwGwMTmR0CmECBgRSBCQwA/AGsBgEQAgYABAwcHu93s4GBqAXEmLrCiYICmICBj4XEgvABIMMqECiIXCgQXCegLYBC4NwF4VcAQNV4EPkEhF4REBgYXCiQvCu4UCAQMFJYRfKgxGBuxfGLgkjFgMCkMBmEjgEigZaBI4XFMYcRC4kBmRhBkMQgI5DF4MFgAXCLARfCFoIvDkZmBhnF4sA5gvDYghfEHIQJDAAhQBIAPwVQMTgQvCNIMhAwJfBR4MMU4JRB+RJBiUQgUDVwMgYwMBgcwX4amBqBQBiTqBgUQh8RmJhCL4IvC4HMR4ZaEAgIBBL4LBDL5EBmI5BkQvBXwIGBmMPMwMvkEFR4VcR4UgU4MSC4UQmIJBn7dBiQNBqoXBPYNQh8Q+MB+MvgEvG4JyBj8A+RkBhlQd4ZHBiBYCL4bBELxEAA==")) \ No newline at end of file From feb78c0704f1f9d7aa0a2b0ccf3e99d9c846a62d Mon Sep 17 00:00:00 2001 From: foostuff <97034053+foostuff@users.noreply.github.com> Date: Sat, 5 Mar 2022 11:44:45 +0100 Subject: [PATCH 09/61] Update ChangeLog --- apps/clockcal/ChangeLog | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/apps/clockcal/ChangeLog b/apps/clockcal/ChangeLog index ac49dcbd7..e874c8c67 100644 --- a/apps/clockcal/ChangeLog +++ b/apps/clockcal/ChangeLog @@ -1,11 +1 @@ -0.01: New App! -0.02: Load widgets after setUI so widclk knows when to hide -0.03: Clock now shows day of week under date. -0.04: Clock can optionally show seconds, date optionally in ISO-8601 format, weekdays and uppercase configurable, too. -0.05: Clock can optionally show ISO-8601 calendar weeknumber (default: Off) - when weekday name "Off": week #: - when weekday name "On": weekday name is cut at 6th position and .# is added -0.06: fixes #1271 - wrong settings name - when weekday name and calendar weeknumber are on then display is # - week is buffered until date or timezone changes -0.07: align default settings with app.js (otherwise the initial displayed settings will be confusing to users) \ No newline at end of file +0.01: Initial upload From 7027baea542ddc3687f9a16c5f17ab5ee3a5b01c Mon Sep 17 00:00:00 2001 From: foostuff <97034053+foostuff@users.noreply.github.com> Date: Sat, 5 Mar 2022 11:45:41 +0100 Subject: [PATCH 10/61] Update README.md --- apps/clockcal/README.md | 92 ++++++++--------------------------------- 1 file changed, 17 insertions(+), 75 deletions(-) diff --git a/apps/clockcal/README.md b/apps/clockcal/README.md index 28a38f5fd..cf6fa6ed9 100644 --- a/apps/clockcal/README.md +++ b/apps/clockcal/README.md @@ -1,79 +1,21 @@ -# Anton Clock - Large font digital watch with seconds and date +# Clock & Calendar by Michael -Anton clock uses the "Anton" bold font to show the time in a clear, easily readable manner. On the Bangle.js 2, the time can be read easily even if the screen is locked and unlit. +This is my "Hello World". I first made this watchface almost 10 years ago for my original Pebble and Pebble Time and I missed this so much, that I had to write it for the BangleJS2. +I know that it seems redundant because there already **is** a *time&cal*-app, but it didn't fit my style. -## Features +- locked screen with only one minimal update/minute +- ![locked screen](https://foostuff.github.io/BangleApps/apps/clockcal/screenshot.png) +- unlocked screen (twist?) with seconds +- ![unlocked screen](https://foostuff.github.io/BangleApps/apps/clockcal/screenshot2.png) -The basic time representation only shows hours and minutes of the current time. However, Anton clock can show additional information: +## Configurable Features +- Number of calendar rows (weeks) +- Buzz on connect/disconnect (I know, this should be an extra widget, but for now, it is a configurable setting) +- Clock Mode (24h/12h). Doesn't have an am/pm indicator, because I don't really care. It's configurable because it was easy. +- First day of the week +- Red Saturday +- Red Sunday -* Seconds can be shown, either always or only if the screen is unlocked. -* To help easy recognition, the seconds can be coloured in blue on the Bangle.js 2. -* Date can be shown in three different formats: - * ISO-8601: 2021-12-19 - * short local format: 19/12/2021, 19.12.2021 - * long local format: DEC 19 2021 -* Weekday can be shown (on seconds screen only instead of year) - -## Usage - -Install Anton clock through the Bangle.js app loader. -Configure it through the default Bangle.js configuration mechanism -(Settings app, "Apps" menu, "Anton clock" submenu). -If you like it, make it your default watch face -(Settings app, "System" menu, "Clock" submenu, select "Anton clock"). - -## Configuration - -Anton clock is configured by the standard settings mechanism of Bangle.js's operating system: -Open the "Settings" app, then the "Apps" submenu and below it the "Anton clock" menu. -You configure Anton clock through several "on/off" switches in two menus. - -### The main menu - -The main menu contains several settings covering Anton clock in general. - -* **Seconds...** - Opens the submenu for configuring the presentation of the current time's seconds. -* **Date** - Format of the date representation. Possible values are - * **Long** - "Long" date format in the current locale. Usually with the month as name, not number. - * **Short** - "Short" date format in the current locale. Usually with the month as number. - * **ISO8601** - Show the date in ISO-8601 format (YYYY-MM-DD), irrespective of the current locale. -* **Show Weekday** - Weekday is shown in the time presentation without seconds. -Weekday name depends on the current locale. -If seconds are shown, the weekday is never shown as there is not enough space on the watch face. -* **Show CalWeek** - Week-number (ISO-8601) is shown. (default: Off) -If "Show Weekday" is "Off" displays the week-number as "week #". -If "Show Weekday" is "On" displays "weekday name short" with " #" . -If seconds are shown, the week number is never shown as there is not enough space on the watch face. -* **Vector font** - Use the built-in vector font for dates and weekday. -This can improve readability. -Otherwise, a scaled version of the built-in 6x8 pixels font is used. - -### The "Seconds" submenu - -The "Seconds" submenu configures how (and if) seconds are shown on the "Anton" watch face. - -* **Show** - Configure when the seconds should be shown at all: - * **Never** - Seconds are never shown. -In this case, hour and minute are a bit more centered on the screen and the clock will always only update every minute. -This saves battery power. - * **Unlocked** - Seconds are shown if the display is unlocked. -On locked displays, only hour, minutes, date and optionally the weekday are shown. -_This option is highly recommended on the Bangle.js 2!_ - * **Always** - Seconds are _always_ shown, irrespective of the display's unlock state. -_Enabling this option increases power consumption as the watch face will update once per second instead of once per minute._ -* **With ":"** - If enabled, a colon ":" is prepended to the seconds. -This resembles the usual time representation "hh:mm:ss", even though the seconds are printed on a separate line. -* **Color** - If enabled, seconds are shown in blue instead of black. -If the date is shown on the seconds screen, it is colored read instead of black. -This make the visual orientation much easier on the watch face. -* **Date** - It is possible to show the date together with the seconds: - * **No** - Date is _not_ shown in the seconds screen. -In this case, the seconds are centered below hour and minute. - * **Year** - Date is shown with day, month, and year. If "Date" in the main settings is configured to _ISO8601_, this is used here, too. Otherwise, the short local format is used. - * **Weekday** - Date is shown with day, month, and weekday. - -The date is coloured in red if the "Coloured" option is chosen. - -## Compatibility - -Anton clock makes use of core Bangle.js 2 features (coloured display, display lock state). It also runs on the Bangle.js 1 but these features are not available there due to hardware restrictions. +## Feedback +The clock works for me in a 24h/MondayFirst/WeekendFree environment but is not well-tested with other settings. +So if something isn't working, please tell me. From ae221a9cd7cd890d00e33b0beb0b1b4828363f7b Mon Sep 17 00:00:00 2001 From: foostuff <97034053+foostuff@users.noreply.github.com> Date: Sat, 5 Mar 2022 11:46:56 +0100 Subject: [PATCH 11/61] Update settings.js --- apps/clockcal/settings.js | 191 ++++++++++++++++++-------------------- 1 file changed, 88 insertions(+), 103 deletions(-) diff --git a/apps/clockcal/settings.js b/apps/clockcal/settings.js index a69cab556..cc2a78181 100644 --- a/apps/clockcal/settings.js +++ b/apps/clockcal/settings.js @@ -1,107 +1,92 @@ -// Settings menu for the enhanced Anton clock +(function (back) { + var FILE = "clockcal.json"; -(function(back) { - var FILE = "clockcal.json"; - // Load settings - var settings = Object.assign({ - secondsOnUnlock: false, - }, require('Storage').readJSON(FILE, true) || {}); + settings = Object.assign({ + CAL_ROWS: 4, //number of calendar rows.(weeks) Shouldn't exceed 5 when using widgets. + BUZZ_ON_BT: true, //2x slow buzz on disconnect, 2x fast buzz on connect. Will be extra widget eventually + MODE24: true, //24h mode vs 12h mode + FIRSTDAY: 6, //First day of the week: mo, tu, we, th, fr, sa, su + REDSUN: true, // Use red color for sunday? + REDSAT: true, // Use red color for saturday? + }, require('Storage').readJSON(FILE, true) || {}); - function writeSettings() { - require('Storage').writeJSON(FILE, settings); - } - // Helper method which uses int-based menu item for set of string values - function stringItems(startvalue, writer, values) { - return { - value: (startvalue === undefined ? 0 : values.indexOf(startvalue)), - format: v => values[v], - min: 0, - max: values.length - 1, - wrap: true, - step: 1, - onchange: v => { - writer(values[v]); - writeSettings(); - } - }; - } + function writeSettings() { + require('Storage').writeJSON(FILE, settings); + } - // Helper method which breaks string set settings down to local settings object - function stringInSettings(name, values) { - return stringItems(settings[name], v => settings[name] = v, values); - } - - var mainmenu = { - "": { - "title": "clockcal clock" - }, - "< Back": () => back(), - "Seconds...": () => E.showMenu(secmenu), - "Date": stringInSettings("dateOnMain", ["Long", "Short", "ISO8601"]), - "Show Weekday": { - value: (settings.weekDay !== undefined ? settings.weekDay : true), - format: v => v ? "On" : "Off", - onchange: v => { - settings.weekDay = v; - writeSettings(); - } - }, - "Show CalWeek": { - value: (settings.calWeek !== undefined ? settings.calWeek : false), - format: v => v ? "On" : "Off", - onchange: v => { - settings.calWeek = v; - writeSettings(); - } - }, - "Uppercase": { - value: (settings.upperCase !== undefined ? settings.upperCase : true), - format: v => v ? "On" : "Off", - onchange: v => { - settings.upperCase = v; - writeSettings(); - } - }, - "Vector font": { - value: (settings.vectorFont !== undefined ? settings.vectorFont : false), - format: v => v ? "On" : "Off", - onchange: v => { - settings.vectorFont = v; - writeSettings(); - } - }, - }; - - // Submenu - var secmenu = { - "": { - "title": "Show seconds..." - }, - "< Back": () => E.showMenu(mainmenu), - "Show": stringInSettings("secondsMode", ["Never", "Unlocked", "Always"]), - "With \":\"": { - value: (settings.secondsWithColon !== undefined ? settings.secondsWithColon : true), - format: v => v ? "On" : "Off", - onchange: v => { - settings.secondsWithColon = v; - writeSettings(); - } - }, - "Color": { - value: (settings.secondsColoured !== undefined ? settings.secondsColoured : true), - format: v => v ? "On" : "Off", - onchange: v => { - settings.secondsColoured = v; - writeSettings(); - } - }, - "Date": stringInSettings("dateOnSecs", ["Year", "Weekday", "No"]) - }; - - // Actually display the menu - E.showMenu(mainmenu); - -}); - -// end of file + menu = { + "": { "title": "Clock & Calendar" }, + "< Back": () => back(), + 'Buzz(dis)conn.?': { + value: settings.BUZZ_ON_BT, + format: v => v ? "On" : "Off", + onchange: v => { + settings.BUZZ_ON_BT = v; + writeSettings(); + } + }, + '#Calendar Rows': { + value: settings.CAL_ROWS, + min: 0, max: 6, + onchange: v => { + settings.CAL_ROWS = v; + writeSettings(); + } + }, + 'Clock mode': { + value: settings.MODE24, + format: v => v ? "24h" : "12h", + onchange: v => { + settings.MODE24 = v; + writeSettings(); + } + }, + 'First Day': { + value: settings.FIRSTDAY, + min: 0, max: 6, + format: v => ["Sun", "Sat", "Fri", "Thu", "Wed", "Tue", "Mon"][v], + onchange: v => { + settings.FIRSTDAY = v; + writeSettings(); + } + }, + 'Red Saturday?': { + value: settings.REDSAT, + format: v => v ? "On" : "Off", + onchange: v => { + settings.REDSAT = v; + writeSettings(); + } + }, + 'Red Sunday?': { + value: settings.REDSUN, + format: v => v ? "On" : "Off", + onchange: v => { + settings.REDSUN = v; + writeSettings(); + } + }, + 'Load deafauls?': { + value: 0, + min: 0, max: 1, + format: v => ["No", "Yes"][v], + onchange: v => { + if (v == 1) { + settings = { + CAL_ROWS: 4, //number of calendar rows.(weeks) Shouldn't exceed 5 when using widgets. + BUZZ_ON_BT: true, //2x slow buzz on disconnect, 2x fast buzz on connect. + MODE24: true, //24h mode vs 12h mode + FIRSTDAY: 6, //First day of the week: mo, tu, we, th, fr, sa, su + REDSUN: true, // Use red color for sunday? + REDSAT: true, // Use red color for saturday? + }; + writeSettings(); + load() + } + } + }, + } + // Show the menu + E.showMenu(menu); +}) From 2f47070e11d6ad5ee7213dae9b072348a3b25416 Mon Sep 17 00:00:00 2001 From: foostuff <97034053+foostuff@users.noreply.github.com> Date: Sat, 5 Mar 2022 11:48:42 +0100 Subject: [PATCH 12/61] Update metadata.json --- apps/clockcal/metadata.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/clockcal/metadata.json b/apps/clockcal/metadata.json index 9c20dca22..ccc84a980 100644 --- a/apps/clockcal/metadata.json +++ b/apps/clockcal/metadata.json @@ -1,11 +1,11 @@ { "id": "clockcal", - "name": "clockcal Clock", - "version": "0.07", - "description": "A clockcal.", + "name": "Clock & Calendar", + "version": "0.01", + "description": "Clock with Calendar", "readme":"README.md", "icon": "app.png", - "screenshots": [{"url":"screenshot.png"}], + "screenshots": [{"url":"screenshot.png"},{"url":"screenshot2.png"}], "type": "clock", "tags": "clock", "supports": ["BANGLEJS","BANGLEJS2"], From 6ae1498eac545d563e50ade6841d905cc73e160c Mon Sep 17 00:00:00 2001 From: foostuff <97034053+foostuff@users.noreply.github.com> Date: Sat, 5 Mar 2022 11:53:17 +0100 Subject: [PATCH 13/61] Update README.md --- apps/clockcal/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/clockcal/README.md b/apps/clockcal/README.md index cf6fa6ed9..b37fbeaa4 100644 --- a/apps/clockcal/README.md +++ b/apps/clockcal/README.md @@ -18,4 +18,4 @@ I know that it seems redundant because there already **is** a *time&cal*-app, bu ## Feedback The clock works for me in a 24h/MondayFirst/WeekendFree environment but is not well-tested with other settings. -So if something isn't working, please tell me. +So if something isn't working, please tell me: https://github.com/foostuff/BangleApps/issues From d91a7a68e44f57bdb7a39076f6d0913f82b7871d Mon Sep 17 00:00:00 2001 From: foostuff <97034053+foostuff@users.noreply.github.com> Date: Sat, 5 Mar 2022 12:04:47 +0100 Subject: [PATCH 14/61] Update README.md --- apps/clockcal/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/clockcal/README.md b/apps/clockcal/README.md index b37fbeaa4..c19ee54a6 100644 --- a/apps/clockcal/README.md +++ b/apps/clockcal/README.md @@ -10,8 +10,8 @@ I know that it seems redundant because there already **is** a *time&cal*-app, bu ## Configurable Features - Number of calendar rows (weeks) -- Buzz on connect/disconnect (I know, this should be an extra widget, but for now, it is a configurable setting) -- Clock Mode (24h/12h). Doesn't have an am/pm indicator, because I don't really care. It's configurable because it was easy. +- Buzz on connect/disconnect (I know, this should be an extra widget, but for now, it is included) +- Clock Mode (24h/12h). Doesn't have an am/pm indicator. It's only there because it was easy. - First day of the week - Red Saturday - Red Sunday From aebc8bb3d505c5ebe78891865c8e647733ca5513 Mon Sep 17 00:00:00 2001 From: Salim Blume Date: Mon, 28 Feb 2022 23:54:27 -0600 Subject: [PATCH 15/61] Initial commit --- apps/locale/locales.js | 1 + apps/run/ChangeLog | 1 + apps/run/README.md | 8 +++----- apps/run/app.js | 14 ++++++++------ apps/run/metadata.json | 5 +++-- apps/run/settings.js | 24 +++++++++++++++--------- modules/Layout.js | 2 +- modules/exstats.js | 18 +++++++++--------- 8 files changed, 41 insertions(+), 32 deletions(-) diff --git a/apps/locale/locales.js b/apps/locale/locales.js index 073f4903f..dd650d7d7 100644 --- a/apps/locale/locales.js +++ b/apps/locale/locales.js @@ -110,6 +110,7 @@ var locales = { int_curr_symbol: "INR", speed: 'kmh', distance: { "0": "m", "1": "km" }, + paceLength: 1000, temperature: '°C', ampm: { 0: "am", 1: "pm" }, timePattern: { 0: "%HH:%MM:%SS ", 1: "%HH:%MM" }, diff --git a/apps/run/ChangeLog b/apps/run/ChangeLog index 0d61aa789..bd478c12e 100644 --- a/apps/run/ChangeLog +++ b/apps/run/ChangeLog @@ -6,3 +6,4 @@ 0.05: exstats updated so update 'distance' label is updated, option for 'speed' 0.06: Add option to record a run using the recorder app automatically 0.07: Fix crash if an odd number of active boxes are configured (fix #1473) +0.08: Support all stats from exstats \ No newline at end of file diff --git a/apps/run/README.md b/apps/run/README.md index 5b3bb635a..11d41d4bd 100644 --- a/apps/run/README.md +++ b/apps/run/README.md @@ -13,7 +13,7 @@ the red `STOP` in the bottom right turns to a green `RUN`. the GPS updates your position as it gets more satellites your position changes and the distance shown will increase, even if you are standing still. * `TIME` - the elapsed time for your run -* `PACE` - the number of minutes it takes you to run a kilometer **based on your run so far** +* `PACE` - the number of minutes it takes you to run a given distance, configured in settings (default 1km) **based on your run so far** * `HEART` - Your heart rate * `STEPS` - Steps since you started exercising * `CADENCE` - Steps per second based on your step rate *over the last minute* @@ -24,9 +24,8 @@ so if you have no GPS lock you just need to wait. ## Recording Tracks -`Run` doesn't directly allow you to record your tracks at the moment. -However you can just install the `Recorder` app, turn recording on in -that, and then start the `Run` app. +`Run` depends on the `Recorder` app and it will be installed automatically. +Starting and stopping a run will automatically start and stop recordings with the `Recorder` app. ## Settings @@ -41,7 +40,6 @@ record GPS/HRM/etc data every time you start a run? ## TODO -* Allow this app to trigger the `Recorder` app on and off directly. * Keep a log of each run's stats (distance/steps/etc) ## Development diff --git a/apps/run/app.js b/apps/run/app.js index bc1d54de2..fc8869fa7 100644 --- a/apps/run/app.js +++ b/apps/run/app.js @@ -1,5 +1,5 @@ var ExStats = require("exstats"); -var B2 = process.env.HWVERSION==2; +var B2 = process.env.HWVERSION===2; var Layout = require("Layout"); var locale = require("locale"); var fontHeading = "6x8:2"; @@ -18,12 +18,14 @@ let settings = Object.assign({ B1 : "dist", B2 : "time", B3 : "pacea", - B4 : "bpm", - B5 : "step", - B6 : "caden", + B4 : "pacec", + B5 : "bpm", + B6 : "step", + B7 : "caden", + B8 : "speed", paceLength : 1000 }, require("Storage").readJSON("run.json", 1) || {}); -var statIDs = [settings.B1,settings.B2,settings.B3,settings.B4,settings.B5,settings.B6].filter(s=>s!=""); +var statIDs = [settings.B1,settings.B2,settings.B3,settings.B4,settings.B5,settings.B6].filter(s=>s!==""); var exs = ExStats.getStats(statIDs, settings); // --------------------------- @@ -88,7 +90,7 @@ layout.render(); Bangle.on("GPS", function(fix) { layout.gps.bgCol = fix.fix ? "#0f0" : "#f00"; if (!fix.fix) return; // only process actual fixes - if (fixCount++ == 0) { + if (fixCount++ === 0) { Bangle.buzz(); // first fix, does not need to respect quiet mode } }); diff --git a/apps/run/metadata.json b/apps/run/metadata.json index 7aabf8b53..f256aefa4 100644 --- a/apps/run/metadata.json +++ b/apps/run/metadata.json @@ -1,6 +1,6 @@ { "id": "run", "name": "Run", - "version":"0.07", + "version":"0.08", "description": "Displays distance, time, steps, cadence, pace and more for runners.", "icon": "app.png", "tags": "run,running,fitness,outdoors,gps", @@ -12,5 +12,6 @@ {"name":"run.img","url":"app-icon.js","evaluate":true}, {"name":"run.settings.js","url":"settings.js"} ], - "data": [{"name":"run.json"}] + "data": [{"name":"run.json"}], + "dependencies" : { "messages":"recorder" } } diff --git a/apps/run/settings.js b/apps/run/settings.js index 7eb8a8611..aaf834214 100644 --- a/apps/run/settings.js +++ b/apps/run/settings.js @@ -9,14 +9,18 @@ // This way saved values are preserved if a new version adds more settings const storage = require('Storage') let settings = Object.assign({ - record : true, - B1 : "dist", - B2 : "time", - B3 : "pacea", - B4 : "bpm", - B5 : "step", - B6 : "caden", - paceLength : 1000 + record: true, + B1: "dist", + B2: "time", + B3: "pacea", + B4: "pacec", + B5: "bpm", + B6: "step", + B7: "caden", + B8: "speed", + paceLength: 1000, + notify: false, + }, storage.readJSON(SETTINGS_FILE, 1) || {}); function saveSettings() { storage.write(SETTINGS_FILE, settings) @@ -24,7 +28,7 @@ function getBoxChooser(boxID) { return { - min :0, max: statsIDs.length-1, + min: 0, max: statsIDs.length-1, value: Math.max(statsIDs.indexOf(settings[boxID]),0), format: v => statsList[v].name, onchange: v => { @@ -55,6 +59,8 @@ 'Box 4': getBoxChooser("B4"), 'Box 5': getBoxChooser("B5"), 'Box 6': getBoxChooser("B6"), + 'Box 7': getBoxChooser("B7"), + 'Box 8': getBoxChooser("B8"), }); E.showMenu(menu); }) diff --git a/modules/Layout.js b/modules/Layout.js index 4223867a4..20fa2be8b 100644 --- a/modules/Layout.js +++ b/modules/Layout.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2022 Bangle.js contibutors. See the file LICENSE for copying permission. */ +/* Copyright (c) 2022 Bangle.js contributors. See the file LICENSE for copying permission. */ /* Take a look at README.md for hints on developing with this library. diff --git a/modules/exstats.js b/modules/exstats.js index b72ee6584..c2a4bfb9e 100644 --- a/modules/exstats.js +++ b/modules/exstats.js @@ -1,4 +1,4 @@ -/* Copyright (c) 2022 Bangle.js contibutors. See the file LICENSE for copying permission. */ +/* Copyright (c) 2022 Bangle.js contributors. See the file LICENSE for copying permission. */ /* Exercise Stats module Take a look at README.md for hints on developing with this library. @@ -69,10 +69,10 @@ var stats = {}; // distance between 2 lat and lons, in meters, Mean Earth Radius = 6371km // https://www.movable-type.co.uk/scripts/latlong.html +// (Equirectangular approximation) function calcDistance(a,b) { - function radians(a) { return a*Math.PI/180; } - var x = radians(a.lon-b.lon) * Math.cos(radians((a.lat+b.lat)/2)); - var y = radians(b.lat-a.lat); + var x = b.lon-a.lon * Math.cos((a.lat+b.lat)/2); + var y = b.lat-a.lat; return Math.sqrt(x*x + y*y) * 6371000; } @@ -126,7 +126,7 @@ Bangle.on("HRM", function(h) { if (h.confidence>=60) { state.BPM = h.bpm; state.BPMage = 0; - stats["bpm"].emit("changed",stats["bpm"]); + if (stats["bpm"]) stats["bpm"].emit("changed",stats["bpm"]); } }); @@ -137,13 +137,13 @@ exports.getList = function() { {name: "Distance", id:"dist"}, {name: "Steps", id:"step"}, {name: "Heart (BPM)", id:"bpm"}, - {name: "Pace (avr)", id:"pacea"}, - {name: "Pace (current)", id:"pacec"}, + {name: "Pace (avg)", id:"pacea"}, + {name: "Pace (curr)", id:"pacec"}, {name: "Speed", id:"speed"}, {name: "Cadence", id:"caden"}, ]; }; -/** Instatiate the given list of statistic IDs (see comments at top) +/** Instantiate the given list of statistic IDs (see comments at top) options = { paceLength : meters to measure pace over } @@ -159,7 +159,7 @@ exports.getStats = function(statIDs, options) { getValue : function() { return Date.now()-state.startTime; }, getString : function() { return formatTime(this.getValue()) }, }; - }; + } if (statIDs.includes("dist")) { needGPS = true; stats["dist"]={ From f307101aad064e35667e57aad4bfe526d47a4d28 Mon Sep 17 00:00:00 2001 From: Salim Blume Date: Mon, 28 Feb 2022 23:58:45 -0600 Subject: [PATCH 16/61] Remove recorder dependency --- apps/run/metadata.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/run/metadata.json b/apps/run/metadata.json index f256aefa4..8f139c2d5 100644 --- a/apps/run/metadata.json +++ b/apps/run/metadata.json @@ -12,6 +12,5 @@ {"name":"run.img","url":"app-icon.js","evaluate":true}, {"name":"run.settings.js","url":"settings.js"} ], - "data": [{"name":"run.json"}], - "dependencies" : { "messages":"recorder" } + "data": [{"name":"run.json"}] } From 7cd78bfd17204eefa23d21827bf648d2691a2ea7 Mon Sep 17 00:00:00 2001 From: Salim Blume Date: Tue, 1 Mar 2022 00:16:24 -0600 Subject: [PATCH 17/61] Cleanup --- apps/run/app.js | 18 ++++++++---------- apps/run/settings.js | 13 ++++--------- 2 files changed, 12 insertions(+), 19 deletions(-) diff --git a/apps/run/app.js b/apps/run/app.js index fc8869fa7..287d60969 100644 --- a/apps/run/app.js +++ b/apps/run/app.js @@ -14,16 +14,14 @@ Bangle.drawWidgets(); // --------------------------- let settings = Object.assign({ - record : true, - B1 : "dist", - B2 : "time", - B3 : "pacea", - B4 : "pacec", - B5 : "bpm", - B6 : "step", - B7 : "caden", - B8 : "speed", - paceLength : 1000 + record: true, + B1: "dist", + B2: "time", + B3: "pacea", + B4: "bpm", + B5: "step", + B6: "caden", + paceLength: 1000 }, require("Storage").readJSON("run.json", 1) || {}); var statIDs = [settings.B1,settings.B2,settings.B3,settings.B4,settings.B5,settings.B6].filter(s=>s!==""); var exs = ExStats.getStats(statIDs, settings); diff --git a/apps/run/settings.js b/apps/run/settings.js index aaf834214..6718a381b 100644 --- a/apps/run/settings.js +++ b/apps/run/settings.js @@ -13,14 +13,11 @@ B1: "dist", B2: "time", B3: "pacea", - B4: "pacec", - B5: "bpm", - B6: "step", - B7: "caden", - B8: "speed", - paceLength: 1000, + B4: "bpm", + B5: "step", + B6: "caden", + paceLength: 1000, // TODO: Default to either 1km or 1mi based on locale notify: false, - }, storage.readJSON(SETTINGS_FILE, 1) || {}); function saveSettings() { storage.write(SETTINGS_FILE, settings) @@ -59,8 +56,6 @@ 'Box 4': getBoxChooser("B4"), 'Box 5': getBoxChooser("B5"), 'Box 6': getBoxChooser("B6"), - 'Box 7': getBoxChooser("B7"), - 'Box 8': getBoxChooser("B8"), }); E.showMenu(menu); }) From 5e3e7a0c0fd0a119ce51efe0e608f2d778711afc Mon Sep 17 00:00:00 2001 From: Salim Blume Date: Sat, 5 Mar 2022 00:15:35 -0600 Subject: [PATCH 18/61] Testing exstats notifications --- apps/locale/ChangeLog | 2 +- apps/locale/locales.js | 1 - apps/recorder/app.js | 2 +- apps/run/README.md | 4 +- apps/run/app.js | 6 +- apps/run/settings.js | 4 +- modules/exstats.js | 32 +- yarn.lock | 864 +++++++++++++++++++++++++++++++++++++++++ 8 files changed, 906 insertions(+), 9 deletions(-) create mode 100644 yarn.lock diff --git a/apps/locale/ChangeLog b/apps/locale/ChangeLog index 39b825e02..2dbb4febb 100644 --- a/apps/locale/ChangeLog +++ b/apps/locale/ChangeLog @@ -7,7 +7,7 @@ 0.06: Remove translations if not required Ensure 'on' is always supplied for translations 0.07: Improve handling of non-ASCII characters (fix #469) -0.08: Added Mavigation units and en_NAV +0.08: Added Navigation units and en_NAV 0.09: Added New Zealand en_NZ 0.10: Apply 12hour setting to time 0.11: Added translations for nl_NL and changes one formatting diff --git a/apps/locale/locales.js b/apps/locale/locales.js index dd650d7d7..073f4903f 100644 --- a/apps/locale/locales.js +++ b/apps/locale/locales.js @@ -110,7 +110,6 @@ var locales = { int_curr_symbol: "INR", speed: 'kmh', distance: { "0": "m", "1": "km" }, - paceLength: 1000, temperature: '°C', ampm: { 0: "am", 1: "pm" }, timePattern: { 0: "%HH:%MM:%SS ", 1: "%HH:%MM" }, diff --git a/apps/recorder/app.js b/apps/recorder/app.js index 7075563aa..d28cef585 100644 --- a/apps/recorder/app.js +++ b/apps/recorder/app.js @@ -305,7 +305,7 @@ function viewTrack(filename, info) { g.drawString(require("locale").distance(dist),g.getWidth() / 2, g.getHeight() - 20); g.setFont("6x8",2); g.setFontAlign(0,0,3); - g.drawString("Back",g.getWidth() - 10, g.getHeight() - 40); + g.drawString("Back",g.getWidth() - 10, g.getHeight() - 40); // TODO: this position depends on Bangle1 vs 2 setWatch(function() { viewTrack(info.fn, info); }, global.BTN3||BTN1); diff --git a/apps/run/README.md b/apps/run/README.md index 11d41d4bd..67d62185d 100644 --- a/apps/run/README.md +++ b/apps/run/README.md @@ -24,8 +24,8 @@ so if you have no GPS lock you just need to wait. ## Recording Tracks -`Run` depends on the `Recorder` app and it will be installed automatically. -Starting and stopping a run will automatically start and stop recordings with the `Recorder` app. +When the `Recorder` app is installed, `Run` will automatically start and stop tracks +as needed, prompting you to overwrite or begin a new track, if necessary. ## Settings diff --git a/apps/run/app.js b/apps/run/app.js index 287d60969..06340526f 100644 --- a/apps/run/app.js +++ b/apps/run/app.js @@ -7,6 +7,8 @@ var fontValue = B2 ? "6x15:2" : "6x8:3"; var headingCol = "#888"; var fixCount = 0; var isMenuDisplayed = false; +var nextNotifyTime = 0; +var nextNotifyDist = 0; g.clear(); Bangle.loadWidgets(); @@ -21,7 +23,9 @@ let settings = Object.assign({ B4: "bpm", B5: "step", B6: "caden", - paceLength: 1000 + paceLength: 1000, + notifyDistance: false, + notifyTime: false, }, require("Storage").readJSON("run.json", 1) || {}); var statIDs = [settings.B1,settings.B2,settings.B3,settings.B4,settings.B5,settings.B6].filter(s=>s!==""); var exs = ExStats.getStats(statIDs, settings); diff --git a/apps/run/settings.js b/apps/run/settings.js index 6718a381b..1ac16e734 100644 --- a/apps/run/settings.js +++ b/apps/run/settings.js @@ -17,7 +17,8 @@ B5: "step", B6: "caden", paceLength: 1000, // TODO: Default to either 1km or 1mi based on locale - notify: false, + notifyDistance: false, + notifyTime: false, }, storage.readJSON(SETTINGS_FILE, 1) || {}); function saveSettings() { storage.write(SETTINGS_FILE, settings) @@ -48,6 +49,7 @@ saveSettings(); } }; + ExStats.appendMenuItems(menu, settings, saveSettings); Object.assign(menu,{ 'Box 1': getBoxChooser("B1"), diff --git a/modules/exstats.js b/modules/exstats.js index c2a4bfb9e..da32ffa12 100644 --- a/modules/exstats.js +++ b/modules/exstats.js @@ -63,6 +63,9 @@ var state = { // cadence // steps per minute adjusted if <1 minute // BPM // beats per minute // BPMage // how many seconds was BPM set? + // Notifies: 0 for disabled, otherwise how often to notify in meters and seconds + notifyDistance: 0, notifyTime: 0, notifySteps: 0, + nextNotifyDistance: 0, nextNotifyTime: 0, nextNotifySteps: 0, }; // list of active stats (indexed by ID) var stats = {}; @@ -71,8 +74,9 @@ var stats = {}; // https://www.movable-type.co.uk/scripts/latlong.html // (Equirectangular approximation) function calcDistance(a,b) { - var x = b.lon-a.lon * Math.cos((a.lat+b.lat)/2); - var y = b.lat-a.lat; + function radians(a) { return a*Math.PI/180; } + var x = radians(b.lon-a.lon) * Math.cos(radians((a.lat+b.lat)/2)); + var y = radians(b.lat-a.lat); return Math.sqrt(x*x + y*y) * 6371000; } @@ -114,6 +118,10 @@ Bangle.on("GPS", function(fix) { if (stats["pacea"]) stats["pacea"].emit("changed",stats["pacea"]); if (stats["pacec"]) stats["pacec"].emit("changed",stats["pacec"]); if (stats["speed"]) stats["speed"].emit("changed",stats["speed"]); + if (state.notifyDistance > 0 && state.nextNotifyDist < stats["dist"]) { + stats["dist"].emit("notify",stats["dist"]); + state.nextNotifyDist = stats["dist"] + state.notifyDistance; + } }); Bangle.on("step", function(steps) { @@ -121,6 +129,10 @@ Bangle.on("step", function(steps) { if (stats["step"]) stats["step"].emit("changed",stats["step"]); state.stepHistory[0] += steps-state.lastStepCount; state.lastStepCount = steps; + if (state.notifySteps > 0 && state.nextNotifySteps < steps) { + stats["step"].emit("notify",stats["step"]); + state.nextNotifySteps = steps + state.notifySteps; + } }); Bangle.on("HRM", function(h) { if (h.confidence>=60) { @@ -146,6 +158,9 @@ exports.getList = function() { /** Instantiate the given list of statistic IDs (see comments at top) options = { paceLength : meters to measure pace over + notifyDistance : meters to notify have elapsed (repeats) + notifyTime : ms to notify have elapsed (repeats) + notifySteps : number of steps to notify have elapsed (repeats) } */ exports.getStats = function(statIDs, options) { @@ -235,6 +250,10 @@ exports.getStats = function(statIDs, options) { state.BPM = 0; if (stats["bpm"]) stats["bpm"].emit("changed",stats["bpm"]); } + if (state.notifyTime > 0 && state.nextNotifyTime < stats["time"]) { + stats["time"].emit("notify",stats["time"]); + state.nextNotifyTime = stats["time"] + state.notifyDistance; + } }, 1000); function reset() { state.startTime = Date.now(); @@ -273,4 +292,13 @@ exports.appendMenuItems = function(menu, settings, saveSettings) { saveSettings(); }, }; + menu['Ntfy Dist'] = { + min :0, max: paceNames.length-1, + value: Math.max(paceAmts.indexOf(settings.paceLength),0), + format: v => paceNames[v], + onchange: v => { + state.notifyDistance = paceAmts[v]; + saveSettings(); + }, + }; }; diff --git a/yarn.lock b/yarn.lock new file mode 100644 index 000000000..f3224947f --- /dev/null +++ b/yarn.lock @@ -0,0 +1,864 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@babel/code-frame@^7.0.0": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.16.7.tgz#44416b6bd7624b998f5b1af5d470856c40138789" + integrity sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg== + dependencies: + "@babel/highlight" "^7.16.7" + +"@babel/helper-validator-identifier@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz#e8c602438c4a8195751243da9031d1607d247cad" + integrity sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw== + +"@babel/highlight@^7.16.7": + version "7.16.10" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.16.10.tgz#744f2eb81579d6eea753c227b0f570ad785aba88" + integrity sha512-5FnTQLSLswEj6IkgVw5KusNUUFY9ZGqe/TRFnP/BKYHYgfh7tc+C7mwiy95/yNP7Dh9x580Vv8r7u7ZfTBFxdw== + dependencies: + "@babel/helper-validator-identifier" "^7.16.7" + chalk "^2.0.0" + js-tokens "^4.0.0" + +acorn-jsx@^5.3.1: + version "5.3.2" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" + integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== + +acorn@^7.2.0, acorn@^7.4.0: + version "7.4.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" + integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== + +ajv@^6.10.0, ajv@^6.10.2: + version "6.12.6" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" + integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== + dependencies: + fast-deep-equal "^3.1.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + +ansi-escapes@^4.2.1: + version "4.3.2" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" + integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== + dependencies: + type-fest "^0.21.3" + +ansi-regex@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" + integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg== + +ansi-regex@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" + integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== + +ansi-styles@^3.2.0, ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== + dependencies: + color-convert "^1.9.0" + +ansi-styles@^4.1.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +argparse@^1.0.7: + version "1.0.10" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" + integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== + dependencies: + sprintf-js "~1.0.2" + +astral-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9" + integrity sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg== + +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +callsites@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" + integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== + +chalk@^2.0.0: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +chalk@^4.0.0, chalk@^4.1.0: + version "4.1.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +chardet@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" + integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== + +cli-cursor@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307" + integrity sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw== + dependencies: + restore-cursor "^3.1.0" + +cli-width@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-3.0.0.tgz#a2f48437a2caa9a22436e794bf071ec9e61cedf6" + integrity sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw== + +color-convert@^1.9.0: + version "1.9.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= + +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= + +cross-spawn@^7.0.2: + version "7.0.3" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" + integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + +debug@^4.0.1: + version "4.3.3" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.3.tgz#04266e0b70a98d4462e6e288e38259213332b664" + integrity sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q== + dependencies: + ms "2.1.2" + +deep-is@^0.1.3: + version "0.1.4" + resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" + integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== + +doctrine@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" + integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== + dependencies: + esutils "^2.0.2" + +emoji-regex@^7.0.1: + version "7.0.3" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" + integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA== + +emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== + +escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= + +eslint-scope@^5.0.0: + version "5.1.1" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" + integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== + dependencies: + esrecurse "^4.3.0" + estraverse "^4.1.1" + +eslint-utils@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-2.1.0.tgz#d2de5e03424e707dc10c74068ddedae708741b27" + integrity sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg== + dependencies: + eslint-visitor-keys "^1.1.0" + +eslint-visitor-keys@^1.1.0, eslint-visitor-keys@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e" + integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ== + +eslint@7.1.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.1.0.tgz#d9a1df25e5b7859b0a3d86bb05f0940ab676a851" + integrity sha512-DfS3b8iHMK5z/YLSme8K5cge168I8j8o1uiVmFCgnnjxZQbCGyraF8bMl7Ju4yfBmCuxD7shOF7eqGkcuIHfsA== + dependencies: + "@babel/code-frame" "^7.0.0" + ajv "^6.10.0" + chalk "^4.0.0" + cross-spawn "^7.0.2" + debug "^4.0.1" + doctrine "^3.0.0" + eslint-scope "^5.0.0" + eslint-utils "^2.0.0" + eslint-visitor-keys "^1.1.0" + espree "^7.0.0" + esquery "^1.2.0" + esutils "^2.0.2" + file-entry-cache "^5.0.1" + functional-red-black-tree "^1.0.1" + glob-parent "^5.0.0" + globals "^12.1.0" + ignore "^4.0.6" + import-fresh "^3.0.0" + imurmurhash "^0.1.4" + inquirer "^7.0.0" + is-glob "^4.0.0" + js-yaml "^3.13.1" + json-stable-stringify-without-jsonify "^1.0.1" + levn "^0.4.1" + lodash "^4.17.14" + minimatch "^3.0.4" + natural-compare "^1.4.0" + optionator "^0.9.1" + progress "^2.0.0" + regexpp "^3.1.0" + semver "^7.2.1" + strip-ansi "^6.0.0" + strip-json-comments "^3.1.0" + table "^5.2.3" + text-table "^0.2.0" + v8-compile-cache "^2.0.3" + +espree@^7.0.0: + version "7.3.1" + resolved "https://registry.yarnpkg.com/espree/-/espree-7.3.1.tgz#f2df330b752c6f55019f8bd89b7660039c1bbbb6" + integrity sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g== + dependencies: + acorn "^7.4.0" + acorn-jsx "^5.3.1" + eslint-visitor-keys "^1.3.0" + +esprima@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" + integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== + +esquery@^1.2.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.4.0.tgz#2148ffc38b82e8c7057dfed48425b3e61f0f24a5" + integrity sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w== + dependencies: + estraverse "^5.1.0" + +esrecurse@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" + integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== + dependencies: + estraverse "^5.2.0" + +estraverse@^4.1.1: + version "4.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" + integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== + +estraverse@^5.1.0, estraverse@^5.2.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" + integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== + +esutils@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" + integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== + +external-editor@^3.0.3: + version "3.1.0" + resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495" + integrity sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew== + dependencies: + chardet "^0.7.0" + iconv-lite "^0.4.24" + tmp "^0.0.33" + +fast-deep-equal@^3.1.1: + version "3.1.3" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" + integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== + +fast-json-stable-stringify@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" + integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== + +fast-levenshtein@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= + +figures@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/figures/-/figures-3.2.0.tgz#625c18bd293c604dc4a8ddb2febf0c88341746af" + integrity sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg== + dependencies: + escape-string-regexp "^1.0.5" + +file-entry-cache@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-5.0.1.tgz#ca0f6efa6dd3d561333fb14515065c2fafdf439c" + integrity sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g== + dependencies: + flat-cache "^2.0.1" + +flat-cache@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-2.0.1.tgz#5d296d6f04bda44a4630a301413bdbc2ec085ec0" + integrity sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA== + dependencies: + flatted "^2.0.0" + rimraf "2.6.3" + write "1.0.3" + +flatted@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.2.tgz#4575b21e2bcee7434aa9be662f4b7b5f9c2b5138" + integrity sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA== + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= + +functional-red-black-tree@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" + integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= + +glob-parent@^5.0.0: + version "5.1.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== + dependencies: + is-glob "^4.0.1" + +glob@^7.1.3: + version "7.2.0" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023" + integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +globals@^12.1.0: + version "12.4.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-12.4.0.tgz#a18813576a41b00a24a97e7f815918c2e19925f8" + integrity sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg== + dependencies: + type-fest "^0.8.1" + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +iconv-lite@^0.4.24: + version "0.4.24" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" + integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== + dependencies: + safer-buffer ">= 2.1.2 < 3" + +ignore@^4.0.6: + version "4.0.6" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" + integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== + +import-fresh@^3.0.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" + integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== + dependencies: + parent-module "^1.0.0" + resolve-from "^4.0.0" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +inquirer@^7.0.0: + version "7.3.3" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-7.3.3.tgz#04d176b2af04afc157a83fd7c100e98ee0aad003" + integrity sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA== + dependencies: + ansi-escapes "^4.2.1" + chalk "^4.1.0" + cli-cursor "^3.1.0" + cli-width "^3.0.0" + external-editor "^3.0.3" + figures "^3.0.0" + lodash "^4.17.19" + mute-stream "0.0.8" + run-async "^2.4.0" + rxjs "^6.6.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + through "^2.3.6" + +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= + +is-fullwidth-code-point@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" + integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= + +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== + +is-glob@^4.0.0, is-glob@^4.0.1: + version "4.0.3" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + dependencies: + is-extglob "^2.1.1" + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= + +js-tokens@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + +js-yaml@^3.13.1: + version "3.14.1" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" + integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== + +json-stable-stringify-without-jsonify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" + integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE= + +levn@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" + integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== + dependencies: + prelude-ls "^1.2.1" + type-check "~0.4.0" + +lodash@^4.17.14, lodash@^4.17.19: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== + +lru-cache@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" + integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== + dependencies: + yallist "^4.0.0" + +mimic-fn@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" + integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== + +minimatch@^3.0.4: + version "3.1.2" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + +minimist@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" + integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== + +mkdirp@^0.5.1: + version "0.5.5" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def" + integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ== + dependencies: + minimist "^1.2.5" + +ms@2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +mute-stream@0.0.8: + version "0.0.8" + resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" + integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA== + +natural-compare@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" + integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= + +once@^1.3.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= + dependencies: + wrappy "1" + +onetime@^5.1.0: + version "5.1.2" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" + integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== + dependencies: + mimic-fn "^2.1.0" + +optionator@^0.9.1: + version "0.9.1" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.1.tgz#4f236a6373dae0566a6d43e1326674f50c291499" + integrity sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw== + dependencies: + deep-is "^0.1.3" + fast-levenshtein "^2.0.6" + levn "^0.4.1" + prelude-ls "^1.2.1" + type-check "^0.4.0" + word-wrap "^1.2.3" + +os-tmpdir@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" + integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= + +parent-module@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" + integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== + dependencies: + callsites "^3.0.0" + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= + +path-key@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" + integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== + +prelude-ls@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" + integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== + +progress@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" + integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== + +punycode@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" + integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== + +regexpp@^3.1.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2" + integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg== + +resolve-from@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" + integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== + +restore-cursor@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e" + integrity sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA== + dependencies: + onetime "^5.1.0" + signal-exit "^3.0.2" + +rimraf@2.6.3: + version "2.6.3" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" + integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA== + dependencies: + glob "^7.1.3" + +run-async@^2.4.0: + version "2.4.1" + resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455" + integrity sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ== + +rxjs@^6.6.0: + version "6.6.7" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.7.tgz#90ac018acabf491bf65044235d5863c4dab804c9" + integrity sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ== + dependencies: + tslib "^1.9.0" + +"safer-buffer@>= 2.1.2 < 3": + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + +semver@^7.2.1: + version "7.3.5" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7" + integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ== + dependencies: + lru-cache "^6.0.0" + +shebang-command@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" + integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== + dependencies: + shebang-regex "^3.0.0" + +shebang-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" + integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== + +signal-exit@^3.0.2: + version "3.0.7" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" + integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== + +slice-ansi@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-2.1.0.tgz#cacd7693461a637a5788d92a7dd4fba068e81636" + integrity sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ== + dependencies: + ansi-styles "^3.2.0" + astral-regex "^1.0.0" + is-fullwidth-code-point "^2.0.0" + +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= + +string-width@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" + integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w== + dependencies: + emoji-regex "^7.0.1" + is-fullwidth-code-point "^2.0.0" + strip-ansi "^5.1.0" + +string-width@^4.1.0: + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +strip-ansi@^5.1.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" + integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA== + dependencies: + ansi-regex "^4.1.0" + +strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-json-comments@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" + integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== + +supports-color@^5.3.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.0" + +supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + +table@^5.2.3: + version "5.4.6" + resolved "https://registry.yarnpkg.com/table/-/table-5.4.6.tgz#1292d19500ce3f86053b05f0e8e7e4a3bb21079e" + integrity sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug== + dependencies: + ajv "^6.10.2" + lodash "^4.17.14" + slice-ansi "^2.1.0" + string-width "^3.0.0" + +text-table@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" + integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= + +through@^2.3.6: + version "2.3.8" + resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" + integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= + +tmp@^0.0.33: + version "0.0.33" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" + integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw== + dependencies: + os-tmpdir "~1.0.2" + +tslib@^1.9.0: + version "1.14.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" + integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== + +type-check@^0.4.0, type-check@~0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" + integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== + dependencies: + prelude-ls "^1.2.1" + +type-fest@^0.21.3: + version "0.21.3" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" + integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== + +type-fest@^0.8.1: + version "0.8.1" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" + integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== + +uri-js@^4.2.2: + version "4.4.1" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" + integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== + dependencies: + punycode "^2.1.0" + +v8-compile-cache@^2.0.3: + version "2.3.0" + resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee" + integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA== + +which@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + +word-wrap@^1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" + integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= + +write@1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/write/-/write-1.0.3.tgz#0800e14523b923a387e415123c865616aae0f5c3" + integrity sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig== + dependencies: + mkdirp "^0.5.1" + +yallist@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" + integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== From 35d1cf85e8d549bb56740ec8fbc1f97f19c6712e Mon Sep 17 00:00:00 2001 From: Salim Blume Date: Sat, 5 Mar 2022 00:32:07 -0600 Subject: [PATCH 19/61] More notification testing --- apps/run/app.js | 8 ++++++++ modules/exstats.js | 46 ++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 50 insertions(+), 4 deletions(-) diff --git a/apps/run/app.js b/apps/run/app.js index 06340526f..8a5d84142 100644 --- a/apps/run/app.js +++ b/apps/run/app.js @@ -74,6 +74,14 @@ for (var i=0;ilayout[e.id].label = e.getString()); if (sb) sb.on('changed', e=>layout[e.id].label = e.getString()); + if (sa) sa.on('notify', (e)=>{ + Bangle.buzz(); + console.log(`notify from ${JSON.stringify(e)}`); + }); + if (sb) sa.on('notify', (e)=>{ + Bangle.buzz(); + console.log(`notify from ${JSON.stringify(e)}`); + }); } // At the bottom put time/GPS state/etc lc.push({ type:"h", filly:1, c:[ diff --git a/modules/exstats.js b/modules/exstats.js index da32ffa12..7a01e9aec 100644 --- a/modules/exstats.js +++ b/modules/exstats.js @@ -166,6 +166,9 @@ exports.getList = function() { exports.getStats = function(statIDs, options) { options = options||{}; options.paceLength = options.paceLength||1000; + options.notifyDistance = options.notifyDistance||0; + options.notifyTime = options.notifyTime||0; + options.notifySteps = options.notifySteps||0; var needGPS,needHRM; // ====================== if (statIDs.includes("time")) { @@ -266,6 +269,18 @@ exports.getStats = function(statIDs, options) { state.curSpeed = 0; state.BPM = 0; state.BPMage = 0; + state.notifyTime = options.notifyTime; + state.notifyDistance = options.notifyDistance; + state.notifySteps = options.notifySteps; + if (options.notifyTime) { + state.nextNotifyTime = state.startTime + options.notifyTime; + } + if (options.notifyDistance) { + state.nextNotifyDist = state.distance + options.notifyDistance; + } + if (options.notifySteps) { + state.nextNotifySteps = state.lastSteps + options.notifySteps; + } } reset(); return { @@ -292,12 +307,35 @@ exports.appendMenuItems = function(menu, settings, saveSettings) { saveSettings(); }, }; + var distNames = ['Off', ...paceNames]; + var distAmts = [0, ...paceAmts]; menu['Ntfy Dist'] = { - min :0, max: paceNames.length-1, - value: Math.max(paceAmts.indexOf(settings.paceLength),0), - format: v => paceNames[v], + min :0, max: distNames.length-1, + value: Math.max(distAmts.indexOf(settings.notifyDistance),0), + format: v => distNames[v], onchange: v => { - state.notifyDistance = paceAmts[v]; + settings.notifyDistance = distAmts[v]; + saveSettings(); + }, + }; + var timeNames = ['Off', '30s', '1min', '2min', '5min', '10min', '30min', '1hr']; + var timeAmts = [0, 30000, 60000, 120000, 300000, 600000, 1800000, 3600000]; + menu['Ntfy Time'] = { + min :0, max: timeNames.length-1, + value: Math.max(timeAmts.indexOf(settings.notifyTime),0), + format: v => timeNames[v], + onchange: v => { + settings.notifyTime = timeAmts[v]; + saveSettings(); + }, + }; + var stepAmts = [0, 100, 500, 1000, 5000, 10000]; + menu['Ntfy Steps'] = { + min :0, max: stepAmts.length-1, + value: Math.max(stepAmts.indexOf(settings.notifySteps),0), + format: v => stepAmts[v], + onchange: v => { + settings.notifySteps = stepAmts[v]; saveSettings(); }, }; From b923423238540380794e08be2c1615e2ea1cdf1d Mon Sep 17 00:00:00 2001 From: Salim Blume Date: Sat, 5 Mar 2022 00:40:23 -0600 Subject: [PATCH 20/61] Cleanup --- apps/run/app.js | 5 +++-- apps/run/settings.js | 6 +++--- modules/exstats.js | 24 ++++++++++++------------ 3 files changed, 18 insertions(+), 17 deletions(-) diff --git a/apps/run/app.js b/apps/run/app.js index 8a5d84142..31fd3336c 100644 --- a/apps/run/app.js +++ b/apps/run/app.js @@ -24,8 +24,9 @@ let settings = Object.assign({ B5: "step", B6: "caden", paceLength: 1000, - notifyDistance: false, - notifyTime: false, + notifyDist: 0, + notifyTime: 0, + notifySteps: 0, }, require("Storage").readJSON("run.json", 1) || {}); var statIDs = [settings.B1,settings.B2,settings.B3,settings.B4,settings.B5,settings.B6].filter(s=>s!==""); var exs = ExStats.getStats(statIDs, settings); diff --git a/apps/run/settings.js b/apps/run/settings.js index 1ac16e734..9a8259f85 100644 --- a/apps/run/settings.js +++ b/apps/run/settings.js @@ -17,8 +17,9 @@ B5: "step", B6: "caden", paceLength: 1000, // TODO: Default to either 1km or 1mi based on locale - notifyDistance: false, - notifyTime: false, + notifyDist: 0, + notifyTime: 0, + notifySteps: 0, }, storage.readJSON(SETTINGS_FILE, 1) || {}); function saveSettings() { storage.write(SETTINGS_FILE, settings) @@ -49,7 +50,6 @@ saveSettings(); } }; - ExStats.appendMenuItems(menu, settings, saveSettings); Object.assign(menu,{ 'Box 1': getBoxChooser("B1"), diff --git a/modules/exstats.js b/modules/exstats.js index 7a01e9aec..d42fa1517 100644 --- a/modules/exstats.js +++ b/modules/exstats.js @@ -64,8 +64,8 @@ var state = { // BPM // beats per minute // BPMage // how many seconds was BPM set? // Notifies: 0 for disabled, otherwise how often to notify in meters and seconds - notifyDistance: 0, notifyTime: 0, notifySteps: 0, - nextNotifyDistance: 0, nextNotifyTime: 0, nextNotifySteps: 0, + notifyDist: 0, notifyTime: 0, notifySteps: 0, + nextNotifyDist: 0, nextNotifyTime: 0, nextNotifySteps: 0, }; // list of active stats (indexed by ID) var stats = {}; @@ -118,9 +118,9 @@ Bangle.on("GPS", function(fix) { if (stats["pacea"]) stats["pacea"].emit("changed",stats["pacea"]); if (stats["pacec"]) stats["pacec"].emit("changed",stats["pacec"]); if (stats["speed"]) stats["speed"].emit("changed",stats["speed"]); - if (state.notifyDistance > 0 && state.nextNotifyDist < stats["dist"]) { + if (state.notifyDist > 0 && state.nextNotifyDist < stats["dist"]) { stats["dist"].emit("notify",stats["dist"]); - state.nextNotifyDist = stats["dist"] + state.notifyDistance; + state.nextNotifyDist = stats["dist"] + state.notifyDist; } }); @@ -158,7 +158,7 @@ exports.getList = function() { /** Instantiate the given list of statistic IDs (see comments at top) options = { paceLength : meters to measure pace over - notifyDistance : meters to notify have elapsed (repeats) + notifyDist : meters to notify have elapsed (repeats) notifyTime : ms to notify have elapsed (repeats) notifySteps : number of steps to notify have elapsed (repeats) } @@ -166,7 +166,7 @@ exports.getList = function() { exports.getStats = function(statIDs, options) { options = options||{}; options.paceLength = options.paceLength||1000; - options.notifyDistance = options.notifyDistance||0; + options.notifyDist = options.notifyDist||0; options.notifyTime = options.notifyTime||0; options.notifySteps = options.notifySteps||0; var needGPS,needHRM; @@ -255,7 +255,7 @@ exports.getStats = function(statIDs, options) { } if (state.notifyTime > 0 && state.nextNotifyTime < stats["time"]) { stats["time"].emit("notify",stats["time"]); - state.nextNotifyTime = stats["time"] + state.notifyDistance; + state.nextNotifyTime = stats["time"] + state.notifyTime; } }, 1000); function reset() { @@ -270,13 +270,13 @@ exports.getStats = function(statIDs, options) { state.BPM = 0; state.BPMage = 0; state.notifyTime = options.notifyTime; - state.notifyDistance = options.notifyDistance; + state.notifyDist = options.notifyDist; state.notifySteps = options.notifySteps; if (options.notifyTime) { state.nextNotifyTime = state.startTime + options.notifyTime; } - if (options.notifyDistance) { - state.nextNotifyDist = state.distance + options.notifyDistance; + if (options.notifyDist) { + state.nextNotifyDist = state.distance + options.notifyDist; } if (options.notifySteps) { state.nextNotifySteps = state.lastSteps + options.notifySteps; @@ -311,10 +311,10 @@ exports.appendMenuItems = function(menu, settings, saveSettings) { var distAmts = [0, ...paceAmts]; menu['Ntfy Dist'] = { min :0, max: distNames.length-1, - value: Math.max(distAmts.indexOf(settings.notifyDistance),0), + value: Math.max(distAmts.indexOf(settings.notifyDist),0), format: v => distNames[v], onchange: v => { - settings.notifyDistance = distAmts[v]; + settings.notifyDist = distAmts[v]; saveSettings(); }, }; From c3fc12dfa2086d342fbd4e4164a7ff4f27fca661 Mon Sep 17 00:00:00 2001 From: Salim Blume Date: Sat, 5 Mar 2022 00:52:46 -0600 Subject: [PATCH 21/61] Chasing down a settings bug --- modules/exstats.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/modules/exstats.js b/modules/exstats.js index d42fa1517..8469fab78 100644 --- a/modules/exstats.js +++ b/modules/exstats.js @@ -299,7 +299,7 @@ exports.appendMenuItems = function(menu, settings, saveSettings) { var paceNames = ["1000m","1 mile","1/2 Mthn", "Marathon",]; var paceAmts = [1000,1609,21098,42195]; menu['Pace'] = { - min :0, max: paceNames.length-1, + min: 0, max: paceNames.length-1, value: Math.max(paceAmts.indexOf(settings.paceLength),0), format: v => paceNames[v], onchange: v => { @@ -310,7 +310,7 @@ exports.appendMenuItems = function(menu, settings, saveSettings) { var distNames = ['Off', ...paceNames]; var distAmts = [0, ...paceAmts]; menu['Ntfy Dist'] = { - min :0, max: distNames.length-1, + min: 0, max: distNames.length-1, value: Math.max(distAmts.indexOf(settings.notifyDist),0), format: v => distNames[v], onchange: v => { @@ -321,7 +321,7 @@ exports.appendMenuItems = function(menu, settings, saveSettings) { var timeNames = ['Off', '30s', '1min', '2min', '5min', '10min', '30min', '1hr']; var timeAmts = [0, 30000, 60000, 120000, 300000, 600000, 1800000, 3600000]; menu['Ntfy Time'] = { - min :0, max: timeNames.length-1, + min: 0, max: timeNames.length-1, value: Math.max(timeAmts.indexOf(settings.notifyTime),0), format: v => timeNames[v], onchange: v => { @@ -331,9 +331,9 @@ exports.appendMenuItems = function(menu, settings, saveSettings) { }; var stepAmts = [0, 100, 500, 1000, 5000, 10000]; menu['Ntfy Steps'] = { - min :0, max: stepAmts.length-1, + min: 0, max: stepAmts.length-1, value: Math.max(stepAmts.indexOf(settings.notifySteps),0), - format: v => stepAmts[v], + format: v => stepAmts[v].toString(), onchange: v => { settings.notifySteps = stepAmts[v]; saveSettings(); From 4b371e1f1817fc7afed5103a3f20705309631dbe Mon Sep 17 00:00:00 2001 From: Salim Blume Date: Sat, 5 Mar 2022 01:02:00 -0600 Subject: [PATCH 22/61] Don't use spread operator --- modules/exstats.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/exstats.js b/modules/exstats.js index 8469fab78..fcee51f5e 100644 --- a/modules/exstats.js +++ b/modules/exstats.js @@ -307,8 +307,8 @@ exports.appendMenuItems = function(menu, settings, saveSettings) { saveSettings(); }, }; - var distNames = ['Off', ...paceNames]; - var distAmts = [0, ...paceAmts]; + var distNames = ['Off', "1000m","1 mile","1/2 Mthn", "Marathon",]; + var distAmts = [0, 1000,1609,21098,42195]; menu['Ntfy Dist'] = { min: 0, max: distNames.length-1, value: Math.max(distAmts.indexOf(settings.notifyDist),0), From 1cf5a077619ee5e75623cba22c857595480ab282 Mon Sep 17 00:00:00 2001 From: Salim Blume Date: Sat, 5 Mar 2022 01:11:42 -0600 Subject: [PATCH 23/61] Debug --- modules/exstats.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/modules/exstats.js b/modules/exstats.js index fcee51f5e..f3a2ced9f 100644 --- a/modules/exstats.js +++ b/modules/exstats.js @@ -272,6 +272,8 @@ exports.getStats = function(statIDs, options) { state.notifyTime = options.notifyTime; state.notifyDist = options.notifyDist; state.notifySteps = options.notifySteps; + console.log("options:"); + console.log(JSON.stringify(options)); if (options.notifyTime) { state.nextNotifyTime = state.startTime + options.notifyTime; } @@ -281,6 +283,8 @@ exports.getStats = function(statIDs, options) { if (options.notifySteps) { state.nextNotifySteps = state.lastSteps + options.notifySteps; } + console.log("state:"); + console.log(JSON.stringify(state)); } reset(); return { @@ -329,11 +333,12 @@ exports.appendMenuItems = function(menu, settings, saveSettings) { saveSettings(); }, }; + var stepNames = ['Off', '100', '500', '1000', '5000', '10000']; var stepAmts = [0, 100, 500, 1000, 5000, 10000]; menu['Ntfy Steps'] = { - min: 0, max: stepAmts.length-1, + min: 0, max: stepNames.length-1, value: Math.max(stepAmts.indexOf(settings.notifySteps),0), - format: v => stepAmts[v].toString(), + format: v => stepNames[v], onchange: v => { settings.notifySteps = stepAmts[v]; saveSettings(); From d0cb22e7df1badec000332930f5217a1e6041b0b Mon Sep 17 00:00:00 2001 From: Salim Blume Date: Sat, 5 Mar 2022 01:21:21 -0600 Subject: [PATCH 24/61] Bug fixes --- modules/exstats.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/modules/exstats.js b/modules/exstats.js index f3a2ced9f..7055b5b35 100644 --- a/modules/exstats.js +++ b/modules/exstats.js @@ -239,7 +239,8 @@ exports.getStats = function(statIDs, options) { setInterval(function() { // run once a second.... if (!state.active) return; // called once a second - var duration = Date.now() - state.startTime; // in ms + var now = Date.now(); + var duration = now - state.startTime; // in ms // set cadence -> steps over last minute state.stepsPerMin = Math.round(60000 * E.sum(state.stepHistory) / Math.min(duration,60000)); if (stats["caden"]) stats["caden"].emit("changed",stats["caden"]); @@ -253,7 +254,7 @@ exports.getStats = function(statIDs, options) { state.BPM = 0; if (stats["bpm"]) stats["bpm"].emit("changed",stats["bpm"]); } - if (state.notifyTime > 0 && state.nextNotifyTime < stats["time"]) { + if (state.notifyTime > 0 && state.nextNotifyTime < now) { stats["time"].emit("notify",stats["time"]); state.nextNotifyTime = stats["time"] + state.notifyTime; } @@ -281,7 +282,7 @@ exports.getStats = function(statIDs, options) { state.nextNotifyDist = state.distance + options.notifyDist; } if (options.notifySteps) { - state.nextNotifySteps = state.lastSteps + options.notifySteps; + state.nextNotifySteps = state.startSteps + options.notifySteps; } console.log("state:"); console.log(JSON.stringify(state)); From 3a6009a96376b985f25b87e33093197486fe0f30 Mon Sep 17 00:00:00 2001 From: Salim Blume Date: Sat, 5 Mar 2022 01:58:46 -0600 Subject: [PATCH 25/61] Add vibration settings and reorg to use object for settings --- apps/run/app.js | 23 ++++++++---- apps/run/settings.js | 46 ++++++++++++++++++++++-- modules/exstats.js | 83 +++++++++++++++++++++++++++----------------- 3 files changed, 111 insertions(+), 41 deletions(-) diff --git a/apps/run/app.js b/apps/run/app.js index 31fd3336c..f689daebe 100644 --- a/apps/run/app.js +++ b/apps/run/app.js @@ -7,8 +7,6 @@ var fontValue = B2 ? "6x15:2" : "6x8:3"; var headingCol = "#888"; var fixCount = 0; var isMenuDisplayed = false; -var nextNotifyTime = 0; -var nextNotifyDist = 0; g.clear(); Bangle.loadWidgets(); @@ -24,9 +22,20 @@ let settings = Object.assign({ B5: "step", B6: "caden", paceLength: 1000, - notifyDist: 0, - notifyTime: 0, - notifySteps: 0, + notify: { + dist: { + value: 0, + notification: [], + }, + steps: { + value: 0, + notification: [], + }, + time: { + value: 0, + notification: [], + }, + }, }, require("Storage").readJSON("run.json", 1) || {}); var statIDs = [settings.B1,settings.B2,settings.B3,settings.B4,settings.B5,settings.B6].filter(s=>s!==""); var exs = ExStats.getStats(statIDs, settings); @@ -76,11 +85,11 @@ for (var i=0;ilayout[e.id].label = e.getString()); if (sb) sb.on('changed', e=>layout[e.id].label = e.getString()); if (sa) sa.on('notify', (e)=>{ - Bangle.buzz(); + settings.notify[id].notifications.forEach((vibTime) => Bangle.buzz(vibTime)); console.log(`notify from ${JSON.stringify(e)}`); }); if (sb) sa.on('notify', (e)=>{ - Bangle.buzz(); + settings.notify[id].notifications.forEach((vibTime) => Bangle.buzz(vibTime)); console.log(`notify from ${JSON.stringify(e)}`); }); } diff --git a/apps/run/settings.js b/apps/run/settings.js index 9a8259f85..8606ef304 100644 --- a/apps/run/settings.js +++ b/apps/run/settings.js @@ -17,9 +17,20 @@ B5: "step", B6: "caden", paceLength: 1000, // TODO: Default to either 1km or 1mi based on locale - notifyDist: 0, - notifyTime: 0, - notifySteps: 0, + notify: { + dist: { + increment: 0, + notification: [], + }, + steps: { + increment: 0, + notification: [], + }, + time: { + increment: 0, + notification: [], + }, + }, }, storage.readJSON(SETTINGS_FILE, 1) || {}); function saveSettings() { storage.write(SETTINGS_FILE, settings) @@ -50,6 +61,35 @@ saveSettings(); } }; + var vibPatterns = [/*LANG*/"Off", ".", "-", "--", "-.-", "---"]; + var vibTimes = [[], [100], [500],[500,500],[500,100,500],[500,500,500]]; + menu[/*LANG*/"Time Notifctn"] = { + value: Math.max(0,vibPatterns.indexOf(settings.timeNotification)), + min: 0, max: vibPatterns.length, + format: v => vibPatterns[v]||"Off", + onchange: v => { + settings.notify.time.notification = vibTimes[v]; + saveSettings(); + } + } + menu[/*LANG*/"Dist Notifctn"] = { + value: Math.max(0,vibPatterns.indexOf(settings.distNotification)), + min: 0, max: vibPatterns.length, + format: v => vibPatterns[v]||"Off", + onchange: v => { + settings.notify.dist.notification = vibTimes[v]; + saveSettings(); + } + } + menu[/*LANG*/"Step Notifctn"] = { + value: Math.max(0,vibPatterns.indexOf(settings.stepNotification)), + min: 0, max: vibPatterns.length, + format: v => vibPatterns[v]||"Off", + onchange: v => { + settings.notify.steps.notification = vibTimes[v]; + saveSettings(); + } + } ExStats.appendMenuItems(menu, settings, saveSettings); Object.assign(menu,{ 'Box 1': getBoxChooser("B1"), diff --git a/modules/exstats.js b/modules/exstats.js index 7055b5b35..c9fa54224 100644 --- a/modules/exstats.js +++ b/modules/exstats.js @@ -63,9 +63,24 @@ var state = { // cadence // steps per minute adjusted if <1 minute // BPM // beats per minute // BPMage // how many seconds was BPM set? - // Notifies: 0 for disabled, otherwise how often to notify in meters and seconds - notifyDist: 0, notifyTime: 0, notifySteps: 0, - nextNotifyDist: 0, nextNotifyTime: 0, nextNotifySteps: 0, + // Notifies: 0 for disabled, otherwise how often to notify in meters, seconds, or steps + notify: { + dist: { + increment: 0, + notification: [], + next: 0, + }, + steps: { + increment: 0, + notification: [], + next: 0, + }, + time: { + increment: 0, + notification: [], + next: 0, + }, + }, }; // list of active stats (indexed by ID) var stats = {}; @@ -118,9 +133,9 @@ Bangle.on("GPS", function(fix) { if (stats["pacea"]) stats["pacea"].emit("changed",stats["pacea"]); if (stats["pacec"]) stats["pacec"].emit("changed",stats["pacec"]); if (stats["speed"]) stats["speed"].emit("changed",stats["speed"]); - if (state.notifyDist > 0 && state.nextNotifyDist < stats["dist"]) { + if (state.notify.dist.increment > 0 && state.notify.dist.next < stats["dist"]) { stats["dist"].emit("notify",stats["dist"]); - state.nextNotifyDist = stats["dist"] + state.notifyDist; + state.notify.dist.next = stats["dist"] + state.notify.dist.increment; } }); @@ -129,9 +144,9 @@ Bangle.on("step", function(steps) { if (stats["step"]) stats["step"].emit("changed",stats["step"]); state.stepHistory[0] += steps-state.lastStepCount; state.lastStepCount = steps; - if (state.notifySteps > 0 && state.nextNotifySteps < steps) { - stats["step"].emit("notify",stats["step"]); - state.nextNotifySteps = steps + state.notifySteps; + if (state.notify.steps.increment > 0 && state.notify.steps.next < steps) { + stats["steps"].emit("notify",stats["steps"]); + state.notify.steps.next = steps + state.notify.steps.increment; } }); Bangle.on("HRM", function(h) { @@ -158,17 +173,25 @@ exports.getList = function() { /** Instantiate the given list of statistic IDs (see comments at top) options = { paceLength : meters to measure pace over - notifyDist : meters to notify have elapsed (repeats) - notifyTime : ms to notify have elapsed (repeats) - notifySteps : number of steps to notify have elapsed (repeats) + notify: { + dist: { + increment: 0 to not notify on distance milestones, otherwise the number of meters to notify after, repeating + }, + steps: { + increment: 0 to not notify on step milestones, otherwise the number of steps to notify after, repeating + }, + time: { + increment: 0 to not notify on time milestones, otherwise the number of milliseconds to notify after, repeating + } + } } */ exports.getStats = function(statIDs, options) { options = options||{}; options.paceLength = options.paceLength||1000; - options.notifyDist = options.notifyDist||0; - options.notifyTime = options.notifyTime||0; - options.notifySteps = options.notifySteps||0; + options.notify.dist.increment = options.notify.dist.increment||0; + options.notify.steps.increment = options.notify.steps.increment||0; + options.notify.time.increment = options.notify.time.increment||0; var needGPS,needHRM; // ====================== if (statIDs.includes("time")) { @@ -254,9 +277,9 @@ exports.getStats = function(statIDs, options) { state.BPM = 0; if (stats["bpm"]) stats["bpm"].emit("changed",stats["bpm"]); } - if (state.notifyTime > 0 && state.nextNotifyTime < now) { + if (state.notify.time.increment > 0 && state.notify.time.next < now) { stats["time"].emit("notify",stats["time"]); - state.nextNotifyTime = stats["time"] + state.notifyTime; + state.notify.time.next = stats["time"] + state.notify.time.increment; } }, 1000); function reset() { @@ -270,19 +293,17 @@ exports.getStats = function(statIDs, options) { state.curSpeed = 0; state.BPM = 0; state.BPMage = 0; - state.notifyTime = options.notifyTime; - state.notifyDist = options.notifyDist; - state.notifySteps = options.notifySteps; + state.notify = options.notify; console.log("options:"); console.log(JSON.stringify(options)); - if (options.notifyTime) { - state.nextNotifyTime = state.startTime + options.notifyTime; + if (options.notify.dist.increment > 0) { + state.notify.dist.next = state.distance + options.notify.dist.increment; } - if (options.notifyDist) { - state.nextNotifyDist = state.distance + options.notifyDist; + if (options.notify.steps.increment > 0) { + state.notify.steps.next = state.startTime + options.notify.steps.increment; } - if (options.notifySteps) { - state.nextNotifySteps = state.startSteps + options.notifySteps; + if (options.notify.time.increment > 0) { + state.notify.time.next = state.startTime + options.notify.time.increment; } console.log("state:"); console.log(JSON.stringify(state)); @@ -316,10 +337,10 @@ exports.appendMenuItems = function(menu, settings, saveSettings) { var distAmts = [0, 1000,1609,21098,42195]; menu['Ntfy Dist'] = { min: 0, max: distNames.length-1, - value: Math.max(distAmts.indexOf(settings.notifyDist),0), + value: Math.max(distAmts.indexOf(settings.notify.dist.increment),0), format: v => distNames[v], onchange: v => { - settings.notifyDist = distAmts[v]; + settings.notify.dist.increment = distAmts[v]; saveSettings(); }, }; @@ -327,10 +348,10 @@ exports.appendMenuItems = function(menu, settings, saveSettings) { var timeAmts = [0, 30000, 60000, 120000, 300000, 600000, 1800000, 3600000]; menu['Ntfy Time'] = { min: 0, max: timeNames.length-1, - value: Math.max(timeAmts.indexOf(settings.notifyTime),0), + value: Math.max(timeAmts.indexOf(settings.notify.time.increment),0), format: v => timeNames[v], onchange: v => { - settings.notifyTime = timeAmts[v]; + settings.notify.time.increment = timeAmts[v]; saveSettings(); }, }; @@ -338,10 +359,10 @@ exports.appendMenuItems = function(menu, settings, saveSettings) { var stepAmts = [0, 100, 500, 1000, 5000, 10000]; menu['Ntfy Steps'] = { min: 0, max: stepNames.length-1, - value: Math.max(stepAmts.indexOf(settings.notifySteps),0), + value: Math.max(stepAmts.indexOf(settings.notify.steps.increment),0), format: v => stepNames[v], onchange: v => { - settings.notifySteps = stepAmts[v]; + settings.notify.steps.increment = stepAmts[v]; saveSettings(); }, }; From dc154ade90bf41474410883ee392a2251ea8a4c0 Mon Sep 17 00:00:00 2001 From: Salim Blume Date: Sat, 5 Mar 2022 02:00:46 -0600 Subject: [PATCH 26/61] Preview vibrations in settings --- apps/run/settings.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/run/settings.js b/apps/run/settings.js index 8606ef304..8daa4533f 100644 --- a/apps/run/settings.js +++ b/apps/run/settings.js @@ -69,6 +69,7 @@ format: v => vibPatterns[v]||"Off", onchange: v => { settings.notify.time.notification = vibTimes[v]; + vibTimes[v].forEach((b) => Bangle.buzz(b)); saveSettings(); } } @@ -78,6 +79,7 @@ format: v => vibPatterns[v]||"Off", onchange: v => { settings.notify.dist.notification = vibTimes[v]; + vibTimes[v].forEach((b) => Bangle.buzz(b)); saveSettings(); } } @@ -87,6 +89,7 @@ format: v => vibPatterns[v]||"Off", onchange: v => { settings.notify.steps.notification = vibTimes[v]; + vibTimes[v].forEach((b) => Bangle.buzz(b)); saveSettings(); } } From 63426d9b97b8c1da975b6573076f8abdf370d79c Mon Sep 17 00:00:00 2001 From: Salim Blume Date: Sat, 5 Mar 2022 02:08:22 -0600 Subject: [PATCH 27/61] Correct initial step notification increment --- modules/exstats.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/exstats.js b/modules/exstats.js index c9fa54224..fd6ca9042 100644 --- a/modules/exstats.js +++ b/modules/exstats.js @@ -300,7 +300,7 @@ exports.getStats = function(statIDs, options) { state.notify.dist.next = state.distance + options.notify.dist.increment; } if (options.notify.steps.increment > 0) { - state.notify.steps.next = state.startTime + options.notify.steps.increment; + state.notify.steps.next = state.startSteps + options.notify.steps.increment; } if (options.notify.time.increment > 0) { state.notify.time.next = state.startTime + options.notify.time.increment; From 4d83a4ce98e8aeef5d22e07b97505fda6e0b3de1 Mon Sep 17 00:00:00 2001 From: Salim Blume Date: Sat, 5 Mar 2022 02:22:14 -0600 Subject: [PATCH 28/61] Bug fixes --- apps/run/app.js | 12 ++++++++++-- apps/run/settings.js | 26 +++++++++++++------------- 2 files changed, 23 insertions(+), 15 deletions(-) diff --git a/apps/run/app.js b/apps/run/app.js index f689daebe..5577c3151 100644 --- a/apps/run/app.js +++ b/apps/run/app.js @@ -85,11 +85,19 @@ for (var i=0;ilayout[e.id].label = e.getString()); if (sb) sb.on('changed', e=>layout[e.id].label = e.getString()); if (sa) sa.on('notify', (e)=>{ - settings.notify[id].notifications.forEach((vibTime) => Bangle.buzz(vibTime)); + settings.notify[e.id].notifications.reduce(function (promise, buzzTime) { + return promise.then(function () { + return Bangle.buzz(buzzTime); + }); + }, Promise.resolve()); console.log(`notify from ${JSON.stringify(e)}`); }); if (sb) sa.on('notify', (e)=>{ - settings.notify[id].notifications.forEach((vibTime) => Bangle.buzz(vibTime)); + settings.notify[e.id].notifications.reduce(function (promise, buzzTime) { + return promise.then(function () { + return Bangle.buzz(buzzTime); + }); + }, Promise.resolve());g console.log(`notify from ${JSON.stringify(e)}`); }); } diff --git a/apps/run/settings.js b/apps/run/settings.js index 8daa4533f..a75cc33c1 100644 --- a/apps/run/settings.js +++ b/apps/run/settings.js @@ -61,20 +61,11 @@ saveSettings(); } }; + ExStats.appendMenuItems(menu, settings, saveSettings); var vibPatterns = [/*LANG*/"Off", ".", "-", "--", "-.-", "---"]; var vibTimes = [[], [100], [500],[500,500],[500,100,500],[500,500,500]]; - menu[/*LANG*/"Time Notifctn"] = { - value: Math.max(0,vibPatterns.indexOf(settings.timeNotification)), - min: 0, max: vibPatterns.length, - format: v => vibPatterns[v]||"Off", - onchange: v => { - settings.notify.time.notification = vibTimes[v]; - vibTimes[v].forEach((b) => Bangle.buzz(b)); - saveSettings(); - } - } menu[/*LANG*/"Dist Notifctn"] = { - value: Math.max(0,vibPatterns.indexOf(settings.distNotification)), + value: Math.max(0,vibPatterns.indexOf(settings.notify.dist.notification)), min: 0, max: vibPatterns.length, format: v => vibPatterns[v]||"Off", onchange: v => { @@ -84,7 +75,7 @@ } } menu[/*LANG*/"Step Notifctn"] = { - value: Math.max(0,vibPatterns.indexOf(settings.stepNotification)), + value: Math.max(0,vibPatterns.indexOf(settings.notify.steps.notification)), min: 0, max: vibPatterns.length, format: v => vibPatterns[v]||"Off", onchange: v => { @@ -93,7 +84,16 @@ saveSettings(); } } - ExStats.appendMenuItems(menu, settings, saveSettings); + menu[/*LANG*/"Time Notifctn"] = { + value: Math.max(0,vibPatterns.indexOf(settings.notify.time.notification)), + min: 0, max: vibPatterns.length, + format: v => vibPatterns[v]||"Off", + onchange: v => { + settings.notify.time.notification = vibTimes[v]; + vibTimes[v].forEach((b) => Bangle.buzz(b)); + saveSettings(); + } + } Object.assign(menu,{ 'Box 1': getBoxChooser("B1"), 'Box 2': getBoxChooser("B2"), From afd4bc697dd8fac9b060051367ad51c7873c36a6 Mon Sep 17 00:00:00 2001 From: Salim Blume Date: Sat, 5 Mar 2022 02:22:33 -0600 Subject: [PATCH 29/61] Typo fix --- apps/run/app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/run/app.js b/apps/run/app.js index 5577c3151..0f8969e70 100644 --- a/apps/run/app.js +++ b/apps/run/app.js @@ -97,7 +97,7 @@ for (var i=0;i Date: Sat, 5 Mar 2022 02:40:40 -0600 Subject: [PATCH 30/61] Fix for step notification, debug for time notification, better buzzes --- apps/run/settings.js | 16 ++++++++++++---- modules/exstats.js | 6 ++++-- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/apps/run/settings.js b/apps/run/settings.js index a75cc33c1..6dcbb05c0 100644 --- a/apps/run/settings.js +++ b/apps/run/settings.js @@ -48,6 +48,14 @@ } } + function sampleBuzz(buzzTimes) { + buzzTimes.reduce(function (promise, buzzTime) { + return promise.then(function () { + return Bangle.buzz(buzzTime); + }); + }, Promise.resolve()); + } + var menu = { '': { 'title': 'Run' }, '< Back': back, @@ -63,14 +71,14 @@ }; ExStats.appendMenuItems(menu, settings, saveSettings); var vibPatterns = [/*LANG*/"Off", ".", "-", "--", "-.-", "---"]; - var vibTimes = [[], [100], [500],[500,500],[500,100,500],[500,500,500]]; + var vibTimes = [[], [[100, 1]], [[500, 1]],[[500, 1], [50, 0], [500, 1]],[[500, 1],[50, 0], [100, 1], [50, 0], [500, 1]],[[500, 1],[50,0],[500, 1],[50,0],[500, 1]]]; menu[/*LANG*/"Dist Notifctn"] = { value: Math.max(0,vibPatterns.indexOf(settings.notify.dist.notification)), min: 0, max: vibPatterns.length, format: v => vibPatterns[v]||"Off", onchange: v => { settings.notify.dist.notification = vibTimes[v]; - vibTimes[v].forEach((b) => Bangle.buzz(b)); + sampleBuzz(vibTimes[v]); saveSettings(); } } @@ -80,7 +88,7 @@ format: v => vibPatterns[v]||"Off", onchange: v => { settings.notify.steps.notification = vibTimes[v]; - vibTimes[v].forEach((b) => Bangle.buzz(b)); + sampleBuzz(vibTimes[v]); saveSettings(); } } @@ -90,7 +98,7 @@ format: v => vibPatterns[v]||"Off", onchange: v => { settings.notify.time.notification = vibTimes[v]; - vibTimes[v].forEach((b) => Bangle.buzz(b)); + sampleBuzz(vibTimes[v]); saveSettings(); } } diff --git a/modules/exstats.js b/modules/exstats.js index fd6ca9042..2a22f9974 100644 --- a/modules/exstats.js +++ b/modules/exstats.js @@ -145,7 +145,7 @@ Bangle.on("step", function(steps) { state.stepHistory[0] += steps-state.lastStepCount; state.lastStepCount = steps; if (state.notify.steps.increment > 0 && state.notify.steps.next < steps) { - stats["steps"].emit("notify",stats["steps"]); + stats["step"].emit("notify",stats["step"]); state.notify.steps.next = steps + state.notify.steps.increment; } }); @@ -277,9 +277,11 @@ exports.getStats = function(statIDs, options) { state.BPM = 0; if (stats["bpm"]) stats["bpm"].emit("changed",stats["bpm"]); } + console.log(now); + console.log(state.notify.time.next); if (state.notify.time.increment > 0 && state.notify.time.next < now) { stats["time"].emit("notify",stats["time"]); - state.notify.time.next = stats["time"] + state.notify.time.increment; + state.notify.time.next = now + state.notify.time.increment; } }, 1000); function reset() { From f5c50a7e1e916065ec353f33cc6d053002450341 Mon Sep 17 00:00:00 2001 From: Salim Blume Date: Sat, 5 Mar 2022 02:54:08 -0600 Subject: [PATCH 31/61] Fix for step notification --- apps/run/settings.js | 4 ++-- modules/exstats.js | 14 +++++++------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/apps/run/settings.js b/apps/run/settings.js index 6dcbb05c0..fe54ac6fd 100644 --- a/apps/run/settings.js +++ b/apps/run/settings.js @@ -83,11 +83,11 @@ } } menu[/*LANG*/"Step Notifctn"] = { - value: Math.max(0,vibPatterns.indexOf(settings.notify.steps.notification)), + value: Math.max(0,vibPatterns.indexOf(settings.notify.step.notification)), min: 0, max: vibPatterns.length, format: v => vibPatterns[v]||"Off", onchange: v => { - settings.notify.steps.notification = vibTimes[v]; + settings.notify.step.notification = vibTimes[v]; sampleBuzz(vibTimes[v]); saveSettings(); } diff --git a/modules/exstats.js b/modules/exstats.js index 2a22f9974..9e7c87e4c 100644 --- a/modules/exstats.js +++ b/modules/exstats.js @@ -144,9 +144,9 @@ Bangle.on("step", function(steps) { if (stats["step"]) stats["step"].emit("changed",stats["step"]); state.stepHistory[0] += steps-state.lastStepCount; state.lastStepCount = steps; - if (state.notify.steps.increment > 0 && state.notify.steps.next < steps) { + if (state.notify.step.increment > 0 && state.notify.step.next < steps) { stats["step"].emit("notify",stats["step"]); - state.notify.steps.next = steps + state.notify.steps.increment; + state.notify.step.next = steps + state.notify.step.increment; } }); Bangle.on("HRM", function(h) { @@ -190,7 +190,7 @@ exports.getStats = function(statIDs, options) { options = options||{}; options.paceLength = options.paceLength||1000; options.notify.dist.increment = options.notify.dist.increment||0; - options.notify.steps.increment = options.notify.steps.increment||0; + options.notify.step.increment = options.notify.step.increment||0; options.notify.time.increment = options.notify.time.increment||0; var needGPS,needHRM; // ====================== @@ -301,8 +301,8 @@ exports.getStats = function(statIDs, options) { if (options.notify.dist.increment > 0) { state.notify.dist.next = state.distance + options.notify.dist.increment; } - if (options.notify.steps.increment > 0) { - state.notify.steps.next = state.startSteps + options.notify.steps.increment; + if (options.notify.step.increment > 0) { + state.notify.step.next = state.startSteps + options.notify.step.increment; } if (options.notify.time.increment > 0) { state.notify.time.next = state.startTime + options.notify.time.increment; @@ -361,10 +361,10 @@ exports.appendMenuItems = function(menu, settings, saveSettings) { var stepAmts = [0, 100, 500, 1000, 5000, 10000]; menu['Ntfy Steps'] = { min: 0, max: stepNames.length-1, - value: Math.max(stepAmts.indexOf(settings.notify.steps.increment),0), + value: Math.max(stepAmts.indexOf(settings.notify.step.increment),0), format: v => stepNames[v], onchange: v => { - settings.notify.steps.increment = stepAmts[v]; + settings.notify.step.increment = stepAmts[v]; saveSettings(); }, }; From efb136e194b6cd22d4fe205e52ff2783a64da3c0 Mon Sep 17 00:00:00 2001 From: Salim Blume Date: Sat, 5 Mar 2022 02:59:13 -0600 Subject: [PATCH 32/61] Potential fix for time notification --- apps/run/app.js | 40 ++++++++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/apps/run/app.js b/apps/run/app.js index 0f8969e70..bf45a196b 100644 --- a/apps/run/app.js +++ b/apps/run/app.js @@ -84,22 +84,6 @@ for (var i=0;ilayout[e.id].label = e.getString()); if (sb) sb.on('changed', e=>layout[e.id].label = e.getString()); - if (sa) sa.on('notify', (e)=>{ - settings.notify[e.id].notifications.reduce(function (promise, buzzTime) { - return promise.then(function () { - return Bangle.buzz(buzzTime); - }); - }, Promise.resolve()); - console.log(`notify from ${JSON.stringify(e)}`); - }); - if (sb) sa.on('notify', (e)=>{ - settings.notify[e.id].notifications.reduce(function (promise, buzzTime) { - return promise.then(function () { - return Bangle.buzz(buzzTime); - }); - }, Promise.resolve()); - console.log(`notify from ${JSON.stringify(e)}`); - }); } // At the bottom put time/GPS state/etc lc.push({ type:"h", filly:1, c:[ @@ -114,6 +98,30 @@ var layout = new Layout( { delete lc; layout.render(); +function configureNotification(stat) { + stat.on('notify', (e)=>{ + settings.notify[stat.id].notifications.reduce(function (promise, buzzTime) { + return promise.then(function () { + return Bangle.buzz(buzzTime); + }); + }, Promise.resolve()); + console.log(`notify from ${JSON.stringify(e)}`); + }); +} + +// TODO: Should really loop over Object.keys(settings.notify) +if (settings.notify.dist.increment > 0) { + configureNotification(exs.stats.dist); +} + +if (settings.notify.step.increment > 0) { + configureNotification(exs.stats.step); +} + +if (settings.notify.time.increment > 0) { + configureNotification(exs.stats.time); +} + // Handle GPS state change for icon Bangle.on("GPS", function(fix) { layout.gps.bgCol = fix.fix ? "#0f0" : "#f00"; From 9c17fe8c5dd66ca9f62f345e3c0fb4f84cbda87c Mon Sep 17 00:00:00 2001 From: Salim Blume Date: Sat, 5 Mar 2022 03:01:02 -0600 Subject: [PATCH 33/61] More pause in vibration times --- apps/run/settings.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/apps/run/settings.js b/apps/run/settings.js index fe54ac6fd..d50bc4889 100644 --- a/apps/run/settings.js +++ b/apps/run/settings.js @@ -71,7 +71,13 @@ }; ExStats.appendMenuItems(menu, settings, saveSettings); var vibPatterns = [/*LANG*/"Off", ".", "-", "--", "-.-", "---"]; - var vibTimes = [[], [[100, 1]], [[500, 1]],[[500, 1], [50, 0], [500, 1]],[[500, 1],[50, 0], [100, 1], [50, 0], [500, 1]],[[500, 1],[50,0],[500, 1],[50,0],[500, 1]]]; + var vibTimes = [ + [], + [[100, 1]], + [[500, 1]],[[500, 1], [100, 0], [500, 1]], + [[500, 1],[100, 0], [100, 1], [100, 0], [500, 1]], + [[500, 1],[100, 0],[500, 1],[100, 0],[500, 1]], + ]; menu[/*LANG*/"Dist Notifctn"] = { value: Math.max(0,vibPatterns.indexOf(settings.notify.dist.notification)), min: 0, max: vibPatterns.length, From 50ca281500c61b9725d0ed86a0cbaa29f50fb496 Mon Sep 17 00:00:00 2001 From: Salim Blume Date: Sat, 5 Mar 2022 03:07:10 -0600 Subject: [PATCH 34/61] Settings fix --- apps/run/app.js | 2 +- apps/run/settings.js | 2 +- modules/exstats.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/run/app.js b/apps/run/app.js index bf45a196b..fa1d41729 100644 --- a/apps/run/app.js +++ b/apps/run/app.js @@ -27,7 +27,7 @@ let settings = Object.assign({ value: 0, notification: [], }, - steps: { + step: { value: 0, notification: [], }, diff --git a/apps/run/settings.js b/apps/run/settings.js index d50bc4889..67f5e3d83 100644 --- a/apps/run/settings.js +++ b/apps/run/settings.js @@ -22,7 +22,7 @@ increment: 0, notification: [], }, - steps: { + step: { increment: 0, notification: [], }, diff --git a/modules/exstats.js b/modules/exstats.js index 9e7c87e4c..5eb0dc2be 100644 --- a/modules/exstats.js +++ b/modules/exstats.js @@ -177,7 +177,7 @@ exports.getList = function() { dist: { increment: 0 to not notify on distance milestones, otherwise the number of meters to notify after, repeating }, - steps: { + step: { increment: 0 to not notify on step milestones, otherwise the number of steps to notify after, repeating }, time: { From e823ae8496cd7e5c9fae084a79f9d679600dbc4b Mon Sep 17 00:00:00 2001 From: Salim Blume Date: Sat, 5 Mar 2022 03:15:58 -0600 Subject: [PATCH 35/61] Fix for nested options not set yet --- modules/exstats.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/exstats.js b/modules/exstats.js index 5eb0dc2be..82bb40c2f 100644 --- a/modules/exstats.js +++ b/modules/exstats.js @@ -189,9 +189,9 @@ exports.getList = function() { exports.getStats = function(statIDs, options) { options = options||{}; options.paceLength = options.paceLength||1000; - options.notify.dist.increment = options.notify.dist.increment||0; - options.notify.step.increment = options.notify.step.increment||0; - options.notify.time.increment = options.notify.time.increment||0; + options.notify.dist.increment = (options.notify && options.notify.dist && options.notify.dist.increment)||0; + options.notify.step.increment = (options.notify && options.notify.step && options.notify.step.increment)||0; + options.notify.time.increment = (options.notify && options.notify.time && options.notify.time.increment)||0; var needGPS,needHRM; // ====================== if (statIDs.includes("time")) { From 8a7b30cf6cb1d5c6265f3f4784a4e701d9377efc Mon Sep 17 00:00:00 2001 From: Salim Blume Date: Sat, 5 Mar 2022 03:28:23 -0600 Subject: [PATCH 36/61] Cleanup --- apps/run/app.js | 6 +++--- apps/run/settings.js | 15 ++++++++------- modules/exstats.js | 9 --------- 3 files changed, 11 insertions(+), 19 deletions(-) diff --git a/apps/run/app.js b/apps/run/app.js index fa1d41729..2f4c44f17 100644 --- a/apps/run/app.js +++ b/apps/run/app.js @@ -25,15 +25,15 @@ let settings = Object.assign({ notify: { dist: { value: 0, - notification: [], + notifications: [], }, step: { value: 0, - notification: [], + notifications: [], }, time: { value: 0, - notification: [], + notifications: [], }, }, }, require("Storage").readJSON("run.json", 1) || {}); diff --git a/apps/run/settings.js b/apps/run/settings.js index 67f5e3d83..e0b03256c 100644 --- a/apps/run/settings.js +++ b/apps/run/settings.js @@ -20,15 +20,15 @@ notify: { dist: { increment: 0, - notification: [], + notifications: [], }, step: { increment: 0, - notification: [], + notifications: [], }, time: { increment: 0, - notification: [], + notifications: [], }, }, }, storage.readJSON(SETTINGS_FILE, 1) || {}); @@ -48,10 +48,10 @@ } } - function sampleBuzz(buzzTimes) { - buzzTimes.reduce(function (promise, buzzTime) { + function sampleBuzz(buzzPatterns) { + buzzPatterns.reduce(function (promise, buzzPattern) { return promise.then(function () { - return Bangle.buzz(buzzTime); + return Bangle.buzz(buzzPattern[0], buzzPattern[1]); }); }, Promise.resolve()); } @@ -74,7 +74,8 @@ var vibTimes = [ [], [[100, 1]], - [[500, 1]],[[500, 1], [100, 0], [500, 1]], + [[500, 1]], + [[500, 1], [100, 0], [500, 1]], [[500, 1],[100, 0], [100, 1], [100, 0], [500, 1]], [[500, 1],[100, 0],[500, 1],[100, 0],[500, 1]], ]; diff --git a/modules/exstats.js b/modules/exstats.js index 82bb40c2f..e5a1acd7d 100644 --- a/modules/exstats.js +++ b/modules/exstats.js @@ -67,17 +67,14 @@ var state = { notify: { dist: { increment: 0, - notification: [], next: 0, }, steps: { increment: 0, - notification: [], next: 0, }, time: { increment: 0, - notification: [], next: 0, }, }, @@ -277,8 +274,6 @@ exports.getStats = function(statIDs, options) { state.BPM = 0; if (stats["bpm"]) stats["bpm"].emit("changed",stats["bpm"]); } - console.log(now); - console.log(state.notify.time.next); if (state.notify.time.increment > 0 && state.notify.time.next < now) { stats["time"].emit("notify",stats["time"]); state.notify.time.next = now + state.notify.time.increment; @@ -296,8 +291,6 @@ exports.getStats = function(statIDs, options) { state.BPM = 0; state.BPMage = 0; state.notify = options.notify; - console.log("options:"); - console.log(JSON.stringify(options)); if (options.notify.dist.increment > 0) { state.notify.dist.next = state.distance + options.notify.dist.increment; } @@ -307,8 +300,6 @@ exports.getStats = function(statIDs, options) { if (options.notify.time.increment > 0) { state.notify.time.next = state.startTime + options.notify.time.increment; } - console.log("state:"); - console.log(JSON.stringify(state)); } reset(); return { From 96ad9b3e01e27b6e22e5816a449746fb4359d950 Mon Sep 17 00:00:00 2001 From: Salim Blume Date: Sat, 5 Mar 2022 03:29:42 -0600 Subject: [PATCH 37/61] Obey buzz intensity --- apps/run/app.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/run/app.js b/apps/run/app.js index 2f4c44f17..cb9beac5f 100644 --- a/apps/run/app.js +++ b/apps/run/app.js @@ -100,9 +100,9 @@ layout.render(); function configureNotification(stat) { stat.on('notify', (e)=>{ - settings.notify[stat.id].notifications.reduce(function (promise, buzzTime) { + settings.notify[stat.id].notifications.reduce(function (promise, buzzPattern) { return promise.then(function () { - return Bangle.buzz(buzzTime); + return Bangle.buzz(buzzPattern[0], buzzPattern[1]); }); }, Promise.resolve()); console.log(`notify from ${JSON.stringify(e)}`); From 4810eefe08cb6c7ebc7c979a1b7aafa0520c12a4 Mon Sep 17 00:00:00 2001 From: Salim Blume Date: Sat, 5 Mar 2022 03:42:07 -0600 Subject: [PATCH 38/61] More tweaks --- apps/run/app.js | 3 +-- apps/run/settings.js | 8 ++++---- modules/exstats.js | 6 +++--- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/apps/run/app.js b/apps/run/app.js index cb9beac5f..e0eaf00af 100644 --- a/apps/run/app.js +++ b/apps/run/app.js @@ -100,12 +100,11 @@ layout.render(); function configureNotification(stat) { stat.on('notify', (e)=>{ - settings.notify[stat.id].notifications.reduce(function (promise, buzzPattern) { + settings.notify[e.id].notifications.reduce(function (promise, buzzPattern) { return promise.then(function () { return Bangle.buzz(buzzPattern[0], buzzPattern[1]); }); }, Promise.resolve()); - console.log(`notify from ${JSON.stringify(e)}`); }); } diff --git a/apps/run/settings.js b/apps/run/settings.js index e0b03256c..e386106e0 100644 --- a/apps/run/settings.js +++ b/apps/run/settings.js @@ -49,7 +49,7 @@ } function sampleBuzz(buzzPatterns) { - buzzPatterns.reduce(function (promise, buzzPattern) { + return buzzPatterns.reduce(function (promise, buzzPattern) { return promise.then(function () { return Bangle.buzz(buzzPattern[0], buzzPattern[1]); }); @@ -75,9 +75,9 @@ [], [[100, 1]], [[500, 1]], - [[500, 1], [100, 0], [500, 1]], - [[500, 1],[100, 0], [100, 1], [100, 0], [500, 1]], - [[500, 1],[100, 0],[500, 1],[100, 0],[500, 1]], + [[500, 1], [200, 0], [500, 1]], + [[500, 1],[200, 0], [100, 1], [200, 0], [500, 1]], + [[500, 1],[200, 0],[500, 1],[200, 0],[500, 1]], ]; menu[/*LANG*/"Dist Notifctn"] = { value: Math.max(0,vibPatterns.indexOf(settings.notify.dist.notification)), diff --git a/modules/exstats.js b/modules/exstats.js index e5a1acd7d..8b097a198 100644 --- a/modules/exstats.js +++ b/modules/exstats.js @@ -130,7 +130,7 @@ Bangle.on("GPS", function(fix) { if (stats["pacea"]) stats["pacea"].emit("changed",stats["pacea"]); if (stats["pacec"]) stats["pacec"].emit("changed",stats["pacec"]); if (stats["speed"]) stats["speed"].emit("changed",stats["speed"]); - if (state.notify.dist.increment > 0 && state.notify.dist.next < stats["dist"]) { + if (state.notify.dist.increment > 0 && state.notify.dist.next <= stats["dist"]) { stats["dist"].emit("notify",stats["dist"]); state.notify.dist.next = stats["dist"] + state.notify.dist.increment; } @@ -141,7 +141,7 @@ Bangle.on("step", function(steps) { if (stats["step"]) stats["step"].emit("changed",stats["step"]); state.stepHistory[0] += steps-state.lastStepCount; state.lastStepCount = steps; - if (state.notify.step.increment > 0 && state.notify.step.next < steps) { + if (state.notify.step.increment > 0 && state.notify.step.next <= steps) { stats["step"].emit("notify",stats["step"]); state.notify.step.next = steps + state.notify.step.increment; } @@ -274,7 +274,7 @@ exports.getStats = function(statIDs, options) { state.BPM = 0; if (stats["bpm"]) stats["bpm"].emit("changed",stats["bpm"]); } - if (state.notify.time.increment > 0 && state.notify.time.next < now) { + if (state.notify.time.increment > 0 && state.notify.time.next <= now) { stats["time"].emit("notify",stats["time"]); state.notify.time.next = now + state.notify.time.increment; } From 2bd1da264fa4bbe9971ed297d647e69016e24a81 Mon Sep 17 00:00:00 2001 From: Salim Blume Date: Sat, 5 Mar 2022 12:35:39 -0600 Subject: [PATCH 39/61] Debug --- apps/run/app.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/run/app.js b/apps/run/app.js index e0eaf00af..ba8090f51 100644 --- a/apps/run/app.js +++ b/apps/run/app.js @@ -101,10 +101,12 @@ layout.render(); function configureNotification(stat) { stat.on('notify', (e)=>{ settings.notify[e.id].notifications.reduce(function (promise, buzzPattern) { + console.log(buzzPattern); return promise.then(function () { return Bangle.buzz(buzzPattern[0], buzzPattern[1]); }); - }, Promise.resolve()); + }, Promise.resolve()) + .then(console.log); }); } From 6ffa4b28b3ef399607fcef767c02fefb2806d8f9 Mon Sep 17 00:00:00 2001 From: Salim Blume Date: Sat, 5 Mar 2022 14:05:48 -0600 Subject: [PATCH 40/61] Menu fixes and tweaking vibe options --- apps/run/settings.js | 9 +++++---- modules/exstats.js | 41 ++++++++++++++++++++++++++--------------- 2 files changed, 31 insertions(+), 19 deletions(-) diff --git a/apps/run/settings.js b/apps/run/settings.js index e386106e0..405cb03b8 100644 --- a/apps/run/settings.js +++ b/apps/run/settings.js @@ -70,14 +70,15 @@ } }; ExStats.appendMenuItems(menu, settings, saveSettings); + ExStats.appendNotifyMenuItems(menu, settings, saveSettings); var vibPatterns = [/*LANG*/"Off", ".", "-", "--", "-.-", "---"]; var vibTimes = [ [], [[100, 1]], - [[500, 1]], - [[500, 1], [200, 0], [500, 1]], - [[500, 1],[200, 0], [100, 1], [200, 0], [500, 1]], - [[500, 1],[200, 0],[500, 1],[200, 0],[500, 1]], + [[300, 1]], + [[300, 1], [200, 0], [300, 1]], + [[300, 1],[200, 0], [100, 1], [200, 0], [300, 1]], + [[300, 1],[200, 0],[300, 1],[200, 0],[300, 1]], ]; menu[/*LANG*/"Dist Notifctn"] = { value: Math.max(0,vibPatterns.indexOf(settings.notify.dist.notification)), diff --git a/modules/exstats.js b/modules/exstats.js index 8b097a198..b106622d0 100644 --- a/modules/exstats.js +++ b/modules/exstats.js @@ -48,6 +48,15 @@ var menu = { ... }; ExStats.appendMenuItems(menu, settings, saveSettingsFunction); E.showMenu(menu); +// Additionally, if your app makes use of the stat notifications, you can display additional menu +// settings for configuring when to notify (note the added line in the example below)W + +var menu = { ... }; +ExStats.appendMenuItems(menu, settings, saveSettingsFunction); +ExStats.appendNotifyMenuItems(menu, settings, saveSettingsFunction); +E.showMenu(menu); + + */ var state = { active : false, // are we working or not? @@ -315,17 +324,19 @@ exports.getStats = function(statIDs, options) { }; exports.appendMenuItems = function(menu, settings, saveSettings) { - var paceNames = ["1000m","1 mile","1/2 Mthn", "Marathon",]; - var paceAmts = [1000,1609,21098,42195]; + var paceNames = ["1000m", "1 mile", "1/2 Mthn", "Marathon",]; + var paceAmts = [1000, 1609, 21098, 42195]; menu['Pace'] = { - min: 0, max: paceNames.length-1, - value: Math.max(paceAmts.indexOf(settings.paceLength),0), + min: 0, max: paceNames.length - 1, + value: Math.max(paceAmts.indexOf(settings.paceLength), 0), format: v => paceNames[v], onchange: v => { settings.paceLength = paceAmts[v]; saveSettings(); }, }; +} +exports.appendNotifyMenuItems = function(menu, settings, saveSettings) { var distNames = ['Off', "1000m","1 mile","1/2 Mthn", "Marathon",]; var distAmts = [0, 1000,1609,21098,42195]; menu['Ntfy Dist'] = { @@ -337,17 +348,6 @@ exports.appendMenuItems = function(menu, settings, saveSettings) { saveSettings(); }, }; - var timeNames = ['Off', '30s', '1min', '2min', '5min', '10min', '30min', '1hr']; - var timeAmts = [0, 30000, 60000, 120000, 300000, 600000, 1800000, 3600000]; - menu['Ntfy Time'] = { - min: 0, max: timeNames.length-1, - value: Math.max(timeAmts.indexOf(settings.notify.time.increment),0), - format: v => timeNames[v], - onchange: v => { - settings.notify.time.increment = timeAmts[v]; - saveSettings(); - }, - }; var stepNames = ['Off', '100', '500', '1000', '5000', '10000']; var stepAmts = [0, 100, 500, 1000, 5000, 10000]; menu['Ntfy Steps'] = { @@ -359,4 +359,15 @@ exports.appendMenuItems = function(menu, settings, saveSettings) { saveSettings(); }, }; + var timeNames = ['Off', '30s', '1min', '2min', '5min', '10min', '30min', '1hr']; + var timeAmts = [0, 30000, 60000, 120000, 300000, 600000, 1800000, 3600000]; + menu['Ntfy Time'] = { + min: 0, max: timeNames.length-1, + value: Math.max(timeAmts.indexOf(settings.notify.time.increment),0), + format: v => timeNames[v], + onchange: v => { + settings.notify.time.increment = timeAmts[v]; + saveSettings(); + }, + }; }; From a2a16443d69e67c13a49bc0cd84571a476b2297e Mon Sep 17 00:00:00 2001 From: Salim Blume Date: Sat, 5 Mar 2022 14:07:35 -0600 Subject: [PATCH 41/61] Tweak menu option labels --- apps/run/settings.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/run/settings.js b/apps/run/settings.js index 405cb03b8..cc2ba46b8 100644 --- a/apps/run/settings.js +++ b/apps/run/settings.js @@ -80,7 +80,7 @@ [[300, 1],[200, 0], [100, 1], [200, 0], [300, 1]], [[300, 1],[200, 0],[300, 1],[200, 0],[300, 1]], ]; - menu[/*LANG*/"Dist Notifctn"] = { + menu[/*LANG*/"Dist Ntfy Ptrn"] = { value: Math.max(0,vibPatterns.indexOf(settings.notify.dist.notification)), min: 0, max: vibPatterns.length, format: v => vibPatterns[v]||"Off", @@ -90,7 +90,7 @@ saveSettings(); } } - menu[/*LANG*/"Step Notifctn"] = { + menu[/*LANG*/"Step Ntfy Ptrn"] = { value: Math.max(0,vibPatterns.indexOf(settings.notify.step.notification)), min: 0, max: vibPatterns.length, format: v => vibPatterns[v]||"Off", @@ -100,7 +100,7 @@ saveSettings(); } } - menu[/*LANG*/"Time Notifctn"] = { + menu[/*LANG*/"Time Ntfy Ptrn"] = { value: Math.max(0,vibPatterns.indexOf(settings.notify.time.notification)), min: 0, max: vibPatterns.length, format: v => vibPatterns[v]||"Off", From 525980d7f7884e96a484a34a842d7dac24d406f5 Mon Sep 17 00:00:00 2001 From: Salim Blume Date: Sat, 5 Mar 2022 14:30:58 -0600 Subject: [PATCH 42/61] Cleanup, fix for starting time before track, and some debug --- apps/run/app.js | 47 +++++++++++++++++++++++------------------------ 1 file changed, 23 insertions(+), 24 deletions(-) diff --git a/apps/run/app.js b/apps/run/app.js index ba8090f51..deeaec45e 100644 --- a/apps/run/app.js +++ b/apps/run/app.js @@ -44,18 +44,10 @@ var exs = ExStats.getStats(statIDs, settings); // Called to start/stop running function onStartStop() { var running = !exs.state.active; - if (running) { - exs.start(); - } else { - exs.stop(); - } - layout.button.label = running ? "STOP" : "START"; - layout.status.label = running ? "RUN" : "STOP"; - layout.status.bgCol = running ? "#0f0" : "#f00"; - // if stopping running, don't clear state - // so we can at least refer to what we've done - layout.render(); + // start/stop recording + // Do this first in case recorder needs to prompt for + // an overwrite before we begin things like the total time if (settings.record && WIDGETS["recorder"]) { if (running) { isMenuDisplayed = true; @@ -68,6 +60,18 @@ function onStartStop() { WIDGETS["recorder"].setRecording(false); } } + + if (running) { + exs.start(); + } else { + exs.stop(); + } + layout.button.label = running ? "STOP" : "START"; + layout.status.label = running ? "RUN" : "STOP"; + layout.status.bgCol = running ? "#0f0" : "#f00"; + // if stopping running, don't clear state + // so we can at least refer to what we've done + layout.render(); } var lc = []; @@ -100,28 +104,23 @@ layout.render(); function configureNotification(stat) { stat.on('notify', (e)=>{ + console.log(`Got notify from ${e}`); settings.notify[e.id].notifications.reduce(function (promise, buzzPattern) { console.log(buzzPattern); return promise.then(function () { - return Bangle.buzz(buzzPattern[0], buzzPattern[1]); + console.log('Should buzz now'); + return Bangle.buzz(buzzPattern[0], buzzPattern[1]); }); }, Promise.resolve()) .then(console.log); }); } -// TODO: Should really loop over Object.keys(settings.notify) -if (settings.notify.dist.increment > 0) { - configureNotification(exs.stats.dist); -} - -if (settings.notify.step.increment > 0) { - configureNotification(exs.stats.step); -} - -if (settings.notify.time.increment > 0) { - configureNotification(exs.stats.time); -} +Object.keys(settings.notify).forEach((statType) => { + if (settings.notify[statType].increment > 0) { + configureNotification(exs.stats[statType]); + } +}); // Handle GPS state change for icon Bangle.on("GPS", function(fix) { From 2edad3887f734af66464636117ecb671e070fda7 Mon Sep 17 00:00:00 2001 From: Salim Blume Date: Sat, 5 Mar 2022 14:38:23 -0600 Subject: [PATCH 43/61] Menu and typo fixes --- apps/run/app.js | 45 ++++++++++++++++++++++++++------------------ apps/run/settings.js | 12 ++++++------ 2 files changed, 33 insertions(+), 24 deletions(-) diff --git a/apps/run/app.js b/apps/run/app.js index deeaec45e..c717e12fd 100644 --- a/apps/run/app.js +++ b/apps/run/app.js @@ -44,6 +44,7 @@ var exs = ExStats.getStats(statIDs, settings); // Called to start/stop running function onStartStop() { var running = !exs.state.active; + var prepPromises = []; // start/stop recording // Do this first in case recorder needs to prompt for @@ -51,27 +52,34 @@ function onStartStop() { if (settings.record && WIDGETS["recorder"]) { if (running) { isMenuDisplayed = true; - WIDGETS["recorder"].setRecording(true).then(() => { - isMenuDisplayed = false; - layout.forgetLazyState(); - layout.render(); - }); + prepPromises.push( + WIDGETS["recorder"].setRecording(true).then(() => { + isMenuDisplayed = false; + layout.forgetLazyState(); + layout.render(); + }) + ); } else { - WIDGETS["recorder"].setRecording(false); + prepPromises.push( + WIDGETS["recorder"].setRecording(false) + ); } } - if (running) { - exs.start(); - } else { - exs.stop(); - } - layout.button.label = running ? "STOP" : "START"; - layout.status.label = running ? "RUN" : "STOP"; - layout.status.bgCol = running ? "#0f0" : "#f00"; - // if stopping running, don't clear state - // so we can at least refer to what we've done - layout.render(); + Promise.all(prepPromises) + .then(() => { + if (running) { + exs.start(); + } else { + exs.stop(); + } + layout.button.label = running ? "STOP" : "START"; + layout.status.label = running ? "RUN" : "STOP"; + layout.status.bgCol = running ? "#0f0" : "#f00"; + // if stopping running, don't clear state + // so we can at least refer to what we've done + layout.render(); + }); } var lc = []; @@ -104,7 +112,8 @@ layout.render(); function configureNotification(stat) { stat.on('notify', (e)=>{ - console.log(`Got notify from ${e}`); + console.log(`Got notify from ${JSON.stringify(e)}`); + console.log(JSON.stringify(settings.notify[e.id])); settings.notify[e.id].notifications.reduce(function (promise, buzzPattern) { console.log(buzzPattern); return promise.then(function () { diff --git a/apps/run/settings.js b/apps/run/settings.js index cc2ba46b8..a5faece9d 100644 --- a/apps/run/settings.js +++ b/apps/run/settings.js @@ -81,31 +81,31 @@ [[300, 1],[200, 0],[300, 1],[200, 0],[300, 1]], ]; menu[/*LANG*/"Dist Ntfy Ptrn"] = { - value: Math.max(0,vibPatterns.indexOf(settings.notify.dist.notification)), + value: Math.max(0,vibPatterns.indexOf(settings.notify.dist.notifications)), min: 0, max: vibPatterns.length, format: v => vibPatterns[v]||"Off", onchange: v => { - settings.notify.dist.notification = vibTimes[v]; + settings.notify.dist.notifications = vibTimes[v]; sampleBuzz(vibTimes[v]); saveSettings(); } } menu[/*LANG*/"Step Ntfy Ptrn"] = { - value: Math.max(0,vibPatterns.indexOf(settings.notify.step.notification)), + value: Math.max(0,vibPatterns.indexOf(settings.notify.step.notifications)), min: 0, max: vibPatterns.length, format: v => vibPatterns[v]||"Off", onchange: v => { - settings.notify.step.notification = vibTimes[v]; + settings.notify.step.notifications = vibTimes[v]; sampleBuzz(vibTimes[v]); saveSettings(); } } menu[/*LANG*/"Time Ntfy Ptrn"] = { - value: Math.max(0,vibPatterns.indexOf(settings.notify.time.notification)), + value: Math.max(0,vibPatterns.indexOf(settings.notify.time.notifications)), min: 0, max: vibPatterns.length, format: v => vibPatterns[v]||"Off", onchange: v => { - settings.notify.time.notification = vibTimes[v]; + settings.notify.time.notifications = vibTimes[v]; sampleBuzz(vibTimes[v]); saveSettings(); } From 191dd52747a533df41b1bc3303a616e144f1d268 Mon Sep 17 00:00:00 2001 From: Salim Blume Date: Sat, 5 Mar 2022 14:47:42 -0600 Subject: [PATCH 44/61] Debug --- apps/run/app.js | 2 ++ apps/run/settings.js | 3 +++ 2 files changed, 5 insertions(+) diff --git a/apps/run/app.js b/apps/run/app.js index c717e12fd..a595ab477 100644 --- a/apps/run/app.js +++ b/apps/run/app.js @@ -113,6 +113,8 @@ layout.render(); function configureNotification(stat) { stat.on('notify', (e)=>{ console.log(`Got notify from ${JSON.stringify(e)}`); + console.log(`Got notify from ${JSON.stringify(e.id)}`); + console.log(JSON.stringify(settings.notify)); console.log(JSON.stringify(settings.notify[e.id])); settings.notify[e.id].notifications.reduce(function (promise, buzzPattern) { console.log(buzzPattern); diff --git a/apps/run/settings.js b/apps/run/settings.js index a5faece9d..a810ef107 100644 --- a/apps/run/settings.js +++ b/apps/run/settings.js @@ -88,6 +88,7 @@ settings.notify.dist.notifications = vibTimes[v]; sampleBuzz(vibTimes[v]); saveSettings(); + console.log(JSON.stringify(settings)); } } menu[/*LANG*/"Step Ntfy Ptrn"] = { @@ -98,6 +99,7 @@ settings.notify.step.notifications = vibTimes[v]; sampleBuzz(vibTimes[v]); saveSettings(); + console.log(JSON.stringify(settings)); } } menu[/*LANG*/"Time Ntfy Ptrn"] = { @@ -108,6 +110,7 @@ settings.notify.time.notifications = vibTimes[v]; sampleBuzz(vibTimes[v]); saveSettings(); + console.log(JSON.stringify(settings)); } } Object.assign(menu,{ From 447b896a1402e0fa8f82e45fb84f99a48861216b Mon Sep 17 00:00:00 2001 From: Salim Blume Date: Sat, 5 Mar 2022 14:58:34 -0600 Subject: [PATCH 45/61] Remove debug --- apps/run/app.js | 9 +-------- apps/run/settings.js | 3 --- 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/apps/run/app.js b/apps/run/app.js index a595ab477..01ae22987 100644 --- a/apps/run/app.js +++ b/apps/run/app.js @@ -112,18 +112,11 @@ layout.render(); function configureNotification(stat) { stat.on('notify', (e)=>{ - console.log(`Got notify from ${JSON.stringify(e)}`); - console.log(`Got notify from ${JSON.stringify(e.id)}`); - console.log(JSON.stringify(settings.notify)); - console.log(JSON.stringify(settings.notify[e.id])); settings.notify[e.id].notifications.reduce(function (promise, buzzPattern) { - console.log(buzzPattern); return promise.then(function () { - console.log('Should buzz now'); return Bangle.buzz(buzzPattern[0], buzzPattern[1]); }); - }, Promise.resolve()) - .then(console.log); + }, Promise.resolve()); }); } diff --git a/apps/run/settings.js b/apps/run/settings.js index a810ef107..a5faece9d 100644 --- a/apps/run/settings.js +++ b/apps/run/settings.js @@ -88,7 +88,6 @@ settings.notify.dist.notifications = vibTimes[v]; sampleBuzz(vibTimes[v]); saveSettings(); - console.log(JSON.stringify(settings)); } } menu[/*LANG*/"Step Ntfy Ptrn"] = { @@ -99,7 +98,6 @@ settings.notify.step.notifications = vibTimes[v]; sampleBuzz(vibTimes[v]); saveSettings(); - console.log(JSON.stringify(settings)); } } menu[/*LANG*/"Time Ntfy Ptrn"] = { @@ -110,7 +108,6 @@ settings.notify.time.notifications = vibTimes[v]; sampleBuzz(vibTimes[v]); saveSettings(); - console.log(JSON.stringify(settings)); } } Object.assign(menu,{ From 5dca4a8b1e029294a2cc7f402dd19a8696d4924e Mon Sep 17 00:00:00 2001 From: Salim Blume Date: Sat, 5 Mar 2022 16:02:48 -0600 Subject: [PATCH 46/61] Notifications submenu and fix for displaying vibTimes in settings --- apps/run/settings.js | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/apps/run/settings.js b/apps/run/settings.js index a5faece9d..b4073008d 100644 --- a/apps/run/settings.js +++ b/apps/run/settings.js @@ -69,19 +69,23 @@ saveSettings(); } }; + var notificationsMenu = { + '< Back': function() { E.showMenu(menu) }, + } + menu[/*LANG*/"Notifications"] = function() { E.showMenu(notificationsMenu)}; ExStats.appendMenuItems(menu, settings, saveSettings); - ExStats.appendNotifyMenuItems(menu, settings, saveSettings); + ExStats.appendNotifyMenuItems(notificationsMenu, settings, saveSettings); var vibPatterns = [/*LANG*/"Off", ".", "-", "--", "-.-", "---"]; var vibTimes = [ [], [[100, 1]], [[300, 1]], - [[300, 1], [200, 0], [300, 1]], - [[300, 1],[200, 0], [100, 1], [200, 0], [300, 1]], - [[300, 1],[200, 0],[300, 1],[200, 0],[300, 1]], + [[300, 1], [300, 0], [300, 1]], + [[300, 1],[300, 0], [100, 1], [300, 0], [300, 1]], + [[300, 1],[300, 0],[300, 1],[300, 0],[300, 1]], ]; menu[/*LANG*/"Dist Ntfy Ptrn"] = { - value: Math.max(0,vibPatterns.indexOf(settings.notify.dist.notifications)), + value: Math.max(0,vibPatterns.findIndex((p) => JSON.stringify(p) === JSON.stringify(settings.notify.dist.notifications))), min: 0, max: vibPatterns.length, format: v => vibPatterns[v]||"Off", onchange: v => { @@ -91,7 +95,7 @@ } } menu[/*LANG*/"Step Ntfy Ptrn"] = { - value: Math.max(0,vibPatterns.indexOf(settings.notify.step.notifications)), + value: Math.max(0,vibPatterns.findIndex((p) => JSON.stringify(p) === JSON.stringify(settings.notify.step.notifications))), min: 0, max: vibPatterns.length, format: v => vibPatterns[v]||"Off", onchange: v => { @@ -101,7 +105,7 @@ } } menu[/*LANG*/"Time Ntfy Ptrn"] = { - value: Math.max(0,vibPatterns.indexOf(settings.notify.time.notifications)), + value: Math.max(0,vibPatterns.findIndex((p) => JSON.stringify(p) === JSON.stringify(settings.notify.time.notifications))), min: 0, max: vibPatterns.length, format: v => vibPatterns[v]||"Off", onchange: v => { From 93dedd9015e671389af131e3c899eea9c73d2142 Mon Sep 17 00:00:00 2001 From: Salim Blume Date: Sat, 5 Mar 2022 16:14:07 -0600 Subject: [PATCH 47/61] Consolidating menus --- apps/run/settings.js | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/apps/run/settings.js b/apps/run/settings.js index b4073008d..29a2f43cc 100644 --- a/apps/run/settings.js +++ b/apps/run/settings.js @@ -84,7 +84,7 @@ [[300, 1],[300, 0], [100, 1], [300, 0], [300, 1]], [[300, 1],[300, 0],[300, 1],[300, 0],[300, 1]], ]; - menu[/*LANG*/"Dist Ntfy Ptrn"] = { + notificationsMenu[/*LANG*/"Dist Pattern"] = { value: Math.max(0,vibPatterns.findIndex((p) => JSON.stringify(p) === JSON.stringify(settings.notify.dist.notifications))), min: 0, max: vibPatterns.length, format: v => vibPatterns[v]||"Off", @@ -94,7 +94,7 @@ saveSettings(); } } - menu[/*LANG*/"Step Ntfy Ptrn"] = { + notificationsMenu[/*LANG*/"Step Pattern"] = { value: Math.max(0,vibPatterns.findIndex((p) => JSON.stringify(p) === JSON.stringify(settings.notify.step.notifications))), min: 0, max: vibPatterns.length, format: v => vibPatterns[v]||"Off", @@ -104,7 +104,7 @@ saveSettings(); } } - menu[/*LANG*/"Time Ntfy Ptrn"] = { + notificationsMenu[/*LANG*/"Time Pattern"] = { value: Math.max(0,vibPatterns.findIndex((p) => JSON.stringify(p) === JSON.stringify(settings.notify.time.notifications))), min: 0, max: vibPatterns.length, format: v => vibPatterns[v]||"Off", @@ -114,7 +114,10 @@ saveSettings(); } } - Object.assign(menu,{ + var boxMenu = { + '< Back': function() { E.showMenu(menu) }, + } + Object.assign(boxMenu,{ 'Box 1': getBoxChooser("B1"), 'Box 2': getBoxChooser("B2"), 'Box 3': getBoxChooser("B3"), @@ -122,5 +125,6 @@ 'Box 5': getBoxChooser("B5"), 'Box 6': getBoxChooser("B6"), }); + menu[/*LANG*/"Boxes"] = function() { E.showMenu(boxMenu)}; E.showMenu(menu); }) From e1e9b6e96a1d5cd96bd48dd9cb04ffefea1ec5bd Mon Sep 17 00:00:00 2001 From: Salim Blume Date: Sat, 5 Mar 2022 17:01:53 -0600 Subject: [PATCH 48/61] Better comment --- apps/run/app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/run/app.js b/apps/run/app.js index 01ae22987..45daf878e 100644 --- a/apps/run/app.js +++ b/apps/run/app.js @@ -48,7 +48,7 @@ function onStartStop() { // start/stop recording // Do this first in case recorder needs to prompt for - // an overwrite before we begin things like the total time + // an overwrite before we start tracking exstats if (settings.record && WIDGETS["recorder"]) { if (running) { isMenuDisplayed = true; From 4253f7db260b9d7a09b5b86198b20b70e4fd7fe3 Mon Sep 17 00:00:00 2001 From: Salim Blume Date: Sat, 5 Mar 2022 17:26:07 -0600 Subject: [PATCH 49/61] Update README.md --- apps/run/README.md | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/apps/run/README.md b/apps/run/README.md index 67d62185d..89750eb7d 100644 --- a/apps/run/README.md +++ b/apps/run/README.md @@ -25,7 +25,7 @@ so if you have no GPS lock you just need to wait. ## Recording Tracks When the `Recorder` app is installed, `Run` will automatically start and stop tracks -as needed, prompting you to overwrite or begin a new track, if necessary. +as needed, prompting you to overwrite or begin a new track if necessary. ## Settings @@ -34,9 +34,26 @@ Under `Settings` -> `App` -> `Run` you can change settings for this app. * `Record Run` (only displayed if `Recorder` app installed) should the Run app automatically record GPS/HRM/etc data every time you start a run? * `Pace` is the distance that pace should be shown over - 1km, 1 mile, 1/2 Marathon or 1 Marathon -* `Box 1/2/3/4/5/6` are what should be shown in each of the 6 boxes on the display. From the top left, down. - If you set it to `-` nothing will be displayed, so you can display only 4 boxes of information - if you wish by setting the last 2 boxes to `-`. +* `Boxes` leads to a submenu where you can configure what is shown in each of the 6 boxes on the display. + Available stats are "Time", "Distance", "Steps", "Heart (BPM)", "Pace (avg)", "Pace (curr)", "Speed", and "Cadence". + Any box set to "-" will display no information. + * Box 1 is the top left (defaults to "Distance") + * Box 2 is the top right (defaults to "Time") + * Box 3 is the middle left (defaults to "Pace (avg)") + * Box 4 is the middle right (defaults to "Heart (BPM)") + * Box 5 is the bottom left (defaults to "Steps") + * Box 6 is the bottom right (defaults to "Cadence") +* `Notifications` leads to a submenu where you can configure if the app will notify you after +your distance, steps, or time repeatedly pass your configured thresholds + * `Ntfy Dist`: The distance that you must pass before you are notified. Follows the `Pace` options + * "Off" (default), "1km", "1 mile", "1/2 Marathon", "1 Marathon" + * `Ntfy Steps`: The number of steps that must pass before you are notified. + * "Off" (default), 100, 500, 1000, 5000, 10000 + * `Ntfy Time`: The amount of time that must pass before you are notified. + * "Off" (default), "30 sec", "1 min", "2 min", "5 min", "10 min", "30 min", "1 hour" + * `Dist Pattern`: The vibration pattern to use to notify you about meeting your distance threshold + * `Step Pattern`: The vibration pattern to use to notify you about meeting your step threshold + * `Time Pattern`: The vibration pattern to use to notify you about meeting your time threshold ## TODO From 539ea98a29c1043fe455aa5aedf702c0ad2a8344 Mon Sep 17 00:00:00 2001 From: Salim Blume Date: Sat, 5 Mar 2022 17:27:21 -0600 Subject: [PATCH 50/61] Update CHANGELOG --- apps/run/ChangeLog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/run/ChangeLog b/apps/run/ChangeLog index bd478c12e..0a697ecb9 100644 --- a/apps/run/ChangeLog +++ b/apps/run/ChangeLog @@ -6,4 +6,4 @@ 0.05: exstats updated so update 'distance' label is updated, option for 'speed' 0.06: Add option to record a run using the recorder app automatically 0.07: Fix crash if an odd number of active boxes are configured (fix #1473) -0.08: Support all stats from exstats \ No newline at end of file +0.08: Added support for notifications from exstats. Support all stats from exstats \ No newline at end of file From 9414d785dd878b7dad775e580bcd93969723b1b5 Mon Sep 17 00:00:00 2001 From: Salim Blume Date: Sat, 5 Mar 2022 21:12:53 -0600 Subject: [PATCH 51/61] Removing yarn.lock --- yarn.lock | 864 ------------------------------------------------------ 1 file changed, 864 deletions(-) delete mode 100644 yarn.lock diff --git a/yarn.lock b/yarn.lock deleted file mode 100644 index f3224947f..000000000 --- a/yarn.lock +++ /dev/null @@ -1,864 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -"@babel/code-frame@^7.0.0": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.16.7.tgz#44416b6bd7624b998f5b1af5d470856c40138789" - integrity sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg== - dependencies: - "@babel/highlight" "^7.16.7" - -"@babel/helper-validator-identifier@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz#e8c602438c4a8195751243da9031d1607d247cad" - integrity sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw== - -"@babel/highlight@^7.16.7": - version "7.16.10" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.16.10.tgz#744f2eb81579d6eea753c227b0f570ad785aba88" - integrity sha512-5FnTQLSLswEj6IkgVw5KusNUUFY9ZGqe/TRFnP/BKYHYgfh7tc+C7mwiy95/yNP7Dh9x580Vv8r7u7ZfTBFxdw== - dependencies: - "@babel/helper-validator-identifier" "^7.16.7" - chalk "^2.0.0" - js-tokens "^4.0.0" - -acorn-jsx@^5.3.1: - version "5.3.2" - resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" - integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== - -acorn@^7.2.0, acorn@^7.4.0: - version "7.4.1" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" - integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== - -ajv@^6.10.0, ajv@^6.10.2: - version "6.12.6" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" - integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== - dependencies: - fast-deep-equal "^3.1.1" - fast-json-stable-stringify "^2.0.0" - json-schema-traverse "^0.4.1" - uri-js "^4.2.2" - -ansi-escapes@^4.2.1: - version "4.3.2" - resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" - integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== - dependencies: - type-fest "^0.21.3" - -ansi-regex@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" - integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg== - -ansi-regex@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" - integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== - -ansi-styles@^3.2.0, ansi-styles@^3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" - integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== - dependencies: - color-convert "^1.9.0" - -ansi-styles@^4.1.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" - integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== - dependencies: - color-convert "^2.0.1" - -argparse@^1.0.7: - version "1.0.10" - resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" - integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== - dependencies: - sprintf-js "~1.0.2" - -astral-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9" - integrity sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg== - -balanced-match@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" - integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== - -brace-expansion@^1.1.7: - version "1.1.11" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" - integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== - dependencies: - balanced-match "^1.0.0" - concat-map "0.0.1" - -callsites@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" - integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== - -chalk@^2.0.0: - version "2.4.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" - integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== - dependencies: - ansi-styles "^3.2.1" - escape-string-regexp "^1.0.5" - supports-color "^5.3.0" - -chalk@^4.0.0, chalk@^4.1.0: - version "4.1.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" - integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== - dependencies: - ansi-styles "^4.1.0" - supports-color "^7.1.0" - -chardet@^0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" - integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== - -cli-cursor@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307" - integrity sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw== - dependencies: - restore-cursor "^3.1.0" - -cli-width@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-3.0.0.tgz#a2f48437a2caa9a22436e794bf071ec9e61cedf6" - integrity sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw== - -color-convert@^1.9.0: - version "1.9.3" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" - integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== - dependencies: - color-name "1.1.3" - -color-convert@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" - integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== - dependencies: - color-name "~1.1.4" - -color-name@1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" - integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= - -color-name@~1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" - integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== - -concat-map@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" - integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= - -cross-spawn@^7.0.2: - version "7.0.3" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" - integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== - dependencies: - path-key "^3.1.0" - shebang-command "^2.0.0" - which "^2.0.1" - -debug@^4.0.1: - version "4.3.3" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.3.tgz#04266e0b70a98d4462e6e288e38259213332b664" - integrity sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q== - dependencies: - ms "2.1.2" - -deep-is@^0.1.3: - version "0.1.4" - resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" - integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== - -doctrine@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" - integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== - dependencies: - esutils "^2.0.2" - -emoji-regex@^7.0.1: - version "7.0.3" - resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" - integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA== - -emoji-regex@^8.0.0: - version "8.0.0" - resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" - integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== - -escape-string-regexp@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" - integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= - -eslint-scope@^5.0.0: - version "5.1.1" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" - integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== - dependencies: - esrecurse "^4.3.0" - estraverse "^4.1.1" - -eslint-utils@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-2.1.0.tgz#d2de5e03424e707dc10c74068ddedae708741b27" - integrity sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg== - dependencies: - eslint-visitor-keys "^1.1.0" - -eslint-visitor-keys@^1.1.0, eslint-visitor-keys@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e" - integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ== - -eslint@7.1.0: - version "7.1.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.1.0.tgz#d9a1df25e5b7859b0a3d86bb05f0940ab676a851" - integrity sha512-DfS3b8iHMK5z/YLSme8K5cge168I8j8o1uiVmFCgnnjxZQbCGyraF8bMl7Ju4yfBmCuxD7shOF7eqGkcuIHfsA== - dependencies: - "@babel/code-frame" "^7.0.0" - ajv "^6.10.0" - chalk "^4.0.0" - cross-spawn "^7.0.2" - debug "^4.0.1" - doctrine "^3.0.0" - eslint-scope "^5.0.0" - eslint-utils "^2.0.0" - eslint-visitor-keys "^1.1.0" - espree "^7.0.0" - esquery "^1.2.0" - esutils "^2.0.2" - file-entry-cache "^5.0.1" - functional-red-black-tree "^1.0.1" - glob-parent "^5.0.0" - globals "^12.1.0" - ignore "^4.0.6" - import-fresh "^3.0.0" - imurmurhash "^0.1.4" - inquirer "^7.0.0" - is-glob "^4.0.0" - js-yaml "^3.13.1" - json-stable-stringify-without-jsonify "^1.0.1" - levn "^0.4.1" - lodash "^4.17.14" - minimatch "^3.0.4" - natural-compare "^1.4.0" - optionator "^0.9.1" - progress "^2.0.0" - regexpp "^3.1.0" - semver "^7.2.1" - strip-ansi "^6.0.0" - strip-json-comments "^3.1.0" - table "^5.2.3" - text-table "^0.2.0" - v8-compile-cache "^2.0.3" - -espree@^7.0.0: - version "7.3.1" - resolved "https://registry.yarnpkg.com/espree/-/espree-7.3.1.tgz#f2df330b752c6f55019f8bd89b7660039c1bbbb6" - integrity sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g== - dependencies: - acorn "^7.4.0" - acorn-jsx "^5.3.1" - eslint-visitor-keys "^1.3.0" - -esprima@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" - integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== - -esquery@^1.2.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.4.0.tgz#2148ffc38b82e8c7057dfed48425b3e61f0f24a5" - integrity sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w== - dependencies: - estraverse "^5.1.0" - -esrecurse@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" - integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== - dependencies: - estraverse "^5.2.0" - -estraverse@^4.1.1: - version "4.3.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" - integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== - -estraverse@^5.1.0, estraverse@^5.2.0: - version "5.3.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" - integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== - -esutils@^2.0.2: - version "2.0.3" - resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" - integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== - -external-editor@^3.0.3: - version "3.1.0" - resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495" - integrity sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew== - dependencies: - chardet "^0.7.0" - iconv-lite "^0.4.24" - tmp "^0.0.33" - -fast-deep-equal@^3.1.1: - version "3.1.3" - resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" - integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== - -fast-json-stable-stringify@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" - integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== - -fast-levenshtein@^2.0.6: - version "2.0.6" - resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" - integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= - -figures@^3.0.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/figures/-/figures-3.2.0.tgz#625c18bd293c604dc4a8ddb2febf0c88341746af" - integrity sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg== - dependencies: - escape-string-regexp "^1.0.5" - -file-entry-cache@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-5.0.1.tgz#ca0f6efa6dd3d561333fb14515065c2fafdf439c" - integrity sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g== - dependencies: - flat-cache "^2.0.1" - -flat-cache@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-2.0.1.tgz#5d296d6f04bda44a4630a301413bdbc2ec085ec0" - integrity sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA== - dependencies: - flatted "^2.0.0" - rimraf "2.6.3" - write "1.0.3" - -flatted@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.2.tgz#4575b21e2bcee7434aa9be662f4b7b5f9c2b5138" - integrity sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA== - -fs.realpath@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" - integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= - -functional-red-black-tree@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" - integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= - -glob-parent@^5.0.0: - version "5.1.2" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" - integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== - dependencies: - is-glob "^4.0.1" - -glob@^7.1.3: - version "7.2.0" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023" - integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q== - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.0.4" - once "^1.3.0" - path-is-absolute "^1.0.0" - -globals@^12.1.0: - version "12.4.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-12.4.0.tgz#a18813576a41b00a24a97e7f815918c2e19925f8" - integrity sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg== - dependencies: - type-fest "^0.8.1" - -has-flag@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" - integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= - -has-flag@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" - integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== - -iconv-lite@^0.4.24: - version "0.4.24" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" - integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== - dependencies: - safer-buffer ">= 2.1.2 < 3" - -ignore@^4.0.6: - version "4.0.6" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" - integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== - -import-fresh@^3.0.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" - integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== - dependencies: - parent-module "^1.0.0" - resolve-from "^4.0.0" - -imurmurhash@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" - integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= - -inflight@^1.0.4: - version "1.0.6" - resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" - integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= - dependencies: - once "^1.3.0" - wrappy "1" - -inherits@2: - version "2.0.4" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" - integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== - -inquirer@^7.0.0: - version "7.3.3" - resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-7.3.3.tgz#04d176b2af04afc157a83fd7c100e98ee0aad003" - integrity sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA== - dependencies: - ansi-escapes "^4.2.1" - chalk "^4.1.0" - cli-cursor "^3.1.0" - cli-width "^3.0.0" - external-editor "^3.0.3" - figures "^3.0.0" - lodash "^4.17.19" - mute-stream "0.0.8" - run-async "^2.4.0" - rxjs "^6.6.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - through "^2.3.6" - -is-extglob@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" - integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= - -is-fullwidth-code-point@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" - integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= - -is-fullwidth-code-point@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" - integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== - -is-glob@^4.0.0, is-glob@^4.0.1: - version "4.0.3" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" - integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== - dependencies: - is-extglob "^2.1.1" - -isexe@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" - integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= - -js-tokens@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" - integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== - -js-yaml@^3.13.1: - version "3.14.1" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" - integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== - dependencies: - argparse "^1.0.7" - esprima "^4.0.0" - -json-schema-traverse@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" - integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== - -json-stable-stringify-without-jsonify@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" - integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE= - -levn@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" - integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== - dependencies: - prelude-ls "^1.2.1" - type-check "~0.4.0" - -lodash@^4.17.14, lodash@^4.17.19: - version "4.17.21" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" - integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== - -lru-cache@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" - integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== - dependencies: - yallist "^4.0.0" - -mimic-fn@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" - integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== - -minimatch@^3.0.4: - version "3.1.2" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" - integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== - dependencies: - brace-expansion "^1.1.7" - -minimist@^1.2.5: - version "1.2.5" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" - integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== - -mkdirp@^0.5.1: - version "0.5.5" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def" - integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ== - dependencies: - minimist "^1.2.5" - -ms@2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" - integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== - -mute-stream@0.0.8: - version "0.0.8" - resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" - integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA== - -natural-compare@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" - integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= - -once@^1.3.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" - integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= - dependencies: - wrappy "1" - -onetime@^5.1.0: - version "5.1.2" - resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" - integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== - dependencies: - mimic-fn "^2.1.0" - -optionator@^0.9.1: - version "0.9.1" - resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.1.tgz#4f236a6373dae0566a6d43e1326674f50c291499" - integrity sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw== - dependencies: - deep-is "^0.1.3" - fast-levenshtein "^2.0.6" - levn "^0.4.1" - prelude-ls "^1.2.1" - type-check "^0.4.0" - word-wrap "^1.2.3" - -os-tmpdir@~1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" - integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= - -parent-module@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" - integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== - dependencies: - callsites "^3.0.0" - -path-is-absolute@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" - integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= - -path-key@^3.1.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" - integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== - -prelude-ls@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" - integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== - -progress@^2.0.0: - version "2.0.3" - resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" - integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== - -punycode@^2.1.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" - integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== - -regexpp@^3.1.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2" - integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg== - -resolve-from@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" - integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== - -restore-cursor@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e" - integrity sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA== - dependencies: - onetime "^5.1.0" - signal-exit "^3.0.2" - -rimraf@2.6.3: - version "2.6.3" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" - integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA== - dependencies: - glob "^7.1.3" - -run-async@^2.4.0: - version "2.4.1" - resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455" - integrity sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ== - -rxjs@^6.6.0: - version "6.6.7" - resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.7.tgz#90ac018acabf491bf65044235d5863c4dab804c9" - integrity sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ== - dependencies: - tslib "^1.9.0" - -"safer-buffer@>= 2.1.2 < 3": - version "2.1.2" - resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" - integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== - -semver@^7.2.1: - version "7.3.5" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7" - integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ== - dependencies: - lru-cache "^6.0.0" - -shebang-command@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" - integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== - dependencies: - shebang-regex "^3.0.0" - -shebang-regex@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" - integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== - -signal-exit@^3.0.2: - version "3.0.7" - resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" - integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== - -slice-ansi@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-2.1.0.tgz#cacd7693461a637a5788d92a7dd4fba068e81636" - integrity sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ== - dependencies: - ansi-styles "^3.2.0" - astral-regex "^1.0.0" - is-fullwidth-code-point "^2.0.0" - -sprintf-js@~1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" - integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= - -string-width@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" - integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w== - dependencies: - emoji-regex "^7.0.1" - is-fullwidth-code-point "^2.0.0" - strip-ansi "^5.1.0" - -string-width@^4.1.0: - version "4.2.3" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" - integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.1" - -strip-ansi@^5.1.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" - integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA== - dependencies: - ansi-regex "^4.1.0" - -strip-ansi@^6.0.0, strip-ansi@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" - integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== - dependencies: - ansi-regex "^5.0.1" - -strip-json-comments@^3.1.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" - integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== - -supports-color@^5.3.0: - version "5.5.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" - integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== - dependencies: - has-flag "^3.0.0" - -supports-color@^7.1.0: - version "7.2.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" - integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== - dependencies: - has-flag "^4.0.0" - -table@^5.2.3: - version "5.4.6" - resolved "https://registry.yarnpkg.com/table/-/table-5.4.6.tgz#1292d19500ce3f86053b05f0e8e7e4a3bb21079e" - integrity sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug== - dependencies: - ajv "^6.10.2" - lodash "^4.17.14" - slice-ansi "^2.1.0" - string-width "^3.0.0" - -text-table@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" - integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= - -through@^2.3.6: - version "2.3.8" - resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" - integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= - -tmp@^0.0.33: - version "0.0.33" - resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" - integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw== - dependencies: - os-tmpdir "~1.0.2" - -tslib@^1.9.0: - version "1.14.1" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" - integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== - -type-check@^0.4.0, type-check@~0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" - integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== - dependencies: - prelude-ls "^1.2.1" - -type-fest@^0.21.3: - version "0.21.3" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" - integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== - -type-fest@^0.8.1: - version "0.8.1" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" - integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== - -uri-js@^4.2.2: - version "4.4.1" - resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" - integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== - dependencies: - punycode "^2.1.0" - -v8-compile-cache@^2.0.3: - version "2.3.0" - resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee" - integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA== - -which@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" - integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== - dependencies: - isexe "^2.0.0" - -word-wrap@^1.2.3: - version "1.2.3" - resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" - integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== - -wrappy@1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" - integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= - -write@1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/write/-/write-1.0.3.tgz#0800e14523b923a387e415123c865616aae0f5c3" - integrity sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig== - dependencies: - mkdirp "^0.5.1" - -yallist@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" - integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== From 73b493bb86891d572c05260c54be8a24b105b1f1 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Mon, 7 Mar 2022 15:54:53 +0000 Subject: [PATCH 52/61] recorder 0.12: Fix 'Back' label positioning on track/graph display, make translateable --- apps/recorder/ChangeLog | 1 + apps/recorder/app.js | 52 +++++++++++++++++++------------------ apps/recorder/metadata.json | 2 +- 3 files changed, 29 insertions(+), 26 deletions(-) diff --git a/apps/recorder/ChangeLog b/apps/recorder/ChangeLog index 60477ae97..963944144 100644 --- a/apps/recorder/ChangeLog +++ b/apps/recorder/ChangeLog @@ -15,3 +15,4 @@ 0.09: Show correct number for log in overwrite prompt 0.10: Fix broken recorder settings (when launched from settings app) 0.11: Fix KML and GPX export when there is no GPS data +0.12: Fix 'Back' label positioning on track/graph display, make translateable diff --git a/apps/recorder/app.js b/apps/recorder/app.js index 7075563aa..d900c12c1 100644 --- a/apps/recorder/app.js +++ b/apps/recorder/app.js @@ -49,11 +49,11 @@ function showMainMenu() { }; } const mainmenu = { - '': { 'title': 'Recorder' }, + '': { 'title': /*LANG*/'Recorder' }, '< Back': ()=>{load();}, - 'RECORD': { + /*LANG*/'RECORD': { value: !!settings.recording, - format: v=>v?"On":"Off", + format: v=>v?/*LANG*/"On":/*LANG*/"Off", onchange: v => { setTimeout(function() { E.showMenu(); @@ -66,7 +66,7 @@ function showMainMenu() { }, 1); } }, - 'File #': { + /*LANG*/'File #': { value: getTrackNumber(settings.file), min: 0, max: 99, @@ -77,8 +77,8 @@ function showMainMenu() { updateSettings(); } }, - 'View Tracks': ()=>{viewTracks();}, - 'Time Period': { + /*LANG*/'View Tracks': ()=>{viewTracks();}, + /*LANG*/'Time Period': { value: settings.period||10, min: 1, max: 120, @@ -103,15 +103,15 @@ function showMainMenu() { function viewTracks() { const menu = { - '': { 'title': 'Tracks' } + '': { 'title': /*LANG*/'Tracks' } }; var found = false; require("Storage").list(/^recorder\.log.*\.csv$/,{sf:true}).forEach(filename=>{ found = true; - menu["Track "+getTrackNumber(filename)] = ()=>viewTrack(filename,false); + menu[/*LANG*/"Track "+getTrackNumber(filename)] = ()=>viewTrack(filename,false); }); if (!found) - menu["No Tracks found"] = function(){}; + menu[/*LANG*/"No Tracks found"] = function(){}; menu['< Back'] = () => { showMainMenu(); }; return E.showMenu(menu); } @@ -175,38 +175,38 @@ function asTime(v){ function viewTrack(filename, info) { if (!info) { - E.showMessage("Loading...","Track "+getTrackNumber(filename)); + E.showMessage(/*LANG*/"Loading...",/*LANG*/"Track "+getTrackNumber(filename)); info = getTrackInfo(filename); } //console.log(info); const menu = { - '': { 'title': 'Track '+info.fn } + '': { 'title': /*LANG*/'Track '+info.fn } }; if (info.time) menu[info.time.toISOString().substr(0,16).replace("T"," ")] = function(){}; menu["Duration"] = { value : asTime(info.duration)}; menu["Records"] = { value : ""+info.records }; if (info.fields.includes("Latitude")) - menu['Plot Map'] = function() { + menu[/*LANG*/'Plot Map'] = function() { info.qOSTM = false; plotTrack(info); }; if (osm && info.fields.includes("Latitude")) - menu['Plot OpenStMap'] = function() { + menu[/*LANG*/'Plot OpenStMap'] = function() { info.qOSTM = true; plotTrack(info); } if (info.fields.includes("Altitude")) - menu['Plot Alt.'] = function() { + menu[/*LANG*/'Plot Alt.'] = function() { plotGraph(info, "Altitude"); }; if (info.fields.includes("Latitude")) - menu['Plot Speed'] = function() { + menu[/*LANG*/'Plot Speed'] = function() { plotGraph(info, "Speed"); }; // TODO: steps, heart rate? - menu['Erase'] = function() { - E.showPrompt("Delete Track?").then(function(v) { + menu[/*LANG*/'Erase'] = function() { + E.showPrompt(/*LANG*/"Delete Track?").then(function(v) { if (v) { settings.recording = false; updateSettings(); @@ -238,7 +238,7 @@ function viewTrack(filename, info) { } E.showMenu(); // remove menu - E.showMessage("Drawing...","Track "+info.fn); + E.showMessage(/*LANG*/"Drawing...",/*LANG*/"Track "+info.fn); g.flip(); // on buffered screens, draw a not saying we're busy g.clear(1); var s = require("Storage"); @@ -305,17 +305,18 @@ function viewTrack(filename, info) { g.drawString(require("locale").distance(dist),g.getWidth() / 2, g.getHeight() - 20); g.setFont("6x8",2); g.setFontAlign(0,0,3); - g.drawString("Back",g.getWidth() - 10, g.getHeight() - 40); + var isBTN3 = "BTN3" in global; + g.drawString(/*LANG*/"Back",g.getWidth() - 10, isBTN3 ? (g.getHeight() - 40) : (g.getHeight()/2)); setWatch(function() { viewTrack(info.fn, info); - }, global.BTN3||BTN1); + }, isBTN3?BTN3:BTN1); Bangle.drawWidgets(); g.flip(); } function plotGraph(info, style) { "ram" E.showMenu(); // remove menu - E.showMessage("Calculating...","Track "+info.fn); + E.showMessage(/*LANG*/"Calculating...",/*LANG*/"Track "+info.fn); var filename = info.filename; var infn = new Float32Array(80); var infc = new Uint16Array(80); @@ -334,7 +335,7 @@ function viewTrack(filename, info) { strt = c[timeIdx]; } if (style=="Altitude") { - title = "Altitude (m)"; + title = /*LANG*/"Altitude (m)"; var altIdx = info.fields.indexOf("Altitude"); while(l!==undefined) { ++nl;c=l.split(",");l = f.readLine(f); @@ -344,7 +345,7 @@ function viewTrack(filename, info) { infc[i]++; } } else if (style=="Speed") { - title = "Speed (m/s)"; + title = /*LANG*/"Speed (m/s)"; var latIdx = info.fields.indexOf("Latitude"); var lonIdx = info.fields.indexOf("Longitude"); // skip until we find our first data @@ -404,10 +405,11 @@ function viewTrack(filename, info) { }); g.setFont("6x8",2); g.setFontAlign(0,0,3); - g.drawString("Back",g.getWidth() - 10, g.getHeight() - 40); + var isBTN3 = "BTN3" in global; + g.drawString(/*LANG*/"Back",g.getWidth() - 10, isBTN3 ? (g.getHeight() - 40) : (g.getHeight()/2)); setWatch(function() { viewTrack(info.filename, info); - }, global.BTN3||BTN1); + }, isBTN3?BTN3:BTN1); g.flip(); } diff --git a/apps/recorder/metadata.json b/apps/recorder/metadata.json index 56865e885..09873dada 100644 --- a/apps/recorder/metadata.json +++ b/apps/recorder/metadata.json @@ -2,7 +2,7 @@ "id": "recorder", "name": "Recorder", "shortName": "Recorder", - "version": "0.11", + "version": "0.12", "description": "Record GPS position, heart rate and more in the background, then download to your PC.", "icon": "app.png", "tags": "tool,outdoors,gps,widget", From 09dc646415facd7d854629553306f5e0a8612778 Mon Sep 17 00:00:00 2001 From: Salim Blume Date: Mon, 7 Mar 2022 10:14:51 -0600 Subject: [PATCH 53/61] Removing unneeded message --- apps/recorder/app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/recorder/app.js b/apps/recorder/app.js index d28cef585..7075563aa 100644 --- a/apps/recorder/app.js +++ b/apps/recorder/app.js @@ -305,7 +305,7 @@ function viewTrack(filename, info) { g.drawString(require("locale").distance(dist),g.getWidth() / 2, g.getHeight() - 20); g.setFont("6x8",2); g.setFontAlign(0,0,3); - g.drawString("Back",g.getWidth() - 10, g.getHeight() - 40); // TODO: this position depends on Bangle1 vs 2 + g.drawString("Back",g.getWidth() - 10, g.getHeight() - 40); setWatch(function() { viewTrack(info.fn, info); }, global.BTN3||BTN1); From 40db573458e17543221c7d2699f3224a5e8b3ab8 Mon Sep 17 00:00:00 2001 From: Marco H Date: Mon, 7 Mar 2022 17:59:18 +0100 Subject: [PATCH 54/61] Initial version of Barometer Alarm Widget --- apps/widbaroalarm/ChangeLog | 1 + apps/widbaroalarm/README.md | 24 ++++ apps/widbaroalarm/default.json | 10 ++ apps/widbaroalarm/metadata.json | 19 +++ apps/widbaroalarm/screenshot.png | Bin 0 -> 2707 bytes apps/widbaroalarm/settings.js | 85 +++++++++++++ apps/widbaroalarm/widget.js | 199 +++++++++++++++++++++++++++++++ apps/widbaroalarm/widget.png | Bin 0 -> 9872 bytes apps/widbaroalarm/widget24.png | Bin 0 -> 10100 bytes 9 files changed, 338 insertions(+) create mode 100644 apps/widbaroalarm/ChangeLog create mode 100644 apps/widbaroalarm/README.md create mode 100644 apps/widbaroalarm/default.json create mode 100644 apps/widbaroalarm/metadata.json create mode 100644 apps/widbaroalarm/screenshot.png create mode 100644 apps/widbaroalarm/settings.js create mode 100644 apps/widbaroalarm/widget.js create mode 100644 apps/widbaroalarm/widget.png create mode 100644 apps/widbaroalarm/widget24.png diff --git a/apps/widbaroalarm/ChangeLog b/apps/widbaroalarm/ChangeLog new file mode 100644 index 000000000..ec66c5568 --- /dev/null +++ b/apps/widbaroalarm/ChangeLog @@ -0,0 +1 @@ +0.01: Initial version diff --git a/apps/widbaroalarm/README.md b/apps/widbaroalarm/README.md new file mode 100644 index 000000000..6708b1e2b --- /dev/null +++ b/apps/widbaroalarm/README.md @@ -0,0 +1,24 @@ +# Barometer alarm widget + +Get a notification when the pressure reaches defined thresholds. + +![Screenshot](screenshot.png) + +## Settings + +* Interval: check interval of sensor data in minutes. 0 to disable automatic check. +* Low alarm: Toggle low alarm + * Low threshold: Warn when pressure drops below this value +* High alarm: Toggle high alarm + * High threshold: Warn when pressure exceeds above this value +* Change alarm: Warn when pressure changes more than this value in the recent 3 hours (having at least 30 min of data) + 0 to disable this alarm. +* Show widget: Enable/disable widget visibility +* Buzz on alarm: Enable/disable buzzer on alarm + + +## Widget +The widget shows two rows: pressure value of last measurement and pressure average of the the last three hours. + +## Creator +Marco ([myxor](https://github.com/myxor)) diff --git a/apps/widbaroalarm/default.json b/apps/widbaroalarm/default.json new file mode 100644 index 000000000..7dbe6fc17 --- /dev/null +++ b/apps/widbaroalarm/default.json @@ -0,0 +1,10 @@ +{ + "buzz": true, + "lowalarm": false, + "min": 950, + "highalarm": false, + "max": 1030, + "changeIn3h": 2, + "show": true, + "interval": 15 +} diff --git a/apps/widbaroalarm/metadata.json b/apps/widbaroalarm/metadata.json new file mode 100644 index 000000000..3dd02019d --- /dev/null +++ b/apps/widbaroalarm/metadata.json @@ -0,0 +1,19 @@ +{ + "id": "widbaroalarm", + "name": "Barometer alarm widget", + "shortName": "Barometer alarm", + "version": "0.01", + "description": "A widget that can alarm on when the pressure reaches defined thresholds.", + "icon": "widget.png", + "screenshots": [{"url":"screenshot.png"}], + "type": "widget", + "tags": "tool,barometer", + "supports": ["BANGLEJS2"], + "readme": "README.md", + "storage": [ + {"name":"widbaroalarm.wid.js","url":"widget.js"}, + {"name":"widbaroalarm.settings.js","url":"settings.js"}, + {"name":"widbaroalarm.default.json","url":"default.json"} + ], + "data": [{"name":"widbaroalarm.json"}, {"name":"widbaroalarm.log"}] +} diff --git a/apps/widbaroalarm/screenshot.png b/apps/widbaroalarm/screenshot.png new file mode 100644 index 0000000000000000000000000000000000000000..c398b0aa875007e1d4f9d3b8aa0eaafad35a3b1a GIT binary patch literal 2707 zcmd6p`#0448pl8188bAEXey+HjdB}NWN*i%CJu7Tq)CRM+Dy4e7}xoZ5@L5z$caYb z*fxW&lg4Ej(~Zb9Be}<%**~7Y;GEA|pXXVh^;zqAp7lJR^?rS_k9#^R z<1}#q0A*JfN3z`4|FxB{a$DE(fhKoQEZLa^YG3W1mLC*iNv=Lh@|B|Wa~1$NJ6Fde zJ`9?;gjGWHO zt6a&(0jYJFRFe3WOVmi&_--QJ*Z+wx-3EIRidC)o@F9`Qruq+;!ggHA;+3Xh)L`}K zzZJFCt7^>?9fSw!6{5UNlSmuSONP1$mz^fK%zGgeK-&^}xL8fJr<7iF)5s;;Mv~EN z?`ikZ3Q^8-c(-m^Br~$EjdZ9UUA_NFu!}|}S<-_5MbEtB9P1ICk&s;N4n%L~)w_?PGTxm;_DJk~bi=1ruiwOvp7IjslLHC*^TDN-0J?KaYq zeeF1z6B%B{Jy7{OHZo*#kupDSFg+St9p5P-`M$-x%Q<2?_S|JtbU z6jb16BA6#UTC@B6a{s6dp;<{p0a-RPo0;QyJYtda;U>qDzDd^zjpUKkBOJC1V-#P- z?DI_AdJ1hSCb_&F3qTi|b|j$vVsaO~Fdf0&lXD9+X?aBBX^@~jc?;x^LKkyUncZuK zG1@%R9X3uXENMNp^h)b-k~%4M$}`#Gab9w)dOF?~>z8v4aW%JSlRjTCag?$#S>{ZHF(M1cokLWnV4Qpmk`^btfo4ll5gXmH( zl;kw?2&WUL&emh?VpA$U={(@}FmxBMv!@xI+X{{RmRBDDfOZPSfFI+QqxZmPbed40 z*e2yi6~z3e9|SzL?28qHG+a0URBq9Jg*L~RQviG-Q)LR$z>-Y>Qq_|=5Af)!9Y8er zwkHu>Wews$^o;baE$BJ?zXxLDG?n>)#{~fy8L{s#Wuy)10EV%ooC3 zBcd&bxguQ`%^P0r}v%;&F@@%Bb}y;ExeqQ^`;`cqneU4$~@|IMmd&$XVB9WEU*#Qf*jug9`Sj)~)AV zs=lC=ui8lW{9Ne5nHyNOIQ!;Mn5Y4}9d0>Vi&2EDr`#&=`oZ-!ru>b8xq)L7?Lj&6 zAqu%0em7cBVQ(e`f!BDHwLkH;CZ&WRKJ2%qtqfb0=Gi;1MJ+tDnTV5lz{yuDa`k@F zFPSONDCOuj8DyS}u3|>9T-s(i83xRnoiT%`!dgttd_>7Kv~2C?3;{$1qtB(<5T7*? zrfLb@Z6xk`1wzF<3egXfjm$TVvc+9K56|=NQZHgf`8I!Lr9!vWejPL;ibgh=T8M!T znK&jmRX}Ov*EUhc*8&|*Pnkf1u%TB}lrVH6*`vIq?lG3HHd2PE+W)SRHJAQSi@uoB z1lher+2TY6X109|g=*J78`meW+^oz2dR!OR2NDl-u)*4UboeHoDBieWy~8}EZXW=*Cl*U z@4Hav0k9(OZ1KBRAFvd;5E_-Zw7n%nUre0p-&*i}a7J%rr+CRd8Fc8O(NcH)h~^W( zG#FnMkoOcPxTnjZL?DranuHb^$xl z?ulu|h-@x@8-1xT6JNzl_2+rkvA;d0_!6H|Qky5EAotsbNkwU&V>$MEYaSTi%|0eQ zX3zLVXA}@l-wC>CVVFy(*yvcn{VMpO?zFCeut<{jdPj2dpv2EceMwB zr>PT$6%vL~66=|BtP`&jj1f)6+QDZiN&ckPPwL>h5Bt$L4%Ew4$5GzQTQdinsSt>F z%VN36F-T7BjhAyRa+8H>6#&k^@rENYV3??j{XwodE(<#aaul{3JUv{F0=uj1&$Y|P z&~im1%Ll-EZ|LDIC@@=~ioPXhVEJmUSkB6E!dV?M^#7g|VG86z?C9gyC;wOiS0_)$ JT2fH@e*hao { + return x != 0 ? x + ' min' : 'off'; + }, + onchange: x => save("interval", x) + }, + "Low alarm": { + value: settings.lowalarm, + format: x => { + return x ? 'Yes' : 'No'; + }, + onchange: x => save("lowalarm", x), + }, + "Low threshold": { + value: settings.min, + min: 600, + max: 1000, + step: 10, + onchange: x => save("min", x), + }, + "High alarm": { + value: settings.highalarm, + format: x => { + return x ? 'Yes' : 'No'; + }, + onchange: x => save("highalarm", x), + }, + "High threshold": { + value: settings.max, + min: 1000, + max: 1100, + step: 10, + onchange: x => save("max", x), + }, + "Change alarm": { + value: settings.changeIn3h, + min: 0, + max: 10, + step: 1, + format: x => { + return x != 0 ? x + ' hPa/3h' : 'off'; + }, + onchange: x => save("changeIn3h", x) + }, + "Show widget": { + value: settings.show, + format: x => { + return x ? 'Yes' : 'No'; + }, + onchange: x => save('show', x) + }, + "Buzz on alarm": { + value: settings.buzz, + format: x => { + return x ? 'Yes' : 'No'; + }, + onchange: x => save('buzz', x) + }, + }; + E.showMenu(menu); + } + + showMainMenu(); +}); diff --git a/apps/widbaroalarm/widget.js b/apps/widbaroalarm/widget.js new file mode 100644 index 000000000..b0a8f110c --- /dev/null +++ b/apps/widbaroalarm/widget.js @@ -0,0 +1,199 @@ +(function() { + let lastPressure; + let avrPressure; + let threeHourAvrPressure; + + const LOG_FILE = "widbaroalarm.log.json"; + const SETTINGS_FILE = "widbaroalarm.json"; + const storage = require('Storage'); + let settings = Object.assign( + storage.readJSON("widbaroalarm.default.json", true) || {}, + storage.readJSON(SETTINGS_FILE, true) || {} + ); + + function setting(key) { + return settings[key]; + } + const interval = setting("interval"); + + let history3 = storage.readJSON(LOG_FILE, true) || []; // history of recent 3 hours + + function showAlarm(text, value, value2, icon) { + if (text == undefined || value == undefined) return; + const Layout = require("Layout"); + layout = new Layout({ + type: "v", + c: [{ + type: "h", + c: [{ + type: "img", + pad: 0, + src: function() { + return icon || require("heatshrink").decompress(atob("jEY4cA///gH4/++mkK30kiWC4H8x3BGDmSGgYDCgmSoEAg3bsAIDpAIFkmSpMAm3btgIFDQwIGNQpTYkAIJwAHEgMoCA0JgMEyBnBCAW3KoQQDhu3oAIH5JnDBAW24IIBEYm2EYwACBCIACA")); + } + }, + { + type: "txt", + id: "title", + font: "6x8:2", + label: "Alarm", + pad: 2 + }, + ] + }, + { + type: "txt", + id: "text", + font: "6x8:2", + label: text, + pad: 3 + }, + { + type: "txt", + id: "value", + font: "6x8:2", + label: value, + halign: 0, + pad: 3 + }, + { + type: "txt", + id: "value2", + font: "6x8:1", + label: value2 || "", + halign: 0, + pad: 3 + }, + ] + }, { + btns: [{ + label: "OK", + cb: function() { + load(); // close + } + }], + lazy: false + }); + + g.clear(); + layout.render(); + + if (setting("buzz") && + !(storage.readJSON('setting.json', 1) || {}).quiet) { + Bangle.buzz(); + } + } + + let alreadyWarned = false; + + function baroHandler(data) { + if (data === undefined) { + setTimeout(() => Bangle.getPressure().then(baroHandler), 500); + } else { + lastPressure = Math.round(data.pressure); + if (lastPressure == undefined || lastPressure <= 0) return; + + const ts = Math.round(Date.now() / 1000); // seconds + const d = { + "ts": ts, + "p": lastPressure + }; + + // delete entries older than 3h + for (let i = 0; i < history3.length; i++) { + if (history3[i]["ts"] < ts - (3 * 60 * 60)) { + history3.shift(); + } + } + // delete oldest entries until we have max 50 + while (history3.length > 50) { + history3.shift(); + } + + history3.push(d); + // write data to storage + storage.writeJSON(LOG_FILE, history3); + + // we need at least three entries for reliable detection + if (history3.length >= 3) { + + // calculate average of recent three entries + avrPressure = (history3[history3.length - 1]["p"] + history3[history3.length - 2]["p"] + history3[history3.length - 3]["p"]) / 3; + + if (setting("lowalarm") && avrPressure <= setting("min")) { + showAlarm("Pressure low", Math.round(avrPressure) + " hPa"); + alreadyWarned = true; + } + if (setting("highalarm") && avrPressure >= setting("max")) { + showAlarm("Pressure high", Math.round(avrPressure) + " hPa"); + alreadyWarned = true; + } + + if (!alreadyWarned) { + // 3h change detection + const threeHourChange = setting("changeIn3h"); + if (threeHourChange > 0) { + // we need at least 30min of data for reliable detection + if (history3[0]["ts"] > ts - (30 * 60)) { + return; + } + + // Average of oldest three entries + const oldestAvgPressure = (history3[0]["p"] + history3[1]["p"] + history3[2]["p"]) / 3; + if (oldestAvgPressure != undefined && oldestAvgPressure > 0) { + const diff = oldestAvgPressure - avrPressure; + if (Math.abs(diff) > threeHourChange) { + showAlarm("Pressure " + (diff > 0 ? "drop" : "raise"), (Math.round(Math.abs(diff) * 10) / 10) + " hPa/3h", + Math.round(oldestAvgPressure) + " hPa -> " + Math.round(avrPressure) + " hPa"); + } + } + } + } + } + + // calculate 3h average for widget + let sum = 0; + for (let i = 0; i < history3.length; i++) { + sum += history3[i]["p"]; + } + threeHourAvrPressure = sum / history3.length; + } + } + + function check() { + Bangle.getPressure().then(baroHandler); + } + + function reload() { + check(); + } + + function draw() { + g.reset(); + if (setting("show") && lastPressure != undefined) { + g.setFont("6x8", 1).setFontAlign(1, 0); + g.drawString(Math.round(lastPressure), this.x + 24, this.y + 6); + if (threeHourAvrPressure != undefined && threeHourAvrPressure > 0) { + g.drawString(Math.round(threeHourAvrPressure), this.x + 24, this.y + 6 + 10); + } + } + } + + if (global.WIDGETS != undefined && typeof WIDGETS === "object") { + WIDGETS["baroalarm"] = { + width: setting("show") ? 24 : 0, + reload: reload, + area: "tr", + draw: draw + }; + } + + // Let's delay check a bit + setTimeout(function() { + check(); + if (interval > 0) { + setInterval(check, interval * 60000); + } + }, 10000); + +})(); diff --git a/apps/widbaroalarm/widget.png b/apps/widbaroalarm/widget.png new file mode 100644 index 0000000000000000000000000000000000000000..5be2921432b2d43167309be3ca50e52e3216dc71 GIT binary patch literal 9872 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 am%74g<61aCeHq`{01Xvg Date: Mon, 7 Mar 2022 21:37:41 +0100 Subject: [PATCH 55/61] Use notify module to show notification --- apps/widbaroalarm/metadata.json | 2 +- apps/widbaroalarm/screenshot.png | Bin 2707 -> 0 bytes apps/widbaroalarm/widget.js | 76 ++++++------------------------- 3 files changed, 14 insertions(+), 64 deletions(-) delete mode 100644 apps/widbaroalarm/screenshot.png diff --git a/apps/widbaroalarm/metadata.json b/apps/widbaroalarm/metadata.json index 3dd02019d..0976df531 100644 --- a/apps/widbaroalarm/metadata.json +++ b/apps/widbaroalarm/metadata.json @@ -5,10 +5,10 @@ "version": "0.01", "description": "A widget that can alarm on when the pressure reaches defined thresholds.", "icon": "widget.png", - "screenshots": [{"url":"screenshot.png"}], "type": "widget", "tags": "tool,barometer", "supports": ["BANGLEJS2"], + "dependencies": {"notify":"type"}, "readme": "README.md", "storage": [ {"name":"widbaroalarm.wid.js","url":"widget.js"}, diff --git a/apps/widbaroalarm/screenshot.png b/apps/widbaroalarm/screenshot.png deleted file mode 100644 index c398b0aa875007e1d4f9d3b8aa0eaafad35a3b1a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2707 zcmd6p`#0448pl8188bAEXey+HjdB}NWN*i%CJu7Tq)CRM+Dy4e7}xoZ5@L5z$caYb z*fxW&lg4Ej(~Zb9Be}<%**~7Y;GEA|pXXVh^;zqAp7lJR^?rS_k9#^R z<1}#q0A*JfN3z`4|FxB{a$DE(fhKoQEZLa^YG3W1mLC*iNv=Lh@|B|Wa~1$NJ6Fde zJ`9?;gjGWHO zt6a&(0jYJFRFe3WOVmi&_--QJ*Z+wx-3EIRidC)o@F9`Qruq+;!ggHA;+3Xh)L`}K zzZJFCt7^>?9fSw!6{5UNlSmuSONP1$mz^fK%zGgeK-&^}xL8fJr<7iF)5s;;Mv~EN z?`ikZ3Q^8-c(-m^Br~$EjdZ9UUA_NFu!}|}S<-_5MbEtB9P1ICk&s;N4n%L~)w_?PGTxm;_DJk~bi=1ruiwOvp7IjslLHC*^TDN-0J?KaYq zeeF1z6B%B{Jy7{OHZo*#kupDSFg+St9p5P-`M$-x%Q<2?_S|JtbU z6jb16BA6#UTC@B6a{s6dp;<{p0a-RPo0;QyJYtda;U>qDzDd^zjpUKkBOJC1V-#P- z?DI_AdJ1hSCb_&F3qTi|b|j$vVsaO~Fdf0&lXD9+X?aBBX^@~jc?;x^LKkyUncZuK zG1@%R9X3uXENMNp^h)b-k~%4M$}`#Gab9w)dOF?~>z8v4aW%JSlRjTCag?$#S>{ZHF(M1cokLWnV4Qpmk`^btfo4ll5gXmH( zl;kw?2&WUL&emh?VpA$U={(@}FmxBMv!@xI+X{{RmRBDDfOZPSfFI+QqxZmPbed40 z*e2yi6~z3e9|SzL?28qHG+a0URBq9Jg*L~RQviG-Q)LR$z>-Y>Qq_|=5Af)!9Y8er zwkHu>Wews$^o;baE$BJ?zXxLDG?n>)#{~fy8L{s#Wuy)10EV%ooC3 zBcd&bxguQ`%^P0r}v%;&F@@%Bb}y;ExeqQ^`;`cqneU4$~@|IMmd&$XVB9WEU*#Qf*jug9`Sj)~)AV zs=lC=ui8lW{9Ne5nHyNOIQ!;Mn5Y4}9d0>Vi&2EDr`#&=`oZ-!ru>b8xq)L7?Lj&6 zAqu%0em7cBVQ(e`f!BDHwLkH;CZ&WRKJ2%qtqfb0=Gi;1MJ+tDnTV5lz{yuDa`k@F zFPSONDCOuj8DyS}u3|>9T-s(i83xRnoiT%`!dgttd_>7Kv~2C?3;{$1qtB(<5T7*? zrfLb@Z6xk`1wzF<3egXfjm$TVvc+9K56|=NQZHgf`8I!Lr9!vWejPL;ibgh=T8M!T znK&jmRX}Ov*EUhc*8&|*Pnkf1u%TB}lrVH6*`vIq?lG3HHd2PE+W)SRHJAQSi@uoB z1lher+2TY6X109|g=*J78`meW+^oz2dR!OR2NDl-u)*4UboeHoDBieWy~8}EZXW=*Cl*U z@4Hav0k9(OZ1KBRAFvd;5E_-Zw7n%nUre0p-&*i}a7J%rr+CRd8Fc8O(NcH)h~^W( zG#FnMkoOcPxTnjZL?DranuHb^$xl z?ulu|h-@x@8-1xT6JNzl_2+rkvA;d0_!6H|Qky5EAotsbNkwU&V>$MEYaSTi%|0eQ zX3zLVXA}@l-wC>CVVFy(*yvcn{VMpO?zFCeut<{jdPj2dpv2EceMwB zr>PT$6%vL~66=|BtP`&jj1f)6+QDZiN&ckPPwL>h5Bt$L4%Ew4$5GzQTQdinsSt>F z%VN36F-T7BjhAyRa+8H>6#&k^@rENYV3??j{XwodE(<#aaul{3JUv{F0=uj1&$Y|P z&~im1%Ll-EZ|LDIC@@=~ioPXhVEJmUSkB6E!dV?M^#7g|VG86z?C9gyC;wOiS0_)$ JT2fH@e*hao= setting("max")) { - showAlarm("Pressure high", Math.round(avrPressure) + " hPa"); + showAlarm("Pressure high: " + Math.round(avrPressure) + " hPa"); alreadyWarned = true; } @@ -143,8 +92,9 @@ if (oldestAvgPressure != undefined && oldestAvgPressure > 0) { const diff = oldestAvgPressure - avrPressure; if (Math.abs(diff) > threeHourChange) { - showAlarm("Pressure " + (diff > 0 ? "drop" : "raise"), (Math.round(Math.abs(diff) * 10) / 10) + " hPa/3h", - Math.round(oldestAvgPressure) + " hPa -> " + Math.round(avrPressure) + " hPa"); + showAlarm((Math.round(Math.abs(diff) * 10) / 10) + " hPa/3h from " + + Math.round(oldestAvgPressure) + " to " + Math.round(avrPressure) + " hPa", + "Pressure " + (diff > 0 ? "drop" : "raise")); } } } @@ -188,7 +138,7 @@ }; } - // Let's delay check a bit + // Let's delay the first check a bit setTimeout(function() { check(); if (interval > 0) { From c235a22c1661bad84ff2d07d11bb5b84b1683424 Mon Sep 17 00:00:00 2001 From: Richard de Boer Date: Mon, 7 Mar 2022 23:19:35 +0100 Subject: [PATCH 56/61] qmsched: unbreak app for new Bangle.j2 2 menu --- apps/qmsched/ChangeLog | 3 +- apps/qmsched/app.js | 59 ++++++++++++++++---------------------- apps/qmsched/metadata.json | 2 +- 3 files changed, 28 insertions(+), 36 deletions(-) diff --git a/apps/qmsched/ChangeLog b/apps/qmsched/ChangeLog index c868b6668..94fcffe1a 100644 --- a/apps/qmsched/ChangeLog +++ b/apps/qmsched/ChangeLog @@ -5,4 +5,5 @@ 0.05: Avoid immediately redrawing widgets on load 0.06: Fix: don't try to redraw widget when widgets not loaded 0.07: Option to switch theme - Changed time selection to 5-minute intervals \ No newline at end of file + Changed time selection to 5-minute intervals +0.08: Support new Bangle.js 2 menu \ No newline at end of file diff --git a/apps/qmsched/app.js b/apps/qmsched/app.js index e05eff6a2..f80cfcf4d 100644 --- a/apps/qmsched/app.js +++ b/apps/qmsched/app.js @@ -2,7 +2,7 @@ Bangle.loadWidgets(); Bangle.drawWidgets(); const modeNames = ["Off", "Alarms", "Silent"]; - +const B2 = process.env.HWVERSION===2; // load global settings let bSettings = require('Storage').readJSON('setting.json',true)||{}; let current = 0|bSettings.quiet; @@ -109,26 +109,19 @@ function setAppQuietMode(mode) { let m; function showMainMenu() { - let menu = { - "": {"title": "Quiet Mode"}, - "< Exit": () => load() - }; + let menu = {"": {"title": "Quiet Mode"},}; + menu[B2 ? "< Back" : "< Exit"] = () => {load();}; // "Current Mode""Silent" won't fit on Bangle.js 2 menu["Current"+((process.env.HWVERSION===2) ? "" : " Mode")] = { value: current, min:0, max:2, wrap: true, - format: () => modeNames[current], + format: v => modeNames[v], onchange: require("qmsched").setMode, // library calls setAppMode(), which updates `current` }; scheds.sort((a, b) => (a.hr-b.hr)); scheds.forEach((sched, idx) => { - menu[formatTime(sched.hr)] = { - format: () => modeNames[sched.mode], // abuse format to right-align text - onchange: () => { - m.draw = ()=> {}; // prevent redraw of main menu over edit menu (needed because we abuse format/onchange) - showEditMenu(idx); - } - }; + menu[formatTime(sched.hr)] = () => { showEditMenu(idx); }; + menu[formatTime(sched.hr)].format = () => modeNames[sched.mode]+' >'; // this does nothing :-( }); menu["Add Schedule"] = () => showEditMenu(-1); menu["Switch Theme"] = { @@ -150,25 +143,23 @@ function showEditMenu(index) { mins = Math.round((s.hr-hrs)*60); mode = s.mode; } - const menu = { - "": {"title": (isNew ? "Add" : "Edit")+" Schedule"}, - "< Cancel": () => showMainMenu(), - "Hours": { - value: hrs, - min:0, max:23, wrap:true, - onchange: v => {hrs = v;}, - }, - "Minutes": { - value: mins, - min:0, max:55, step:5, wrap:true, - onchange: v => {mins = v;}, - }, - "Switch to": { - value: mode, - min:0, max:2, wrap:true, - format: v => modeNames[v], - onchange: v => {mode = v;}, - }, + let menu = {"": {"title": (isNew ? "Add" : "Edit")+" Schedule"}}; + menu[B2 ? "< Back" : "< Cancel"] = () => showMainMenu(); + menu["Hours"] = { + value: hrs, + min:0, max:23, wrap:true, + onchange: v => {hrs = v;}, + }; + menu["Minutes"] = { + value: mins, + min:0, max:55, step:5, wrap:true, + onchange: v => {mins = v;}, + }; + menu["Switch to"] = { + value: mode, + min:0, max:2, wrap:true, + format: v => modeNames[v], + onchange: v => {mode = v;}, }; function getSched() { return { @@ -176,7 +167,7 @@ function showEditMenu(index) { mode: mode, }; } - menu["> Save"] = function() { + menu[B2 ? "Save" : "> Save"] = function() { if (isNew) { scheds.push(getSched()); } else { @@ -186,7 +177,7 @@ function showEditMenu(index) { showMainMenu(); }; if (!isNew) { - menu["> Delete"] = function() { + menu[B2 ? "Delete" : "> Delete"] = function() { scheds.splice(index, 1); save(); showMainMenu(); diff --git a/apps/qmsched/metadata.json b/apps/qmsched/metadata.json index daeaad624..326a8fc4f 100644 --- a/apps/qmsched/metadata.json +++ b/apps/qmsched/metadata.json @@ -2,7 +2,7 @@ "id": "qmsched", "name": "Quiet Mode Schedule and Widget", "shortName": "Quiet Mode", - "version": "0.07", + "version": "0.08", "description": "Automatically turn Quiet Mode on or off at set times, change theme and LCD options while Quiet Mode is active.", "icon": "app.png", "screenshots": [{"url":"screenshot_b1_main.png"},{"url":"screenshot_b1_edit.png"},{"url":"screenshot_b1_lcd.png"}, From 9c7e5fa06861c1226f81571a0995c723151835ca Mon Sep 17 00:00:00 2001 From: Richard de Boer Date: Mon, 7 Mar 2022 23:22:23 +0100 Subject: [PATCH 57/61] qmsched: add /*LANG*/ translation hints --- apps/qmsched/app.js | 45 ++++++++++++++++++++++----------------------- 1 file changed, 22 insertions(+), 23 deletions(-) diff --git a/apps/qmsched/app.js b/apps/qmsched/app.js index f80cfcf4d..8cd0fa8d9 100644 --- a/apps/qmsched/app.js +++ b/apps/qmsched/app.js @@ -1,7 +1,7 @@ Bangle.loadWidgets(); Bangle.drawWidgets(); -const modeNames = ["Off", "Alarms", "Silent"]; +const modeNames = [/*LANG*/"Off", /*LANG*/"Alarms", /*LANG*/"Silent"]; const B2 = process.env.HWVERSION===2; // load global settings let bSettings = require('Storage').readJSON('setting.json',true)||{}; @@ -109,10 +109,9 @@ function setAppQuietMode(mode) { let m; function showMainMenu() { - let menu = {"": {"title": "Quiet Mode"},}; - menu[B2 ? "< Back" : "< Exit"] = () => {load();}; - // "Current Mode""Silent" won't fit on Bangle.js 2 - menu["Current"+((process.env.HWVERSION===2) ? "" : " Mode")] = { + let menu = {"": {"title": /*LANG*/"Quiet Mode"},}; + menu[B2 ? /*LANG*/"< Back" : /*LANG*/"< Exit"] = () => {load();}; + menu[/*LANG*/"Current Mode"] = { value: current, min:0, max:2, wrap: true, format: v => modeNames[v], @@ -123,13 +122,13 @@ function showMainMenu() { menu[formatTime(sched.hr)] = () => { showEditMenu(idx); }; menu[formatTime(sched.hr)].format = () => modeNames[sched.mode]+' >'; // this does nothing :-( }); - menu["Add Schedule"] = () => showEditMenu(-1); - menu["Switch Theme"] = { + menu[/*LANG*/"Add Schedule"] = () => showEditMenu(-1); + menu[/*LANG*/"Switch Theme"] = { value: !!get("switchTheme"), format: v => v ? /*LANG*/"Yes" : /*LANG*/"No", onchange: v => v ? set("switchTheme", v) : unset("switchTheme"), }; - menu["LCD Settings"] = () => showOptionsMenu(); + menu[/*LANG*/"LCD Settings"] = () => showOptionsMenu(); m = E.showMenu(menu); } @@ -143,19 +142,19 @@ function showEditMenu(index) { mins = Math.round((s.hr-hrs)*60); mode = s.mode; } - let menu = {"": {"title": (isNew ? "Add" : "Edit")+" Schedule"}}; - menu[B2 ? "< Back" : "< Cancel"] = () => showMainMenu(); - menu["Hours"] = { + let menu = {"": {"title": (isNew ? /*LANG*/"Add Schedule" : /*LANG*/"Edit Schedule")}}; + menu[B2 ? /*LANG*/"< Back" : /*LANG*/"< Cancel"] = () => showMainMenu(); + menu[/*LANG*/"Hours"] = { value: hrs, min:0, max:23, wrap:true, onchange: v => {hrs = v;}, }; - menu["Minutes"] = { + menu[/*LANG*/"Minutes"] = { value: mins, min:0, max:55, step:5, wrap:true, onchange: v => {mins = v;}, }; - menu["Switch to"] = { + menu[/*LANG*/"Switch to"] = { value: mode, min:0, max:2, wrap:true, format: v => modeNames[v], @@ -167,7 +166,7 @@ function showEditMenu(index) { mode: mode, }; } - menu[B2 ? "Save" : "> Save"] = function() { + menu[B2 ? /*LANG*/"Save" : /*LANG*/"> Save"] = function() { if (isNew) { scheds.push(getSched()); } else { @@ -177,7 +176,7 @@ function showEditMenu(index) { showMainMenu(); }; if (!isNew) { - menu[B2 ? "Delete" : "> Delete"] = function() { + menu[B2 ? /*LANG*/"Delete" : /*LANG*/"> Delete"] = function() { scheds.splice(index, 1); save(); showMainMenu(); @@ -187,7 +186,7 @@ function showEditMenu(index) { } function showOptionsMenu() { - const disabledFormat = v => v ? "Off" : "-"; + const disabledFormat = v => v ? /*LANG*/"Off" : "-"; function toggle(option) { // we disable wakeOn* events by setting them to `false` in options // not disabled = not present in options at all @@ -200,9 +199,9 @@ function showOptionsMenu() { } let resetTimeout; const oMenu = { - "": {"title": "LCD Settings"}, - "< Back": () => showMainMenu(), - "LCD Brightness": { + "": {"title": /*LANG*/"LCD Settings"}, + /*LANG*/"< Back": () => showMainMenu(), + /*LANG*/"LCD Brightness": { value: get("brightness", 0), min: 0, // 0 = use default max: 1, @@ -224,7 +223,7 @@ function showOptionsMenu() { } }, }, - "LCD Timeout": { + /*LANG*/"LCD Timeout": { value: get("timeout", 0), min: 0, // 0 = use default (no constant on for quiet mode) max: 60, @@ -237,17 +236,17 @@ function showOptionsMenu() { }, // we disable wakeOn* events by overwriting them as false in options // not disabled = not present in options at all - "Wake on FaceUp": { + /*LANG*/"Wake on FaceUp": { value: "wakeOnFaceUp" in options, format: disabledFormat, onchange: () => {toggle("wakeOnFaceUp");}, }, - "Wake on Touch": { + /*LANG*/"Wake on Touch": { value: "wakeOnTouch" in options, format: disabledFormat, onchange: () => {toggle("wakeOnTouch");}, }, - "Wake on Twist": { + /*LANG*/"Wake on Twist": { value: "wakeOnTwist" in options, format: disabledFormat, onchange: () => {toggle("wakeOnTwist");}, From 1e7b9f1b65dceed11c8f3ae46b79a864d4f56324 Mon Sep 17 00:00:00 2001 From: Marco H Date: Tue, 8 Mar 2022 09:54:16 +0100 Subject: [PATCH 58/61] Allow configuration of drop and raise alarm independently --- apps/widbaroalarm/README.md | 4 +++- apps/widbaroalarm/default.json | 3 ++- apps/widbaroalarm/settings.js | 16 +++++++++++++--- apps/widbaroalarm/widget.js | 26 ++++++++++++++++++++------ 4 files changed, 38 insertions(+), 11 deletions(-) diff --git a/apps/widbaroalarm/README.md b/apps/widbaroalarm/README.md index 6708b1e2b..b92a51050 100644 --- a/apps/widbaroalarm/README.md +++ b/apps/widbaroalarm/README.md @@ -11,7 +11,9 @@ Get a notification when the pressure reaches defined thresholds. * Low threshold: Warn when pressure drops below this value * High alarm: Toggle high alarm * High threshold: Warn when pressure exceeds above this value -* Change alarm: Warn when pressure changes more than this value in the recent 3 hours (having at least 30 min of data) +* Drop alarm: Warn when pressure drops more than this value in the recent 3 hours (having at least 30 min of data) + 0 to disable this alarm. +* Raise alarm: Warn when pressure raises more than this value in the recent 3 hours (having at least 30 min of data) 0 to disable this alarm. * Show widget: Enable/disable widget visibility * Buzz on alarm: Enable/disable buzzer on alarm diff --git a/apps/widbaroalarm/default.json b/apps/widbaroalarm/default.json index 7dbe6fc17..3d81baa81 100644 --- a/apps/widbaroalarm/default.json +++ b/apps/widbaroalarm/default.json @@ -4,7 +4,8 @@ "min": 950, "highalarm": false, "max": 1030, - "changeIn3h": 2, + "drop3halarm": 2, + "raise3halarm": 0, "show": true, "interval": 15 } diff --git a/apps/widbaroalarm/settings.js b/apps/widbaroalarm/settings.js index d3d2df0ae..1455072e4 100644 --- a/apps/widbaroalarm/settings.js +++ b/apps/widbaroalarm/settings.js @@ -53,15 +53,25 @@ step: 10, onchange: x => save("max", x), }, - "Change alarm": { - value: settings.changeIn3h, + "Drop alarm": { + value: settings.drop3halarm, min: 0, max: 10, step: 1, format: x => { return x != 0 ? x + ' hPa/3h' : 'off'; }, - onchange: x => save("changeIn3h", x) + onchange: x => save("drop3halarm", x) + }, + "Raise alarm": { + value: settings.raise3halarm, + min: 0, + max: 10, + step: 1, + format: x => { + return x != 0 ? x + ' hPa/3h' : 'off'; + }, + onchange: x => save("raise3halarm", x) }, "Show widget": { value: settings.show, diff --git a/apps/widbaroalarm/widget.js b/apps/widbaroalarm/widget.js index 443b6c68c..9b65ffe5b 100644 --- a/apps/widbaroalarm/widget.js +++ b/apps/widbaroalarm/widget.js @@ -80,8 +80,9 @@ if (!alreadyWarned) { // 3h change detection - const threeHourChange = setting("changeIn3h"); - if (threeHourChange > 0) { + const drop3halarm = setting("drop3halarm"); + const raise3halarm = setting("raise3halarm"); + if (drop3halarm > 0 || raise3halarm > 0) { // we need at least 30min of data for reliable detection if (history3[0]["ts"] > ts - (30 * 60)) { return; @@ -91,10 +92,23 @@ const oldestAvgPressure = (history3[0]["p"] + history3[1]["p"] + history3[2]["p"]) / 3; if (oldestAvgPressure != undefined && oldestAvgPressure > 0) { const diff = oldestAvgPressure - avrPressure; - if (Math.abs(diff) > threeHourChange) { - showAlarm((Math.round(Math.abs(diff) * 10) / 10) + " hPa/3h from " + - Math.round(oldestAvgPressure) + " to " + Math.round(avrPressure) + " hPa", - "Pressure " + (diff > 0 ? "drop" : "raise")); + + // drop alarm + if (drop3halarm > 0 && oldestAvgPressure > avrPressure) { + if (Math.abs(diff) > drop3halarm) { + showAlarm((Math.round(Math.abs(diff) * 10) / 10) + " hPa/3h from " + + Math.round(oldestAvgPressure) + " to " + Math.round(avrPressure) + " hPa", + "Pressure drop")); + } + } + + // raise alarm + if (raise3halarm > 0 && oldestAvgPressure < avrPressure) { + if (Math.abs(diff) > raise3halarm) { + showAlarm((Math.round(Math.abs(diff) * 10) / 10) + " hPa/3h from " + + Math.round(oldestAvgPressure) + " to " + Math.round(avrPressure) + " hPa", + "Pressure raise")); + } } } } From cf365dc451822a15997e13bab147d97077c701fa Mon Sep 17 00:00:00 2001 From: Marco H Date: Tue, 8 Mar 2022 11:27:13 +0100 Subject: [PATCH 59/61] Use median calculation instead of average to get valid measurements --- apps/widbaroalarm/widget.js | 256 ++++++++++++++++++++---------------- 1 file changed, 139 insertions(+), 117 deletions(-) diff --git a/apps/widbaroalarm/widget.js b/apps/widbaroalarm/widget.js index 9b65ffe5b..7279a963a 100644 --- a/apps/widbaroalarm/widget.js +++ b/apps/widbaroalarm/widget.js @@ -1,51 +1,47 @@ (function() { - let lastPressure; - let avrPressure; - let threeHourAvrPressure; + let medianPressure; + let threeHourAvrPressure; + let currentPressures = []; - const LOG_FILE = "widbaroalarm.log.json"; - const SETTINGS_FILE = "widbaroalarm.json"; - const storage = require('Storage'); - let settings = Object.assign( - storage.readJSON("widbaroalarm.default.json", true) || {}, - storage.readJSON(SETTINGS_FILE, true) || {} - ); + const LOG_FILE = "widbaroalarm.log.json"; + const SETTINGS_FILE = "widbaroalarm.json"; + const storage = require('Storage'); + let settings = Object.assign( + storage.readJSON("widbaroalarm.default.json", true) || {}, + storage.readJSON(SETTINGS_FILE, true) || {} + ); - function setting(key) { - return settings[key]; - } - const interval = setting("interval"); - - let history3 = storage.readJSON(LOG_FILE, true) || []; // history of recent 3 hours - - function showAlarm(body, title) { - if (body == undefined) return; - - require("notify").show({ - title: title || "Pressure", - body: body, - icon: require("heatshrink").decompress(atob("jEY4cA///gH4/++mkK30kiWC4H8x3BGDmSGgYDCgmSoEAg3bsAIDpAIFkmSpMAm3btgIFDQwIGNQpTYkAIJwAHEgMoCA0JgMEyBnBCAW3KoQQDhu3oAIH5JnDBAW24IIBEYm2EYwACBCIACA")) - }); - - if (setting("buzz") && - !(storage.readJSON('setting.json', 1) || {}).quiet) { - Bangle.buzz(); + function setting(key) { + return settings[key]; } - } + const interval = setting("interval"); - let alreadyWarned = false; + let history3 = storage.readJSON(LOG_FILE, true) || []; // history of recent 3 hours - function baroHandler(data) { - if (data === undefined) { - setTimeout(() => Bangle.getPressure().then(baroHandler), 500); - } else { - lastPressure = Math.round(data.pressure); - if (lastPressure == undefined || lastPressure <= 0) return; + function showAlarm(body, title) { + if (body == undefined) return; + + require("notify").show({ + title: title || "Pressure", + body: body, + icon: require("heatshrink").decompress(atob("jEY4cA///gH4/++mkK30kiWC4H8x3BGDmSGgYDCgmSoEAg3bsAIDpAIFkmSpMAm3btgIFDQwIGNQpTYkAIJwAHEgMoCA0JgMEyBnBCAW3KoQQDhu3oAIH5JnDBAW24IIBEYm2EYwACBCIACA")) + }); + + if (setting("buzz") && + !(storage.readJSON('setting.json', 1) || {}).quiet) { + Bangle.buzz(); + } + } + + let alreadyWarned = false; + + function checkForAlarms(pressure) { + if (pressure == undefined || pressure <= 0) return; const ts = Math.round(Date.now() / 1000); // seconds const d = { "ts": ts, - "p": lastPressure + "p": pressure }; // delete entries older than 3h @@ -63,101 +59,127 @@ // write data to storage storage.writeJSON(LOG_FILE, history3); - // we need at least three entries for reliable detection - if (history3.length >= 3) { + if (setting("lowalarm") && pressure <= setting("min")) { + showAlarm("Pressure low: " + Math.round(pressure) + " hPa"); + alreadyWarned = true; + } + if (setting("highalarm") && pressure >= setting("max")) { + showAlarm("Pressure high: " + Math.round(pressure) + " hPa"); + alreadyWarned = true; + } - // calculate average of recent three entries - avrPressure = (history3[history3.length - 1]["p"] + history3[history3.length - 2]["p"] + history3[history3.length - 3]["p"]) / 3; + if (!alreadyWarned) { + // 3h change detection + const drop3halarm = setting("drop3halarm"); + const raise3halarm = setting("raise3halarm"); + if (drop3halarm > 0 || raise3halarm > 0) { + // we need at least 30min of data for reliable detection + if (history3[0]["ts"] > ts - (30 * 60)) { + return; + } - if (setting("lowalarm") && avrPressure <= setting("min")) { - showAlarm("Pressure low: " + Math.round(avrPressure) + " hPa"); - alreadyWarned = true; - } - if (setting("highalarm") && avrPressure >= setting("max")) { - showAlarm("Pressure high: " + Math.round(avrPressure) + " hPa"); - alreadyWarned = true; - } + // Get oldest entry: + const oldestPressure = history3[0]["p"]; + if (oldestPressure != undefined && oldestPressure > 0) { + const diff = oldestPressure - pressure; - if (!alreadyWarned) { - // 3h change detection - const drop3halarm = setting("drop3halarm"); - const raise3halarm = setting("raise3halarm"); - if (drop3halarm > 0 || raise3halarm > 0) { - // we need at least 30min of data for reliable detection - if (history3[0]["ts"] > ts - (30 * 60)) { - return; + // drop alarm + if (drop3halarm > 0 && oldestPressure > pressure) { + if (Math.abs(diff) > drop3halarm) { + showAlarm((Math.round(Math.abs(diff) * 10) / 10) + " hPa/3h from " + + Math.round(oldestPressure) + " to " + Math.round(pressure) + " hPa", "Pressure drop"); } + } - // Average of oldest three entries - const oldestAvgPressure = (history3[0]["p"] + history3[1]["p"] + history3[2]["p"]) / 3; - if (oldestAvgPressure != undefined && oldestAvgPressure > 0) { - const diff = oldestAvgPressure - avrPressure; - - // drop alarm - if (drop3halarm > 0 && oldestAvgPressure > avrPressure) { - if (Math.abs(diff) > drop3halarm) { - showAlarm((Math.round(Math.abs(diff) * 10) / 10) + " hPa/3h from " + - Math.round(oldestAvgPressure) + " to " + Math.round(avrPressure) + " hPa", - "Pressure drop")); - } - } - - // raise alarm - if (raise3halarm > 0 && oldestAvgPressure < avrPressure) { - if (Math.abs(diff) > raise3halarm) { - showAlarm((Math.round(Math.abs(diff) * 10) / 10) + " hPa/3h from " + - Math.round(oldestAvgPressure) + " to " + Math.round(avrPressure) + " hPa", - "Pressure raise")); - } - } - } + // raise alarm + if (raise3halarm > 0 && oldestPressure < pressure) { + if (Math.abs(diff) > raise3halarm) { + showAlarm((Math.round(Math.abs(diff) * 10) / 10) + " hPa/3h from " + + Math.round(oldestPressure) + " to " + Math.round(pressure) + " hPa", "Pressure raise"); } } } - - // calculate 3h average for widget - let sum = 0; - for (let i = 0; i < history3.length; i++) { - sum += history3[i]["p"]; - } - threeHourAvrPressure = sum / history3.length; } } - function check() { - Bangle.getPressure().then(baroHandler); + // calculate 3h average for widget + let sum = 0; + for (let i = 0; i < history3.length; i++) { + sum += history3[i]["p"]; } + threeHourAvrPressure = sum / history3.length; +} - function reload() { - check(); + + +function baroHandler(data) { + if (data) { + const pressure = Math.round(data.pressure); + if (pressure == undefined || pressure <= 0) return; + currentPressures.push(pressure); } +} - function draw() { - g.reset(); - if (setting("show") && lastPressure != undefined) { - g.setFont("6x8", 1).setFontAlign(1, 0); - g.drawString(Math.round(lastPressure), this.x + 24, this.y + 6); - if (threeHourAvrPressure != undefined && threeHourAvrPressure > 0) { - g.drawString(Math.round(threeHourAvrPressure), this.x + 24, this.y + 6 + 10); - } - } - } - - if (global.WIDGETS != undefined && typeof WIDGETS === "object") { - WIDGETS["baroalarm"] = { - width: setting("show") ? 24 : 0, - reload: reload, - area: "tr", - draw: draw - }; - } - - // Let's delay the first check a bit +/* + turn on barometer power + take 5 measurements + sort the results + take the middle one (median) + turn off barometer power +*/ +function check() { + Bangle.setBarometerPower(true, "widbaroalarm"); setTimeout(function() { - check(); - if (interval > 0) { - setInterval(check, interval * 60000); + currentPressures = []; + + Bangle.getPressure().then(baroHandler); + Bangle.getPressure().then(baroHandler); + Bangle.getPressure().then(baroHandler); + Bangle.getPressure().then(baroHandler); + Bangle.getPressure().then(baroHandler); + + setTimeout(function() { + Bangle.setBarometerPower(false, "widbaroalarm"); + + currentPressures.sort(); + + // take median value + medianPressure = currentPressures[3]; + checkForAlarms(medianPressure); + }, 1000); + }, 500); +} + +function reload() { + check(); +} + +function draw() { + g.reset(); + if (setting("show") && medianPressure != undefined) { + g.setFont("6x8", 1).setFontAlign(1, 0); + g.drawString(Math.round(medianPressure), this.x + 24, this.y + 6); + if (threeHourAvrPressure != undefined && threeHourAvrPressure > 0) { + g.drawString(Math.round(threeHourAvrPressure), this.x + 24, this.y + 6 + 10); } - }, 10000); + } +} + +if (global.WIDGETS != undefined && typeof WIDGETS === "object") { + WIDGETS["baroalarm"] = { + width: setting("show") ? 24 : 0, + reload: reload, + area: "tr", + draw: draw + }; +} + +// Let's delay the first check a bit +setTimeout(function() { +check(); +if (interval > 0) { + setInterval(check, interval * 60000); +} +}, 5000); })(); From 401f197d1e7ecd14f0848ebfc4f1a4a84c86eca7 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Tue, 8 Mar 2022 11:43:04 +0000 Subject: [PATCH 60/61] fix #1548 --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 9cf30065a..38ce09f75 100644 --- a/README.md +++ b/README.md @@ -243,6 +243,7 @@ and which gives information about the app for the Launcher. "screenshots" : [ { url:"screenshot.png" } ], // optional screenshot for app "type":"...", // optional(if app) - // 'app' - an application + // 'clock' - a clock - required for clocks to automatically start // 'widget' - a widget // 'launch' - replacement launcher app // 'bootloader' - code that runs at startup only From eca40798282f5ebde99238c4581bc458835c793f Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Tue, 8 Mar 2022 13:00:31 +0000 Subject: [PATCH 61/61] Fix issue with code uploader where it'd silently refuse to upload code with warnings in --- apps/custom/custom.html | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/apps/custom/custom.html b/apps/custom/custom.html index 684f813ae..307f2fd2f 100644 --- a/apps/custom/custom.html +++ b/apps/custom/custom.html @@ -16,12 +16,12 @@

Type your javascript code here

-

Then click

+

Then click