From 43b0d8897e7a50556b93a58eff19d068d2f43544 Mon Sep 17 00:00:00 2001 From: Richard de Boer Date: Fri, 17 Apr 2020 21:25:56 +0200 Subject: [PATCH 01/73] widbatpc: Save settings in data file --- apps.json | 8 +++++--- apps/widbatpc/ChangeLog | 1 + apps/widbatpc/settings.js | 2 +- apps/widbatpc/widget.js | 2 +- 4 files changed, 8 insertions(+), 5 deletions(-) diff --git a/apps.json b/apps.json index 0c97b9e57..315120cc7 100644 --- a/apps.json +++ b/apps.json @@ -342,14 +342,16 @@ "name": "Battery Level Widget (with percentage)", "shortName": "Battery Widget", "icon": "widget.png", - "version":"0.09", + "version":"0.10", "description": "Show the current battery level and charging status in the top right of the clock, with charge percentage", "tags": "widget,battery", "type":"widget", "storage": [ {"name":"widbatpc.wid.js","url":"widget.js"}, - {"name":"widbatpc.settings.js","url":"settings.js"}, - {"name":"widbatpc.settings.json","content": "{}"} + {"name":"widbatpc.settings.js","url":"settings.js"} + ], + "data": [ + {"name":"widbatpc.json"} ] }, { "id": "widbt", diff --git a/apps/widbatpc/ChangeLog b/apps/widbatpc/ChangeLog index 129707320..138c1adc8 100644 --- a/apps/widbatpc/ChangeLog +++ b/apps/widbatpc/ChangeLog @@ -6,3 +6,4 @@ 0.07: Add settings: percentage/color/charger icon 0.08: Draw percentage as inverted on monochrome battery 0.09: Fix regression stopping correct widget updates +0.10: Don't overwrite existing settings on app update diff --git a/apps/widbatpc/settings.js b/apps/widbatpc/settings.js index 5c0bdbcae..88988cf22 100644 --- a/apps/widbatpc/settings.js +++ b/apps/widbatpc/settings.js @@ -3,7 +3,7 @@ * @param {function} back Use back() to return to settings menu */ (function(back) { - const SETTINGS_FILE = 'widbatpc.settings.json' + const SETTINGS_FILE = 'widbatpc.json' const COLORS = ['By Level', 'Green', 'Monochrome'] // initialize with default settings... diff --git a/apps/widbatpc/widget.js b/apps/widbatpc/widget.js index aca690ce0..189ca215f 100644 --- a/apps/widbatpc/widget.js +++ b/apps/widbatpc/widget.js @@ -11,7 +11,7 @@ const COLORS = { 'ok': 0xFD20, // "Orange" 'low':0xF800, // "Red" } -const SETTINGS_FILE = 'widbatpc.settings.json' +const SETTINGS_FILE = 'widbatpc.json' let settings function loadSettings() { From b691f783aa7cb956c0644658907a93e27ce836c9 Mon Sep 17 00:00:00 2001 From: Richard de Boer Date: Fri, 17 Apr 2020 21:29:56 +0200 Subject: [PATCH 02/73] welcome: Save settings in data file fwelcom --- apps.json | 6 ++++-- apps/welcome/ChangeLog | 1 + apps/welcome/boot.js | 4 ++-- apps/welcome/settings-default.json | 3 --- apps/welcome/settings.js | 4 ++-- 5 files changed, 9 insertions(+), 9 deletions(-) delete mode 100644 apps/welcome/settings-default.json diff --git a/apps.json b/apps.json index 315120cc7..a8b29b685 100644 --- a/apps.json +++ b/apps.json @@ -78,7 +78,7 @@ { "id": "welcome", "name": "Welcome", "icon": "app.png", - "version":"0.07", + "version":"0.08", "description": "Appears at first boot and explains how to use Bangle.js", "tags": "start,welcome", "allow_emulator":true, @@ -86,8 +86,10 @@ {"name":"welcome.boot.js","url":"boot.js"}, {"name":"welcome.app.js","url":"app.js"}, {"name":"welcome.settings.js","url":"settings.js"}, - {"name":"welcome.settings.json","url":"settings-default.json","evaluate":true}, {"name":"welcome.img","url":"app-icon.js","evaluate":true} + ], + "data": [ + {"name":"welcome.json"} ] }, { "id": "gbridge", diff --git a/apps/welcome/ChangeLog b/apps/welcome/ChangeLog index b8786af6a..a377fc81e 100644 --- a/apps/welcome/ChangeLog +++ b/apps/welcome/ChangeLog @@ -7,3 +7,4 @@ 0.07: Run again when updated Don't run again when settings app is updated (or absent) Add "Run Now" option to settings +0.08: Don't overwrite existing settings on app update diff --git a/apps/welcome/boot.js b/apps/welcome/boot.js index bc5afcc66..f6ba6d2d6 100644 --- a/apps/welcome/boot.js +++ b/apps/welcome/boot.js @@ -1,11 +1,11 @@ (function() { - let s = require('Storage').readJSON('welcome.settings.json', 1) + let s = require('Storage').readJSON('welcome.json', 1) || require('Storage').readJSON('setting.json', 1) || {welcomed: true} // do NOT run if global settings are also absent if (!s.welcomed && require('Storage').read('welcome.app.js')) { setTimeout(() => { s.welcomed = true - require('Storage').write('welcome.settings.json', {welcomed: "yes"}) + require('Storage').write('welcome.json', {welcomed: "yes"}) load('welcome.app.js') }) } diff --git a/apps/welcome/settings-default.json b/apps/welcome/settings-default.json deleted file mode 100644 index d250efff5..000000000 --- a/apps/welcome/settings-default.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "welcomed": false -} diff --git a/apps/welcome/settings.js b/apps/welcome/settings.js index b11921646..e873c2785 100644 --- a/apps/welcome/settings.js +++ b/apps/welcome/settings.js @@ -1,13 +1,13 @@ // The welcome app is special, and gets to use global settings (function(back) { - let settings = require('Storage').readJSON('welcome.settings.json', 1) + let settings = require('Storage').readJSON('welcome.sjson', 1) || require('Storage').readJSON('setting.json', 1) || {} E.showMenu({ '': { 'title': 'Welcome App' }, 'Run on Next Boot': { value: !settings.welcomed, format: v => v ? 'OK' : 'No', - onchange: v => require('Storage').write('welcome.settings.json', {welcomed: !v}), + onchange: v => require('Storage').write('welcome.json', {welcomed: !v}), }, 'Run Now': () => load('welcome.app.js'), '< Back': back, From b047f14d4ada97c510edc7a773a3e1f08982bc5d Mon Sep 17 00:00:00 2001 From: Richard de Boer Date: Fri, 17 Apr 2020 21:35:59 +0200 Subject: [PATCH 03/73] setting: Save settings in data file --- apps.json | 6 ++++-- apps/setting/ChangeLog | 1 + apps/setting/settings-default.json | 25 ------------------------- 3 files changed, 5 insertions(+), 27 deletions(-) delete mode 100644 apps/setting/settings-default.json diff --git a/apps.json b/apps.json index a8b29b685..4d5493e49 100644 --- a/apps.json +++ b/apps.json @@ -122,15 +122,17 @@ { "id": "setting", "name": "Settings", "icon": "settings.png", - "version":"0.16", + "version":"0.17", "description": "A menu for setting up Bangle.js", "tags": "tool,system", "storage": [ {"name":"setting.app.js","url":"settings.js"}, {"name":"setting.boot.js","url":"boot.js"}, - {"name":"setting.json","url":"settings-default.json","evaluate":true}, {"name":"setting.img","url":"settings-icon.js","evaluate":true} ], + "data": [ + {"name":"setting.json"} + ], "sortorder" : -2 }, { "id": "alarm", diff --git a/apps/setting/ChangeLog b/apps/setting/ChangeLog index 3acfb5fb0..773b510f0 100644 --- a/apps/setting/ChangeLog +++ b/apps/setting/ChangeLog @@ -18,3 +18,4 @@ 0.14: Reduce memory usage when running app settings page 0.15: Reduce memory usage when running default clock chooser (#294) 0.16: Reduce memory usage further when running app settings page +0.17: Don't overwrite existing settings on app update diff --git a/apps/setting/settings-default.json b/apps/setting/settings-default.json deleted file mode 100644 index c61fd6109..000000000 --- a/apps/setting/settings-default.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - ble: true, // Bluetooth enabled by default - blerepl: true, // Is REPL on Bluetooth - can Espruino IDE be used? - log: false, // Do log messages appear on screen? - timeout: 10, // Default LCD timeout in seconds - vibrate: true, // Vibration enabled by default. App must support - beep: "vib", // Beep enabled by default. App must support - timezone: 0, // Set the timezone for the device - HID : false, // BLE HID mode, off by default - clock: null, // a string for the default clock's name - "12hour" : false, // 12 or 24 hour clock? - // welcomed : undefined/true (whether welcome app should show) - brightness: 1, // LCD brightness from 0 to 1 - options: { - wakeOnBTN1: true, - wakeOnBTN2: true, - wakeOnBTN3: true, - wakeOnFaceUp: false, - wakeOnTouch: false, - wakeOnTwist: true, - twistThreshold: 819.2, - twistMaxY: -800, - twistTimeout: 1000 - } -} From 9358b4b5995e2efa6a49a1ca7865a0484f0c2c3f Mon Sep 17 00:00:00 2001 From: Richard de Boer Date: Fri, 17 Apr 2020 21:39:27 +0200 Subject: [PATCH 04/73] alarm: Save settings in data file --- apps.json | 6 ++++-- apps/alarm/ChangeLog | 1 + 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/apps.json b/apps.json index 4d5493e49..30fb669d2 100644 --- a/apps.json +++ b/apps.json @@ -139,16 +139,18 @@ "name": "Default Alarm", "shortName":"Alarms", "icon": "app.png", - "version":"0.06", + "version":"0.07", "description": "Set and respond to alarms", "tags": "tool,alarm,widget", "storage": [ {"name":"alarm.app.js","url":"app.js"}, {"name":"alarm.boot.js","url":"boot.js"}, {"name":"alarm.js","url":"alarm.js"}, - {"name":"alarm.json","content":"[]"}, {"name":"alarm.img","url":"app-icon.js","evaluate":true}, {"name":"alarm.wid.js","url":"widget.js"} + ], + "data": [ + {"name":"alarm.json"} ] }, { "id": "wclock", diff --git a/apps/alarm/ChangeLog b/apps/alarm/ChangeLog index 2ff60e658..ca92a0d97 100644 --- a/apps/alarm/ChangeLog +++ b/apps/alarm/ChangeLog @@ -4,3 +4,4 @@ 0.04: Tweaks for variable size widget system 0.05: Add alarm.boot.js and move code from the bootloader 0.06: Change 'New Alarm' to 'Save', allow Deletion of Alarms +0.07: Don't overwrite existing settings on app update From e4c0574ab77ad2b8064e3c50dd1e900f5a2fe7fb Mon Sep 17 00:00:00 2001 From: Richard de Boer Date: Fri, 17 Apr 2020 21:45:48 +0200 Subject: [PATCH 05/73] heart: Save settings in data file, add recording files to data --- apps.json | 7 +++++-- apps/heart/ChangeLog | 3 ++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/apps.json b/apps.json index 30fb669d2..6509458bf 100644 --- a/apps.json +++ b/apps.json @@ -300,15 +300,18 @@ { "id": "heart", "name": "Heart Rate Recorder", "icon": "app.png", - "version":"0.01", + "version":"0.02", "interface": "interface.html", "description": "Application that allows you to record your heart rate. Can run in background", "tags": "tool,health,widget", "storage": [ {"name":"heart.app.js","url":"app.js"}, - {"name":"heart.json","url":"app-settings.json","evaluate":true}, {"name":"heart.img","url":"app-icon.js","evaluate":true}, {"name":"heart.wid.js","url":"widget.js"} + ], + "data": [ + {"name":"heart.json"}, + {"wildcard":".heart?","storageFile": true} ] }, { "id": "slevel", diff --git a/apps/heart/ChangeLog b/apps/heart/ChangeLog index 4c4db83bc..70134af27 100644 --- a/apps/heart/ChangeLog +++ b/apps/heart/ChangeLog @@ -1,2 +1,3 @@ 0.01: New App! - +0.02: Don't overwrite existing settings on app update + Clean up recordings on app removal From db35edede6527b4613ed147298be6497def457ee Mon Sep 17 00:00:00 2001 From: Richard de Boer Date: Fri, 17 Apr 2020 21:49:57 +0200 Subject: [PATCH 06/73] ncstart: Save settings in data file --- apps.json | 6 ++++-- apps/ncstart/ChangeLog | 1 + apps/ncstart/boot.js | 4 ++-- apps/ncstart/settings-default.json | 3 --- apps/ncstart/settings.js | 4 ++-- 5 files changed, 9 insertions(+), 9 deletions(-) delete mode 100644 apps/ncstart/settings-default.json diff --git a/apps.json b/apps.json index 6509458bf..c3544abee 100644 --- a/apps.json +++ b/apps.json @@ -528,20 +528,22 @@ "id": "ncstart", "name": "NCEU Startup", "icon": "start.png", - "version":"0.04", + "version":"0.05", "description": "NodeConfEU 2019 'First Start' Sequence", "tags": "start,welcome", "storage": [ {"name":"ncstart.app.js","url":"start.js"}, {"name":"ncstart.boot.js","url":"boot.js"}, {"name":"ncstart.settings.js","url":"settings.js"}, - {"name":"ncstart.settings.json","url":"settings-default.json","evaluate":true}, {"name":"ncstart.img","url":"start-icon.js","evaluate":true}, {"name":"nc-bangle.img","url":"start-bangle.js","evaluate":true}, {"name":"nc-nceu.img","url":"start-nceu.js","evaluate":true}, {"name":"nc-nfr.img","url":"start-nfr.js","evaluate":true}, {"name":"nc-nodew.img","url":"start-nodew.js","evaluate":true}, {"name":"nc-tf.img","url":"start-tf.js","evaluate":true} + ], + "data": [ + {"name":"ncstart.json"} ] }, { "id": "ncfrun", diff --git a/apps/ncstart/ChangeLog b/apps/ncstart/ChangeLog index f4418827e..522633f7b 100644 --- a/apps/ncstart/ChangeLog +++ b/apps/ncstart/ChangeLog @@ -5,3 +5,4 @@ 0.04: Run again when updated Don't run again when settings app is updated (or absent) Add "Run Now" option to settings +0.05: Don't overwrite existing settings on app update diff --git a/apps/ncstart/boot.js b/apps/ncstart/boot.js index e3f514f5b..094033094 100644 --- a/apps/ncstart/boot.js +++ b/apps/ncstart/boot.js @@ -1,11 +1,11 @@ (function() { - let s = require('Storage').readJSON('ncstart.settings.json', 1) + let s = require('Storage').readJSON('ncstart.json', 1) || require('Storage').readJSON('setting.json', 1) || {welcomed: true} // do NOT run if global settings are also absent if (!s.welcomed && require('Storage').read('ncstart.app.js')) { setTimeout(() => { s.welcomed = true - require('Storage').write('ncstart.settings.json', s) + require('Storage').write('ncstart.json', s) load('ncstart.app.js') }) } diff --git a/apps/ncstart/settings-default.json b/apps/ncstart/settings-default.json deleted file mode 100644 index d250efff5..000000000 --- a/apps/ncstart/settings-default.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "welcomed": false -} diff --git a/apps/ncstart/settings.js b/apps/ncstart/settings.js index 2b24095cf..6780264a7 100644 --- a/apps/ncstart/settings.js +++ b/apps/ncstart/settings.js @@ -1,13 +1,13 @@ // The welcome app is special, and gets to use global settings (function(back) { - let settings = require('Storage').readJSON('ncstart.settings.json', 1) + let settings = require('Storage').readJSON('ncstart.json', 1) || require('Storage').readJSON('setting.json', 1) || {} E.showMenu({ '': { 'title': 'NCEU Startup' }, 'Run on Next Boot': { value: !settings.welcomed, format: v => v ? 'OK' : 'No', - onchange: v => require('Storage').write('ncstart.settings.json', {welcomed: !v}), + onchange: v => require('Storage').write('ncstart.json', {welcomed: !v}), }, 'Run Now': () => load('ncstart.app.js'), '< Back': back, From 595de45e348799bb38d0728dd8a82aecc5c09287 Mon Sep 17 00:00:00 2001 From: Richard de Boer Date: Fri, 17 Apr 2020 21:52:42 +0200 Subject: [PATCH 07/73] numerals: Save settings in data file --- apps.json | 8 +++++--- apps/numerals/ChangeLog | 3 ++- apps/numerals/numerals-default.json | 5 ----- 3 files changed, 7 insertions(+), 9 deletions(-) delete mode 100644 apps/numerals/numerals-default.json diff --git a/apps.json b/apps.json index c3544abee..18fad4cfe 100644 --- a/apps.json +++ b/apps.json @@ -1235,7 +1235,7 @@ "name": "Numerals Clock", "shortName": "Numerals Clock", "icon": "numerals.png", - "version":"0.03", + "version":"0.04", "description": "A simple big numerals clock", "tags": "numerals,clock", "type":"clock", @@ -1243,8 +1243,10 @@ "storage": [ {"name":"numerals.app.js","url":"numerals.app.js"}, {"name":"numerals.img","url":"numerals-icon.js","evaluate":true}, - {"name":"numerals.settings.js","url":"numerals.settings.js"}, - {"name":"numerals.json","url":"numerals-default.json","evaluate":true} + {"name":"numerals.settings.js","url":"numerals.settings.js"} + ], + "data":[ + {"name":"numerals.json"} ] }, { "id": "bledetect", diff --git a/apps/numerals/ChangeLog b/apps/numerals/ChangeLog index ec465a83f..927c4ff5f 100644 --- a/apps/numerals/ChangeLog +++ b/apps/numerals/ChangeLog @@ -1,3 +1,4 @@ 0.01: New App! 0.02: Use BTN2 for settings menu like other clocks -0.03: maximize numerals, make menu button configurable, change icon to mac palette, add default settings file, respect 12hour setting \ No newline at end of file +0.03: maximize numerals, make menu button configurable, change icon to mac palette, add default settings file, respect 12hour setting +0.04: Don't overwrite existing settings on app update diff --git a/apps/numerals/numerals-default.json b/apps/numerals/numerals-default.json deleted file mode 100644 index aa6a25047..000000000 --- a/apps/numerals/numerals-default.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - color:0, - drawMode:"fill", - menuButton:22 -} \ No newline at end of file From a8d1ef3e53b35732bb8871956d1b2d1d13875d5e Mon Sep 17 00:00:00 2001 From: Richard de Boer Date: Fri, 17 Apr 2020 21:42:29 +0200 Subject: [PATCH 08/73] gpsrec: Save settings in data file, add track files to data --- apps.json | 7 +++++-- apps/gpsrec/ChangeLog | 2 ++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/apps.json b/apps.json index 18fad4cfe..a18029abc 100644 --- a/apps.json +++ b/apps.json @@ -286,15 +286,18 @@ { "id": "gpsrec", "name": "GPS Recorder", "icon": "app.png", - "version":"0.07", + "version":"0.08", "interface": "interface.html", "description": "Application that allows you to record a GPS track. Can run in background", "tags": "tool,outdoors,gps,widget", "storage": [ {"name":"gpsrec.app.js","url":"app.js"}, - {"name":"gpsrec.json","url":"app-settings.json","evaluate":true}, {"name":"gpsrec.img","url":"app-icon.js","evaluate":true}, {"name":"gpsrec.wid.js","url":"widget.js"} + ], + "data": [ + {"name":"gpsrec.json"}, + {"wildcard":".gpsrc?","storageFile": true} ] }, { "id": "heart", diff --git a/apps/gpsrec/ChangeLog b/apps/gpsrec/ChangeLog index 8f1c575a1..17678bf3a 100644 --- a/apps/gpsrec/ChangeLog +++ b/apps/gpsrec/ChangeLog @@ -5,3 +5,5 @@ 0.05: Tweaks for variable size widget system 0.06: Ensure widget update itself (fix #118) and change to using icons 0.07: Added @jeffmer's awesome track viewer +0.08: Don't overwrite existing settings on app update + Clean up recorded tracks on app removal From 0df1fb19e3d45f92ed5e490c11a59017df9d27eb Mon Sep 17 00:00:00 2001 From: Michael Bengfort Date: Sun, 19 Apr 2020 13:55:20 +0200 Subject: [PATCH 09/73] initial commit adding metronome app --- apps.json | 20 +++++++ apps/metronome/README.md | 10 ++++ apps/metronome/metronome-icon.js | 1 + apps/metronome/metronome.info | 1 + apps/metronome/metronome.js | 93 ++++++++++++++++++++++++++++++ apps/metronome/metronome_icon.png | Bin 0 -> 7575 bytes 6 files changed, 125 insertions(+) create mode 100644 apps/metronome/README.md create mode 100644 apps/metronome/metronome-icon.js create mode 100644 apps/metronome/metronome.info create mode 100644 apps/metronome/metronome.js create mode 100644 apps/metronome/metronome_icon.png diff --git a/apps.json b/apps.json index 0c97b9e57..590a85e38 100644 --- a/apps.json +++ b/apps.json @@ -1293,5 +1293,25 @@ "evaluate": true } ] + }, + { + "id": "Metronome", + "name": "Metronome", + "icon": "metronome_icon.png", + "version": "0.03", + "description": "Makes the watch blinking and vibrating with a given rate", + "tags": "tool", + "allow_emulator": true, + "storage": [ + { + "name": "metronome.app.js", + "url": "metronome.js" + }, + { + "name": "metronome.img", + "url": "metronome-icon.js", + "evaluate": true + } + ] } ] diff --git a/apps/metronome/README.md b/apps/metronome/README.md new file mode 100644 index 000000000..19d489327 --- /dev/null +++ b/apps/metronome/README.md @@ -0,0 +1,10 @@ +# Metronome + +This metronome makes your watch blink and vibrate with a given rate. + +## Usage + +* Tap the screen at least three times. The app calculates the mean rate of your tapping. This rate is displayed in bmp while the text blinks and the watch softly vibrates with every beat. +* Use `BTN1` to increase the bmp value by one. +* Use `BTN3` to decrease the bmp value by one. +* You can change the bpm value any time by tapping the screen or using `BTN1` and `BTN3`. diff --git a/apps/metronome/metronome-icon.js b/apps/metronome/metronome-icon.js new file mode 100644 index 000000000..8b45f233b --- /dev/null +++ b/apps/metronome/metronome-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwxH+ABt4AB4fOFyFOABtUGDotOAAYvcp4ARqovbq0rACAvbqwABF98yGCAvdGAcHgAAEF8tWmIuGGA6QaF4lWFw4vgFwovPmIvuYDIvd0ejF59cF6qQFFwIvnMAguSqxfaFyQvYvOi0QuTF64uCAAQuRXwIvUqouEF6guFF5+cAAiOZF6iOaF5sxv+iF6xfRmVWFwWjv8rp4tSL6YvBqwuDMgQvnFwovURwIvQRggAELygvPgwuIF8ouEBwIvnFwwwXF54uBvwuFq0yF6buCF5guClQuFGAgvfFwcAF49WmIvRFwQvKFwkAmQvHYQMxF7l+FwgvKGAIvalQuGF5dWFx1VABVUvF4p0qAAdPCZNPF51OAD4vOKQIACF/4waF9wuEqgv/F/gwMF97vvAAUqADYtQAAMAADYuRGDgmLA=")) diff --git a/apps/metronome/metronome.info b/apps/metronome/metronome.info new file mode 100644 index 000000000..74dcbd2c7 --- /dev/null +++ b/apps/metronome/metronome.info @@ -0,0 +1 @@ +{"id":"metronome","name":"Metronome","src":"metronome.app.js", "icon": "metronome_icon.png", "sortorder":-2,"version":"0.03","files":"metronome.info,metronome.app.js, metronome_icon.png"} diff --git a/apps/metronome/metronome.js b/apps/metronome/metronome.js new file mode 100644 index 000000000..acd4b70b8 --- /dev/null +++ b/apps/metronome/metronome.js @@ -0,0 +1,93 @@ +var tStart = Date.now(); +var cindex=0; // index to iterate through colous +var bpm=60; // ininital bpm value +var time_diffs = [1000, 1000, 1000]; //array to calculate mean bpm +var tindex=0; //index to iterate through time_diffs + +Bangle.setLCDTimeout(undefined); //do not deaktivate display while running this app + +function changecolor() { + const maxColors = 2; + const colors = { + 0: { value: 0xFFFF, name: "White" }, + 1: { value: 0x000F, name: "Navy" }, + // 2: { value: 0x03E0, name: "DarkGreen" }, + // 3: { value: 0x03EF, name: "DarkCyan" }, + // 4: { value: 0x7800, name: "Maroon" }, + // 5: { value: 0x780F, name: "Purple" }, + // 6: { value: 0x7BE0, name: "Olive" }, + // 7: { value: 0xC618, name: "LightGray" }, + // 8: { value: 0x7BEF, name: "DarkGrey" }, + // 9: { value: 0x001F, name: "Blue" }, + // 10: { value: 0x07E0, name: "Green" }, + // 11: { value: 0x07FF, name: "Cyan" }, + // 12: { value: 0xF800, name: "Red" }, + // 13: { value: 0xF81F, name: "Magenta" }, + // 14: { value: 0xFFE0, name: "Yellow" }, + // 15: { value: 0xFFFF, name: "White" }, + // 16: { value: 0xFD20, name: "Orange" }, + // 17: { value: 0xAFE5, name: "GreenYellow" }, + // 18: { value: 0xF81F, name: "Pink" }, + }; + g.setColor(colors[cindex].value); + if (cindex == maxColors-1) { + cindex = 0; + } + else { + cindex += 1; + } + return cindex; +} + +function updateScreen() { + g.clear(); + changecolor(); + Bangle.buzz(50, 0.75); + g.setFont("Vector",48); + g.drawString(Math.floor(bpm)+"bpm", -1, 70); +} + +Bangle.on('touch', function(button) { +// setting bpm by tapping the screen. Uses the mean time difference between several tappings. + if (tindex < time_diffs.length) { + if (Date.now()-tStart < 5000) { + time_diffs[tindex] = Date.now()-tStart; + } + } else { + tindex=0; + time_diffs[tindex] = Date.now()-tStart; + } + tindex += 1; + mean_time = 0.0; + for(count = 0; count < time_diffs.length; count++) { + mean_time += time_diffs[count]; + } + time_diff = mean_time/count; + + tStart = Date.now(); + clearInterval(time_diff); + g.clear(); + g.setFont("Vector",48); + bpm = (60 * 1000/(time_diff)); + g.drawString(Math.floor(bpm)+"bpm", -1, 70); + clearInterval(interval); + interval = setInterval(updateScreen, 60000 / bpm); + return bpm; +}); + +// enable bpm finetuning via buttons. +setWatch(() => { + bpm += 1; + clearInterval(interval); + interval = setInterval(updateScreen, 60000 / bpm); +}, BTN1, {repeat:true}); + +setWatch(() => { + if (bpm > 1) { + bpm -= 1; + clearInterval(interval); + interval = setInterval(updateScreen, 60000 / bpm); + } +}, BTN3, {repeat:true}); + +interval = setInterval(updateScreen, 60000 / bpm); diff --git a/apps/metronome/metronome_icon.png b/apps/metronome/metronome_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..4dac7117f9e91221b0cfec54538e339c81df1939 GIT binary patch literal 7575 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 literal 0 HcmV?d00001 From 28dc51c377cb8b1c692df97f5f0bbc741b16ed7d Mon Sep 17 00:00:00 2001 From: Michael Bengfort Date: Sun, 19 Apr 2020 14:03:11 +0200 Subject: [PATCH 10/73] correct app path --- apps.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps.json b/apps.json index 590a85e38..83c0ba88f 100644 --- a/apps.json +++ b/apps.json @@ -1295,7 +1295,7 @@ ] }, { - "id": "Metronome", + "id": "metronome", "name": "Metronome", "icon": "metronome_icon.png", "version": "0.03", From 0bdf476ea6fe78aafaaf5318d92ac7f0fe8b5b60 Mon Sep 17 00:00:00 2001 From: Michael Bengfort Date: Sun, 19 Apr 2020 14:13:26 +0200 Subject: [PATCH 11/73] remove metronome.info --- apps/metronome/metronome.info | 1 - 1 file changed, 1 deletion(-) delete mode 100644 apps/metronome/metronome.info diff --git a/apps/metronome/metronome.info b/apps/metronome/metronome.info deleted file mode 100644 index 74dcbd2c7..000000000 --- a/apps/metronome/metronome.info +++ /dev/null @@ -1 +0,0 @@ -{"id":"metronome","name":"Metronome","src":"metronome.app.js", "icon": "metronome_icon.png", "sortorder":-2,"version":"0.03","files":"metronome.info,metronome.app.js, metronome_icon.png"} From 1596b0246b9693bdf7fd26a04417e49aa61dfb9d Mon Sep 17 00:00:00 2001 From: Amos Blanton Date: Sun, 19 Apr 2020 16:18:13 +0200 Subject: [PATCH 12/73] Add setting to hide widget when battery is over 20%. --- apps/widbatpc/{settings.js => widbatpc.settings.js} | 12 +++++++++--- apps/widbatpc/widbatpc.settings.json | 1 + apps/widbatpc/{widget.js => widbatpc.wid.js} | 13 ++++++++++--- 3 files changed, 20 insertions(+), 6 deletions(-) rename apps/widbatpc/{settings.js => widbatpc.settings.js} (88%) create mode 100644 apps/widbatpc/widbatpc.settings.json rename apps/widbatpc/{widget.js => widbatpc.wid.js} (95%) diff --git a/apps/widbatpc/settings.js b/apps/widbatpc/widbatpc.settings.js similarity index 88% rename from apps/widbatpc/settings.js rename to apps/widbatpc/widbatpc.settings.js index 5c0bdbcae..9f39b5d07 100644 --- a/apps/widbatpc/settings.js +++ b/apps/widbatpc/widbatpc.settings.js @@ -11,6 +11,7 @@ 'color': COLORS[0], 'percentage': true, 'charger': true, + 'hideifmorethan20pct': false, } // ...and overwrite them with any saved values // This way saved values are preserved if a new version adds more settings @@ -51,8 +52,13 @@ const newIndex = (oldIndex + 1) % COLORS.length s.color = COLORS[newIndex] save('color')(s.color) - }, - }, - } + } + }, + 'Hide when \> 20\%': { + value: s.hideifmorethan20pct, + format: onOffFormat, + onchange: save('hideifmorethan20pct'), + }, + } E.showMenu(menu) }) diff --git a/apps/widbatpc/widbatpc.settings.json b/apps/widbatpc/widbatpc.settings.json new file mode 100644 index 000000000..7a22adfc0 --- /dev/null +++ b/apps/widbatpc/widbatpc.settings.json @@ -0,0 +1 @@ +{"color":"By Level","percentage":true,"charger":true,"hideifmorethan20pct":false} diff --git a/apps/widbatpc/widget.js b/apps/widbatpc/widbatpc.wid.js similarity index 95% rename from apps/widbatpc/widget.js rename to apps/widbatpc/widbatpc.wid.js index aca690ce0..959ec211f 100644 --- a/apps/widbatpc/widget.js +++ b/apps/widbatpc/widbatpc.wid.js @@ -3,6 +3,7 @@ const DEFAULTS = { 'color': 'By Level', 'percentage': true, 'charger': true, + 'hideifmorethan20pct': false, } const COLORS = { 'white': -1, @@ -53,8 +54,16 @@ function setWidth() { } } function draw() { + var s = 39; var x = this.x, y = this.y; + const l = E.getBattery(), + c = levelColor(l); + const xl = x+4+l*(s-12)/100 + + if(!Bangle.isCharging() && setting('hideifmorethan20pct') && l > 20){ + return;} + if (Bangle.isCharging() && setting('charger')) { g.setColor(chargerColor()).drawImage(atob( "DhgBHOBzgc4HOP////////////////////3/4HgB4AeAHgB4AeAHgB4AeAHg"),x,y); @@ -64,9 +73,7 @@ function draw() { g.fillRect(x,y+2,x+s-4,y+21); g.clearRect(x+2,y+4,x+s-6,y+19); g.fillRect(x+s-3,y+10,x+s,y+14); - const l = E.getBattery(), - c = levelColor(l); - const xl = x+4+l*(s-12)/100 + g.setColor(c).fillRect(x+4,y+6,xl,y+17); g.setColor(-1); if (!setting('percentage')) { From 4d52de224ceddc49aabc107bf246374da8393106 Mon Sep 17 00:00:00 2001 From: Stefano Baldan Date: Sun, 19 Apr 2020 18:03:14 +0200 Subject: [PATCH 13/73] Added app for running --- apps.json | 21 +++ apps/banglerun/ChangeLog | 1 + apps/banglerun/app-icon.js | 1 + apps/banglerun/app.js | 314 +++++++++++++++++++++++++++++++++++ apps/banglerun/banglerun.png | Bin 0 -> 10456 bytes 5 files changed, 337 insertions(+) create mode 100755 apps/banglerun/ChangeLog create mode 100644 apps/banglerun/app-icon.js create mode 100644 apps/banglerun/app.js create mode 100644 apps/banglerun/banglerun.png diff --git a/apps.json b/apps.json index 0c97b9e57..143b02bd3 100644 --- a/apps.json +++ b/apps.json @@ -1293,5 +1293,26 @@ "evaluate": true } ] + }, + { + "id": "banglerun", + "name": "BangleRun", + "shortName": "BangleRun", + "icon": "banglerun.png", + "version": "0.01", + "description": "An app for running sessions.", + "tags": "run,running,fitness,outdoors", + "allow_emulator": false, + "storage": [ + { + "name": "banglerun.app.js", + "url": "app.js" + }, + { + "name": "banglerun.img", + "url": "app-icon.js", + "evaluate": true + } + ] } ] diff --git a/apps/banglerun/ChangeLog b/apps/banglerun/ChangeLog new file mode 100755 index 000000000..7b83706bf --- /dev/null +++ b/apps/banglerun/ChangeLog @@ -0,0 +1 @@ +0.01: First release diff --git a/apps/banglerun/app-icon.js b/apps/banglerun/app-icon.js new file mode 100644 index 000000000..0ccbedab4 --- /dev/null +++ b/apps/banglerun/app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwwMB/4ACx4ED/0DApP8AqAXB84GDg/DAgXj/+DCAUABgIFB4EAv4FCwEAj0PAoJPBgwFEgEfDgMOAoM/AoMegFAAoP8jkA8F/AoM8gP4DgP4nBvD/F4KQfwuAFE+A/CAoPgAofx8A/CKYRwELIIFDLII6BAoZSBLIYeC/0BwAFDgfAGAQFBHgf8g4BBIIUH/wFBSYMPAoXwAog/Bj4FEv4FDDQQCBQoQFCZYYFi/6KE/+P/4A=")) diff --git a/apps/banglerun/app.js b/apps/banglerun/app.js new file mode 100644 index 000000000..fc21e3627 --- /dev/null +++ b/apps/banglerun/app.js @@ -0,0 +1,314 @@ +/** Global constants */ +const DEG_TO_RAD = Math.PI / 180; +const EARTH_RADIUS = 6371008.8; + +/** Utilities for handling vectors */ +class Vector { + static magnitude(a) { + let sum = 0; + for (const key of Object.keys(a)) { + sum += a[key] * a[key]; + } + return Math.sqrt(sum); + } + + static add(a, b) { + const result = {}; + for (const key of Object.keys(a)) { + result[key] = a[key] + b[key]; + } + return result; + } + + static sub(a, b) { + const result = {}; + for (const key of Object.keys(a)) { + result[key] = a[key] - b[key]; + } + return result; + } + + static multiplyScalar(a, x) { + const result = {}; + for (const key of Object.keys(a)) { + result[key] = a[key] * x; + } + return result; + } + + static divideScalar(a, x) { + const result = {}; + for (const key of Object.keys(a)) { + result[key] = a[key] / x; + } + return result; + } +} + +/** Interquartile range filter, to detect outliers */ +class IqrFilter { + constructor(size, threshold) { + const q = Math.floor(size / 4); + this._buffer = []; + this._size = 4 * q + 2; + this._i1 = q; + this._i3 = 3 * q + 1; + this._threshold = threshold; + } + + isReady() { + return this._buffer.length === this._size; + } + + isOutlier(point) { + let result = true; + if (this._buffer.length === this._size) { + result = false; + for (const key of Object.keys(point)) { + const data = this._buffer.map(item => item[key]); + data.sort((a, b) => (a - b) / Math.abs(a - b)); + const q1 = data[this._i1]; + const q3 = data[this._i3]; + const iqr = q3 - q1; + const lower = q1 - this._threshold * iqr; + const upper = q3 + this._threshold * iqr; + if (point[key] < lower || point[key] > upper) { + result = true; + break; + } + } + } + this._buffer.push(point); + this._buffer = this._buffer.slice(-this._size); + return result; + } +} + +/** Process GPS data */ +class Gps { + constructor() { + this._lastCall = Date.now(); + this._lastValid = 0; + this._coords = null; + this._filter = new IqrFilter(10, 1.5); + this._shift = { x: 0, y: 0, z: 0 }; + } + + isReady() { + return this._filter.isReady(); + } + + getDistance(gps) { + const time = Date.now(); + const interval = (time - this._lastCall) / 1000; + this._lastCall = time; + + if (!gps.fix) { + return { t: interval, d: 0 }; + } + + const p = gps.lat * DEG_TO_RAD; + const q = gps.lon * DEG_TO_RAD; + const coords = { + x: EARTH_RADIUS * Math.sin(p) * Math.cos(q), + y: EARTH_RADIUS * Math.sin(p) * Math.sin(q), + z: EARTH_RADIUS * Math.cos(p), + }; + + if (!this._coords) { + this._coords = coords; + this._lastValid = time; + return { t: interval, d: 0 }; + } + + const ds = Vector.sub(coords, this._coords); + const dt = (time - this._lastValid) / 1000; + const v = Vector.divideScalar(ds, dt); + + if (this._filter.isOutlier(v)) { + return { t: interval, d: 0 }; + } + + this._shift = Vector.add(this._shift, ds); + const length = Vector.magnitude(this._shift); + const remainder = length % 10; + const distance = length - remainder; + + this._coords = coords; + this._lastValid = time; + if (distance > 0) { + this._shift = Vector.multiplyScalar(this._shift, remainder / length); + } + + return { t: interval, d: distance }; + } +} + +/** Process step counter data */ +class Step { + constructor(size) { + this._buffer = []; + this._size = size; + } + + getCadence() { + this._buffer.push(Date.now() / 1000); + this._buffer = this._buffer.slice(-this._size); + const interval = this._buffer[this._buffer.length - 1] - this._buffer[0]; + return interval ? Math.round(60 * (this._buffer.length - 1) / interval) : 0; + } +} + +const gps = new Gps(); +const step = new Step(10); + +let totDist = 0; +let totTime = 0; +let totSteps = 0; + +let speed = 0; +let cadence = 0; +let heartRate = 0; + +let gpsReady = false; +let hrmReady = false; +let running = false; + +function formatClock(date) { + return ('0' + date.getHours()).substr(-2) + ':' + ('0' + date.getMinutes()).substr(-2); +} + +function formatDistance(m) { + return ('0' + (m / 1000).toFixed(2) + ' km').substr(-7); +} + +function formatTime(s) { + const hrs = Math.floor(s / 3600); + const min = Math.floor(s / 60); + const sec = Math.floor(s % 60); + return (hrs ? hrs + ':' : '') + ('0' + min).substr(-2) + `:` + ('0' + sec).substr(-2); +} + +function formatSpeed(kmh) { + if (kmh <= 0.6) { + return `__'__"`; + } + const skm = 3600 / kmh; + const min = Math.floor(skm / 60); + const sec = Math.floor(skm % 60); + return ('0' + min).substr(-2) + `'` + ('0' + sec).substr(-2) + `"`; +} + +function drawBackground() { + g.setColor(running ? 0x00E0 : 0x0000); + g.fillRect(0, 30, 240, 240); + + g.setColor(0xFFFF); + g.setFontAlign(0, -1, 0); + g.setFont('6x8', 2); + + g.drawString('DISTANCE', 120, 50); + g.drawString('TIME', 60, 100); + g.drawString('PACE', 180, 100); + g.drawString('STEPS', 60, 150); + g.drawString('STP/m', 180, 150); + g.drawString('SPEED', 40, 200); + g.drawString('HEART', 120, 200); + g.drawString('CADENCE', 200, 200); +} + +function draw() { + const totSpeed = totTime ? 3.6 * totDist / totTime : 0; + const totCadence = totTime ? Math.round(60 * totSteps / totTime) : 0; + + g.setColor(running ? 0x00E0 : 0x0000); + g.fillRect(0, 30, 240, 50); + g.fillRect(0, 70, 240, 100); + g.fillRect(0, 120, 240, 150); + g.fillRect(0, 170, 240, 200); + g.fillRect(0, 220, 240, 240); + + g.setFont('6x8', 2); + + g.setFontAlign(-1, -1, 0); + g.setColor(gpsReady ? 0x07E0 : 0xF800); + g.drawString(' GPS', 6, 30); + + g.setFontAlign(1, -1, 0); + g.setColor(0xFFFF); + g.drawString(formatClock(new Date()), 234, 30); + + g.setFontAlign(0, -1, 0); + g.setFontVector(20); + g.drawString(formatDistance(totDist), 120, 70); + g.drawString(formatTime(totTime), 60, 120); + g.drawString(formatSpeed(totSpeed), 180, 120); + g.drawString(totSteps, 60, 170); + g.drawString(totCadence, 180, 170); + + g.setFont('6x8', 2); + g.drawString(formatSpeed(speed), 40, 220); + + g.setColor(hrmReady ? 0x07E0 : 0xF800); + g.drawString(heartRate, 120, 220); + + g.setColor(0xFFFF); + g.drawString(cadence, 200, 220); +} + +function handleGps(coords) { + const step = gps.getDistance(coords); + gpsReady = coords.fix > 0 && gps.isReady(); + speed = isFinite(gps.speed) ? gps.speed : 0; + if (running) { + totDist += step.d; + totTime += step.t; + } +} + +function handleHrm(hrm) { + hrmReady = hrm.confidence > 50; + heartRate = hrm.bpm; +} + +function handleStep() { + cadence = step.getCadence(); + if (running) { + totSteps += 1; + } +} + +function start() { + running = true; + drawBackground(); + draw(); +} + +function stop() { + if (!running) { + totDist = 0; + totTime = 0; + totSteps = 0; + } + running = false; + drawBackground(); + draw(); +} + +Bangle.on('GPS', handleGps); +Bangle.on('HRM', handleHrm); +Bangle.on('step', handleStep); + +Bangle.setGPSPower(1); +Bangle.setHRMPower(1); + +g.clear(); +Bangle.loadWidgets(); +Bangle.drawWidgets(); +drawBackground(); +draw(); + +setInterval(draw, 500); + +setWatch(start, BTN1, { repeat: true }); +setWatch(stop, BTN3, { repeat: true }); diff --git a/apps/banglerun/banglerun.png b/apps/banglerun/banglerun.png new file mode 100644 index 0000000000000000000000000000000000000000..bf2cd8af3ef5f9711d18df1656a03a98283bcc67 GIT binary patch literal 10456 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 O0000 Date: Mon, 20 Apr 2020 09:27:57 +0200 Subject: [PATCH 14/73] Removed href="#" that scrolls page on top --- js/index.js | 2 +- js/utils.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/js/index.js b/js/index.js index ef9bcb4f1..d8c7a4473 100644 --- a/js/index.js +++ b/js/index.js @@ -207,7 +207,7 @@ function refreshLibrary() { var version = getVersionInfo(app, appInstalled); var versionInfo = version.text; if (versionInfo) versionInfo = " ("+versionInfo+")"; - var readme = `Read more...`; + var readme = `Read more...`; var favourite = favourites.find(e => e == app.id); return `
diff --git a/js/utils.js b/js/utils.js index 4913c7129..406e3a0a1 100644 --- a/js/utils.js +++ b/js/utils.js @@ -49,7 +49,7 @@ function getVersionInfo(appListing, appInstalled) { var versionText = ""; var canUpdate = false; function clicky(v) { - return `${v}`; + return `${v}`; } if (!appInstalled) { From 9cc58597cd5d0934f34da6a935b2187cb1b3df36 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Mon, 20 Apr 2020 09:21:27 +0100 Subject: [PATCH 15/73] merge with new namings --- apps/widbatpc/{widbatpc.settings.js => settings.js} | 0 apps/widbatpc/{widbatpc.wid.js => widget.js} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename apps/widbatpc/{widbatpc.settings.js => settings.js} (100%) rename apps/widbatpc/{widbatpc.wid.js => widget.js} (100%) diff --git a/apps/widbatpc/widbatpc.settings.js b/apps/widbatpc/settings.js similarity index 100% rename from apps/widbatpc/widbatpc.settings.js rename to apps/widbatpc/settings.js diff --git a/apps/widbatpc/widbatpc.wid.js b/apps/widbatpc/widget.js similarity index 100% rename from apps/widbatpc/widbatpc.wid.js rename to apps/widbatpc/widget.js From 20bb1aed8456dcfc6028d77400970e45ebf6c2db Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Mon, 20 Apr 2020 10:06:23 +0100 Subject: [PATCH 16/73] Add 'hide if charge greater than' Move 'DEFAULTS' to try and reduce memory usage a little --- apps.json | 4 +-- apps/widbatpc/ChangeLog | 1 + apps/widbatpc/settings.js | 23 +++++++------ apps/widbatpc/widbatpc.settings.json | 1 - apps/widbatpc/widget.js | 50 +++++++++++++++++----------- 5 files changed, 46 insertions(+), 33 deletions(-) delete mode 100644 apps/widbatpc/widbatpc.settings.json diff --git a/apps.json b/apps.json index fe3d5f3eb..5b024eb97 100644 --- a/apps.json +++ b/apps.json @@ -354,7 +354,7 @@ "name": "Battery Level Widget (with percentage)", "shortName": "Battery Widget", "icon": "widget.png", - "version":"0.09", + "version":"0.10", "description": "Show the current battery level and charging status in the top right of the clock, with charge percentage", "tags": "widget,battery", "type":"widget", @@ -1372,7 +1372,7 @@ {"name":"hidcam.img","url":"app-icon.js","evaluate":true} ] }, - { + { "id": "rclock", "name": "Round clock with seconds, minutes and date", "shortName":"Round Clock", diff --git a/apps/widbatpc/ChangeLog b/apps/widbatpc/ChangeLog index 129707320..4c5f16a04 100644 --- a/apps/widbatpc/ChangeLog +++ b/apps/widbatpc/ChangeLog @@ -6,3 +6,4 @@ 0.07: Add settings: percentage/color/charger icon 0.08: Draw percentage as inverted on monochrome battery 0.09: Fix regression stopping correct widget updates +0.10: Add 'hide if charge greater than' diff --git a/apps/widbatpc/settings.js b/apps/widbatpc/settings.js index 9f39b5d07..bfed48f09 100644 --- a/apps/widbatpc/settings.js +++ b/apps/widbatpc/settings.js @@ -11,22 +11,22 @@ 'color': COLORS[0], 'percentage': true, 'charger': true, - 'hideifmorethan20pct': false, + 'hideifmorethan': 100, } // ...and overwrite them with any saved values // This way saved values are preserved if a new version adds more settings const storage = require('Storage') const saved = storage.readJSON(SETTINGS_FILE, 1) || {} for (const key in saved) { - s[key] = saved[key] + s[key] = saved[key]; } // creates a function to safe a specific setting, e.g. save('color')(1) function save(key) { return function (value) { - s[key] = value - storage.write(SETTINGS_FILE, s) - WIDGETS["batpc"].reload() + s[key] = value; + storage.write(SETTINGS_FILE, s); + WIDGETS["batpc"].reload(); } } @@ -54,11 +54,14 @@ save('color')(s.color) } }, - 'Hide when \> 20\%': { - value: s.hideifmorethan20pct, - format: onOffFormat, - onchange: save('hideifmorethan20pct'), + 'Hide if >': { + value: s.hideifmorethan||100, + min: 10, + max : 100, + step: 10, + format: x => x+"%", + onchange: save('hideifmorethan'), }, - } + } E.showMenu(menu) }) diff --git a/apps/widbatpc/widbatpc.settings.json b/apps/widbatpc/widbatpc.settings.json deleted file mode 100644 index 7a22adfc0..000000000 --- a/apps/widbatpc/widbatpc.settings.json +++ /dev/null @@ -1 +0,0 @@ -{"color":"By Level","percentage":true,"charger":true,"hideifmorethan20pct":false} diff --git a/apps/widbatpc/widget.js b/apps/widbatpc/widget.js index 959ec211f..fe6f8550c 100644 --- a/apps/widbatpc/widget.js +++ b/apps/widbatpc/widget.js @@ -1,10 +1,4 @@ (function(){ -const DEFAULTS = { - 'color': 'By Level', - 'percentage': true, - 'charger': true, - 'hideifmorethan20pct': false, -} const COLORS = { 'white': -1, 'charging': 0x07E0, // "Green" @@ -17,10 +11,19 @@ const SETTINGS_FILE = 'widbatpc.settings.json' let settings function loadSettings() { settings = require('Storage').readJSON(SETTINGS_FILE, 1) || {} + const DEFAULTS = { + 'color': 'By Level', + 'percentage': true, + 'charger': true, + 'hideifmorethan': 100, + }; + Object.keys(DEFAULTS).forEach(k=>{ + if (settings[k]===undefined) settings[k]=DEFAULTS[k] + }); } function setting(key) { if (!settings) { loadSettings() } - return (key in settings) ? settings[key] : DEFAULTS[key] + return settings[key]; } const levelColor = (l) => { @@ -46,24 +49,27 @@ const levelColor = (l) => { const chargerColor = () => { return (setting('color') === 'Monochrome') ? COLORS.white : COLORS.charging } - +// sets width, returns true if it changed function setWidth() { - WIDGETS["batpc"].width = 40; - if (Bangle.isCharging() && setting('charger')) { - WIDGETS["batpc"].width += 16; - } + var w = 40; + if (Bangle.isCharging() && setting('charger')) + w += 16; + if (E.getBattery() > setting('hideifmorethan')) + w = 0; + var changed = WIDGETS["batpc"].width != w; + WIDGETS["batpc"].width = w; + return changed; } function draw() { - + // if hidden, don't draw + if (!WIDGETS["batpc"].width) return; + // else... var s = 39; var x = this.x, y = this.y; const l = E.getBattery(), c = levelColor(l); const xl = x+4+l*(s-12)/100 - if(!Bangle.isCharging() && setting('hideifmorethan20pct') && l > 20){ - return;} - if (Bangle.isCharging() && setting('charger')) { g.setColor(chargerColor()).drawImage(atob( "DhgBHOBzgc4HOP////////////////////3/4HgB4AeAHgB4AeAHgB4AeAHg"),x,y); @@ -104,20 +110,24 @@ function reload() { g.clear(); Bangle.drawWidgets(); } +// update widget - redraw just widget, or all widgets if size changed +function update() { + if (setWidth()) Bangle.drawWidgets(); + else WIDGETS["batpc"].draw(); +} Bangle.on('charging',function(charging) { if(charging) Bangle.buzz(); - setWidth(); - Bangle.drawWidgets(); // relayout widgets + update(); g.flip(); }); var batteryInterval; Bangle.on('lcdPower', function(on) { if (on) { - WIDGETS["batpc"].draw(); + update(); // refresh once a minute if LCD on if (!batteryInterval) - batteryInterval = setInterval(()=>WIDGETS["batpc"].draw(), 60000); + batteryInterval = setInterval(update, 60000); } else { if (batteryInterval) { clearInterval(batteryInterval); From 5fe7f48477818c1bb31b7650e9d93f45d594f7e0 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Mon, 20 Apr 2020 10:07:55 +0100 Subject: [PATCH 17/73] Add 'update all' button (fix #237) --- index.html | 1 + js/index.js | 42 ++++++++++++++++++++++++++++++++++++++---- 2 files changed, 39 insertions(+), 4 deletions(-) diff --git a/index.html b/index.html index f016ffb49..3c8b440e4 100644 --- a/index.html +++ b/index.html @@ -113,6 +113,7 @@
+
diff --git a/js/index.js b/js/index.js index 2b1fb1cfc..51b1d71c3 100644 --- a/js/index.js +++ b/js/index.js @@ -218,7 +218,7 @@ function refreshLibrary() {

${escapeHtml(app.description)}${app.readme?`
${readme}`:""}

See the code on GitHub
-
+
@@ -401,10 +401,18 @@ function showLoadingIndicator(id) { panelbody.innerHTML = '
'; } +function getAppsToUpdate() { + var appsToUpdate = []; + appsInstalled.forEach(appInstalled => { + var app = appNameToApp(appInstalled.id); + if (app.version != appInstalled.version) + appsToUpdate.push(app); + }); + return appsToUpdate; +} + function refreshMyApps() { var panelbody = document.querySelector("#myappscontainer .panel-body"); - var tab = document.querySelector("#tab-myappscontainer a"); - tab.setAttribute("data-badge", appsInstalled.length); panelbody.innerHTML = appsInstalled.map(appInstalled => { var app = appNameToApp(appInstalled.id); var version = getVersionInfo(app, appInstalled); @@ -436,6 +444,17 @@ return `
if (icon.classList.contains("icon-download")) handleAppInterface(app); }); }); + var appsToUpdate = getAppsToUpdate(); + var tab = document.querySelector("#tab-myappscontainer a"); + var updateApps = document.querySelector("#myappscontainer .updateapps"); + if (appsToUpdate.length) { + updateApps.innerHTML = `Update ${appsToUpdate.length} apps`; + updateApps.classList.remove("hidden"); + tab.setAttribute("data-badge", `${appsInstalled.length} ⬆${appsToUpdate.length}`); + } else { + updateApps.classList.add("hidden"); + tab.setAttribute("data-badge", appsInstalled.length); + } } let haveInstalledApps = false; @@ -471,6 +490,22 @@ htmlToArray(document.querySelectorAll(".btn.refresh")).map(button => button.addE showToast("Getting app list failed, "+err,"error"); }); })); +htmlToArray(document.querySelectorAll(".btn.updateapps")).map(button => button.addEventListener("click", () => { + var appsToUpdate = getAppsToUpdate(); + var count = appsToUpdate.length; + function updater() { + if (!appsToUpdate.length) return; + var app = appsToUpdate.pop(); + return updateApp(app).then(function() { + return updater(); + }); + } + updater().then(err => { + showToast(`Updated ${count} apps`,"success"); + }).catch(err => { + showToast("Update failed, "+err,"error"); + }); +})); connectMyDeviceBtn.addEventListener("click", () => { if (connectMyDeviceBtn.classList.contains('is-connected')) { Comms.disconnectDevice(); @@ -621,4 +656,3 @@ document.getElementById("installfavourite").addEventListener("click",event=>{ showToast("App Install failed, "+err,"error"); }); }); - From 0f8247e7e49f3b976e96dea0626a3369ea2a9456 Mon Sep 17 00:00:00 2001 From: Richard de Boer Date: Mon, 20 Apr 2020 11:52:19 +0200 Subject: [PATCH 18/73] Data file fixes for settings/welcome/ncstart settings: never delete settings file welcome: fix typo, remove outdated comment ncstart: remove outdated comment --- apps.json | 3 --- apps/ncstart/settings.js | 1 - apps/welcome/settings.js | 3 +-- 3 files changed, 1 insertion(+), 6 deletions(-) diff --git a/apps.json b/apps.json index a18029abc..32a7e7dff 100644 --- a/apps.json +++ b/apps.json @@ -130,9 +130,6 @@ {"name":"setting.boot.js","url":"boot.js"}, {"name":"setting.img","url":"settings-icon.js","evaluate":true} ], - "data": [ - {"name":"setting.json"} - ], "sortorder" : -2 }, { "id": "alarm", diff --git a/apps/ncstart/settings.js b/apps/ncstart/settings.js index 6780264a7..560fad8ba 100644 --- a/apps/ncstart/settings.js +++ b/apps/ncstart/settings.js @@ -1,4 +1,3 @@ -// The welcome app is special, and gets to use global settings (function(back) { let settings = require('Storage').readJSON('ncstart.json', 1) || require('Storage').readJSON('setting.json', 1) || {} diff --git a/apps/welcome/settings.js b/apps/welcome/settings.js index e873c2785..20c2e9b13 100644 --- a/apps/welcome/settings.js +++ b/apps/welcome/settings.js @@ -1,6 +1,5 @@ -// The welcome app is special, and gets to use global settings (function(back) { - let settings = require('Storage').readJSON('welcome.sjson', 1) + let settings = require('Storage').readJSON('welcome.json', 1) || require('Storage').readJSON('setting.json', 1) || {} E.showMenu({ '': { 'title': 'Welcome App' }, From ae738e9d99b9f54f20b230ea23a5e0ad043b7471 Mon Sep 17 00:00:00 2001 From: Purple-Tentacle <59914607+Purple-Tentacle@users.noreply.github.com> Date: Mon, 20 Apr 2020 15:57:26 +0200 Subject: [PATCH 19/73] chronowid 0.03 --- apps/chronowid/ChangeLog | 5 +- apps/chronowid/widget.js | 184 +++++++++++++++++++-------------------- 2 files changed, 95 insertions(+), 94 deletions(-) diff --git a/apps/chronowid/ChangeLog b/apps/chronowid/ChangeLog index 263145407..e173467a1 100644 --- a/apps/chronowid/ChangeLog +++ b/apps/chronowid/ChangeLog @@ -1,2 +1,3 @@ -0.01: New widget and app! -0.02: Setting to reset values, timer buzzes at 00:00 and not later (see readme) \ No newline at end of file +0.01: New widget and app! +0.02: Setting to reset values, timer buzzes at 00:00 and not later (see readme) +0.03: Display only minutes:seconds when less than 1 hour left \ No newline at end of file diff --git a/apps/chronowid/widget.js b/apps/chronowid/widget.js index 557104d92..0c9366b86 100644 --- a/apps/chronowid/widget.js +++ b/apps/chronowid/widget.js @@ -1,93 +1,93 @@ -(() => { - const storage = require('Storage'); - settingsChronowid = storage.readJSON("chronowid.json",1)||{}; //read settingsChronowid from file - var height = 23; - var width = 58; - var interval = 0; //used for the 1 second interval timer - var now = new Date(); - - var time = 0; - var diff = settingsChronowid.goal - now; - - //Convert ms to time - function getTime(t) { - var milliseconds = parseInt((t % 1000) / 100), - seconds = Math.floor((t / 1000) % 60), - minutes = Math.floor((t / (1000 * 60)) % 60), - hours = Math.floor((t / (1000 * 60 * 60)) % 24); - - hours = (hours < 10) ? "0" + hours : hours; - minutes = (minutes < 10) ? "0" + minutes : minutes; - seconds = (seconds < 10) ? "0" + seconds : seconds; - - return hours + ":" + minutes + ":" + seconds; - } - - function printDebug() { - print ("Nowtime: " + getTime(now)); - print ("Now: " + now); - print ("Goaltime: " + getTime(settingsChronowid.goal)); - print ("Goal: " + settingsChronowid.goal); - print("Difftime: " + getTime(diff)); - print("Diff: " + diff); - print ("Started: " + settingsChronowid.started); - print ("----"); - } - - //counts down, calculates and displays - function countDown() { - now = new Date(); - diff = settingsChronowid.goal - now; //calculate difference - WIDGETS["chronowid"].draw(); - //time is up - if (settingsChronowid.started && diff < 1000) { - Bangle.buzz(1500); - //write timer off to file - settingsChronowid.started = false; - storage.writeJSON('chronowid.json', settingsChronowid); - clearInterval(interval); //stop interval - } - //printDebug(); - } - - // draw your widget - function draw() { - if (!settingsChronowid.started) { - width = 0; - return; //do not draw anything if timer is not started - } - g.reset(); - if (diff >= 0) { - if (diff < 600000) { //less than 1 hour left - width = 58; - g.clearRect(this.x,this.y,this.x+width,this.y+height); - g.setFont("6x8", 2); - g.drawString(getTime(diff).substring(3), this.x+1, this.y+5); //remove hour part 00:00:00 -> 00:00 - } - if (diff >= 600000) { //one hour or more left - width = 48; - g.clearRect(this.x,this.y,this.x+width,this.y+height); - g.setFont("6x8", 1); - g.drawString(getTime(diff), this.x+1, this.y+((height/2)-4)); //display hour 00:00:00 - } - } - // not needed anymoe, because we check if diff < 1000 now, so 00:00 is displayed. - // else { - // width = 58; - // g.clearRect(this.x,this.y,this.x+width,this.y+height); - // g.setFont("6x8", 2); - // g.drawString("END", this.x+15, this.y+5); - // } - } - - if (settingsChronowid.started) interval = setInterval(countDown, 1000); //start countdown each second - - // add the widget - WIDGETS["chronowid"]={area:"bl",width:width,draw:draw,reload:function() { - reload(); - Bangle.drawWidgets(); // relayout all widgets - }}; - - //printDebug(); - countDown(); +(() => { + const storage = require('Storage'); + settingsChronowid = storage.readJSON("chronowid.json",1)||{}; //read settingsChronowid from file + var height = 23; + var width = 58; + var interval = 0; //used for the 1 second interval timer + var now = new Date(); + + var time = 0; + var diff = settingsChronowid.goal - now; + + //Convert ms to time + function getTime(t) { + var milliseconds = parseInt((t % 1000) / 100), + seconds = Math.floor((t / 1000) % 60), + minutes = Math.floor((t / (1000 * 60)) % 60), + hours = Math.floor((t / (1000 * 60 * 60)) % 24); + + hours = (hours < 10) ? "0" + hours : hours; + minutes = (minutes < 10) ? "0" + minutes : minutes; + seconds = (seconds < 10) ? "0" + seconds : seconds; + + return hours + ":" + minutes + ":" + seconds; + } + + function printDebug() { + print ("Nowtime: " + getTime(now)); + print ("Now: " + now); + print ("Goaltime: " + getTime(settingsChronowid.goal)); + print ("Goal: " + settingsChronowid.goal); + print("Difftime: " + getTime(diff)); + print("Diff: " + diff); + print ("Started: " + settingsChronowid.started); + print ("----"); + } + + //counts down, calculates and displays + function countDown() { + now = new Date(); + diff = settingsChronowid.goal - now; //calculate difference + WIDGETS["chronowid"].draw(); + //time is up + if (settingsChronowid.started && diff < 1000) { + Bangle.buzz(1500); + //write timer off to file + settingsChronowid.started = false; + storage.writeJSON('chronowid.json', settingsChronowid); + clearInterval(interval); //stop interval + } + //printDebug(); + } + + // draw your widget + function draw() { + if (!settingsChronowid.started) { + width = 0; + return; //do not draw anything if timer is not started + } + g.reset(); + if (diff >= 0) { + if (diff < 3600000) { //less than 1 hour left + width = 58; + g.clearRect(this.x,this.y,this.x+width,this.y+height); + g.setFont("6x8", 2); + g.drawString(getTime(diff).substring(3), this.x+1, this.y+5); //remove hour part 00:00:00 -> 00:00 + } + if (diff >= 3600000) { //one hour or more left + width = 48; + g.clearRect(this.x,this.y,this.x+width,this.y+height); + g.setFont("6x8", 1); + g.drawString(getTime(diff), this.x+1, this.y+((height/2)-4)); //display hour 00:00:00 + } + } + // not needed anymoe, because we check if diff < 1000 now, so 00:00 is displayed. + // else { + // width = 58; + // g.clearRect(this.x,this.y,this.x+width,this.y+height); + // g.setFont("6x8", 2); + // g.drawString("END", this.x+15, this.y+5); + // } + } + + if (settingsChronowid.started) interval = setInterval(countDown, 1000); //start countdown each second + + // add the widget + WIDGETS["chronowid"]={area:"bl",width:width,draw:draw,reload:function() { + reload(); + Bangle.drawWidgets(); // relayout all widgets + }}; + + //printDebug(); + countDown(); })(); \ No newline at end of file From af0ac4041cb772856b7c12ac6d3ada6f360a246e Mon Sep 17 00:00:00 2001 From: Purple-Tentacle <59914607+Purple-Tentacle@users.noreply.github.com> Date: Mon, 20 Apr 2020 15:58:05 +0200 Subject: [PATCH 20/73] chronowid 0.03 --- apps.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps.json b/apps.json index d7bd6a7a1..274a3a8b2 100644 --- a/apps.json +++ b/apps.json @@ -1142,7 +1142,7 @@ "name": "Chrono Widget", "shortName":"Chrono Widget", "icon": "app.png", - "version":"0.02", + "version":"0.03", "description": "Chronometer (timer) which runs as widget.", "tags": "tools,widget", "readme": "README.md", From 74bd784b091ad97964a7923fa888816fd8770412 Mon Sep 17 00:00:00 2001 From: Paul Cockrell Date: Mon, 20 Apr 2020 15:00:06 +0100 Subject: [PATCH 21/73] Initial commit of BuffGym 5x5 training program --- apps.json | 14 ++ apps/buffgym/.eslintrc.json | 33 ++++ apps/buffgym/buffgym-exercise.js | 187 +++++++++++++++++++ apps/buffgym/buffgym-icon.js | 1 + apps/buffgym/buffgym-program.js | 68 +++++++ apps/buffgym/buffgym-set.js | 46 +++++ apps/buffgym/buffgym.app.js | 311 +++++++++++++++++++++++++++++++ apps/buffgym/buffgym.png | Bin 0 -> 1800 bytes 8 files changed, 660 insertions(+) create mode 100644 apps/buffgym/.eslintrc.json create mode 100644 apps/buffgym/buffgym-exercise.js create mode 100644 apps/buffgym/buffgym-icon.js create mode 100644 apps/buffgym/buffgym-program.js create mode 100644 apps/buffgym/buffgym-set.js create mode 100755 apps/buffgym/buffgym.app.js create mode 100644 apps/buffgym/buffgym.png diff --git a/apps.json b/apps.json index 60b47dbd8..e993f0e18 100644 --- a/apps.json +++ b/apps.json @@ -1293,5 +1293,19 @@ "evaluate": true } ] + }, + { + "id": "buffgym", + "name": "BuffGym", + "icon": "buffgym.png", + "version":"0.01", + "description": "BuffGym is the famous 5x5 workout program for the BangleJS", + "tags": "tool,outdoors", + "type": "app", + "storage": [ + {"name":"buffgym"}, + {"name":"buffgym.app.js"}, + {"name":"buffgym.img","url":"buffgym-icon.js","evaluate":true} + ] } ] diff --git a/apps/buffgym/.eslintrc.json b/apps/buffgym/.eslintrc.json new file mode 100644 index 000000000..c91a72544 --- /dev/null +++ b/apps/buffgym/.eslintrc.json @@ -0,0 +1,33 @@ +{ + "env": { + "browser": true, + "commonjs": true, + "es6": true + }, + "extends": "eslint:recommended", + "globals": { + "Atomics": "readonly", + "SharedArrayBuffer": "readonly" + }, + "parserOptions": { + "ecmaVersion": 2018 + }, + "rules": { + "indent": [ + "error", + 2 + ], + "linebreak-style": [ + "error", + "windows" + ], + "quotes": [ + "error", + "double" + ], + "semi": [ + "error", + "always" + ] + } +} \ No newline at end of file diff --git a/apps/buffgym/buffgym-exercise.js b/apps/buffgym/buffgym-exercise.js new file mode 100644 index 000000000..b7a1e3e15 --- /dev/null +++ b/apps/buffgym/buffgym-exercise.js @@ -0,0 +1,187 @@ +const STARTED = 1; +const RESTING = 2; +const COMPLETED = 3; +const ONE_SECOND = 1000; +const INCREMENT = "increment"; +const DECREMENT = "decrement"; + +class Exercise { + constructor(params /*{title, weight, unit, restPeriod}*/) { + const DEFAULTS = { + title: "Unknown", + weight: 0, + unit: "Kg", + restPeriod: 90, + weightIncrement: 2.5, + }; + const p = Object.assign({}, DEFAULTS, params); + + this._title = p.title; + this._weight = p.weight; + this._unit = p.unit; + this._originalRestPeriod = p.restPeriod; // Used when reseting _restPeriod + this._restPeriod = p.restPeriod; + this._weightIncrement = p.weightIncrement; + this._started = new Date(); + this._completed = false; + this._sets = []; + this._restTimeout = null; + this._restInterval = null; + this._state = null; + } + + get title() { + return this._title; + } + + get humanTitle() { + return `${this._title} ${this._weight}${this._unit}`; + } + + get subTitle() { + const totalSets = this._sets.length; + const uncompletedSets = this._sets.filter((set) => !set.isCompleted()).length; + const currentSet = (totalSets - uncompletedSets) + 1; + return `Set ${currentSet} of ${totalSets}`; + } + + get restPeriod() { + return this._restPeriod; + } + + decRestPeriod() { + this._restPeriod--; + } + + get weight() { + return this._weight; + } + + get unit() { + return this._unit; + } + + get started() { + return this._started; + } + + addSet(set) { + this._sets.push(set); + } + + addSets(sets) { + sets.forEach(set => this.addSet(set)); + } + + get currentSet() { + return this._sets.filter(set => !set.isCompleted())[0]; + } + + isLastSet() { + return this._sets.filter(set => !set.isCompleted()).length === 1; + } + + isCompleted() { + return !!this._completed; + } + + canSetCompleted() { + return this._sets.filter(set => set.isCompleted()).length === this._sets.length; + } + + setCompleted() { + if (!this.canSetCompleted()) throw "All sets must be completed"; + if (this.canProgress) this._weight += this._weightIncrement; + this._completed = true; + } + + get canProgress() { + let completedRepsTotalSum = 0; + let targetRepsTotalSum = 0; + + const completedRepsTotal = this._sets.forEach(set => completedRepsTotalSum += set.reps); + const targetRepsTotal = this._sets.forEach(set => targetRepsTotalSum += set.maxReps); + + return (targetRepsTotalSum - completedRepsTotalSum) === 0; + } + + startRestTimer(program) { + this._restTimeout = setTimeout(() => { + this.next(); + }, ONE_SECOND * this._restPeriod); + + this._restInterval = setInterval(() => { + program.emit("redraw"); + }, ONE_SECOND); + } + + resetRestTimer() { + clearTimeout(this._restTimeout); + clearInterval(this._restInterval); + this._restTimeout = null; + this._restInterval = null; + this._restPeriod = this._originalRestPeriod; + } + + isRestTimerRunning() { + return this._restTimeout != null; + } + + setupStartedButtons(program) { + clearWatch(); + + setWatch(() => { + this.currentSet.incReps(); + program.emit("redraw"); + }, BTN1, {repeat: true}); + + setWatch(program.next.bind(program), BTN2, {repeat: false}); + + setWatch(() => { + this.currentSet.decReps(); + program.emit("redraw"); + }, BTN3, {repeat: true}); + } + + setupRestingButtons(program) { + clearWatch(); + setWatch(program.next.bind(program), BTN2, {repeat: true}); + } + + next(program) { + global.poo = this; + switch(this._state) { + case null: + console.log("XXX 1 moving null -> STARTED"); + this._state = STARTED; + this.setupStartedButtons(program); + break; + case STARTED: + console.log("XXX 2 moving STARTED -> RESTING"); + this._state = RESTING; + this.startRestTimer(program); + this.setupRestingButtons(program); + break; + case RESTING: + this.resetRestTimer(); + this.currentSet.setCompleted(); + + if (this.canSetCompleted()) { + console.log("XXX 3b moving RESTING -> COMPLETED"); + this._state = COMPLETED; + this.setCompleted(); + } else { + console.log("XXX 3a moving RESTING -> null"); + this._state = null; + } + // As we are changing state and require it to be reprocessed + // invoke the next step of program + program.next(program); + break; + default: + throw "Exercise: Attempting to move to an unknown state"; + } + + program.emit("redraw"); + } +} \ No newline at end of file diff --git a/apps/buffgym/buffgym-icon.js b/apps/buffgym/buffgym-icon.js new file mode 100644 index 000000000..949b0e45b --- /dev/null +++ b/apps/buffgym/buffgym-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwwhC/AFEEolAC6lN7vdDCcECwPd6guVGCYuDC4cCBQMikQXQJAMjkECmcyIx4XDmUjmYvLC4XUDARHBIoIWLgATCGQdA7tEonQC5ouDDYg0BOxgSEAggwKRwgUCC6ZIDSwoXNogWDDgNCAgIWIkUEoUk6kiCgMkokipsiBIQXIki2CAgNCAoYADC5Eic4Mic4ICCAIIJCC5MzAAcykYGEAAIXOABAXTmUzGoIXVAIIXLB4SICDIovjO76PZbYR3PDI4XiI6530MIh3SC6R33C/oAOC48CCxsgC44A/ADY=")) diff --git a/apps/buffgym/buffgym-program.js b/apps/buffgym/buffgym-program.js new file mode 100644 index 000000000..22f39f10b --- /dev/null +++ b/apps/buffgym/buffgym-program.js @@ -0,0 +1,68 @@ +class Program { + constructor(params) { + const DEFAULTS = { + title: "Unknown", + trainDay: "", // Day of week + }; + const p = Object.assign({}, DEFAULTS, params); + + this._title = p.title; + this._trainDay = p.trainDay; + this._exercises = []; + + this.on("redraw", redraw.bind(null, this)); + } + + get title() { + return `${this._title} - ${this._trainDay}`; + } + + addExercise(exercise) { + this._exercises.push(exercise); + } + + addExercises(exercises) { + exercises.forEach(exercise => this.addExercise(exercise)); + } + + currentExercise() { + return ( + this._exercises + .filter(exercise => !exercise.isCompleted())[0] + ); + } + + canComplete() { + return ( + this._exercises + .filter(exercise => exercise.isCompleted()) + .length === this._exercises.length + ); + } + + setCompleted() { + if (!this.canComplete()) throw "All exercises must be completed"; + this._completed = true; + } + + isCompleted() { + return !!this._completed; + } + + // State machine + next() { + console.log("XXX Program.next"); + const exercise = this.currentExercise(); + + // All exercises are completed so mark the + // Program as comleted + if (this.canComplete()) { + this.setCompleted(); + this.emit("redraw"); + + return; + } + + exercise.next(this); + } +} \ No newline at end of file diff --git a/apps/buffgym/buffgym-set.js b/apps/buffgym/buffgym-set.js new file mode 100644 index 000000000..d7d610a78 --- /dev/null +++ b/apps/buffgym/buffgym-set.js @@ -0,0 +1,46 @@ +class Set { + constructor(maxReps) { + this._minReps = 0; + this._maxReps = maxReps; + this._reps = 0; + this._completed = false; + } + + get title() { + return this._title; + } + + get weight() { + return this._weight; + } + + isCompleted() { + return !!this._completed; + } + + setCompleted() { + this._completed = true; + } + + get reps() { + return this._reps; + } + + get maxReps() { + return this._maxReps; + } + + incReps() { + if (this._completed) return; + if (this._reps >= this._maxReps) return; + + this._reps++; + } + + decReps() { + if (this._completed) return; + if (this._reps <= this._minReps) return; + + this._reps--; + } +} \ No newline at end of file diff --git a/apps/buffgym/buffgym.app.js b/apps/buffgym/buffgym.app.js new file mode 100755 index 000000000..e74b7062a --- /dev/null +++ b/apps/buffgym/buffgym.app.js @@ -0,0 +1,311 @@ +/* global g, setWatch, clearWatch, reset, BTN1, BTN2, BTN3 */ + +(() => { + const W = g.getWidth(); + const H = g.getHeight(); + const RED = "#d32e29"; + const PINK = "#f05a56"; + const WHITE = "#ffffff"; + + const Set = require("set.js"); + const Exercise = require("exercise.js"); + const Program = require("program.js"); + + function centerStringX(str) { + return (W - g.stringWidth(str)) / 2; + } + + function iconIncrement() { + const img = require("heatshrink").decompress(atob("ikUxH+AA3XAAgNHCJIVMBYXQ5PC4XJ6AUJCIQQBAAoVCCQwjCAA/JCgglHA4IpJBYwTHA4RMJCY5oDJo4THKIQKET5IMGCaY7TMaKLTWajbTFJIlICgoVBFYXJYQYSGCggAGCRAVIBgw")); + return img; + } + + function iconDecrement() { + const img = require("heatshrink").decompress(atob("ikUxH+AA3XAAgNHCJIVMBYXQ5PC4XJ6AUJCIQQBAAoVCCQwjCAA/JCgglKFJADBCRYABCYQmOFAhNMKIw6FTw4LHCaY7TMaKLTWajbTFJglFCgoVBFYXJYQYSGCggAGCRAVIBgw=")); + return img; + } + + function iconOk() { + const img = require("heatshrink").decompress(atob("ikUxH+AA3XAAgNHCJIVMBYXQ5PC4XJ6AUJCIQQBAAoVCCQwjCAA/JCgglKFJADBCJQxCCYQmMIwZoDJpQMCKIg6KBYwTGFQgeHHYouCCRI7EMYTXFRhILEK5SfFRgYSIborbSbpglFCgoVBFYXJYQYSGCggAGCRAVIBgwA==")); + return img; + } + + function drawMenu(params) { + const DEFAULT_PARAMS = { + showBTN1: false, + showBTN2: false, + showBTN3: false, + }; + const p = Object.assign({}, DEFAULT_PARAMS, params); + if (p.showBTN1) g.drawImage(iconIncrement(), W - 30, 10); + if (p.showBTN2) g.drawImage(iconOk(), W - 30, 110); + if (p.showBTN3) g.drawImage(iconDecrement(), W - 30, 210); + } + + function clearScreen() { + g.setColor(RED); + g.fillRect(0,0,W,H); + } + + function drawTitle(exercise) { + const title = exercise.humanTitle; + + g.setFont("Vector",20); + g.setColor(WHITE); + g.drawString(title, centerStringX(title), 5); + } + + function drawReps(exercise) { + const set = exercise.currentSet; + if (set.isCompleted()) return; + + g.setColor(PINK); + g.fillCircle(W / 2, H / 2, 50); + g.setColor(WHITE); + g.setFont("Vector", 40); + g.drawString(set.reps, centerStringX(set.reps), (H - 45) / 2); + g.setFont("Vector", 15); + const note = `of ${set.maxReps}`; + g.drawString(note, centerStringX(note), (H / 2) + 25); + } + + function drawSets(exercise) { + const sets = exercise.subTitle; + + g.setColor(WHITE); + g.setFont("Vector", 15); + g.drawString(sets, centerStringX(sets), H - 25); + } + + function drawSetProgress(exercise) { + drawTitle(exercise); + drawReps(exercise); + drawSets(exercise); + drawMenu({showBTN1: true, showBTN2: true, showBTN3: true}); + } + + function drawStartNextExercise() { + const title = "Good work"; + const msg = "No need to rest\nmove straight on\nto the next exercise"; + + g.setColor(WHITE); + g.setFont("Vector", 35); + g.drawString(title, centerStringX(title), 10); + g.setFont("Vector", 15); + g.drawString(msg, 30, 150); + drawMenu({showBTN1: false, showBTN2: true, showBTN3: false}); + } + + function drawProgramCompleted() { + const title1 = "You did"; + const title2 = "GREAT!"; + const msg = "That's the program\ncompleted. Now eat\nsome food and\nget plenty of rest."; + + clearWatch(); + setWatch(reset, BTN2, {repeat: false}); + + g.setColor(WHITE); + g.setFont("Vector", 35); + g.drawString(title1, centerStringX(title1), 10); + g.setFont("Vector", 40); + g.drawString(title2, centerStringX(title2), 50); + g.setFont("Vector", 15); + g.drawString(msg, 30, 150); + drawMenu({showBTN1: false, showBTN2: true, showBTN3: false}); + } + + /* + function drawExerciseCompleted(program) { + const exercise = program.currentExercise(); + const title = exercise.canProgress? + "WELL DONE!" : + "NOT BAD!"; + const msg = exercise.canProgress? + `You weight is automatically increased\nfor ${exercise.title} to ${exercise.weight}${exercise.unit}` : + "It looks like you struggled\non a few sets, your weight will\nstay the same"; + const action = "Move straight on to the next exercise"; + + clearScreen(); + g.setColor(WHITE); + g.setFont("Vector", 20); + g.drawString(title, centerStringX(title), 10); + g.setFont("Vector", 10); + g.drawString(msg, centerStringX(msg), 180); + g.drawString(action, centerStringX(action), 210); + drawMenu({showBTN2: true}); + + clearWatch(); + setWatch(() => { + init(program); + }, BTN2, {repeat: false}); + } + */ + + function drawRestTimer(program) { + const exercise = program.currentExercise(); + const motivation = "Take a breather.."; + clearScreen(); + drawMenu({showBTN2: true}); + + g.setColor(PINK); + g.fillCircle(W / 2, H / 2, 50); + g.setColor(WHITE); + g.setFont("Vector", 15); + g.drawString(motivation, centerStringX(motivation), 25); + g.setFont("Vector", 40); + g.drawString(exercise.restPeriod, centerStringX(exercise.restPeriod), (H - 45) / 2); + exercise.decRestPeriod(); + + if (exercise.restPeriod <= 0) { + exercise.resetRestTimer(); + redraw(program); + } + } + + function redraw(program) { + const exercise = program.currentExercise(); + + clearScreen(); + + if (program.isCompleted()) { + drawProgramCompleted(program); + return; + } + + if (exercise.isRestTimerRunning()) { + if (exercise.isLastSet()) { + drawStartNextExercise(program); + } else { + drawRestTimer(program); + } + + return; + } + + drawSetProgress(exercise); + } + + function init(program) { + clearWatch(); + program.next(); + } + + // Setup training program. This should come from file + + // Squats + function buildPrograms() { + const squats = new Exercise({ + title: "Squats", + weight: 40, + unit: "Kg", + }); + squats.addSets([ + new Set(5), + new Set(5), + new Set(5), + new Set(5), + new Set(5), + ]); + + const bench = new Exercise({ + title: "Bench press", + weight: 20, + unit: "Kg", + }); + bench.addSets([ + new Set(5), + new Set(5), + new Set(5), + new Set(5), + new Set(5), + ]); + + const row = new Exercise({ + title: "Row", + weight: 20, + unit: "Kg", + }); + row.addSets([ + new Set(5), + new Set(5), + new Set(5), + new Set(5), + new Set(5), + ]); + + const ohPress = new Exercise({ + title: "Overhead press", + weight: 20, + unit: "Kg", + }); + ohPress.addSets([ + new Set(5), + new Set(5), + new Set(5), + new Set(5), + new Set(5), + ]); + + const deadlift = new Exercise({ + title: "Deadlift", + weight: 20, + unit: "Kg", + }); + deadlift.addSets([ + new Set(5), + ]); + + const pullups = new Exercise({ + title: "Pullups", + weight: 0, + unit: "Kg", + }); + pullups.addSets([ + new Set(10), + new Set(10), + new Set(10), + ]); + + const triceps = new Exercise({ + title: "Tricep extension", + weight: 20, + unit: "Kg", + }); + triceps.addSets([ + new Set(10), + new Set(10), + new Set(10), + ]); + + const programA = new Program({ + title: "Program A", + }); + programA.addExercises([ + squats, + ohPress, + deadlift, + pullups, + ]); + + const programB = new Program({ + title: "Program B", + }); + programB.addExercises([ + squats, + bench, + row, + triceps, + ]); + + const programs = [ + programA, + programB, + ]; + return programs; + } + + // For this spike, just run the first program, what will + // really happen is the user picks a program to do from + // some menu on a start page. + init(buildPrograms()[0]); +})(); \ No newline at end of file diff --git a/apps/buffgym/buffgym.png b/apps/buffgym/buffgym.png new file mode 100644 index 0000000000000000000000000000000000000000..93a29a4a686f172e5e6dbd2ecb2a1d3edf4751c0 GIT binary patch literal 1800 zcmV+j2lx1iP)tlxqC9)f@Omu&Na^VuQ3o*OkLX&0x0b91a zC7LC3CR;|G&UwKyoC)@U)%oe$2-|YHkk(v4M!t35mBz$@a#wDU>?rxOl>4iDU0;K~&^NeJ~rZV1qG0 z2VEWRN{fW6B-AV=vyLG{LNQb2i6*D;)z1+>HV9oV)YY-AYv;CEAGyt1BxHeIB6`O1 zgNbCKvH5&(h}tjTY&oMqX-z=6c>c(BKect-eBUPt!g0uGg&+h40X>Fzw5_e#pVR#$ zXoP~+BFSrtk0nGN171%U%*9ZeH|HLjvY%#M?bNRbI9pq_zjAQwp^ph~HbFcpN~ZRz z(p@Mo-ho770lfp=4bOss8*F%I4msLmKr#xaD)J*)`yvYx`ky+nJwKX`iBeY-qKGqH z?QS=3P!M$53s7Hu5JniTm@SU>rp6YK0dui1iN|DU+@DO!eyGs{ttdh(`FAE0vla{o z?WidZt%?gW#AR7;<X-pbXX@H zNxpMYdq4RMO4a}WV;wc05JSkxHD~SsCa-dTj zNTxVqQheR_7dUJ%8VslVKYYW7jWB?j;7(;1x|h0^D=>+_|8G8A);PQcVdy~=1vqUM z=Bmmm)pMW?ZosIy0KK;IbR&uXN!$f_n-$fCGwJquLBgH9YRnj{JTt}EHBxNEeXlt^ z=25u`mrr_dyKd3t92OJZd{9ZwAii{~WsvTQjEnfS8xO2y_@!_U?;}HwP2R(Ijz)}m zit&g9Oe?63KH;Lj-FATAd+p`e9q7aT9cJ8VbS}; zQ^kGnzzKFl@TSGDoSS-YQ$q_XStXt~30!=tPYtT;z`;H5V0>y6M#+fsq8;frcBVm9 z*_*JM9oV^KK>zTcC~y_yt(v2JXX>jDabwn+OJjC>_p^QzY!*8o^Zl)_Rq0Y~0Idq0 zS2Ejbz57Z043707FgeP1%EK<&HQJ?2qjG*1bTS%v z%ubCHDDjk|*z-F39AIq&YmVQ|gsn7eCKBY&B;IDWBhQ|XP-F^P(QUxw%mhX!9y3?4 za|0-g(DPbUZ?Ai9XPitl89;gYdW9(B>6do0 z&{d=<|EJJx0R4iRi$%B)8xs*{tC-D)*IL!li9sItRi$t8xdUT=@j7sD@4L`~ZUg#< z@9|7Teoy(EeEDwwZ_kbU;PA;c-%(!VWd_vn&m{hDmP)mv+W`74ORG=SmA{Aypl2;4 z5^=uzMCz^;-3HXM(oa{4%%IK%Ex`EHFzC+|RLpt@yWwJmOe>of#Mu@=51VEH#S6s{ z9o#%D1JN_>#7hfe`U6y8YJ?wyDGkFo zERDt!OF!~i5Yltbc`JfdVhJF1ywFnv_&cBz%HNa*=^#c>zCWO1`&}!lb?WRyb7@D_ zoMJQ4ZGbZ)W6%m}S;fo+s9pL&qm@ky;%p0`2i^anc~wxo1C;V!MN}J*?VR%}kkbG~ qkv|qi@hCO{S(a~Li!HWTm;V6Sm{)4DoNDL*0000 Date: Mon, 20 Apr 2020 15:27:21 +0100 Subject: [PATCH 22/73] Update apps.json --- apps.json | 4 + apps/buffgym/buffgym-programs.json | 101 ++++++++++++++++++++++++ apps/buffgym/buffgym.app.js | 121 +++++------------------------ 3 files changed, 125 insertions(+), 101 deletions(-) create mode 100644 apps/buffgym/buffgym-programs.json diff --git a/apps.json b/apps.json index e993f0e18..bff5fe66b 100644 --- a/apps.json +++ b/apps.json @@ -1305,6 +1305,10 @@ "storage": [ {"name":"buffgym"}, {"name":"buffgym.app.js"}, + {"name":"buffgym-set.js","url":"buffgym-set.js"}, + {"name":"buffgym-exercise.js","url":"buffgym-exercise.js"}, + {"name":"buffgym-program.js","url":"buffgym-program.js"}, + {"name":"buffgym-programs.json","url":"buffgym-program.json"}, {"name":"buffgym.img","url":"buffgym-icon.js","evaluate":true} ] } diff --git a/apps/buffgym/buffgym-programs.json b/apps/buffgym/buffgym-programs.json new file mode 100644 index 000000000..bf5aa0e0d --- /dev/null +++ b/apps/buffgym/buffgym-programs.json @@ -0,0 +1,101 @@ +[ + { + title: "Program A", + exercises: [ + { + title: "Squats", + weight: 40, + unit: "Kg", + sets: [ + 5, + 5, + 5, + 5, + 5 + ] + }, + { + title: "Overhead press", + weight: 20, + unit: "Kg", + sets: [ + 5, + 5, + 5, + 5, + 5 + ] + }, + { + title: "Deadlift", + weight: 20, + unit: "Kg", + sets: [ + 5 + ] + }, + { + title: "Pullups", + weight: 0, + unit: "Kg", + sets: [ + 10, + 10, + 10 + ] + } + ] + }, + { + title: "Program B", + exercises: [ + { + title: "Squats", + weight: 40, + unit: "Kg", + sets: [ + 5, + 5, + 5, + 5, + 5 + ] + }, + { + title: "Bench press", + weight: 20, + unit: "Kg", + sets: [ + 5, + 5, + 5, + 5, + 5 + ] + }, + { + title: "Row", + weight: 20, + unit:"Kg", + sets: [ + 5, + 5, + 5, + 5, + 5 + ] + + }, + { + title: "Tricep extension", + weight: 20, + unit: "Kg", + sets: [ + 10, + 10, + 10 + ] + } + ] + } +] \ No newline at end of file diff --git a/apps/buffgym/buffgym.app.js b/apps/buffgym/buffgym.app.js index e74b7062a..d3a4e6834 100755 --- a/apps/buffgym/buffgym.app.js +++ b/apps/buffgym/buffgym.app.js @@ -194,113 +194,32 @@ // Squats function buildPrograms() { - const squats = new Exercise({ - title: "Squats", - weight: 40, - unit: "Kg", - }); - squats.addSets([ - new Set(5), - new Set(5), - new Set(5), - new Set(5), - new Set(5), - ]); + const programsJSON = require("Storage").readJSON("buffgym-programs.json", 1); - const bench = new Exercise({ - title: "Bench press", - weight: 20, - unit: "Kg", - }); - bench.addSets([ - new Set(5), - new Set(5), - new Set(5), - new Set(5), - new Set(5), - ]); + if (!programsJSON) throw "No programs JSON found"; - const row = new Exercise({ - title: "Row", - weight: 20, - unit: "Kg", - }); - row.addSets([ - new Set(5), - new Set(5), - new Set(5), - new Set(5), - new Set(5), - ]); + const programs = []; - const ohPress = new Exercise({ - title: "Overhead press", - weight: 20, - unit: "Kg", - }); - ohPress.addSets([ - new Set(5), - new Set(5), - new Set(5), - new Set(5), - new Set(5), - ]); + programsJSON.forEach(programJSON => { + const program = new Program({ + title: programJSON.title, + }); + const exercises = programJSON.exercises.map(exerciseJSON => { + const exercise = new Exercise({ + title: exerciseJSON.title, + weight: exerciseJSON.weight, + unit: exerciseJSON.unit, + }); + exerciseJSON.sets.forEach(setJSON => { + exercise.addSet(new Set(setJSON)); + }); - const deadlift = new Exercise({ - title: "Deadlift", - weight: 20, - unit: "Kg", + return exercise; + }); + program.addExercises(exercises); + programs.push(program); }); - deadlift.addSets([ - new Set(5), - ]); - const pullups = new Exercise({ - title: "Pullups", - weight: 0, - unit: "Kg", - }); - pullups.addSets([ - new Set(10), - new Set(10), - new Set(10), - ]); - - const triceps = new Exercise({ - title: "Tricep extension", - weight: 20, - unit: "Kg", - }); - triceps.addSets([ - new Set(10), - new Set(10), - new Set(10), - ]); - - const programA = new Program({ - title: "Program A", - }); - programA.addExercises([ - squats, - ohPress, - deadlift, - pullups, - ]); - - const programB = new Program({ - title: "Program B", - }); - programB.addExercises([ - squats, - bench, - row, - triceps, - ]); - - const programs = [ - programA, - programB, - ]; return programs; } From 8238bb766a6f4fc80c14e2c781f5dd1ff25da22a Mon Sep 17 00:00:00 2001 From: RenaudG <34276398+renaudgweb@users.noreply.github.com> Date: Mon, 20 Apr 2020 16:40:26 +0200 Subject: [PATCH 23/73] Create app.js --- apps/hamloc/app.js | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 apps/hamloc/app.js diff --git a/apps/hamloc/app.js b/apps/hamloc/app.js new file mode 100644 index 000000000..ac608a5f4 --- /dev/null +++ b/apps/hamloc/app.js @@ -0,0 +1,21 @@ +latLonToGridSquare=function(o,a){var t,e,n,s,l,i,r,h,M,f=-100,g=0,u="ABCDEFGHIJKLMNOPQRSTUVWX",d=u.toLowerCase();function N(o){return"number"==typeof o?o:"string"==typeof o?parseFloat(o):"function"==typeof o?parseFloat(o()):void E.showMessage("can't convert \ninput: "+o)}return"object"==typeof o?2===o.length?(f=N(o[0]),g=N(o[1])):"lat"in o&&"lon"in o?(f=N(o.lat),g=N(o.lon)):"latitude"in o&&"longitude"in o?(f=N(o.latitude),g=N(o.longitude)):E.showMessage("can't convert \nobject "+o):(f=N(o),g=N(a)),isNaN(f)&&E.showMessage("lat is NaN"),isNaN(g)&&E.showMessage("lon is NaN"),90===Math.abs(f)&&E.showMessage("grid invalid \nat N/S"),90 Date: Mon, 20 Apr 2020 16:43:00 +0200 Subject: [PATCH 24/73] Add files via upload --- apps/hamloc/app.png | Bin 0 -> 3697 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 apps/hamloc/app.png diff --git a/apps/hamloc/app.png b/apps/hamloc/app.png new file mode 100644 index 0000000000000000000000000000000000000000..54dac5882e4aa4b14cb1e20d04471c4a5efc027b GIT binary patch literal 3697 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 Date: Mon, 20 Apr 2020 16:44:35 +0200 Subject: [PATCH 25/73] Create app-icon.js --- apps/hamloc/app-icon.js | 1 + 1 file changed, 1 insertion(+) create mode 100644 apps/hamloc/app-icon.js diff --git a/apps/hamloc/app-icon.js b/apps/hamloc/app-icon.js new file mode 100644 index 000000000..175b492c7 --- /dev/null +++ b/apps/hamloc/app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwxH+AH4ACwVeAAM6nQECJsYqDFYItCAgQ0DFrxWE2ZhBxOJA4ICBGwhbbxGtAYOz2etnWt2YwBnQCBGgWtxBjXJQQpBLgQABEQIDBMAgwE2YYBwRcUxOtDwgABGgYvGTQQLCMSRNGEQaODF4SQDHgYwUFIlfAgY2DYQQGDsouCGAQSEGBouEKANl1onEwQvGA4QACA4IwQaIISFFwIwDXwI2ExL2BB4YABJgwwKnQAkRpzYDAAbuBA4oABe4aaDD44uGxCNEQwStEdwgAFR4IHGF4iRBxJeLBwIdCcwgvJxLwFFIRgLBo4dBcwj2CF45xIKIxeLAww4FAAuINIYbKMAteso8FAwovPCQllQQtlF4gLFUYwvDsq/HfIShEDhCQDIgIAFnQHGBBITRnWIXwdfAAYGFSYblBNI5KBsobEDo4GCdxyFDr2tR4+tDQrwNF5YlEnQvJaZIvKr4RIEoovaSAIvyXArbBF6OJR6mCXAgvBDwIlFd5IfBd6tfSQQRGCgeIBJE6DIIAFDoIGGF4OCAgIAEnQHGBBITRnWIF4P+V4ZMCWxBoBRw5PBNI7IGnQuCSAIfE1oSB1oADF4WIXxAvHsoIFH4IvEdIJWEDg4vICRTuJSAwABxAcJF5A5C1ovKRwhgCwSQGF6CpEXxBeGMA59JZIIvGA4hhBLw+JF4xRFSBBNDFIhHFe4VfLxhgCAEguIMAJSB1oABSA4HEB4RwBAgQXHss6LxKRDPQTxBsovIRIdexCOGRpwwIr5gFAwbuEAoheBFyQwFRIrwDLwZuBdwgTBC4IuRYYowGRAq+BAoeCAoRABFyIABD4IsCGAgpFGoguBd4eIFyRiEFoIwCEoKJDRwYqCCAJcUGJICBK4JgDKgOtOIQtce4s6AAI2EBAgteAAizBGgYECwQsiAD4")) From 9f5cbc6022ee275ed40e6942cb69388f4d6c6e07 Mon Sep 17 00:00:00 2001 From: RenaudG <34276398+renaudgweb@users.noreply.github.com> Date: Mon, 20 Apr 2020 16:49:49 +0200 Subject: [PATCH 26/73] Update apps.json --- apps.json | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/apps.json b/apps.json index b58fad5ce..e55190ec0 100644 --- a/apps.json +++ b/apps.json @@ -1400,5 +1400,17 @@ {"name":"rclock.app.js","url":"rclock.app.js"}, {"name":"rclock.img","url":"app-icon.js","evaluate":true} ] + }, + { "id": "hamloc", + "name": "QTH Locator / Maidenhead Locator System", + "shortName": "QTH Locator", + "icon": "app.png", + "version":"0.01", + "description": "Convert your current GPS location to the Maidenhead locator system used by HAM amateur radio operators", + "tags": "tool,outdoors,gps", + "storage": [ + {"name":"hamloc.app.js","url":"app.js"}, + {"name":"hamloc.img","url":"app-icon.js","evaluate":true} + ] } ] From 02af1e4b1518b35d09e541df63f4130924df29d2 Mon Sep 17 00:00:00 2001 From: RenaudG <34276398+renaudgweb@users.noreply.github.com> Date: Mon, 20 Apr 2020 16:55:59 +0200 Subject: [PATCH 27/73] Create ChangeLog --- apps/hamloc/ChangeLog | 1 + 1 file changed, 1 insertion(+) create mode 100644 apps/hamloc/ChangeLog diff --git a/apps/hamloc/ChangeLog b/apps/hamloc/ChangeLog new file mode 100644 index 000000000..5560f00bc --- /dev/null +++ b/apps/hamloc/ChangeLog @@ -0,0 +1 @@ +0.01: New App! From e513031a8770146f7fbe34c672d283d177e31f4a Mon Sep 17 00:00:00 2001 From: RenaudG <34276398+renaudgweb@users.noreply.github.com> Date: Mon, 20 Apr 2020 17:11:51 +0200 Subject: [PATCH 28/73] Create README.md --- apps/hamloc/README.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 apps/hamloc/README.md diff --git a/apps/hamloc/README.md b/apps/hamloc/README.md new file mode 100644 index 000000000..493afa899 --- /dev/null +++ b/apps/hamloc/README.md @@ -0,0 +1,14 @@ +# QTH Locator + +Convert your current GPS location to the [Maidenhead](https://en.wikipedia.org/wiki/Maidenhead_Locator_System) locator system used by HAM amateur radio operators. + +## Description + +A Maidenhead locator compresses latitude and longitude into a short string of characters, which is similar in concept to the World Geographic Reference System or GEOREF. This position information is presented in a limited level of precision to limit the number of characters needed for its transmission using voice, Morse code, or any other operating mode.[4] + +The chosen coding uses alternating pairs of letters and digits, like so: + +* BL11bh + +support Paul Brewer KI6CQ HamGridSquare.js +support Chris Veness 2002-2012 LatLon library From 5f9ee09daf8b9baf63e19d067efddd589da20648 Mon Sep 17 00:00:00 2001 From: RenaudG <34276398+renaudgweb@users.noreply.github.com> Date: Mon, 20 Apr 2020 17:13:07 +0200 Subject: [PATCH 29/73] Update README.md --- apps/hamloc/README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/apps/hamloc/README.md b/apps/hamloc/README.md index 493afa899..273e1f54b 100644 --- a/apps/hamloc/README.md +++ b/apps/hamloc/README.md @@ -4,11 +4,12 @@ Convert your current GPS location to the [Maidenhead](https://en.wikipedia.org/w ## Description -A Maidenhead locator compresses latitude and longitude into a short string of characters, which is similar in concept to the World Geographic Reference System or GEOREF. This position information is presented in a limited level of precision to limit the number of characters needed for its transmission using voice, Morse code, or any other operating mode.[4] +A Maidenhead locator compresses latitude and longitude into a short string of characters, which is similar in concept to the World Geographic Reference System or GEOREF. This position information is presented in a limited level of precision to limit the number of characters needed for its transmission using voice, Morse code, or any other operating mode. The chosen coding uses alternating pairs of letters and digits, like so: * BL11bh -support Paul Brewer KI6CQ HamGridSquare.js -support Chris Veness 2002-2012 LatLon library + +* support Paul Brewer KI6CQ HamGridSquare.js +* support Chris Veness 2002-2012 LatLon library From a47ebfaf4841be23a45f4b64533e1c7e55769a95 Mon Sep 17 00:00:00 2001 From: RenaudG <34276398+renaudgweb@users.noreply.github.com> Date: Mon, 20 Apr 2020 17:14:16 +0200 Subject: [PATCH 30/73] Update README.md --- apps/hamloc/README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/hamloc/README.md b/apps/hamloc/README.md index 273e1f54b..5710493bb 100644 --- a/apps/hamloc/README.md +++ b/apps/hamloc/README.md @@ -9,7 +9,6 @@ A Maidenhead locator compresses latitude and longitude into a short string of ch The chosen coding uses alternating pairs of letters and digits, like so: * BL11bh - - +## * support Paul Brewer KI6CQ HamGridSquare.js * support Chris Veness 2002-2012 LatLon library From 4b512af0e2012986ea1d5f3e2f916cb2f88e47b8 Mon Sep 17 00:00:00 2001 From: Purple-Tentacle <59914607+Purple-Tentacle@users.noreply.github.com> Date: Mon, 20 Apr 2020 17:34:33 +0200 Subject: [PATCH 31/73] activepedom 0.03 --- apps/activepedom/ChangeLog | 3 +- apps/activepedom/README.md | 20 +++++- apps/activepedom/app.js | 133 +++++++++++++++++++++++++++++++++++++ apps/activepedom/widget.js | 51 +++++++++----- 4 files changed, 190 insertions(+), 17 deletions(-) create mode 100644 apps/activepedom/app.js diff --git a/apps/activepedom/ChangeLog b/apps/activepedom/ChangeLog index fb0bc78e5..c1b9ec011 100644 --- a/apps/activepedom/ChangeLog +++ b/apps/activepedom/ChangeLog @@ -1,2 +1,3 @@ 0.01: New Widget! -0.02: Distance calculation and display \ No newline at end of file +0.02: Distance calculation and display +0.03: Data logging and display \ No newline at end of file diff --git a/apps/activepedom/README.md b/apps/activepedom/README.md index 055a91f56..f45297e57 100644 --- a/apps/activepedom/README.md +++ b/apps/activepedom/README.md @@ -1,4 +1,4 @@ -# Active Pedometer +# Active Pedometer Pedometer that filters out arm movement and displays a step goal progress. I changed the step counting algorithm completely. @@ -6,6 +6,8 @@ Now every step is counted when in status 'active', if the time difference betwee To get in 'active' mode, you have to reach the step threshold before the active timer runs out. When you reach the step threshold, the steps needed to reach the threshold are counted as well. +Steps are saved to a datafile every 5 minutes. You can watch a graph using the app. + ## Screenshots * 600 steps ![](600.png) @@ -30,6 +32,22 @@ When you reach the step threshold, the steps needed to reach the threshold are c * Steps are saved to a file and read-in at start (to not lose step progress) * Settings can be changed in Settings - App/widget settings - Active Pedometer +## Data storage + +* Data is stored to a file +* Format: now,stepsCounted,active,stepsTooShort,stepsTooLong,stepsOutsideTime +* now is UNIX timestamp in ms +* You can chose the app to watch a steps graph +* You can import the file into Excel +* The file does not include a header +* You can convert UNIX timestamp to a date in Excel using this formula: =DATUM(1970;1;1)+(LINKS(A2;10)/86400) +* You have to format the cell with the formula to a date cell. Example: JJJJ-MM-TT-hh-mm-ss + +## App + +* The app accesses the data stored for the current day +* Timespan is choseable (1h, 4h, 8h, 12h, 16h, 20, 24h), standard is 24h, the whole current day + ## Settings * Max time (ms): Maximum time between two steps in milliseconds, steps will not be counted if exceeded. Standard: 1100 diff --git a/apps/activepedom/app.js b/apps/activepedom/app.js new file mode 100644 index 000000000..f966530d0 --- /dev/null +++ b/apps/activepedom/app.js @@ -0,0 +1,133 @@ +(() => { + +const storage = require("Storage"); +var history = 86400000; // 28800000=8h 43200000=12h //86400000=24h + +//Convert ms to time +function getTime(t) { + date = new Date(t); + offset = date.getTimezoneOffset() / 60; + //var milliseconds = parseInt((t % 1000) / 100), + seconds = Math.floor((t / 1000) % 60); + minutes = Math.floor((t / (1000 * 60)) % 60); + hours = Math.floor((t / (1000 * 60 * 60)) % 24); + hours = hours - offset; + hours = (hours < 10) ? "0" + hours : hours; + minutes = (minutes < 10) ? "0" + minutes : minutes; + seconds = (seconds < 10) ? "0" + seconds : seconds; + return hours + ":" + minutes + ":" + seconds; +} + +function getDate(t) { + date = new Date(t*1); + year = date.getFullYear(); + month = date.getMonth()+1; //month is zero-based + day = date.getDate(); + month = (month < 10) ? "0" + month : month; + day = (day < 10) ? "0" + day : day; + return year + "-" + month + "-" + day; +} + +//columns: 0=time, 1=stepsCounted, 2=active, 3=stepsTooShort, 4=stepsTooLong, 5=stepsOutsideTime +function getArrayFromCSV(file, column) { + i = 0; + array = []; + now = new Date(); + while ((nextLine = file.readLine())) { //as long as there is a next line + if(nextLine) { + dataSplitted = nextLine.split(','); //split line, + diff = now - dataSplitted[0]; //calculate difference between now and stored time + if (diff <= history) { //only entries from the last x ms + array.push(dataSplitted[column]); + } + } + i++; + } + return array; +} + +function drawGraph() { + //times + // actives = getArrayFromCSV(csvFile, 2); + // shorts = getArrayFromCSV(csvFile, 3); + // longs = getArrayFromCSV(csvFile, 4); + // outsides = getArrayFromCSV(csvFile, 5); //array.push(dataSplitted[5].slice(0,-1)); + now = new Date(); + month = now.getMonth() + 1; + if (month < 10) month = "0" + month; + filename = filename = "activepedom-" + now.getFullYear() + month + now.getDate() + ".data"; + var csvFile = storage.open(filename, "r"); + times = getArrayFromCSV(csvFile, 0); + first = getDate(times[0]) + " " + getTime(times[0]); + last = getDate (times[times.length-1]) + " " + getTime(times[times.length-1]); + //free memory + csvFile = undefined; + times = undefined; + + //steps + var csvFile = storage.open(filename, "r"); + steps = getArrayFromCSV(csvFile, 1); + //define y-axis grid labels + stepsLastEntry = steps[steps.length-1]; + if (stepsLastEntry < 1000) gridyValue = 100; + if (stepsLastEntry >= 1000 && stepsLastEntry < 10000) gridyValue = 500; + if (stepsLastEntry > 10000) gridyValue = 5000; + + //draw + drawMenu(); + g.drawString("First: " + first, 40, 30); + g.drawString(" Last: " + last, 40, 40); + require("graph").drawLine(g, steps, { + //title: "Steps Counted", + axes : true, + gridy : gridyValue, + y : 50, //offset on screen + x : 5, //offset on screen + }); + //free memory from big variables + allData = undefined; + allDataFile = undefined; + csvFile = undefined; + times = undefined; +} + +function drawMenu () { + g.clear(); + g.setFont("6x8", 1); + g.drawString("BTN1:Timespan | BTN2:Draw", 20, 10); + g.drawString("Timespan: " + history/1000/60/60 + " hours", 20, 20); +} + +setWatch(function() { //BTN1 + switch(history) { + case 3600000 : //1h + history = 14400000; //4h + break; + case 86400000 : //24 + history = 3600000; //1h + break; + default : + history = history + 14400000; //4h + break; + } + drawMenu(); +}, BTN1, {edge:"rising", debounce:50, repeat:true}); + +setWatch(function() { //BTN2 + g.setFont("6x8", 2); + g.drawString ("Drawing...",30,60); + drawGraph(); +}, BTN2, {edge:"rising", debounce:50, repeat:true}); + +setWatch(function() { //BTN3 +}, BTN3, {edge:"rising", debounce:50, repeat:true}); + +setWatch(function() { //BTN4 +}, BTN4, {edge:"rising", debounce:50, repeat:true}); + +setWatch(function() { //BTN5 +}, BTN5, {edge:"rising", debounce:50, repeat:true}); + +drawMenu(); + +})(); \ No newline at end of file diff --git a/apps/activepedom/widget.js b/apps/activepedom/widget.js index d569716ec..7879b2056 100644 --- a/apps/activepedom/widget.js +++ b/apps/activepedom/widget.js @@ -3,13 +3,14 @@ var startTimeStep = new Date(); //set start time var stopTimeStep = 0; //Time after one step var timerResetActive = 0; //timer to reset active + var timerStoreData = 0; //timer to store data var steps = 0; //steps taken var stepsCounted = 0; //active steps counted var active = 0; //x steps in y seconds achieved var stepGoalPercent = 0; //percentage of step goal var stepGoalBarLength = 0; //length og progress bar var lastUpdate = new Date(); //used to reset counted steps on new day - var width = 45; //width of widget + var width = 46; //width of widget //used for statistics and debugging var stepsTooShort = 0; @@ -18,13 +19,33 @@ var distance = 0; //distance travelled + const s = require('Storage'); const SETTINGS_FILE = 'activepedom.settings.json'; const PEDOMFILE = "activepedom.steps.json"; + var dataFile; + var storeDataInterval = 5*60*1000; //ms let settings; //load settings function loadSettings() { - settings = require('Storage').readJSON(SETTINGS_FILE, 1) || {}; + settings = s.readJSON(SETTINGS_FILE, 1) || {}; + } + + function storeData() { + now = new Date(); + month = now.getMonth() + 1; + if (month < 10) month = "0" + month; + filename = filename = "activepedom-" + now.getFullYear() + month + now.getDate() + ".data"; + dataFile = s.open(filename,"a"); + if (dataFile) dataFile.write([ + now.getTime(), + stepsCounted, + active, + stepsTooShort, + stepsTooLong, + stepsOutsideTime, + ].join(",")+"\n"); + dataFile = undefined; } //return setting @@ -77,20 +98,20 @@ //Remove step if time between first and second step is too long if (stepTimeDiff >= setting('cMaxTime')) { //milliseconds - stepsTooLong++; //count steps which are note counted, because time too long + stepsTooLong++; //count steps which are not counted, because time too long steps--; } - //Remove step if time between first and second step is too short if (stepTimeDiff <= setting('cMinTime')) { //milliseconds - stepsTooShort++; //count steps which are note counted, because time too short + stepsTooShort++; //count steps which are not counted, because time too short steps--; } + //Step threshold reached if (steps >= setting('stepThreshold')) { if (active == 0) { stepsCounted = stepsCounted + (setting('stepThreshold') -1) ; //count steps needed to reach active status, last step is counted anyway, so treshold -1 - stepsOutsideTime = stepsOutsideTime - 10; //substract steps needed to reac active status + stepsOutsideTime = stepsOutsideTime - 10; //substract steps needed to reach active status } active = 1; clearInterval(timerResetActive); //stop timer which resets active @@ -109,14 +130,17 @@ function draw() { var height = 23; //width is deined globally - distance = (stepsCounted * setting('stepLength')) / 100 /1000 //distance in km + distance = (stepsCounted * setting('stepLength')) / 100 /1000; //distance in km //Check if same day let date = new Date(); if (lastUpdate.getDate() == date.getDate()){ //if same day } - else { - stepsCounted = 1; //set stepcount to 1 + else { //different day, set all steps to 0 + stepsCounted = 0; + stepsTooShort = 0; + stepsTooLong = 0; + stepsOutsideTime = 0; } lastUpdate = date; @@ -166,7 +190,7 @@ stepsTooLong : stepsTooLong, stepsOutsideTime : stepsOutsideTime }; - require("Storage").write(PEDOMFILE,d); //write array to file + s.write(PEDOMFILE,d); //write array to file }); //When Step is registered by firmware @@ -182,8 +206,7 @@ }); //Read data from file and set variables - let pedomData = require("Storage").readJSON(PEDOMFILE,1); - + let pedomData = s.readJSON(PEDOMFILE,1); if (pedomData) { if (pedomData.lastUpdate) lastUpdate = new Date(pedomData.lastUpdate); stepsCounted = pedomData.stepsToday|0; @@ -191,12 +214,10 @@ stepsTooLong = pedomData.stepsTooLong; stepsOutsideTime = pedomData.stepsOutsideTime; } - pedomdata = 0; //reset pedomdata to save memory setStepSensitivity(setting('stepSensitivity')); //set step sensitivity (80 is standard, 400 is muss less sensitive) - + timerStoreData = setInterval(storeData, storeDataInterval); //store data regularly //Add widget WIDGETS["activepedom"]={area:"tl",width:width,draw:draw}; - })(); \ No newline at end of file From 35583eb8371551bc055dfd55316c8f2216aedb9e Mon Sep 17 00:00:00 2001 From: Purple-Tentacle <59914607+Purple-Tentacle@users.noreply.github.com> Date: Mon, 20 Apr 2020 17:36:42 +0200 Subject: [PATCH 32/73] activepedom 0.03 --- apps.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps.json b/apps.json index 274a3a8b2..eda9203bc 100644 --- a/apps.json +++ b/apps.json @@ -1127,15 +1127,15 @@ "name": "Active Pedometer", "shortName":"Active Pedometer", "icon": "app.png", - "version":"0.02", - "description": "Pedometer that filters out arm movement and displays a step goal progress.", + "version":"0.03", + "description": "Pedometer that filters out arm movement and displays a step goal progress. Steps are saved to a daily file and can be viewed as graph.", "tags": "outdoors,widget", - "type":"widget", "readme": "README.md", "storage": [ {"name":"activepedom.wid.js","url":"widget.js"}, {"name":"activepedom.settings.js","url":"settings.js"}, - {"name":"activepedom.img","url":"app-icon.js","evaluate":true} + {"name":"activepedom.img","url":"app-icon.js","evaluate":true}, + {"name":"activepedom.app.js","url":"app.js"}, ] }, { "id": "chronowid", From 5d3264e51eb68116677838fc4d3c5e545448b729 Mon Sep 17 00:00:00 2001 From: Purple-Tentacle <59914607+Purple-Tentacle@users.noreply.github.com> Date: Mon, 20 Apr 2020 17:37:45 +0200 Subject: [PATCH 33/73] activepedom 0.03 --- apps.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps.json b/apps.json index eda9203bc..36498423e 100644 --- a/apps.json +++ b/apps.json @@ -1135,7 +1135,7 @@ {"name":"activepedom.wid.js","url":"widget.js"}, {"name":"activepedom.settings.js","url":"settings.js"}, {"name":"activepedom.img","url":"app-icon.js","evaluate":true}, - {"name":"activepedom.app.js","url":"app.js"}, + {"name":"activepedom.app.js","url":"app.js"} ] }, { "id": "chronowid", From 3e9f581b9fb3adcf23421fff4956490f20fdc452 Mon Sep 17 00:00:00 2001 From: Paul Cockrell Date: Mon, 20 Apr 2020 17:09:27 +0100 Subject: [PATCH 34/73] Fix apps.json --- apps.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps.json b/apps.json index bff5fe66b..7a1a3f5fb 100644 --- a/apps.json +++ b/apps.json @@ -1308,7 +1308,7 @@ {"name":"buffgym-set.js","url":"buffgym-set.js"}, {"name":"buffgym-exercise.js","url":"buffgym-exercise.js"}, {"name":"buffgym-program.js","url":"buffgym-program.js"}, - {"name":"buffgym-programs.json","url":"buffgym-program.json"}, + {"name":"buffgym-programs.json","url":"buffgym-programs.json"}, {"name":"buffgym.img","url":"buffgym-icon.js","evaluate":true} ] } From 900805e71b2a670ef5098f87a71525c0b7672c36 Mon Sep 17 00:00:00 2001 From: Paul Cockrell Date: Mon, 20 Apr 2020 17:20:23 +0100 Subject: [PATCH 35/73] Fix apps.json --- apps.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps.json b/apps.json index 7a1a3f5fb..4eeee4e32 100644 --- a/apps.json +++ b/apps.json @@ -1304,7 +1304,7 @@ "type": "app", "storage": [ {"name":"buffgym"}, - {"name":"buffgym.app.js"}, + {"name":"buffgym.app.js", "url": "buffgym.app.js"}, {"name":"buffgym-set.js","url":"buffgym-set.js"}, {"name":"buffgym-exercise.js","url":"buffgym-exercise.js"}, {"name":"buffgym-program.js","url":"buffgym-program.js"}, From fae5b02277014aae97e31109ffd01adc66f04430 Mon Sep 17 00:00:00 2001 From: RenaudG <34276398+renaudgweb@users.noreply.github.com> Date: Mon, 20 Apr 2020 20:39:59 +0200 Subject: [PATCH 36/73] Create osmpoi.html --- apps/osmpoi/osmpoi.html | 228 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 228 insertions(+) create mode 100644 apps/osmpoi/osmpoi.html diff --git a/apps/osmpoi/osmpoi.html b/apps/osmpoi/osmpoi.html new file mode 100644 index 000000000..56a1f8eb6 --- /dev/null +++ b/apps/osmpoi/osmpoi.html @@ -0,0 +1,228 @@ + + + + + + + + +
+
+ +
+ +

Click

+

If ok, Click

+
+ + + + + + + + + From 83253aa5be1e48b6cfabe9fa77d4520e994067f2 Mon Sep 17 00:00:00 2001 From: RenaudG <34276398+renaudgweb@users.noreply.github.com> Date: Mon, 20 Apr 2020 20:40:28 +0200 Subject: [PATCH 37/73] Add files via upload --- apps/osmpoi/app.png | Bin 0 -> 1989 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 apps/osmpoi/app.png diff --git a/apps/osmpoi/app.png b/apps/osmpoi/app.png new file mode 100644 index 0000000000000000000000000000000000000000..31f09b5316318426fe64e8e427541af999cc72ae GIT binary patch literal 1989 zcmV;$2RitPP)<|5#K+5}}kD(!|)9(u%gVg{sw(nl_lqL$MVQDH;j|7FN0}AX{0Khb+6W@0r<| zojY^q-h2AT?8590%RDZWH1V5EGWVSGdwkFDJbvdK_&QOkEyJ_by8*nGm+3wY})8rT{P> zXe?AmAq0ZJI#tug&41xVW858IoL;E0q43XN|EjkB^-WWO$AMP?D__}s2q?f$fG2MI z#=jzaCK2q2C_s3V*$yiJRo&es;M=lqE@xVsS@AofQ_b1=TDN`pq zbu<$f>gpPzT^)KN95%x(7mY|$lYRE!foa0FM*_2f1G#kMBCr^ES@n27l4MC_R;b>R z-bdg0#|&9f)MA`BV$taHcYoCf)Bv488_?1BzXR9~#B%9z<*45PoJl40ETTp{zP{_+ zx$~95V6af<0TfNs00G<$*v068+yr94?jh=QA@ZJUSx{8B8%O}9K)6^va?u`K2S~Eq z1C%+@aZ?G%E>{dFcckMw`BD_zUT+k*#fgqwbKr);TUH*|Bax~>#lwI~uB?zY5b676 zP4=4_f#IV^r+~2;MazJTD9XQ3l!Hi8J(6^k^b%{4USdy?PR$p=O^!fd`~*03Ff#&o zdB6XI1lt6j8t2#JYoi<$~eOw(7ftMt=`)f*hc{^^m zEc^VDYh2{UREj2;570G6`WjI}m9;znk==1^6bgUY&9K z33b}^S=W+FH5?bf5x6pm`+8GkhprD&X`qz!uDO`>3LzwfqbO*8pPO_9zKbMn7`AlT zx#7<|I~!TP)@_L}PoJJlI)}PUzyj)xrlzw)Nx6f;8G(lu#U)jJ5cmxsgzb!gyVS1% z6Og2Jfi=GmdFITWnM=m}@IN17Stf8SlK{Yb$zw;anf=Lu!05okk5nKl-vffCksLB& zc@gmXJb=f)Z24)|l&N_og}rZVZUeSn_9>%ohk5DJ;7uh9Qb|c!>4F7GBq^HGgy)}JNv&g3H%$&@>{W3doCreF=KC)-0lmhcsx~*$Ak5FJYK+a ztu`VakH*%$ycZ#a-PzGfDm4n&*I%DWzy@klr%s;9%evw+jJWP_2zkALB8=44JHocj z@baY}B(}aa%lzd0C;Iknr+~er({La=l{jpC^l@HJ$(lPE4|O|=fF#Qjpxe<%B&*Ui zjnG32>#UX*6ZmO(>5?*i%Nx^y^_k5ErxJUt_O>79WnA-^y`5b}pQQRByIftOt1Cgp zh$~l)mSu&OJW_A9x5a?(0C9xa0#pID1LOzkdtX@A2s;$I&|lE|?ymRD)=Q_d2zWhq zytBjcZmfDd5xb-F%IYVC9e!-dA?xDBDDZ6{-dEE+*!imwFoD16hiXm(#1Gc&PBxtQ zO3$W^n%UNNa)6-EM{hXf_-7Lhzmb^LvfIlP~8$TcU z^DFxkwTGqwv$5?}JsbX7VYXhnd~+t3_+&j4cKp8JtEe#SmSzLMI9z)yS+jo%aDP6| z4@ICJm~Vx{yMR0TzW;&{D|rY2(1qOMdj5g0qxwpyAck3K#|7-jg X&}z;-%?VoU00000NkvXXu0mjfBg)CA literal 0 HcmV?d00001 From 4bdedc08fbb7f12c67094666256953a6c2af5a24 Mon Sep 17 00:00:00 2001 From: RenaudG <34276398+renaudgweb@users.noreply.github.com> Date: Mon, 20 Apr 2020 20:46:00 +0200 Subject: [PATCH 38/73] Update apps.json --- apps.json | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/apps.json b/apps.json index e55190ec0..95669f250 100644 --- a/apps.json +++ b/apps.json @@ -1412,5 +1412,17 @@ {"name":"hamloc.app.js","url":"app.js"}, {"name":"hamloc.img","url":"app-icon.js","evaluate":true} ] + }, + { "id": "osmpoi", + "name": "POI Compass", + "icon": "app.png", + "version":"0.01", + "description": "Uploads all the points of interest in an area onto your watch, same as Beer Compass with more p.o.i.", + "tags": "tool,outdoors,gps", + "custom": "osmpoi.html", + "storage": [ + {"name":"osmpoi.app.js"}, + {"name":"osmpoi.img"} + ] } ] From 95ddcbf4670c1e50376b9c7640221f72dcb698d6 Mon Sep 17 00:00:00 2001 From: RenaudG <34276398+renaudgweb@users.noreply.github.com> Date: Mon, 20 Apr 2020 20:48:07 +0200 Subject: [PATCH 39/73] Create ChangeLog --- apps/osmpoi/ChangeLog | 1 + 1 file changed, 1 insertion(+) create mode 100644 apps/osmpoi/ChangeLog diff --git a/apps/osmpoi/ChangeLog b/apps/osmpoi/ChangeLog new file mode 100644 index 000000000..5560f00bc --- /dev/null +++ b/apps/osmpoi/ChangeLog @@ -0,0 +1 @@ +0.01: New App! From 7d8700a3e91e17bdccbdb940ffa2ec45627e772e Mon Sep 17 00:00:00 2001 From: RenaudG <34276398+renaudgweb@users.noreply.github.com> Date: Mon, 20 Apr 2020 20:50:55 +0200 Subject: [PATCH 40/73] Create README.md --- apps/osmpoi/README.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 apps/osmpoi/README.md diff --git a/apps/osmpoi/README.md b/apps/osmpoi/README.md new file mode 100644 index 000000000..4c59e16f6 --- /dev/null +++ b/apps/osmpoi/README.md @@ -0,0 +1,5 @@ +# Points Of Interest Compass + +## Description + +Uploads all the points of interest in an area onto your watch, same as Beer Compass with more p.o.i. From 707f4a1ccdd4e3f89095529060de429d6d1fa827 Mon Sep 17 00:00:00 2001 From: Paul Cockrell Date: Mon, 20 Apr 2020 21:39:30 +0100 Subject: [PATCH 41/73] More fixes --- apps/buffgym/buffgym-exercise.js | 4 +- apps/buffgym/buffgym-program.js | 2 +- apps/buffgym/buffgym-programs.json | 102 +---- apps/buffgym/buffgym-programs.json.unminified | 101 +++++ apps/buffgym/buffgym-set.js | 2 +- apps/buffgym/buffgym.app.js | 420 +++++++++--------- 6 files changed, 313 insertions(+), 318 deletions(-) create mode 100644 apps/buffgym/buffgym-programs.json.unminified diff --git a/apps/buffgym/buffgym-exercise.js b/apps/buffgym/buffgym-exercise.js index b7a1e3e15..99d658571 100644 --- a/apps/buffgym/buffgym-exercise.js +++ b/apps/buffgym/buffgym-exercise.js @@ -2,10 +2,8 @@ const STARTED = 1; const RESTING = 2; const COMPLETED = 3; const ONE_SECOND = 1000; -const INCREMENT = "increment"; -const DECREMENT = "decrement"; -class Exercise { +exports = class Exercise { constructor(params /*{title, weight, unit, restPeriod}*/) { const DEFAULTS = { title: "Unknown", diff --git a/apps/buffgym/buffgym-program.js b/apps/buffgym/buffgym-program.js index 22f39f10b..956827f56 100644 --- a/apps/buffgym/buffgym-program.js +++ b/apps/buffgym/buffgym-program.js @@ -1,4 +1,4 @@ -class Program { +exports = class Program { constructor(params) { const DEFAULTS = { title: "Unknown", diff --git a/apps/buffgym/buffgym-programs.json b/apps/buffgym/buffgym-programs.json index bf5aa0e0d..7551c7a47 100644 --- a/apps/buffgym/buffgym-programs.json +++ b/apps/buffgym/buffgym-programs.json @@ -1,101 +1 @@ -[ - { - title: "Program A", - exercises: [ - { - title: "Squats", - weight: 40, - unit: "Kg", - sets: [ - 5, - 5, - 5, - 5, - 5 - ] - }, - { - title: "Overhead press", - weight: 20, - unit: "Kg", - sets: [ - 5, - 5, - 5, - 5, - 5 - ] - }, - { - title: "Deadlift", - weight: 20, - unit: "Kg", - sets: [ - 5 - ] - }, - { - title: "Pullups", - weight: 0, - unit: "Kg", - sets: [ - 10, - 10, - 10 - ] - } - ] - }, - { - title: "Program B", - exercises: [ - { - title: "Squats", - weight: 40, - unit: "Kg", - sets: [ - 5, - 5, - 5, - 5, - 5 - ] - }, - { - title: "Bench press", - weight: 20, - unit: "Kg", - sets: [ - 5, - 5, - 5, - 5, - 5 - ] - }, - { - title: "Row", - weight: 20, - unit:"Kg", - sets: [ - 5, - 5, - 5, - 5, - 5 - ] - - }, - { - title: "Tricep extension", - weight: 20, - unit: "Kg", - sets: [ - 10, - 10, - 10 - ] - } - ] - } -] \ No newline at end of file +[{"title":"Program A","exercises":[{"title":"Squats","weight":40,"unit":"Kg","sets":[5,5,5,5,5]},{"title":"Overhead press","weight":20,"unit":"Kg","sets":[5,5,5,5,5]},{"title":"Deadlift","weight":20,"unit":"Kg","sets":[5]},{"title":"Pullups","weight":0,"unit":"Kg","sets":[10,10,10]}]},{"title":"Program B","exercises":[{"title":"Squats","weight":40,"unit":"Kg","sets":[5,5,5,5,5]},{"title":"Bench press","weight":20,"unit":"Kg","sets":[5,5,5,5,5]},{"title":"Row","weight":20,"unit":"Kg","sets":[5,5,5,5,5]},{"title":"Tricep extension","weight":20,"unit":"Kg","sets":[10,10,10]}]}] \ No newline at end of file diff --git a/apps/buffgym/buffgym-programs.json.unminified b/apps/buffgym/buffgym-programs.json.unminified new file mode 100644 index 000000000..cd005eeab --- /dev/null +++ b/apps/buffgym/buffgym-programs.json.unminified @@ -0,0 +1,101 @@ +[ + { + "title": "Program A", + "exercises": [ + { + "title": "Squats", + "weight": 40, + "unit": "Kg", + "sets": [ + 5, + 5, + 5, + 5, + 5 + ] + }, + { + "title": "Overhead press", + "weight": 20, + "unit": "Kg", + "sets": [ + 5, + 5, + 5, + 5, + 5 + ] + }, + { + "title": "Deadlift", + "weight": 20, + "unit": "Kg", + "sets": [ + 5 + ] + }, + { + "title": "Pullups", + "weight": 0, + "unit": "Kg", + "sets": [ + 10, + 10, + 10 + ] + } + ] + }, + { + "title": "Program B", + "exercises": [ + { + "title": "Squats", + "weight": 40, + "unit": "Kg", + "sets": [ + 5, + 5, + 5, + 5, + 5 + ] + }, + { + "title": "Bench press", + "weight": 20, + "unit": "Kg", + "sets": [ + 5, + 5, + 5, + 5, + 5 + ] + }, + { + "title": "Row", + "weight": 20, + "unit":"Kg", + "sets": [ + 5, + 5, + 5, + 5, + 5 + ] + + }, + { + "title": "Tricep extension", + "weight": 20, + "unit": "Kg", + "sets": [ + 10, + 10, + 10 + ] + } + ] + } +] \ No newline at end of file diff --git a/apps/buffgym/buffgym-set.js b/apps/buffgym/buffgym-set.js index d7d610a78..aed6df260 100644 --- a/apps/buffgym/buffgym-set.js +++ b/apps/buffgym/buffgym-set.js @@ -1,4 +1,4 @@ -class Set { +exports = class Set { constructor(maxReps) { this._minReps = 0; this._maxReps = maxReps; diff --git a/apps/buffgym/buffgym.app.js b/apps/buffgym/buffgym.app.js index d3a4e6834..11005900a 100755 --- a/apps/buffgym/buffgym.app.js +++ b/apps/buffgym/buffgym.app.js @@ -1,230 +1,226 @@ -/* global g, setWatch, clearWatch, reset, BTN1, BTN2, BTN3 */ +const W = g.getWidth(); +const H = g.getHeight(); +const RED = "#d32e29"; +const PINK = "#f05a56"; +const WHITE = "#ffffff"; -(() => { - const W = g.getWidth(); - const H = g.getHeight(); - const RED = "#d32e29"; - const PINK = "#f05a56"; - const WHITE = "#ffffff"; +const Set = require("buffgym-set.js"); +const Exercise = require("buffgym-exercise.js"); +const Program = require("buffgym-program.js"); - const Set = require("set.js"); - const Exercise = require("exercise.js"); - const Program = require("program.js"); +function centerStringX(str) { + return (W - g.stringWidth(str)) / 2; +} - function centerStringX(str) { - return (W - g.stringWidth(str)) / 2; +function iconIncrement() { + const img = require("heatshrink").decompress(atob("ikUxH+AA3XAAgNHCJIVMBYXQ5PC4XJ6AUJCIQQBAAoVCCQwjCAA/JCgglHA4IpJBYwTHA4RMJCY5oDJo4THKIQKET5IMGCaY7TMaKLTWajbTFJIlICgoVBFYXJYQYSGCggAGCRAVIBgw")); + return img; +} + +function iconDecrement() { + const img = require("heatshrink").decompress(atob("ikUxH+AA3XAAgNHCJIVMBYXQ5PC4XJ6AUJCIQQBAAoVCCQwjCAA/JCgglKFJADBCRYABCYQmOFAhNMKIw6FTw4LHCaY7TMaKLTWajbTFJglFCgoVBFYXJYQYSGCggAGCRAVIBgw=")); + return img; +} + +function iconOk() { + const img = require("heatshrink").decompress(atob("ikUxH+AA3XAAgNHCJIVMBYXQ5PC4XJ6AUJCIQQBAAoVCCQwjCAA/JCgglKFJADBCJQxCCYQmMIwZoDJpQMCKIg6KBYwTGFQgeHHYouCCRI7EMYTXFRhILEK5SfFRgYSIborbSbpglFCgoVBFYXJYQYSGCggAGCRAVIBgwA==")); + return img; +} + +function drawMenu(params) { + const DEFAULT_PARAMS = { + showBTN1: false, + showBTN2: false, + showBTN3: false, + }; + const p = Object.assign({}, DEFAULT_PARAMS, params); + if (p.showBTN1) g.drawImage(iconIncrement(), W - 30, 10); + if (p.showBTN2) g.drawImage(iconOk(), W - 30, 110); + if (p.showBTN3) g.drawImage(iconDecrement(), W - 30, 210); +} + +function clearScreen() { + g.setColor(RED); + g.fillRect(0,0,W,H); +} + +function drawTitle(exercise) { + const title = exercise.humanTitle; + + g.setFont("Vector",20); + g.setColor(WHITE); + g.drawString(title, centerStringX(title), 5); +} + +function drawReps(exercise) { + const set = exercise.currentSet; + if (set.isCompleted()) return; + + g.setColor(PINK); + g.fillCircle(W / 2, H / 2, 50); + g.setColor(WHITE); + g.setFont("Vector", 40); + g.drawString(set.reps, centerStringX(set.reps), (H - 45) / 2); + g.setFont("Vector", 15); + const note = `of ${set.maxReps}`; + g.drawString(note, centerStringX(note), (H / 2) + 25); +} + +function drawSets(exercise) { + const sets = exercise.subTitle; + + g.setColor(WHITE); + g.setFont("Vector", 15); + g.drawString(sets, centerStringX(sets), H - 25); +} + +function drawSetProgress(exercise) { + drawTitle(exercise); + drawReps(exercise); + drawSets(exercise); + drawMenu({showBTN1: true, showBTN2: true, showBTN3: true}); +} + +function drawStartNextExercise() { + const title = "Good work"; + const msg = "No need to rest\nmove straight on\nto the next exercise"; + + g.setColor(WHITE); + g.setFont("Vector", 35); + g.drawString(title, centerStringX(title), 10); + g.setFont("Vector", 15); + g.drawString(msg, 30, 150); + drawMenu({showBTN1: false, showBTN2: true, showBTN3: false}); +} + +function drawProgramCompleted() { + const title1 = "You did"; + const title2 = "GREAT!"; + const msg = "That's the program\ncompleted. Now eat\nsome food and\nget plenty of rest."; + + clearWatch(); + setWatch(reset, BTN2, {repeat: false}); + + g.setColor(WHITE); + g.setFont("Vector", 35); + g.drawString(title1, centerStringX(title1), 10); + g.setFont("Vector", 40); + g.drawString(title2, centerStringX(title2), 50); + g.setFont("Vector", 15); + g.drawString(msg, 30, 150); + drawMenu({showBTN1: false, showBTN2: true, showBTN3: false}); +} + +/* +function drawExerciseCompleted(program) { + const exercise = program.currentExercise(); + const title = exercise.canProgress? + "WELL DONE!" : + "NOT BAD!"; + const msg = exercise.canProgress? + `You weight is automatically increased\nfor ${exercise.title} to ${exercise.weight}${exercise.unit}` : + "It looks like you struggled\non a few sets, your weight will\nstay the same"; + const action = "Move straight on to the next exercise"; + + clearScreen(); + g.setColor(WHITE); + g.setFont("Vector", 20); + g.drawString(title, centerStringX(title), 10); + g.setFont("Vector", 10); + g.drawString(msg, centerStringX(msg), 180); + g.drawString(action, centerStringX(action), 210); + drawMenu({showBTN2: true}); + + clearWatch(); + setWatch(() => { + init(program); + }, BTN2, {repeat: false}); +} +*/ + +function drawRestTimer(program) { + const exercise = program.currentExercise(); + const motivation = "Take a breather.."; + clearScreen(); + drawMenu({showBTN2: true}); + + g.setColor(PINK); + g.fillCircle(W / 2, H / 2, 50); + g.setColor(WHITE); + g.setFont("Vector", 15); + g.drawString(motivation, centerStringX(motivation), 25); + g.setFont("Vector", 40); + g.drawString(exercise.restPeriod, centerStringX(exercise.restPeriod), (H - 45) / 2); + exercise.decRestPeriod(); + + if (exercise.restPeriod <= 0) { + exercise.resetRestTimer(); + redraw(program); + } +} + +function redraw(program) { + const exercise = program.currentExercise(); + + clearScreen(); + + if (program.isCompleted()) { + drawProgramCompleted(program); + return; } - function iconIncrement() { - const img = require("heatshrink").decompress(atob("ikUxH+AA3XAAgNHCJIVMBYXQ5PC4XJ6AUJCIQQBAAoVCCQwjCAA/JCgglHA4IpJBYwTHA4RMJCY5oDJo4THKIQKET5IMGCaY7TMaKLTWajbTFJIlICgoVBFYXJYQYSGCggAGCRAVIBgw")); - return img; - } - - function iconDecrement() { - const img = require("heatshrink").decompress(atob("ikUxH+AA3XAAgNHCJIVMBYXQ5PC4XJ6AUJCIQQBAAoVCCQwjCAA/JCgglKFJADBCRYABCYQmOFAhNMKIw6FTw4LHCaY7TMaKLTWajbTFJglFCgoVBFYXJYQYSGCggAGCRAVIBgw=")); - return img; - } - - function iconOk() { - const img = require("heatshrink").decompress(atob("ikUxH+AA3XAAgNHCJIVMBYXQ5PC4XJ6AUJCIQQBAAoVCCQwjCAA/JCgglKFJADBCJQxCCYQmMIwZoDJpQMCKIg6KBYwTGFQgeHHYouCCRI7EMYTXFRhILEK5SfFRgYSIborbSbpglFCgoVBFYXJYQYSGCggAGCRAVIBgwA==")); - return img; - } - - function drawMenu(params) { - const DEFAULT_PARAMS = { - showBTN1: false, - showBTN2: false, - showBTN3: false, - }; - const p = Object.assign({}, DEFAULT_PARAMS, params); - if (p.showBTN1) g.drawImage(iconIncrement(), W - 30, 10); - if (p.showBTN2) g.drawImage(iconOk(), W - 30, 110); - if (p.showBTN3) g.drawImage(iconDecrement(), W - 30, 210); - } - - function clearScreen() { - g.setColor(RED); - g.fillRect(0,0,W,H); - } - - function drawTitle(exercise) { - const title = exercise.humanTitle; - - g.setFont("Vector",20); - g.setColor(WHITE); - g.drawString(title, centerStringX(title), 5); - } - - function drawReps(exercise) { - const set = exercise.currentSet; - if (set.isCompleted()) return; - - g.setColor(PINK); - g.fillCircle(W / 2, H / 2, 50); - g.setColor(WHITE); - g.setFont("Vector", 40); - g.drawString(set.reps, centerStringX(set.reps), (H - 45) / 2); - g.setFont("Vector", 15); - const note = `of ${set.maxReps}`; - g.drawString(note, centerStringX(note), (H / 2) + 25); - } - - function drawSets(exercise) { - const sets = exercise.subTitle; - - g.setColor(WHITE); - g.setFont("Vector", 15); - g.drawString(sets, centerStringX(sets), H - 25); - } - - function drawSetProgress(exercise) { - drawTitle(exercise); - drawReps(exercise); - drawSets(exercise); - drawMenu({showBTN1: true, showBTN2: true, showBTN3: true}); - } - - function drawStartNextExercise() { - const title = "Good work"; - const msg = "No need to rest\nmove straight on\nto the next exercise"; - - g.setColor(WHITE); - g.setFont("Vector", 35); - g.drawString(title, centerStringX(title), 10); - g.setFont("Vector", 15); - g.drawString(msg, 30, 150); - drawMenu({showBTN1: false, showBTN2: true, showBTN3: false}); - } - - function drawProgramCompleted() { - const title1 = "You did"; - const title2 = "GREAT!"; - const msg = "That's the program\ncompleted. Now eat\nsome food and\nget plenty of rest."; - - clearWatch(); - setWatch(reset, BTN2, {repeat: false}); - - g.setColor(WHITE); - g.setFont("Vector", 35); - g.drawString(title1, centerStringX(title1), 10); - g.setFont("Vector", 40); - g.drawString(title2, centerStringX(title2), 50); - g.setFont("Vector", 15); - g.drawString(msg, 30, 150); - drawMenu({showBTN1: false, showBTN2: true, showBTN3: false}); - } - - /* - function drawExerciseCompleted(program) { - const exercise = program.currentExercise(); - const title = exercise.canProgress? - "WELL DONE!" : - "NOT BAD!"; - const msg = exercise.canProgress? - `You weight is automatically increased\nfor ${exercise.title} to ${exercise.weight}${exercise.unit}` : - "It looks like you struggled\non a few sets, your weight will\nstay the same"; - const action = "Move straight on to the next exercise"; - - clearScreen(); - g.setColor(WHITE); - g.setFont("Vector", 20); - g.drawString(title, centerStringX(title), 10); - g.setFont("Vector", 10); - g.drawString(msg, centerStringX(msg), 180); - g.drawString(action, centerStringX(action), 210); - drawMenu({showBTN2: true}); - - clearWatch(); - setWatch(() => { - init(program); - }, BTN2, {repeat: false}); - } - */ - - function drawRestTimer(program) { - const exercise = program.currentExercise(); - const motivation = "Take a breather.."; - clearScreen(); - drawMenu({showBTN2: true}); - - g.setColor(PINK); - g.fillCircle(W / 2, H / 2, 50); - g.setColor(WHITE); - g.setFont("Vector", 15); - g.drawString(motivation, centerStringX(motivation), 25); - g.setFont("Vector", 40); - g.drawString(exercise.restPeriod, centerStringX(exercise.restPeriod), (H - 45) / 2); - exercise.decRestPeriod(); - - if (exercise.restPeriod <= 0) { - exercise.resetRestTimer(); - redraw(program); - } - } - - function redraw(program) { - const exercise = program.currentExercise(); - - clearScreen(); - - if (program.isCompleted()) { - drawProgramCompleted(program); - return; + if (exercise.isRestTimerRunning()) { + if (exercise.isLastSet()) { + drawStartNextExercise(program); + } else { + drawRestTimer(program); } - if (exercise.isRestTimerRunning()) { - if (exercise.isLastSet()) { - drawStartNextExercise(program); - } else { - drawRestTimer(program); - } - - return; - } - - drawSetProgress(exercise); + return; } - function init(program) { - clearWatch(); - program.next(); - } + drawSetProgress(exercise); +} - // Setup training program. This should come from file +function init(program) { + clearWatch(); + program.next(); +} - // Squats - function buildPrograms() { - const programsJSON = require("Storage").readJSON("buffgym-programs.json", 1); +// Setup training program. This should come from file - if (!programsJSON) throw "No programs JSON found"; +// Squats +function buildPrograms() { + const programsJSON = require("Storage").readJSON("buffgym-programs.json", 1); - const programs = []; + if (!programsJSON) throw "No programs JSON found"; - programsJSON.forEach(programJSON => { - const program = new Program({ - title: programJSON.title, - }); - const exercises = programJSON.exercises.map(exerciseJSON => { - const exercise = new Exercise({ - title: exerciseJSON.title, - weight: exerciseJSON.weight, - unit: exerciseJSON.unit, - }); - exerciseJSON.sets.forEach(setJSON => { - exercise.addSet(new Set(setJSON)); - }); + const programs = []; - return exercise; - }); - program.addExercises(exercises); - programs.push(program); + programsJSON.forEach(programJSON => { + const program = new Program({ + title: programJSON.title, }); + const exercises = programJSON.exercises.map(exerciseJSON => { + const exercise = new Exercise({ + title: exerciseJSON.title, + weight: exerciseJSON.weight, + unit: exerciseJSON.unit, + }); + exerciseJSON.sets.forEach(setJSON => { + exercise.addSet(new Set(setJSON)); + }); - return programs; - } + return exercise; + }); + program.addExercises(exercises); + programs.push(program); + }); - // For this spike, just run the first program, what will - // really happen is the user picks a program to do from - // some menu on a start page. - init(buildPrograms()[0]); -})(); \ No newline at end of file + return programs; +} + +// For this spike, just run the first program, what will +// really happen is the user picks a program to do from +// some menu on a start page. +init(buildPrograms()[0]); \ No newline at end of file From 6deb376d99b4dab29c9ec31bd78432e08b08510e Mon Sep 17 00:00:00 2001 From: Paul Cockrell Date: Mon, 20 Apr 2020 22:02:55 +0100 Subject: [PATCH 42/73] Return to launcher on exit --- apps/buffgym/buffgym.app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/buffgym/buffgym.app.js b/apps/buffgym/buffgym.app.js index 11005900a..e1ab3e66b 100755 --- a/apps/buffgym/buffgym.app.js +++ b/apps/buffgym/buffgym.app.js @@ -99,7 +99,7 @@ function drawProgramCompleted() { const msg = "That's the program\ncompleted. Now eat\nsome food and\nget plenty of rest."; clearWatch(); - setWatch(reset, BTN2, {repeat: false}); + setWatch(Bangle.showLauncher, BTN2, {repeat: false}); g.setColor(WHITE); g.setFont("Vector", 35); From 15a92c1b38006dfd908c91e69b060ca457d35e9b Mon Sep 17 00:00:00 2001 From: singintime Date: Tue, 21 Apr 2020 01:10:10 +0200 Subject: [PATCH 43/73] Minion clock v0.02 --- apps.json | 2 +- apps/minionclk/ChangeLog | 1 + apps/minionclk/app.js | 10 +++++----- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/apps.json b/apps.json index b58fad5ce..924d2e75c 100644 --- a/apps.json +++ b/apps.json @@ -1126,7 +1126,7 @@ { "id": "minionclk", "name": "Minion clock", "icon": "minionclk.png", - "version": "0.01", + "version": "0.02", "description": "Minion themed clock.", "tags": "clock,minion", "type": "clock", diff --git a/apps/minionclk/ChangeLog b/apps/minionclk/ChangeLog index 7b83706bf..dbe920a80 100755 --- a/apps/minionclk/ChangeLog +++ b/apps/minionclk/ChangeLog @@ -1 +1,2 @@ 0.01: First release +0.02: Improved date readability, fixed drawing of widgets diff --git a/apps/minionclk/app.js b/apps/minionclk/app.js index 88fe446ae..7f00cd362 100755 --- a/apps/minionclk/app.js +++ b/apps/minionclk/app.js @@ -1,4 +1,4 @@ -const bob = require("heatshrink").decompress(atob("nk8hAaXlYLWAEsqvN/0gBBql5lQ2tquj1XV5wBJ52j0hACPsdP1QsBAQQAGBIIBF51/P8OkN5R1GIxF5HLmAFgoDLPZfOpzmZ6vPFwomCPaA6DAYOjeq2A1YyCdI4HGQJQ8F1T2SJ4Oq1XW1es1mtAQOrPoPUAIh3J54ZHIAR5S62s64cBwIBGQIOqHQK4HKQYVDAAIFC1g+BHh9VHAQAFDwQDDHoJ5E54BB6AaBKQ5YGqo6MwJzGHQ4BDeIj/BR4JxDABY8BvI6OOYgaEHwZADHgQ6BZA42GAIusPJNW64eFqzJDlcrERA8BHQI2FqwaBDYYGBPI45GCoIgCLoVWQ5NWXA2rKhaiGLAwOGEAmADxJPDVA51ElQaMC4ouEWALdEHRg8Dc4woCDJo8EAIYxCHQQIFHiwaRegJ5EcYWsHgbrKbBA8GDSrNDO4wfRKgR3FDSh3CN4UrdwZbSHYZ5DHajMFHYQGCHalWO4jtQDQwABwAGCAAQfTKoK0EHahwCeARdFHakASIZWVZ4Q8CO4YgWO4QbCO6hWGEIKYZKzZ3DLog7UG4I6C1lWDSdWO4bpCO4bwUwKYEHajMDwOAlUkLojTUd4gaTZoRWC0YIB1eJLqo4EWiqRE0mjlcr1QkEeKFWOooBCHiB2CC4WA5wzB52rEQgfPHQwABAYJXOHQ2iO4XO6omFEJh1BEAgBGPJlWDIQbC0ej50qgHV1XPEwohKcwRbEvJ3EBQTrLFomkOwOjlR3C5w8GMAR8ClYuBLIgOCvN4HgIZFDQYbBlaOBR4YNCwA5B0XOpzvBHgWqTw4AFxB1EvQ6BAAI8GDZILEdgQBCqp3DPIRfIEQwABvJ1CvGkvGiwA6IAYoBCv6wCAAVOlQ6DAIWkL5ABEwN40Z1CAYJfCv7zEAJNWOYZ3KAIWq5yYHFYLOBLIrVCAIh7BOIzpECoYDDpw7BHAQDG1WqwGkAIN/CwIABLY4LDAAZ9BwAABvLCBC5IBBvOrO44BEAAmjAIPN0XOAJyHIAAgPEquBHBi4BAId+HwWiHxqJDRpYBDq2I1R3LIAQ6BAAOpPogABGgIDDOomk0nP5pIGd42Aq1ewI8CeZI6CHAJhCEAIDCdIo2B0er1esAQIZBC4Z9JlVW1leeKGp0es5+s6+s6ABB0oFBAIervWr0ulub7OqtWmdexJ4BGxB5G0V6pF6wItB0t6p9PvQABvINBudJudPzwXCHQwBDlY6BO4WIwPPPJbvDvA0BFgNzAAIDGugGCzrtHdYh1DAIOBrzxBPIgAIeIXNHgoBCGwYADzoVB0fNOpMyHQdW5+Bro7BHgQAB6jxJAAOjOYhxCAIukOoPN5ujdZFWqyyD0d6AwUrquBwAuB1I1FHgRJBMoQ9BWg1zzw0BDYI6B0R3DAAJ1BvMyp8rAAV4IQWBIodewAeCHAZ5IAAJoBAAXHHAJWDO4TtEdYQvEHgejAwIKClcqIQRdDXYbzFeoQBIGwIDDOot/VgQ6FAAIGBlgBCAAMzmZPBF4LzDACB1FAAOi1WjvFVr0zGYQ7GAAMAAYpPBwNeAIOIwOrfYOA1eA1WkAIWjAIekv4PBwCVBruBq5eBEYIABlcBF4wCEHw55CHwQABIQQBBABkzAILlCHQR1CFYavEPgsAAAIDEDQNdAwQAaHQNWEwQ0DHAh3KleBLoI7dHQKuFWQo0EAIsISoKdBHbyyHNgwADlVVpwEBDANWro7fd4Q6HO495vF5QgIYCd75eBHYUINAN5lQ3EA")); +const bob = require("heatshrink").decompress(atob("nk8hAaXlYLWAEsqvN/0gBBql5lQ2tquj1XV5wBJ52j0hACPsdP1QsBAQQAGBIIBF51/P8OkN5R1GIxF5HLmAFgoDLPZfOpzmZ6vPFwomCPaA6DAYOjeq2A1YyCdI4HGQJQ8F1T2SJ4Oq1XW1es1mtAQOrPoPUAIh3J54ZHIAR5S62s64cBwIBGQIOqHQK4HKQYVDAAIFC1g+BHh9VHAQAFDwQDDHoJ5E54BB6AaBKQ5YGqo6MwJzGHQ4BDeIj/BR4JxDABY8BvI6OOYgaEHwZADHgQ6BZA42GAIusPJNW64eFqzJDlcrERA8BHQI2FqwaBDYYGBPI45GCoIgCLoVWQ5NWXA2rKhaiGLAwOGEAmADxJPDVA51ElQaMC4ouEWALdEHRg8Dc4woCDJo8EAIYxCHQQIFHiwaRegJ5EcYWsHgbrKbBA8GDSrNDO4wfRKgR3FDSh3CN4UrdwZbSHYZ5DHajMFHYQGCHalWO4jtQDQwABwAGCAAQfTKoK0EHahwCeARdFHakASIZWVZ4Q8CO4YgWO4QbCO6hWGEIKYZKzZ3DLog7UG4I6C1lWDSdWO4bpCO4bwUwKYEHajMDwOAlUkLojTUd4gaTZoRWC0YIB1eJLqo4EWiqRE0mjlcr1QkEeKFWOooBCHiB2CC4WA5wzB52rEQgfPHQwABAYJXOHQ2iO4XO6omFEJh1BEAgBGPJlWDIQbC0ej50qgHV1XPEwohKcwRbEvJ3EBQTrLFomkOwOjlR3C5w8GMAR8ClYuBLIgOCvN4HgIZFDQYbBlaOBR4YNCwA5B0XOpzvBHgWqTw4AFxB1EvQ6BAAI8GDZILEdgQBCqp3DPIRfIEQwABvJ1CvGkvGiwA6IAYoBCv6wCAAVOlQ6DAIWkL5ABEwN40Z1CAYJfCv7zEAJNWOYZ3KAIWq5yYHFYLOBLIrVCAIh7BOIzpECoYDDpw7BHAQDG1WqwGkAIN/CwIABLY4LDAAZ9BwAABvLCBC5IBBvOrO44BEAAmjAIPN0XOAJyHIAAgPEquBHBi4BAId+HwWiHxqJDRpYBDq2I1R3LIAQ6BAAOpPogABGgIDDOomk0nP5pIGd42Aq1ewI8CeZI6CHAJhCEAIDCdIo2B0er1esAQIZBC4Z9JlVW1leeKGp0es5+s6+s6ABB0oFBAIervWr0ultr7OqtWmdexJ4BGxB5G0V6pF6wItB0t6p9PvQABvINBttJttPzwXCHQwBDlY6BO4WIwPPPJbvDvA0BFgNtAAIDGtwGCzrtHdYh1DAIOBrzxBPIgAIeIXNHgoBCGwYADzoVB0fNOpMOHQdW5+Bro7BHgQAB6jxJAAOjOYhxCAIukOoPN5ujdZFWqyyD0d6AwUrquBwAuB1I1FHgRJBMoQ9BWg1tzw0BDYI6B0R3DAAJ1BvMOp8rAAV4IQWBIodewAeCHAZ5IAAJoBAAXHHAJWDO4TtEdYQvEHgejAwIKClcqIQRdDXYbzFeoQBIGwIDDOot/VgQ6FAAIGBlgBCAAMzmZPBF4LzDACB1FAAOi1WjvFVr0zGYQ7GAAMAAYpPBwNeAIOIwOrfYOA1eA1WkAIWjAIekv4PBwCVBruBq5eBEYIABlcBF4wCEHw8zgAAiFYivEPgoSEAYo9jGgY4EO5Q7kVwiyFGggBFhASBHkhsKAAcqqtOAgMzd8o6HO495vF5QgMzrw7lhBoBvMqG4g")); const locale = require("locale"); @@ -37,7 +37,7 @@ function draw() { } if (newDate !== date) { - g.setFontVector(12); + g.setFont('6x8', 2); g.setColor(black); g.drawString(date, 120, 228); g.setColor(0xFFFF); @@ -51,6 +51,8 @@ function drawAll() { minute = ''; date = ''; g.drawImage(bob, 0, 0, { scale: 4 }); + Bangle.loadWidgets(); + Bangle.drawWidgets(); draw(); } @@ -60,9 +62,7 @@ Bangle.on('lcdPower', function(on) { } }); -Bangle.loadWidgets(); -Bangle.drawWidgets(); setInterval(draw, 1000); drawAll(); -setWatch(Bangle.showLauncher, BTN2, {repeat:false,edge:"falling"}); +setWatch(Bangle.showLauncher, BTN2, { repeat: false, edge: 'falling' }); From bc4a05e314c1efd71d66a44788ee04ac81bb9cc8 Mon Sep 17 00:00:00 2001 From: singintime Date: Tue, 21 Apr 2020 10:43:54 +0200 Subject: [PATCH 44/73] Addressing review comments --- apps/minionclk/app.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/apps/minionclk/app.js b/apps/minionclk/app.js index 7f00cd362..0f92b28bc 100755 --- a/apps/minionclk/app.js +++ b/apps/minionclk/app.js @@ -9,6 +9,8 @@ let hour; let minute; let date; +let timer; + function draw() { const d = new Date(); @@ -51,7 +53,6 @@ function drawAll() { minute = ''; date = ''; g.drawImage(bob, 0, 0, { scale: 4 }); - Bangle.loadWidgets(); Bangle.drawWidgets(); draw(); } @@ -59,10 +60,13 @@ function drawAll() { Bangle.on('lcdPower', function(on) { if (on) { drawAll(); + timer = setInterval(draw, 1000); + } else if (timer) { + clearInterval(timer); } }); -setInterval(draw, 1000); +Bangle.loadWidgets(); drawAll(); setWatch(Bangle.showLauncher, BTN2, { repeat: false, edge: 'falling' }); From a8cf48c794706420404136190fbdfede3e6080b4 Mon Sep 17 00:00:00 2001 From: singintime Date: Tue, 21 Apr 2020 11:52:36 +0200 Subject: [PATCH 45/73] Addressing review comments 2 --- apps/minionclk/app.js | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/apps/minionclk/app.js b/apps/minionclk/app.js index 0f92b28bc..0725f8fa6 100755 --- a/apps/minionclk/app.js +++ b/apps/minionclk/app.js @@ -48,25 +48,30 @@ function draw() { } } -function drawAll() { +function startDrawing() { hour = ''; minute = ''; date = ''; g.drawImage(bob, 0, 0, { scale: 4 }); Bangle.drawWidgets(); draw(); + setInterval(draw, 1000); +} + +function stopDrawing() { + if (timer) { + clearInterval(timer); + } } Bangle.on('lcdPower', function(on) { + stopDrawing(); if (on) { - drawAll(); - timer = setInterval(draw, 1000); - } else if (timer) { - clearInterval(timer); + startDrawing(); } }); Bangle.loadWidgets(); -drawAll(); +startDrawing(); setWatch(Bangle.showLauncher, BTN2, { repeat: false, edge: 'falling' }); From 7735a2ba97d6156c79450869a7f716d52cd9cffb Mon Sep 17 00:00:00 2001 From: fredericrous Date: Tue, 21 Apr 2020 11:18:29 +0100 Subject: [PATCH 46/73] =?UTF-8?q?New=20game:=20Pong=F0=9F=95=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps.json | 14 +++ apps/pong/ChangeLog | 1 + apps/pong/app-icon.js | 1 + apps/pong/app.js | 282 ++++++++++++++++++++++++++++++++++++++++++ apps/pong/pong.png | Bin 0 -> 894 bytes 5 files changed, 298 insertions(+) create mode 100644 apps/pong/ChangeLog create mode 100644 apps/pong/app-icon.js create mode 100644 apps/pong/app.js create mode 100644 apps/pong/pong.png diff --git a/apps.json b/apps.json index 95669f250..9b381e6f4 100644 --- a/apps.json +++ b/apps.json @@ -1424,5 +1424,19 @@ {"name":"osmpoi.app.js"}, {"name":"osmpoi.img"} ] + }, + { "id": "pong", + "name": "Pong", + "shortName": "Pong", + "icon": "pong.png", + "version": "0.01", + "description": "A clone of the Atari game Pong", + "tags": "game", + "type": "app", + "allow_emulator": true, + "storage": [ + {"name":"pong.app.js","url":"app.js"}, + {"name":"pong.img","url":"app-icon.js","evaluate":true} + ] } ] diff --git a/apps/pong/ChangeLog b/apps/pong/ChangeLog new file mode 100644 index 000000000..5560f00bc --- /dev/null +++ b/apps/pong/ChangeLog @@ -0,0 +1 @@ +0.01: New App! diff --git a/apps/pong/app-icon.js b/apps/pong/app-icon.js new file mode 100644 index 000000000..881e60ba9 --- /dev/null +++ b/apps/pong/app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwgIEBgOABQYFD8AUEApoXFDqIXV4BYGKZIANsIRE+IFE/IFEvCIFGrgXLDqIAOgc/9/2hv+g8///3AoUwvE3xuABYP4m3NzwFB7E2tu/CIMYm09wYFDjoFCj4pB/8HkEP+EBFII7EAosDJxYA=")) diff --git a/apps/pong/app.js b/apps/pong/app.js new file mode 100644 index 000000000..4531b3af8 --- /dev/null +++ b/apps/pong/app.js @@ -0,0 +1,282 @@ +/** + * BangleJS Pong game + * + * Original Author: Frederic Rousseau https://github.com/fredericrous + * Created: April 2020 + * + * Inspired by: + * - Let's make pong, One Man Army Studios, Youtube + * - Pong.js, KanoComputing, Github + * - Coding Challenge #67: Pong!, The Coding Train, Youtube + */ + +const SCREEN_WIDTH = 240; +const FPS = 16; +const MAX_SCORE = 11; +let scores = [0, 0]; +let aiSpeedRandom = 0; + +function Vector(x, y) { + this.x = x; + this.y = y; +} +Vector.prototype.add = function (x) { + this.x += x.x || 0; + this.y += x.y || 0; + return this; +}; + +const constrain = (n, low, high) => Math.max(Math.min(n, high), low); +const random = (min, max) => Math.random() * (max - min) + min; +const intersects = (circ, rect) => { + var c1 = circ.pos, c2 = {x: circ.pos.x+circ.r, y: circ.pos.y+circ.r}; + var r1 = rect.pos, r2 = {x: rect.pos.x+rect.width*2, y: rect.pos.y+rect.height}; + return !(c1.x > r2.x || c2.x < r1.x || + c1.y > r2.y || c2.y < r1.y); +}; + +///////////////////////////// Ball ////////////////////////////////////////// + +function Ball() { + this.r = 4; + this.prevPos = null; + this.originalSpeed = 4; + this.maxSpeed = 6; + + this.reset(); +} +Ball.prototype.show = function () { + if (this.prevPos != null) { + g.setColor(0); + g.fillCircle(this.prevPos.x, this.prevPos.y, this.prevPos.r); + } + g.setColor(-1); + g.fillCircle(this.pos.x, this.pos.y, this.r); + this.prevPos = { + x: this.pos.x, + y: this.pos.y, + r: this.r + }; +}; +Ball.prototype.bouncePlayer = function (multiplyX, multiplyY, player) { + this.speed = constrain(this.speed + 2, this.originalSpeed, this.maxSpeed); + var relativeIntersectY = (player.pos.y+(player.height/2)) - this.pos.y; + var normalizedRelativeIntersectionY = (relativeIntersectY/(player.height/2)); + var MAX_BOUNCE_ANGLE = 4 * Math.PI/12; + var bounceAngle = normalizedRelativeIntersectionY * MAX_BOUNCE_ANGLE; + this.velocity.x = this.speed * Math.cos(bounceAngle) * multiplyX; + this.velocity.y = this.speed * -Math.sin(bounceAngle) * multiplyY; +}; +Ball.prototype.bounce = function (multiplyX, multiplyY, player) { + if (player) + return this.bouncePlayer(multiplyX, multiplyY, player); + + if (multiplyX) { + this.velocity.x = Math.abs(this.velocity.x) * multiplyX; + } + if (multiplyY) { + this.velocity.y = Math.abs(this.velocity.y) * multiplyY; + } +}; +Ball.prototype.checkWallsCollision = function () { + if (this.pos.y < 0) { + this.bounce(0, 1); + } else if (this.pos.y > SCREEN_WIDTH) { + this.bounce(0, -1); + } else if (this.pos.x < 0) { + scores[1]++; + if (scores[1] >= MAX_SCORE) { + this.restart(); + state = 3; + winnerMessage = "AI Wins!"; + } else { + this.reset(); + } + } else if (this.pos.x > SCREEN_WIDTH) { + scores[0]++; + if (scores[0] >= MAX_SCORE) { + this.restart(); + state = 3; + winnerMessage = "You Win!"; + } else { + this.reset(); + } + } else { + return false; + } + return true; +}; +Ball.prototype.checkPlayerCollision = function (player) { + if (intersects(this, player)) { + if (this.pos.x < SCREEN_WIDTH/2) { + this.bounce(1, 1, player); + this.pos.add(new Vector(this.width, 0)); + aiSpeedRandom = random(-1.6, 1.6); + } else { + this.bounce(-1, 1, player); + this.pos.add(new Vector(-(this.width / 2 + 1), 0)); + } + return true; + } + return false; +}; +Ball.prototype.checkCollisions = function () { + return this.checkWallsCollision() || this.checkPlayerCollision(player) || this.checkPlayerCollision(ai); +}; +Ball.prototype.updatePosition = function () { + var elapsed = new Date().getTime() - this.lastUpdate; + var x = (elapsed / 50) * this.velocity.x; + var y = (elapsed / 50) * this.velocity.y; + this.pos.add(new Vector(x, y)); +}; +Ball.prototype.update = function () { + this.updatePosition(); + this.lastUpdate = new Date().getTime(); + this.checkCollisions(); +}; +Ball.prototype.reset = function() { + this.speed = this.originalSpeed; + var x = scores[0] < scores[1] || (scores[0] === 0 && scores[1] === 0) ? -this.speed : this.speed; + var bounceAngle = Math.PI/6; + this.velocity = new Vector(x * Math.cos(bounceAngle), this.speed * -Math.sin(bounceAngle)); + this.pos = new Vector(SCREEN_WIDTH/2, random(0, SCREEN_WIDTH)); +}; +Ball.prototype.restart = function() { + ai.pos = new Vector(SCREEN_WIDTH - ai.width*2, SCREEN_WIDTH/2 - ai.height/2); + player.pos = new Vector(player.width*2, SCREEN_WIDTH/2 - player.height/2); + this.pos = new Vector(SCREEN_WIDTH/2, SCREEN_WIDTH/2); +}; + +//////////////////////////// Player ///////////////////////////////////////// + +function Player() { + this.width = 4; + this.height = 30; + this.pos = new Vector(this.width*2, SCREEN_WIDTH/2 - this.height/2); + this.acc = new Vector(0, 0); + this.speed = 15; + this.maxSpeed = 25; + this.prevPos = null; +} +Player.prototype.show = function () { + if (this.prevPos != null) { + g.setColor(0); + g.fillRect(this.prevPos.x1, this.prevPos.y1, this.prevPos.x2, this.prevPos.y2); + } + g.setColor(-1); + g.fillRect(this.pos.x, this.pos.y, this.pos.x+this.width, this.pos.y+this.height); + this.prevPos = { + x1: this.pos.x, + y1: this.pos.y, + x2: this.pos.x+this.width, + y2: this.pos.y+this.height + }; +}; +Player.prototype.up = function () { + this.acc.y -= this.speed; +}; +Player.prototype.down = function () { + this.acc.y += this.speed; +}; +Player.prototype.stop = function () { + this.acc.y = 0; +}; +Player.prototype.update = function () { + this.acc.y = constrain(this.acc.y, -this.maxSpeed, this.maxSpeed); + this.pos.add(this.acc); + this.pos.y = constrain(this.pos.y, 0, SCREEN_WIDTH-this.height); +}; + +////////////////////////////// AI /////////////////////////////////////////// + +function AI() { + Player.call(this); + this.pos = new Vector(SCREEN_WIDTH-this.width*2, SCREEN_WIDTH/2 - this.height/2); +} +AI.prototype = Object.create(Player.prototype); +AI.prototype.constructor = Player; +AI.prototype.update = function () { + var y = ball.pos.y - (this.height/2 * aiSpeedRandom); + var yConstrained = constrain(y, 0, SCREEN_WIDTH-this.height); + this.pos = new Vector(this.pos.x, yConstrained); +}; + +function net() { + var dashSize = 5; + for (let y = dashSize/2; y < SCREEN_WIDTH; y += dashSize*2) { + g.setColor(-1); + let halfScreen = SCREEN_WIDTH/2; + g.fillRect(halfScreen-dashSize/2, y, halfScreen+dashSize/2, y+dashSize); + } +} + +var player = new Player(); +var ai = new AI(); +var ball = new Ball(); +var state = 0; +var prevScores = [0, 0]; + +function drawScores() { + let x1 = SCREEN_WIDTH/4-5; + let x2 = SCREEN_WIDTH*3/4-5; + + g.setColor(0); + g.setFont('Vector', 20); + g.drawString(prevScores[0], x1, 7); + g.drawString(prevScores[1], x2, 7); + g.setColor(-1); + g.setFont('Vector', 20); + g.drawString(scores[0], x1, 7); + g.drawString(scores[1], x2, 7); + prevScores = scores.slice(); +} + +function drawGameOver() { + g.setFont("Vector", 20); + g.drawString(winnerMessage, 75, SCREEN_WIDTH/2 - 10); +} + +function draw() { + if (state === 1) { + ball.update(); + player.update(); + ai.update(); + ball.show(); + player.show(); + ai.show(); + net(); + ball.show(); + } else if (state === 3) { + g.clear(); + g.setColor(0); + g.fillRect(0,0,240,240); + state++; + } else if (state === 4) { + drawGameOver(); + } else { + player.show(); + ai.show(); + net(); + } + drawScores(); +} + +g.clear(); +g.setColor(0); +g.fillRect(0,0,240,240); + +setInterval(draw, 1000 / FPS); + +setWatch(o => o.state ? player.up() : player.stop(), BTN1, {repeat: true, edge: 'both'}); +setWatch(o => o.state ? player.down() : player.stop(), BTN3, {repeat: true, edge: 'both'}); +//setWatch(o => o.state ? player.down() : player.stop(), BTN5, {repeat: true, edge: 'both'}); +setWatch(o => { + state++; + if (state >= 2) { + ball.restart(); + g.setColor(0); + g.fillRect(0,0,240,240); + scores = [0, 0]; + state = 1; + } +}, BTN2, {repeat: true}); diff --git a/apps/pong/pong.png b/apps/pong/pong.png new file mode 100644 index 0000000000000000000000000000000000000000..cc97f58f7826efaf0e2fafa1b7322a4d17d86f2c GIT binary patch literal 894 zcmV-^1A+XBP)fQkj&A4+ z8^a&FIPdd5`=9@LKc4dekPw)j2~5u*kvfUS5ju7aCH~Xa(S0~!hr{V`I8pjKq9KH! znX*PhOQWF$i4+<`YPCwORw0qfyG4B(iOThBSCQ!C@wPuAgMA0;}Q^Gn(3nfI?o>1%Xt0A&)LYqt!7?yz6xjKWMe}S#5neaHCKt872;E z#Khzj7th(EcDr2*!9@VT-|cOJIRCcy9gMG1^eROoF?1NlyZQ zrf1JvxtK<)(`a>h;tdpdVLXLIg^9C%zyJI45)!pS1Yu!B^MH0yMk3KcW+<0c@t9*$ zI02g^DI*AJdbi89^M0dL3V%p&xtt^^0|3x8#g7XH_oLC!0zXtF-^WQ(_B$3!2w^l? zYU}C+yAp|nQmGpF@Nqp9PB|A0lB8@s6c+r|*41;#Z5`cE4K{bSJwZstIR2)`8jVD_ zJQ0RHe)JFkfMG=dfYujne^{35JtL7kxPK2Gi^cfFl>g?9@)TPHAuTH{ne+uVH-FO9 zp3z!f+V>`ttV7XAq`9eqYbup0Xb3Xqal`3@7)=)LI2L18R#w+TVTD|tK26?nFJCqz zNkbL4Dn!^zI1C~TlSm}lt9ZvgVHjpKTSiBQ?e_lk1fA~grOQ{iX29>`Uml;Nq2jZW z;;Kr1Unso6vT-Og zb*`**@!Jy1vPDH$N@BC2!Dj7+$DLiB2k2ybFT-)1zxhR2>M0?bJJoKFr>wLj6yD&+ zX`0Hi3S?_&U?8if3!0`Ba=FoL;fji0U!&L8@N>jsJcFUNwIBAup@82fm=W;%Oy;M8 zT`rds$MLz@Jx|j#O^uEW&&|$2S;0Sk_Ks(|wA>+37<0?7t*z;=v-vw<`2_&rA3^G( Uj#*TE-v9sr07*qoM6N<$g3p|vv;Y7A literal 0 HcmV?d00001 From 6f00f0ee0b25d504a69be770ed70d3af0bb7d830 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Tue, 21 Apr 2020 11:35:32 +0100 Subject: [PATCH 47/73] minor tweaks --- apps/minionclk/app.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/minionclk/app.js b/apps/minionclk/app.js index 0725f8fa6..3453f49e1 100755 --- a/apps/minionclk/app.js +++ b/apps/minionclk/app.js @@ -1,5 +1,3 @@ -const bob = require("heatshrink").decompress(atob("nk8hAaXlYLWAEsqvN/0gBBql5lQ2tquj1XV5wBJ52j0hACPsdP1QsBAQQAGBIIBF51/P8OkN5R1GIxF5HLmAFgoDLPZfOpzmZ6vPFwomCPaA6DAYOjeq2A1YyCdI4HGQJQ8F1T2SJ4Oq1XW1es1mtAQOrPoPUAIh3J54ZHIAR5S62s64cBwIBGQIOqHQK4HKQYVDAAIFC1g+BHh9VHAQAFDwQDDHoJ5E54BB6AaBKQ5YGqo6MwJzGHQ4BDeIj/BR4JxDABY8BvI6OOYgaEHwZADHgQ6BZA42GAIusPJNW64eFqzJDlcrERA8BHQI2FqwaBDYYGBPI45GCoIgCLoVWQ5NWXA2rKhaiGLAwOGEAmADxJPDVA51ElQaMC4ouEWALdEHRg8Dc4woCDJo8EAIYxCHQQIFHiwaRegJ5EcYWsHgbrKbBA8GDSrNDO4wfRKgR3FDSh3CN4UrdwZbSHYZ5DHajMFHYQGCHalWO4jtQDQwABwAGCAAQfTKoK0EHahwCeARdFHakASIZWVZ4Q8CO4YgWO4QbCO6hWGEIKYZKzZ3DLog7UG4I6C1lWDSdWO4bpCO4bwUwKYEHajMDwOAlUkLojTUd4gaTZoRWC0YIB1eJLqo4EWiqRE0mjlcr1QkEeKFWOooBCHiB2CC4WA5wzB52rEQgfPHQwABAYJXOHQ2iO4XO6omFEJh1BEAgBGPJlWDIQbC0ej50qgHV1XPEwohKcwRbEvJ3EBQTrLFomkOwOjlR3C5w8GMAR8ClYuBLIgOCvN4HgIZFDQYbBlaOBR4YNCwA5B0XOpzvBHgWqTw4AFxB1EvQ6BAAI8GDZILEdgQBCqp3DPIRfIEQwABvJ1CvGkvGiwA6IAYoBCv6wCAAVOlQ6DAIWkL5ABEwN40Z1CAYJfCv7zEAJNWOYZ3KAIWq5yYHFYLOBLIrVCAIh7BOIzpECoYDDpw7BHAQDG1WqwGkAIN/CwIABLY4LDAAZ9BwAABvLCBC5IBBvOrO44BEAAmjAIPN0XOAJyHIAAgPEquBHBi4BAId+HwWiHxqJDRpYBDq2I1R3LIAQ6BAAOpPogABGgIDDOomk0nP5pIGd42Aq1ewI8CeZI6CHAJhCEAIDCdIo2B0er1esAQIZBC4Z9JlVW1leeKGp0es5+s6+s6ABB0oFBAIervWr0ultr7OqtWmdexJ4BGxB5G0V6pF6wItB0t6p9PvQABvINBttJttPzwXCHQwBDlY6BO4WIwPPPJbvDvA0BFgNtAAIDGtwGCzrtHdYh1DAIOBrzxBPIgAIeIXNHgoBCGwYADzoVB0fNOpMOHQdW5+Bro7BHgQAB6jxJAAOjOYhxCAIukOoPN5ujdZFWqyyD0d6AwUrquBwAuB1I1FHgRJBMoQ9BWg1tzw0BDYI6B0R3DAAJ1BvMOp8rAAV4IQWBIodewAeCHAZ5IAAJoBAAXHHAJWDO4TtEdYQvEHgejAwIKClcqIQRdDXYbzFeoQBIGwIDDOot/VgQ6FAAIGBlgBCAAMzmZPBF4LzDACB1FAAOi1WjvFVr0zGYQ7GAAMAAYpPBwNeAIOIwOrfYOA1eA1WkAIWjAIekv4PBwCVBruBq5eBEYIABlcBF4wCEHw8zgAAiFYivEPgoSEAYo9jGgY4EO5Q7kVwiyFGggBFhASBHkhsKAAcqqtOAgMzd8o6HO495vF5QgMzrw7lhBoBvMqG4g")); - const locale = require("locale"); const black = 0x0000; @@ -52,15 +50,17 @@ function startDrawing() { hour = ''; minute = ''; date = ''; + var bob = require("heatshrink").decompress(atob("nk8hAaXlYLWAEsqvN/0gBBql5lQ2tquj1XV5wBJ52j0hACPsdP1QsBAQQAGBIIBF51/P8OkN5R1GIxF5HLmAFgoDLPZfOpzmZ6vPFwomCPaA6DAYOjeq2A1YyCdI4HGQJQ8F1T2SJ4Oq1XW1es1mtAQOrPoPUAIh3J54ZHIAR5S62s64cBwIBGQIOqHQK4HKQYVDAAIFC1g+BHh9VHAQAFDwQDDHoJ5E54BB6AaBKQ5YGqo6MwJzGHQ4BDeIj/BR4JxDABY8BvI6OOYgaEHwZADHgQ6BZA42GAIusPJNW64eFqzJDlcrERA8BHQI2FqwaBDYYGBPI45GCoIgCLoVWQ5NWXA2rKhaiGLAwOGEAmADxJPDVA51ElQaMC4ouEWALdEHRg8Dc4woCDJo8EAIYxCHQQIFHiwaRegJ5EcYWsHgbrKbBA8GDSrNDO4wfRKgR3FDSh3CN4UrdwZbSHYZ5DHajMFHYQGCHalWO4jtQDQwABwAGCAAQfTKoK0EHahwCeARdFHakASIZWVZ4Q8CO4YgWO4QbCO6hWGEIKYZKzZ3DLog7UG4I6C1lWDSdWO4bpCO4bwUwKYEHajMDwOAlUkLojTUd4gaTZoRWC0YIB1eJLqo4EWiqRE0mjlcr1QkEeKFWOooBCHiB2CC4WA5wzB52rEQgfPHQwABAYJXOHQ2iO4XO6omFEJh1BEAgBGPJlWDIQbC0ej50qgHV1XPEwohKcwRbEvJ3EBQTrLFomkOwOjlR3C5w8GMAR8ClYuBLIgOCvN4HgIZFDQYbBlaOBR4YNCwA5B0XOpzvBHgWqTw4AFxB1EvQ6BAAI8GDZILEdgQBCqp3DPIRfIEQwABvJ1CvGkvGiwA6IAYoBCv6wCAAVOlQ6DAIWkL5ABEwN40Z1CAYJfCv7zEAJNWOYZ3KAIWq5yYHFYLOBLIrVCAIh7BOIzpECoYDDpw7BHAQDG1WqwGkAIN/CwIABLY4LDAAZ9BwAABvLCBC5IBBvOrO44BEAAmjAIPN0XOAJyHIAAgPEquBHBi4BAId+HwWiHxqJDRpYBDq2I1R3LIAQ6BAAOpPogABGgIDDOomk0nP5pIGd42Aq1ewI8CeZI6CHAJhCEAIDCdIo2B0er1esAQIZBC4Z9JlVW1leeKGp0es5+s6+s6ABB0oFBAIervWr0ultr7OqtWmdexJ4BGxB5G0V6pF6wItB0t6p9PvQABvINBttJttPzwXCHQwBDlY6BO4WIwPPPJbvDvA0BFgNtAAIDGtwGCzrtHdYh1DAIOBrzxBPIgAIeIXNHgoBCGwYADzoVB0fNOpMOHQdW5+Bro7BHgQAB6jxJAAOjOYhxCAIukOoPN5ujdZFWqyyD0d6AwUrquBwAuB1I1FHgRJBMoQ9BWg1tzw0BDYI6B0R3DAAJ1BvMOp8rAAV4IQWBIodewAeCHAZ5IAAJoBAAXHHAJWDO4TtEdYQvEHgejAwIKClcqIQRdDXYbzFeoQBIGwIDDOot/VgQ6FAAIGBlgBCAAMzmZPBF4LzDACB1FAAOi1WjvFVr0zGYQ7GAAMAAYpPBwNeAIOIwOrfYOA1eA1WkAIWjAIekv4PBwCVBruBq5eBEYIABlcBF4wCEHw8zgAAiFYivEPgoSEAYo9jGgY4EO5Q7kVwiyFGggBFhASBHkhsKAAcqqtOAgMzd8o6HO495vF5QgMzrw7lhBoBvMqG4g")); g.drawImage(bob, 0, 0, { scale: 4 }); Bangle.drawWidgets(); draw(); - setInterval(draw, 1000); + timer = setInterval(draw, 1000); } function stopDrawing() { if (timer) { clearInterval(timer); + timer = undefined; } } From 4a53e768d60837f2554e0b1935529aadc16e8662 Mon Sep 17 00:00:00 2001 From: RenaudG <34276398+renaudgweb@users.noreply.github.com> Date: Tue, 21 Apr 2020 14:03:17 +0200 Subject: [PATCH 48/73] change img_nofix --- apps/osmpoi/osmpoi.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/osmpoi/osmpoi.html b/apps/osmpoi/osmpoi.html index 56a1f8eb6..e0275784e 100644 --- a/apps/osmpoi/osmpoi.html +++ b/apps/osmpoi/osmpoi.html @@ -141,7 +141,7 @@ }); document.getElementById("upload").addEventListener("click", function() { var app = `var features = ${JSON.stringify(features)}; -var img_nofix = require("heatshrink").decompress(atob("mEwxH+AH4A0PgYurg9kr0rGM4nBg9dsgADmUHGUYtHAAddGIJcgFpIxEMTsAlYtMAAZiaLh4AFmQwXLiSTaLiosBnMymUrGCYTBAAgvPCgjwaMh4raF/4v/F/4vUg4vulZgDgAAIF8EyEQUAh0cAAkVisHGA4+HF6gVBiwwFjkONo0HAAMOAAIvTnIhEiovMFQQADNgYvQroUDg4uGjj9EF448DF6a+HAAS+EF5CQCF6SMIeAQvFXYYwHF59eLpSOBF4hgKGAIvPskAFxKOFF80VM4KOFSBs5F6EWRY4xBF43+F5UyF6DuEizZBKwIuHSBQvXdIwvKMYsHlYvQW4IuPYAYRBMggvRgIvCFxwwCTYZlEg4vPlcHjkVFx6WJF6YuXMoTwCF58yVgIvXY4YvQrqqDGDAvvPYIvPsguaYQYv/F7owBF/4vfg4AGTIIAHF7gA/AH4AwA=")); +var img_nofix = require("heatshrink").decompress(atob("mEwxH+6+s6/+AB4TB1gGFq1WlYABAgOBEQQnH68rlQRBD4orGwIkDleBAwQoBEgIABCAY4CgAjGwNbw1bmJFCDYIrGB4OwAIUAGIIrDCIICBA4WBlcxquBF4uslex2AABGYgrE2GxB4WAFoY8ClS0BPwJLCBgUAqyAGlYuCAAmGxgqDF4ZdBEIJSBHoWGwACBAANbTwRqBAYIwFqxTCAAmMF4+GlSDBq0qqotEGYQxDlVWGATBFYAJgIFYIvEJoSKBE4gADxgFESgIwC67AFF51VDQKMBFxAAErg0BGATQBYBy7D2OrlRJBgCGFLgVcGZEqOoKRFYBOGF4WymIXCqovCAQmwrYDBxgJGI4RgEYBQvBGAKlBUILnHdQaPEYQhgGwMxBgQuDRQIvCwCnBqwQCEwY/BFQeAFgQvEmJJBwOBR4dcLIQAD2J6BF4KODEAQhBwA0CSwoMBBAIxClcASAgeCRo2rDIICBOQKOBWoTLBFYYDBrdVG4NVFgK/EDQIrBF4IeCAApbBEgOydwIvBmJuFAAYJBFwIVBAAeMrlWRoIvDwNVF5AeB62xUgVVBAIsGPIRpBHoovBFwIvEXwYvHd4SPDb4ThEAob4DZoQvBDAIvEXwQkBFwpIBAQKPDCILeBwGAEYQnCdQIGDGAcq69WX4YdBKgQAE2GM1YDB2NVIgS0CABFcXwZnDFQJ6Cqy+HMQZeCGoLWBI4KDDAA46EF4VVC4LaCwK+BwBaDAAi+DAgIVCMAJeJAooGBXwusF4JMBQwLAFA4srCwVVCgK4DAQOwrYDErgQBFQJIBAQSPBra3BGIL/CF4ICBA4QoBMAhXCYg2AFwI0CR4MqI4NWRwLvDLQQAB1erD4IuBM4cxDAUxLYKDCFIdVNYT0DmJeF/x8BRgoABdwQAEmLZBGAMrQAIoBLIoAEFwi9BAATwDE4gwBAwlVDIIACq0qFwYRBLQZqClRDCbAIuDYARbCMAgZCqqnBFwgABYYMxBoIwBMAZqBFQJdCqwuEYAQsCFwexrcACYMqgAtFEAIxCAAKGBAAYMEUwIvFM4OMFoY0Bw0AC4RGCLgokD1msG4OBAgIVDler2LtDYAi3FFwgACVQQuBCQOAEQNWFYJrEfgMrwBSCdwrACqouLa4QAB2DKBCIVbRosxagOx2SuDd4ovBmLSBFxRhCrYuBAASmBAAQ4DVoeG1eGqrAGq1cCQLqBFxPXP4ImBOIYADAoOMFoIrBBAWwmKPFP4LKBLpYvCmIlBaQheDNA4ABd4z7B2OAFxmsgBVCF4xbBFo4SBla+GrZdNFwL/BWoYvHAwruCXw8xFyBeIFAIKDFoYABXw3+lYuRF44lCBQIEDXxWBFyQvJFwa+MEAIuNqx7EF4oqC2OrFwy+HqxdOFoewwAvBGwjuHAAWMla+FAwIuKlVb2OMwFVlcrqwCBqozCMAeML4WGrgTDXwsrL5IuBldbC4WBIIKmCwIzFAAI/ECYi/GMA4uBlQXKDQYzCIQITNAAOBGAwuBNIIXLGYwTRGAouCFqIAVGAJyBwIupGATRBewIrmA==")); var img_fix = require("heatshrink").decompress(atob("mEwxH+AH4A/AH4A/AG2JnYv/FzovBGFgvuFwIvCGFQvuFwQvDGFAvuFwYvEGEwvuFwgvFGEgvuFwovGGEQvuFwwvHGEAvuFw4vIGDwvuFxAvJGDgvuFxIvKGDQvuFxQvLGDAvuFxYvMGCwvuFxgvNGCgvuFxovOGCQvuFxwvPGCAvuFx4vQGBwtOCQYvbFRwAJGCwqTGh4uMFS40LEcIA/AH4A/ACQA=")); // https://github.com/Leaflet/Leaflet/blob/master/src/geo/projection/Projection.SphericalMercator.js From 2814e367c0dda1cb3787f1f151416372d16f5c65 Mon Sep 17 00:00:00 2001 From: RenaudG <34276398+renaudgweb@users.noreply.github.com> Date: Tue, 21 Apr 2020 14:09:03 +0200 Subject: [PATCH 49/73] Update ChangeLog --- apps/osmpoi/ChangeLog | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/osmpoi/ChangeLog b/apps/osmpoi/ChangeLog index 5560f00bc..8e73a192e 100644 --- a/apps/osmpoi/ChangeLog +++ b/apps/osmpoi/ChangeLog @@ -1 +1,2 @@ 0.01: New App! +0.02: Change img when no fix From 25f2e3d99732017e64b86e3dfcca212d19f3684a Mon Sep 17 00:00:00 2001 From: RenaudG <34276398+renaudgweb@users.noreply.github.com> Date: Tue, 21 Apr 2020 14:32:55 +0200 Subject: [PATCH 50/73] Update osmpoi.html --- apps/osmpoi/osmpoi.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/osmpoi/osmpoi.html b/apps/osmpoi/osmpoi.html index e0275784e..b4a954c24 100644 --- a/apps/osmpoi/osmpoi.html +++ b/apps/osmpoi/osmpoi.html @@ -142,7 +142,7 @@ document.getElementById("upload").addEventListener("click", function() { var app = `var features = ${JSON.stringify(features)}; var img_nofix = require("heatshrink").decompress(atob("mEwxH+6+s6/+AB4TB1gGFq1WlYABAgOBEQQnH68rlQRBD4orGwIkDleBAwQoBEgIABCAY4CgAjGwNbw1bmJFCDYIrGB4OwAIUAGIIrDCIICBA4WBlcxquBF4uslex2AABGYgrE2GxB4WAFoY8ClS0BPwJLCBgUAqyAGlYuCAAmGxgqDF4ZdBEIJSBHoWGwACBAANbTwRqBAYIwFqxTCAAmMF4+GlSDBq0qqotEGYQxDlVWGATBFYAJgIFYIvEJoSKBE4gADxgFESgIwC67AFF51VDQKMBFxAAErg0BGATQBYBy7D2OrlRJBgCGFLgVcGZEqOoKRFYBOGF4WymIXCqovCAQmwrYDBxgJGI4RgEYBQvBGAKlBUILnHdQaPEYQhgGwMxBgQuDRQIvCwCnBqwQCEwY/BFQeAFgQvEmJJBwOBR4dcLIQAD2J6BF4KODEAQhBwA0CSwoMBBAIxClcASAgeCRo2rDIICBOQKOBWoTLBFYYDBrdVG4NVFgK/EDQIrBF4IeCAApbBEgOydwIvBmJuFAAYJBFwIVBAAeMrlWRoIvDwNVF5AeB62xUgVVBAIsGPIRpBHoovBFwIvEXwYvHd4SPDb4ThEAob4DZoQvBDAIvEXwQkBFwpIBAQKPDCILeBwGAEYQnCdQIGDGAcq69WX4YdBKgQAE2GM1YDB2NVIgS0CABFcXwZnDFQJ6Cqy+HMQZeCGoLWBI4KDDAA46EF4VVC4LaCwK+BwBaDAAi+DAgIVCMAJeJAooGBXwusF4JMBQwLAFA4srCwVVCgK4DAQOwrYDErgQBFQJIBAQSPBra3BGIL/CF4ICBA4QoBMAhXCYg2AFwI0CR4MqI4NWRwLvDLQQAB1erD4IuBM4cxDAUxLYKDCFIdVNYT0DmJeF/x8BRgoABdwQAEmLZBGAMrQAIoBLIoAEFwi9BAATwDE4gwBAwlVDIIACq0qFwYRBLQZqClRDCbAIuDYARbCMAgZCqqnBFwgABYYMxBoIwBMAZqBFQJdCqwuEYAQsCFwexrcACYMqgAtFEAIxCAAKGBAAYMEUwIvFM4OMFoY0Bw0AC4RGCLgokD1msG4OBAgIVDler2LtDYAi3FFwgACVQQuBCQOAEQNWFYJrEfgMrwBSCdwrACqouLa4QAB2DKBCIVbRosxagOx2SuDd4ovBmLSBFxRhCrYuBAASmBAAQ4DVoeG1eGqrAGq1cCQLqBFxPXP4ImBOIYADAoOMFoIrBBAWwmKPFP4LKBLpYvCmIlBaQheDNA4ABd4z7B2OAFxmsgBVCF4xbBFo4SBla+GrZdNFwL/BWoYvHAwruCXw8xFyBeIFAIKDFoYABXw3+lYuRF44lCBQIEDXxWBFyQvJFwa+MEAIuNqx7EF4oqC2OrFwy+HqxdOFoewwAvBGwjuHAAWMla+FAwIuKlVb2OMwFVlcrqwCBqozCMAeML4WGrgTDXwsrL5IuBldbC4WBIIKmCwIzFAAI/ECYi/GMA4uBlQXKDQYzCIQITNAAOBGAwuBNIIXLGYwTRGAouCFqIAVGAJyBwIupGATRBewIrmA==")); -var img_fix = require("heatshrink").decompress(atob("mEwxH+AH4A/AH4A/AG2JnYv/FzovBGFgvuFwIvCGFQvuFwQvDGFAvuFwYvEGEwvuFwgvFGEgvuFwovGGEQvuFwwvHGEAvuFw4vIGDwvuFxAvJGDgvuFxIvKGDQvuFxQvLGDAvuFxYvMGCwvuFxgvNGCgvuFxovOGCQvuFxwvPGCAvuFx4vQGBwtOCQYvbFRwAJGCwqTGh4uMFS40LEcIA/AH4A/ACQA=")); +var img_fix = require("heatshrink").decompress(atob("mEwxH+6+s6/+AB4TB1gGFq1WlYABAgOBEQQnH68rlQRBD4orGwIkDleBAwQoBEgIABCAY4CgAjGwNbw1bmJFCDYIrGB4OwAIUAGIIrDCIICBA4WBlcxquBF4uslex2AABGYgrE2GxB4WAFoY8ClS0BPwJLCBgUAqyAGlYuCAAmGxgqDF4ZdBEIJSBHoWGwACBAANbTwRqBAYIwFqxTCAAmMF4+GlSDBq0qqotEGYQxDlVWGATBFYAJgIFYIvEJoSKBE4gADxgFESgIwC67AFF51VDQKMBFxAAErg0BGATQBYBy7D2OrlRJBgCGFLgVcGZEqOoKRFYBOGF4WymIXCqovCAQmwrYDBxgJGI4RgEYBQvBGAKlBUILnHdQaPEYQhgGwMxBgQuDRQIvCwCnBqwQCEwY/BFQeAFgQvEmJJBwOBR4dcLIQAD2J6BF4KODEAQhBwA0CSwoMBBAIxClcASAgeCRo2rDIICBOQKOBWoTLBFYYDBrdVG4NVFgK/EDQIrBF4IeCAApbBEgOydwIvBmJuFAAYJBFwIVBAAeMrlWRoIvDwNVF5AeB62xUgVVBAIsGPIRpBHoovBFwIvEXwYvHd4SPDb4ThEAob4DZoQvBDAIvEXwQkBFwpIBAQKPDCILeBwGAEYQnCdQIGDGAcq69WX4YdBKgQAE2GM1YDB2NVIgS0CABFcXwZnDFQJ6Cqy+HMQZeCGoLWBI4KDDAA46EF4VVC4LaCwK+BwBaDAAi+DAgIVCMAJeJAooGBXwusF4JMBQwLAFA4srCwVVCgK4DAQOwrYDErgQBFQJIBAQSPBra3BGIL/CF4ICBA4QoBMAhXCYg2AFwI0CR4MqI4NWRwLvDLQQAB1erD4IuBM4cxDAUxLYKDCFIdVNYT0DmJeF/x8BRgoABdwQAEmLZBGAMrQAIoBLIoAEFwi9BAATwDE4gwBAwlVDIIACq0qFwYRBLQZqClRDCbAIuDYARbCMAgZCqqnBFwgABYYMxBoIwBMAZqBFQJdCqwuEYAQsCFwexrcACYMqgAtFEAIxCAAKGBAAYMEUwIvFM4OMFoY0Bw0AC4RGCLgokD1msG4OBAgIVDler2LtDYAi3FFwgACVQQuBCQOAEQNWFYJrEfgMrwBSCdwrACqouLa4QAB2DKBCIVbRosxagOx2SuDd4ovBmLSBFxRhCrYuBAASmBAAQ4DVoeG1eGqrAGq1cCQLqBFxPXP4ImBOIYADAoOMFoIrBBAWwmKPFP4LKBLpYvCmIlBaQheDNA4ABd4z7B2OAFxmsgBVCF4xbBFo4SBla+GrZdNFwL/BWoYvHAwruCXw8xFyBeIFAIKDFoYABXw3+lYuRF44lCBQIEDXxWBFyQvJFwa+MEAIuNqx7EF4oqC2OrFwy+HqxdOFoewwAvBGwjuHAAWMla+FAwIuKlVb2OMwFVlcrqwCBqozCMAeML4WGrgTDXwsrL5IuBldbC4WBIIKmCwIzFAAI/ECYi/GMA4uBlQXKDQYzCIQITNAAOBGAwuBNIIXLGYwTRGAouCFqIAVGAJyBwIupGATRBewIrmA==")); // https://github.com/Leaflet/Leaflet/blob/master/src/geo/projection/Projection.SphericalMercator.js function project(latlong) { From c23c11eb51b9411772a52e048761c779a89bbdb9 Mon Sep 17 00:00:00 2001 From: RenaudG <34276398+renaudgweb@users.noreply.github.com> Date: Tue, 21 Apr 2020 14:50:44 +0200 Subject: [PATCH 51/73] Update osmpoi.html --- apps/osmpoi/osmpoi.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/osmpoi/osmpoi.html b/apps/osmpoi/osmpoi.html index b4a954c24..fa22bead5 100644 --- a/apps/osmpoi/osmpoi.html +++ b/apps/osmpoi/osmpoi.html @@ -141,8 +141,8 @@ }); document.getElementById("upload").addEventListener("click", function() { var app = `var features = ${JSON.stringify(features)}; -var img_nofix = require("heatshrink").decompress(atob("mEwxH+6+s6/+AB4TB1gGFq1WlYABAgOBEQQnH68rlQRBD4orGwIkDleBAwQoBEgIABCAY4CgAjGwNbw1bmJFCDYIrGB4OwAIUAGIIrDCIICBA4WBlcxquBF4uslex2AABGYgrE2GxB4WAFoY8ClS0BPwJLCBgUAqyAGlYuCAAmGxgqDF4ZdBEIJSBHoWGwACBAANbTwRqBAYIwFqxTCAAmMF4+GlSDBq0qqotEGYQxDlVWGATBFYAJgIFYIvEJoSKBE4gADxgFESgIwC67AFF51VDQKMBFxAAErg0BGATQBYBy7D2OrlRJBgCGFLgVcGZEqOoKRFYBOGF4WymIXCqovCAQmwrYDBxgJGI4RgEYBQvBGAKlBUILnHdQaPEYQhgGwMxBgQuDRQIvCwCnBqwQCEwY/BFQeAFgQvEmJJBwOBR4dcLIQAD2J6BF4KODEAQhBwA0CSwoMBBAIxClcASAgeCRo2rDIICBOQKOBWoTLBFYYDBrdVG4NVFgK/EDQIrBF4IeCAApbBEgOydwIvBmJuFAAYJBFwIVBAAeMrlWRoIvDwNVF5AeB62xUgVVBAIsGPIRpBHoovBFwIvEXwYvHd4SPDb4ThEAob4DZoQvBDAIvEXwQkBFwpIBAQKPDCILeBwGAEYQnCdQIGDGAcq69WX4YdBKgQAE2GM1YDB2NVIgS0CABFcXwZnDFQJ6Cqy+HMQZeCGoLWBI4KDDAA46EF4VVC4LaCwK+BwBaDAAi+DAgIVCMAJeJAooGBXwusF4JMBQwLAFA4srCwVVCgK4DAQOwrYDErgQBFQJIBAQSPBra3BGIL/CF4ICBA4QoBMAhXCYg2AFwI0CR4MqI4NWRwLvDLQQAB1erD4IuBM4cxDAUxLYKDCFIdVNYT0DmJeF/x8BRgoABdwQAEmLZBGAMrQAIoBLIoAEFwi9BAATwDE4gwBAwlVDIIACq0qFwYRBLQZqClRDCbAIuDYARbCMAgZCqqnBFwgABYYMxBoIwBMAZqBFQJdCqwuEYAQsCFwexrcACYMqgAtFEAIxCAAKGBAAYMEUwIvFM4OMFoY0Bw0AC4RGCLgokD1msG4OBAgIVDler2LtDYAi3FFwgACVQQuBCQOAEQNWFYJrEfgMrwBSCdwrACqouLa4QAB2DKBCIVbRosxagOx2SuDd4ovBmLSBFxRhCrYuBAASmBAAQ4DVoeG1eGqrAGq1cCQLqBFxPXP4ImBOIYADAoOMFoIrBBAWwmKPFP4LKBLpYvCmIlBaQheDNA4ABd4z7B2OAFxmsgBVCF4xbBFo4SBla+GrZdNFwL/BWoYvHAwruCXw8xFyBeIFAIKDFoYABXw3+lYuRF44lCBQIEDXxWBFyQvJFwa+MEAIuNqx7EF4oqC2OrFwy+HqxdOFoewwAvBGwjuHAAWMla+FAwIuKlVb2OMwFVlcrqwCBqozCMAeML4WGrgTDXwsrL5IuBldbC4WBIIKmCwIzFAAI/ECYi/GMA4uBlQXKDQYzCIQITNAAOBGAwuBNIIXLGYwTRGAouCFqIAVGAJyBwIupGATRBewIrmA==")); -var img_fix = require("heatshrink").decompress(atob("mEwxH+6+s6/+AB4TB1gGFq1WlYABAgOBEQQnH68rlQRBD4orGwIkDleBAwQoBEgIABCAY4CgAjGwNbw1bmJFCDYIrGB4OwAIUAGIIrDCIICBA4WBlcxquBF4uslex2AABGYgrE2GxB4WAFoY8ClS0BPwJLCBgUAqyAGlYuCAAmGxgqDF4ZdBEIJSBHoWGwACBAANbTwRqBAYIwFqxTCAAmMF4+GlSDBq0qqotEGYQxDlVWGATBFYAJgIFYIvEJoSKBE4gADxgFESgIwC67AFF51VDQKMBFxAAErg0BGATQBYBy7D2OrlRJBgCGFLgVcGZEqOoKRFYBOGF4WymIXCqovCAQmwrYDBxgJGI4RgEYBQvBGAKlBUILnHdQaPEYQhgGwMxBgQuDRQIvCwCnBqwQCEwY/BFQeAFgQvEmJJBwOBR4dcLIQAD2J6BF4KODEAQhBwA0CSwoMBBAIxClcASAgeCRo2rDIICBOQKOBWoTLBFYYDBrdVG4NVFgK/EDQIrBF4IeCAApbBEgOydwIvBmJuFAAYJBFwIVBAAeMrlWRoIvDwNVF5AeB62xUgVVBAIsGPIRpBHoovBFwIvEXwYvHd4SPDb4ThEAob4DZoQvBDAIvEXwQkBFwpIBAQKPDCILeBwGAEYQnCdQIGDGAcq69WX4YdBKgQAE2GM1YDB2NVIgS0CABFcXwZnDFQJ6Cqy+HMQZeCGoLWBI4KDDAA46EF4VVC4LaCwK+BwBaDAAi+DAgIVCMAJeJAooGBXwusF4JMBQwLAFA4srCwVVCgK4DAQOwrYDErgQBFQJIBAQSPBra3BGIL/CF4ICBA4QoBMAhXCYg2AFwI0CR4MqI4NWRwLvDLQQAB1erD4IuBM4cxDAUxLYKDCFIdVNYT0DmJeF/x8BRgoABdwQAEmLZBGAMrQAIoBLIoAEFwi9BAATwDE4gwBAwlVDIIACq0qFwYRBLQZqClRDCbAIuDYARbCMAgZCqqnBFwgABYYMxBoIwBMAZqBFQJdCqwuEYAQsCFwexrcACYMqgAtFEAIxCAAKGBAAYMEUwIvFM4OMFoY0Bw0AC4RGCLgokD1msG4OBAgIVDler2LtDYAi3FFwgACVQQuBCQOAEQNWFYJrEfgMrwBSCdwrACqouLa4QAB2DKBCIVbRosxagOx2SuDd4ovBmLSBFxRhCrYuBAASmBAAQ4DVoeG1eGqrAGq1cCQLqBFxPXP4ImBOIYADAoOMFoIrBBAWwmKPFP4LKBLpYvCmIlBaQheDNA4ABd4z7B2OAFxmsgBVCF4xbBFo4SBla+GrZdNFwL/BWoYvHAwruCXw8xFyBeIFAIKDFoYABXw3+lYuRF44lCBQIEDXxWBFyQvJFwa+MEAIuNqx7EF4oqC2OrFwy+HqxdOFoewwAvBGwjuHAAWMla+FAwIuKlVb2OMwFVlcrqwCBqozCMAeML4WGrgTDXwsrL5IuBldbC4WBIIKmCwIzFAAI/ECYi/GMA4uBlQXKDQYzCIQITNAAOBGAwuBNIIXLGYwTRGAouCFqIAVGAJyBwIupGATRBewIrmA==")); +var img_nofix = require("heatshrink").decompress(atob("mEwxH+h8dj3+AB8eCYsejkYhEVAAMIjEcBwQTBh4bE/8ViUVCAgrIjMWifX68VjMHjETi8bHAMPCAIJChATBiMdEAsZxlH0nsD4IzDNYIrB6/WB4NGAIURicb///FgUcjhYBBAMHinsx0aF4sd61FowABGYOP68UiYrDo1FrwDB0nXjIkChETiURiMS60Tiw6CjMRhCAG64uCAAkao4qDAAIEBLoMH/8cinW0kZjOko4ACxgyBB4MdiccGAsWKYQAHF4tHiUd/8YiWOFAIwBjQCBAwICBxkSi//j0TYIrABFo44BF4aeB65NBjHXLAYACMQIWBo8aGIPWixhCcQLAEF5tex0YVoIuDjSgBGAYDD0gbB6xhBjbCEh7AIF4tGiUPjsRW4SIEfIIGDHIIFCiT1BiqREi0aGBDwCruPjX/imOxhTCX4YvBBIIzDBITDBI4MWF4caxovIrwwC68PjiNBFoaRCAQQIDAgiRBJALBEg+PBgQwFdYNe0jYBhGPcoJQBQYLpCMYQABF4aQCx8Ta4MaF4UYZoIZEGYZeBRwLQBP4WkEYIwBAoQJBGQg0D60Rj0deIUPihcGGoQ5C60cj3WWIKiBSIeMAYOkxwDBAQTJDiTuBh8VF4Me64tGLYIhBrtd9hEBx5uFX4ZCCAYR8EVAMaYAIvCg+OF5NGrpfBj0cx1FFwooCCoKsDXgQvCjMHjIvDi4RCdgteo9er1FF4Md6xUCXoQjBSYUZxhkBY4QMBJAMdjZfDXwJYCLwgGCAQKPBjsd69HxrhEdAQCDd4gwBiUPjEcX4UeiZXBAAlFRwQDBr2OjRBBL4SCDAAh9BY4T7DFQMVPQMWXxKnCr5hC0kI/8WxotBQoLuDF4YDCS4VHx0YI4P/UgK+BjRZCF4yOBeYUTh8bSAMaWoQnCFwQJESoS+BFgK+Bjv+izuCr7BFX4YAB60bh8Tx2NXAsZowGCAYLOBx2k68cicej0Vh/+jONLASjCGoRiDEgUT/8HMAIqBQgTEDXYOMxg7Dx0SLwMIg/+/0d6wmCeQIsCPAJkFx4YBi+PL4QkBAQONxmOLQIzCJAPsiv/jpeC/x8BK4YAEBA2Pi3/h8I62M64oBxmNRIJjCYIUZFwMPjyQBFwIABhDwBFwxfFxwZB/4wCiTDBXYaVBLQJqCiUWh8PiiNCAAUaxqNBGIYFBDIONx0ZFwgACjUT9iLBxsaXYJcBxvW68a/5dBjAuEYAgqBGQNFoukiMVKwMRFwkZEAMPjUV6/Wx/WAAUVjITBjcTx8IF4rABF4QtBAgMZiIkBIwUIFwfXV4McBgUcjQ4BjkeBALpBKgXXdoTAEjK3EFwMbLIceiUIh4uBXAOk60UjAqBNgQ0BjEU60aVwXWjovFjWOFxRhDiZMCfYTNB9gzBBgXsxwMBrqBBr2NjIvFjePo4QBFxBhDxgrBAAR1EHAbZBb4IGCxzwGi+kBYLqBFxAABjBfCFIY0EFAVfBQYGB9iPFh8UIAJdKF4fsEoZdGM47vCjwvEj3Xr0aFxkdiMZF5FGRIIAHo8VXw2No4uOf4QvHXAgAEoukXw+PFzIvFr1eeILyBXw3+iYuRLxIvDSQy+GjguSF44pCo9fFwy+GEAMHFxmlPYJUBr4vFBQLsIXxEIjJdNFgIlCjQvBGoRYDrzJI6y+FicdFxUSxgrB0mO68ThEVienGYS+EMYVHCYcXh4vEisaFxXXxnWFYMajoZCj0cjEU6+OGYIABFYgTEdwxgHFwMSFYoAHGYcSFZYAEjYwGFwMZC5gzGCaIwFFwQtRACowBjZ6BF1LDCisTikbFcwA==")); +var img_fix = require("heatshrink").decompress(atob("mEwxH+AH4A/AH4A/AG1Omwv/FzovBGFgvuFwIvCGFQvuFwQvDGFAvuFwYvEGEwvuFwgvFGEgvuFwovGGEQvuFwwvHGEAvuFw4vIGDwvuFxAvJGDgvuFxIvKGDQvuFxQvLGDAvuFxYvMGCwvuFxgvNGCgvuFxovOGCQvuFxwvPGCAvuFx4vQGBwtOCQYvbFRwAJGCwpEprTPGhouLFTA0LEcIA/AH4A/ACQA=")); // https://github.com/Leaflet/Leaflet/blob/master/src/geo/projection/Projection.SphericalMercator.js function project(latlong) { From f938dc3de0933f3b81f9f25a7fff50e9ae57ac5f Mon Sep 17 00:00:00 2001 From: RenaudG <34276398+renaudgweb@users.noreply.github.com> Date: Tue, 21 Apr 2020 14:59:52 +0200 Subject: [PATCH 52/73] Update osmpoi.html --- apps/osmpoi/osmpoi.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/osmpoi/osmpoi.html b/apps/osmpoi/osmpoi.html index fa22bead5..e0275784e 100644 --- a/apps/osmpoi/osmpoi.html +++ b/apps/osmpoi/osmpoi.html @@ -141,8 +141,8 @@ }); document.getElementById("upload").addEventListener("click", function() { var app = `var features = ${JSON.stringify(features)}; -var img_nofix = require("heatshrink").decompress(atob("mEwxH+h8dj3+AB8eCYsejkYhEVAAMIjEcBwQTBh4bE/8ViUVCAgrIjMWifX68VjMHjETi8bHAMPCAIJChATBiMdEAsZxlH0nsD4IzDNYIrB6/WB4NGAIURicb///FgUcjhYBBAMHinsx0aF4sd61FowABGYOP68UiYrDo1FrwDB0nXjIkChETiURiMS60Tiw6CjMRhCAG64uCAAkao4qDAAIEBLoMH/8cinW0kZjOko4ACxgyBB4MdiccGAsWKYQAHF4tHiUd/8YiWOFAIwBjQCBAwICBxkSi//j0TYIrABFo44BF4aeB65NBjHXLAYACMQIWBo8aGIPWixhCcQLAEF5tex0YVoIuDjSgBGAYDD0gbB6xhBjbCEh7AIF4tGiUPjsRW4SIEfIIGDHIIFCiT1BiqREi0aGBDwCruPjX/imOxhTCX4YvBBIIzDBITDBI4MWF4caxovIrwwC68PjiNBFoaRCAQQIDAgiRBJALBEg+PBgQwFdYNe0jYBhGPcoJQBQYLpCMYQABF4aQCx8Ta4MaF4UYZoIZEGYZeBRwLQBP4WkEYIwBAoQJBGQg0D60Rj0deIUPihcGGoQ5C60cj3WWIKiBSIeMAYOkxwDBAQTJDiTuBh8VF4Me64tGLYIhBrtd9hEBx5uFX4ZCCAYR8EVAMaYAIvCg+OF5NGrpfBj0cx1FFwooCCoKsDXgQvCjMHjIvDi4RCdgteo9er1FF4Md6xUCXoQjBSYUZxhkBY4QMBJAMdjZfDXwJYCLwgGCAQKPBjsd69HxrhEdAQCDd4gwBiUPjEcX4UeiZXBAAlFRwQDBr2OjRBBL4SCDAAh9BY4T7DFQMVPQMWXxKnCr5hC0kI/8WxotBQoLuDF4YDCS4VHx0YI4P/UgK+BjRZCF4yOBeYUTh8bSAMaWoQnCFwQJESoS+BFgK+Bjv+izuCr7BFX4YAB60bh8Tx2NXAsZowGCAYLOBx2k68cicej0Vh/+jONLASjCGoRiDEgUT/8HMAIqBQgTEDXYOMxg7Dx0SLwMIg/+/0d6wmCeQIsCPAJkFx4YBi+PL4QkBAQONxmOLQIzCJAPsiv/jpeC/x8BK4YAEBA2Pi3/h8I62M64oBxmNRIJjCYIUZFwMPjyQBFwIABhDwBFwxfFxwZB/4wCiTDBXYaVBLQJqCiUWh8PiiNCAAUaxqNBGIYFBDIONx0ZFwgACjUT9iLBxsaXYJcBxvW68a/5dBjAuEYAgqBGQNFoukiMVKwMRFwkZEAMPjUV6/Wx/WAAUVjITBjcTx8IF4rABF4QtBAgMZiIkBIwUIFwfXV4McBgUcjQ4BjkeBALpBKgXXdoTAEjK3EFwMbLIceiUIh4uBXAOk60UjAqBNgQ0BjEU60aVwXWjovFjWOFxRhDiZMCfYTNB9gzBBgXsxwMBrqBBr2NjIvFjePo4QBFxBhDxgrBAAR1EHAbZBb4IGCxzwGi+kBYLqBFxAABjBfCFIY0EFAVfBQYGB9iPFh8UIAJdKF4fsEoZdGM47vCjwvEj3Xr0aFxkdiMZF5FGRIIAHo8VXw2No4uOf4QvHXAgAEoukXw+PFzIvFr1eeILyBXw3+iYuRLxIvDSQy+GjguSF44pCo9fFwy+GEAMHFxmlPYJUBr4vFBQLsIXxEIjJdNFgIlCjQvBGoRYDrzJI6y+FicdFxUSxgrB0mO68ThEVienGYS+EMYVHCYcXh4vEisaFxXXxnWFYMajoZCj0cjEU6+OGYIABFYgTEdwxgHFwMSFYoAHGYcSFZYAEjYwGFwMZC5gzGCaIwFFwQtRACowBjZ6BF1LDCisTikbFcwA==")); -var img_fix = require("heatshrink").decompress(atob("mEwxH+AH4A/AH4A/AG1Omwv/FzovBGFgvuFwIvCGFQvuFwQvDGFAvuFwYvEGEwvuFwgvFGEgvuFwovGGEQvuFwwvHGEAvuFw4vIGDwvuFxAvJGDgvuFxIvKGDQvuFxQvLGDAvuFxYvMGCwvuFxgvNGCgvuFxovOGCQvuFxwvPGCAvuFx4vQGBwtOCQYvbFRwAJGCwpEprTPGhouLFTA0LEcIA/AH4A/ACQA=")); +var img_nofix = require("heatshrink").decompress(atob("mEwxH+6+s6/+AB4TB1gGFq1WlYABAgOBEQQnH68rlQRBD4orGwIkDleBAwQoBEgIABCAY4CgAjGwNbw1bmJFCDYIrGB4OwAIUAGIIrDCIICBA4WBlcxquBF4uslex2AABGYgrE2GxB4WAFoY8ClS0BPwJLCBgUAqyAGlYuCAAmGxgqDF4ZdBEIJSBHoWGwACBAANbTwRqBAYIwFqxTCAAmMF4+GlSDBq0qqotEGYQxDlVWGATBFYAJgIFYIvEJoSKBE4gADxgFESgIwC67AFF51VDQKMBFxAAErg0BGATQBYBy7D2OrlRJBgCGFLgVcGZEqOoKRFYBOGF4WymIXCqovCAQmwrYDBxgJGI4RgEYBQvBGAKlBUILnHdQaPEYQhgGwMxBgQuDRQIvCwCnBqwQCEwY/BFQeAFgQvEmJJBwOBR4dcLIQAD2J6BF4KODEAQhBwA0CSwoMBBAIxClcASAgeCRo2rDIICBOQKOBWoTLBFYYDBrdVG4NVFgK/EDQIrBF4IeCAApbBEgOydwIvBmJuFAAYJBFwIVBAAeMrlWRoIvDwNVF5AeB62xUgVVBAIsGPIRpBHoovBFwIvEXwYvHd4SPDb4ThEAob4DZoQvBDAIvEXwQkBFwpIBAQKPDCILeBwGAEYQnCdQIGDGAcq69WX4YdBKgQAE2GM1YDB2NVIgS0CABFcXwZnDFQJ6Cqy+HMQZeCGoLWBI4KDDAA46EF4VVC4LaCwK+BwBaDAAi+DAgIVCMAJeJAooGBXwusF4JMBQwLAFA4srCwVVCgK4DAQOwrYDErgQBFQJIBAQSPBra3BGIL/CF4ICBA4QoBMAhXCYg2AFwI0CR4MqI4NWRwLvDLQQAB1erD4IuBM4cxDAUxLYKDCFIdVNYT0DmJeF/x8BRgoABdwQAEmLZBGAMrQAIoBLIoAEFwi9BAATwDE4gwBAwlVDIIACq0qFwYRBLQZqClRDCbAIuDYARbCMAgZCqqnBFwgABYYMxBoIwBMAZqBFQJdCqwuEYAQsCFwexrcACYMqgAtFEAIxCAAKGBAAYMEUwIvFM4OMFoY0Bw0AC4RGCLgokD1msG4OBAgIVDler2LtDYAi3FFwgACVQQuBCQOAEQNWFYJrEfgMrwBSCdwrACqouLa4QAB2DKBCIVbRosxagOx2SuDd4ovBmLSBFxRhCrYuBAASmBAAQ4DVoeG1eGqrAGq1cCQLqBFxPXP4ImBOIYADAoOMFoIrBBAWwmKPFP4LKBLpYvCmIlBaQheDNA4ABd4z7B2OAFxmsgBVCF4xbBFo4SBla+GrZdNFwL/BWoYvHAwruCXw8xFyBeIFAIKDFoYABXw3+lYuRF44lCBQIEDXxWBFyQvJFwa+MEAIuNqx7EF4oqC2OrFwy+HqxdOFoewwAvBGwjuHAAWMla+FAwIuKlVb2OMwFVlcrqwCBqozCMAeML4WGrgTDXwsrL5IuBldbC4WBIIKmCwIzFAAI/ECYi/GMA4uBlQXKDQYzCIQITNAAOBGAwuBNIIXLGYwTRGAouCFqIAVGAJyBwIupGATRBewIrmA==")); +var img_fix = require("heatshrink").decompress(atob("mEwxH+AH4A/AH4A/AG2JnYv/FzovBGFgvuFwIvCGFQvuFwQvDGFAvuFwYvEGEwvuFwgvFGEgvuFwovGGEQvuFwwvHGEAvuFw4vIGDwvuFxAvJGDgvuFxIvKGDQvuFxQvLGDAvuFxYvMGCwvuFxgvNGCgvuFxovOGCQvuFxwvPGCAvuFx4vQGBwtOCQYvbFRwAJGCwqTGh4uMFS40LEcIA/AH4A/ACQA=")); // https://github.com/Leaflet/Leaflet/blob/master/src/geo/projection/Projection.SphericalMercator.js function project(latlong) { From 9a64b8aa35a4108b1745c812dac119b0943290f8 Mon Sep 17 00:00:00 2001 From: RenaudG <34276398+renaudgweb@users.noreply.github.com> Date: Tue, 21 Apr 2020 15:17:57 +0200 Subject: [PATCH 53/73] Update osmpoi.html --- apps/osmpoi/osmpoi.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/osmpoi/osmpoi.html b/apps/osmpoi/osmpoi.html index e0275784e..3b1fc5ba8 100644 --- a/apps/osmpoi/osmpoi.html +++ b/apps/osmpoi/osmpoi.html @@ -141,8 +141,8 @@ }); document.getElementById("upload").addEventListener("click", function() { var app = `var features = ${JSON.stringify(features)}; -var img_nofix = require("heatshrink").decompress(atob("mEwxH+6+s6/+AB4TB1gGFq1WlYABAgOBEQQnH68rlQRBD4orGwIkDleBAwQoBEgIABCAY4CgAjGwNbw1bmJFCDYIrGB4OwAIUAGIIrDCIICBA4WBlcxquBF4uslex2AABGYgrE2GxB4WAFoY8ClS0BPwJLCBgUAqyAGlYuCAAmGxgqDF4ZdBEIJSBHoWGwACBAANbTwRqBAYIwFqxTCAAmMF4+GlSDBq0qqotEGYQxDlVWGATBFYAJgIFYIvEJoSKBE4gADxgFESgIwC67AFF51VDQKMBFxAAErg0BGATQBYBy7D2OrlRJBgCGFLgVcGZEqOoKRFYBOGF4WymIXCqovCAQmwrYDBxgJGI4RgEYBQvBGAKlBUILnHdQaPEYQhgGwMxBgQuDRQIvCwCnBqwQCEwY/BFQeAFgQvEmJJBwOBR4dcLIQAD2J6BF4KODEAQhBwA0CSwoMBBAIxClcASAgeCRo2rDIICBOQKOBWoTLBFYYDBrdVG4NVFgK/EDQIrBF4IeCAApbBEgOydwIvBmJuFAAYJBFwIVBAAeMrlWRoIvDwNVF5AeB62xUgVVBAIsGPIRpBHoovBFwIvEXwYvHd4SPDb4ThEAob4DZoQvBDAIvEXwQkBFwpIBAQKPDCILeBwGAEYQnCdQIGDGAcq69WX4YdBKgQAE2GM1YDB2NVIgS0CABFcXwZnDFQJ6Cqy+HMQZeCGoLWBI4KDDAA46EF4VVC4LaCwK+BwBaDAAi+DAgIVCMAJeJAooGBXwusF4JMBQwLAFA4srCwVVCgK4DAQOwrYDErgQBFQJIBAQSPBra3BGIL/CF4ICBA4QoBMAhXCYg2AFwI0CR4MqI4NWRwLvDLQQAB1erD4IuBM4cxDAUxLYKDCFIdVNYT0DmJeF/x8BRgoABdwQAEmLZBGAMrQAIoBLIoAEFwi9BAATwDE4gwBAwlVDIIACq0qFwYRBLQZqClRDCbAIuDYARbCMAgZCqqnBFwgABYYMxBoIwBMAZqBFQJdCqwuEYAQsCFwexrcACYMqgAtFEAIxCAAKGBAAYMEUwIvFM4OMFoY0Bw0AC4RGCLgokD1msG4OBAgIVDler2LtDYAi3FFwgACVQQuBCQOAEQNWFYJrEfgMrwBSCdwrACqouLa4QAB2DKBCIVbRosxagOx2SuDd4ovBmLSBFxRhCrYuBAASmBAAQ4DVoeG1eGqrAGq1cCQLqBFxPXP4ImBOIYADAoOMFoIrBBAWwmKPFP4LKBLpYvCmIlBaQheDNA4ABd4z7B2OAFxmsgBVCF4xbBFo4SBla+GrZdNFwL/BWoYvHAwruCXw8xFyBeIFAIKDFoYABXw3+lYuRF44lCBQIEDXxWBFyQvJFwa+MEAIuNqx7EF4oqC2OrFwy+HqxdOFoewwAvBGwjuHAAWMla+FAwIuKlVb2OMwFVlcrqwCBqozCMAeML4WGrgTDXwsrL5IuBldbC4WBIIKmCwIzFAAI/ECYi/GMA4uBlQXKDQYzCIQITNAAOBGAwuBNIIXLGYwTRGAouCFqIAVGAJyBwIupGATRBewIrmA==")); -var img_fix = require("heatshrink").decompress(atob("mEwxH+AH4A/AH4A/AG2JnYv/FzovBGFgvuFwIvCGFQvuFwQvDGFAvuFwYvEGEwvuFwgvFGEgvuFwovGGEQvuFwwvHGEAvuFw4vIGDwvuFxAvJGDgvuFxIvKGDQvuFxQvLGDAvuFxYvMGCwvuFxgvNGCgvuFxovOGCQvuFxwvPGCAvuFx4vQGBwtOCQYvbFRwAJGCwqTGh4uMFS40LEcIA/AH4A/ACQA=")); +var img_nofix = require("heatshrink").decompress(atob("mEwhHX1nX/wAPCYOsAwtWq0rAAIEBwIiCE4/XlcqCIIfFFY2BEgcrwIGCFAIkBAAIQDHAUAEY2BreGrcxIoQbBFYwPB2ABCgAxBFYYRBAQIHCwMrmNVwIvF1kr2OwAAIzEFYmw2IPCwAtDHgUqWYJ+BJYQMCgFWQA0rFwQAEw2MFQYvDLoIhBKQI9Cw2AAQIABraeCNQIDBGAtWKYQAExgvHw0qQYNWlVVFogzCGIcqqwwCYIrABMBArBF4hNCRQInEAAeMAoiUBGAXXYAovOqoaBRgIuIAAlcGgIwCaALAOXYex1cqJIMAQwpcCrgzIlR1BSIrAJwwvC2UxC4VVF4QCE2FbAYOMBIxHCMAjAKF4IwBUoKhBc47qDR4jCEMA2BmIMCFwaKBF4WAU4NWCAQmDH4IqDwAsCF4kxJIOBwKPDrhZCAAexPQIvBRwYgCEIOAGgSWFBgIIBGIUrgCQEDwSNG1YZBAQJyBRwK1CZYIrDAYNbqo3BqosBX4gaBFYIvBDwQAFLYIkB2TuBF4MxNwoADBIIuBCoIADxlcqyNBF4eBqovIDwPW2KkCqoIBFgx5CNII9FF4IuBF4i+DF47vCR4bfCcIgFDfAbNCF4IYBF4i+CEgIuFJAICBR4YRBbwOAwAjCE4TqBAwYwDlXXqy/DDoJUCAAmwxmrAYOxqpECWgQAIri+DM4YqBPQVWXw5iDLwQ1BawJHBQYYAHHQgvCqoXBbQWBXwOALQYAEXwYEBCoRgBLxIFFAwK+F1gvBJgKGBYAoHFlYWCqoUBXAYCB2FbAYlcCAIqBJAICCR4NbW4IxBf4QvBAQIHCFAJgEK4TEGwAuBGgSPBlRHBqyOBd4ZaCAAOr1YfBFwJnDmIYCmJbBQYQpDqprCegcxLwv+PgKMFAALuCAAkxbIIwBlaABFAJZFAAguEXoIACeAYnEGAIGEqoZBAAVWlQuDCIJaDNQUqIYTYBFwbACLYRgEDIVVU4IuEAALDBmINBGAJgDNQIqBLoVWFwjACFgQuD2NbgATBlUAFoogBGIQABQwIADBgimBF4pnBxgtDGgOGgAXCIwRcFEges1g3BwIEBCocr1exdobAEW4ouEAASqCFwISBwAiBqwrBNYj8BleAKQTuFYAVVFxbXCAAOwZQIRCraNFmLUB2OyVwbvFF4MxaQIuKMIVbFwIACUwIACHAatDw2rw1VYA1WrgSBdQIuJ65/BEwJxDAAYFBxgtBFYIIC2ExR4p/BZQJdLF4UxEoLSELwZoHAALvGfYOxwAuM1kAKoQvGLYItHCQMrXw1bLpouBf4K1DF44GFdwS+HmIuQLxAoBBQYtDAAK+G/0rFyIvHEoQKBAga+KwIuSF5IuDXxggBFxtWPYgvFFQWx1YuGXw9WLpwtD2GAF4I2Edw4ACxkrXwoGBFxUqrexxmAqsrldWAQNVGYRgDxhfCw1cCYa+FlZfJFwMrrYXCwJBBUwWBGYoABH4gTEX4xgHFwMqC5QaDGYRCBCZoABwIwGFwJpBC5YzGCaIwFFwQtRACowBOQOBF1IwCaIL2BFcw")); +var img_fix = require("heatshrink").decompress(atob("mEwhH+AH4A/AH4A/AGuJnYv/FzovBGFgvuFwIvCGFQvuFwQvDGFAvuFwYvEGEwvuFwgvFGEgvuFwovGGEQvuFwwvHGEAvuFw4vIGDwvuFxAvJGDgvuFxIvKGDQvuFxQvLGDAvuFxYvMGCwvuFxgvNGCgvuFxovOGCQvuFxwvPGCAvuFx4vQGBwtOCQYvbFRwAJGCwqTGh4uMFS40LEcIA/AH4A/ACQA=")); // https://github.com/Leaflet/Leaflet/blob/master/src/geo/projection/Projection.SphericalMercator.js function project(latlong) { From b711e10d4f09293bb9a9e0bbe615777268cd1321 Mon Sep 17 00:00:00 2001 From: RenaudG <34276398+renaudgweb@users.noreply.github.com> Date: Tue, 21 Apr 2020 15:31:26 +0200 Subject: [PATCH 54/73] Update osmpoi.html --- apps/osmpoi/osmpoi.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/osmpoi/osmpoi.html b/apps/osmpoi/osmpoi.html index 3b1fc5ba8..58a182721 100644 --- a/apps/osmpoi/osmpoi.html +++ b/apps/osmpoi/osmpoi.html @@ -141,8 +141,8 @@ }); document.getElementById("upload").addEventListener("click", function() { var app = `var features = ${JSON.stringify(features)}; -var img_nofix = require("heatshrink").decompress(atob("mEwhHX1nX/wAPCYOsAwtWq0rAAIEBwIiCE4/XlcqCIIfFFY2BEgcrwIGCFAIkBAAIQDHAUAEY2BreGrcxIoQbBFYwPB2ABCgAxBFYYRBAQIHCwMrmNVwIvF1kr2OwAAIzEFYmw2IPCwAtDHgUqWYJ+BJYQMCgFWQA0rFwQAEw2MFQYvDLoIhBKQI9Cw2AAQIABraeCNQIDBGAtWKYQAExgvHw0qQYNWlVVFogzCGIcqqwwCYIrABMBArBF4hNCRQInEAAeMAoiUBGAXXYAovOqoaBRgIuIAAlcGgIwCaALAOXYex1cqJIMAQwpcCrgzIlR1BSIrAJwwvC2UxC4VVF4QCE2FbAYOMBIxHCMAjAKF4IwBUoKhBc47qDR4jCEMA2BmIMCFwaKBF4WAU4NWCAQmDH4IqDwAsCF4kxJIOBwKPDrhZCAAexPQIvBRwYgCEIOAGgSWFBgIIBGIUrgCQEDwSNG1YZBAQJyBRwK1CZYIrDAYNbqo3BqosBX4gaBFYIvBDwQAFLYIkB2TuBF4MxNwoADBIIuBCoIADxlcqyNBF4eBqovIDwPW2KkCqoIBFgx5CNII9FF4IuBF4i+DF47vCR4bfCcIgFDfAbNCF4IYBF4i+CEgIuFJAICBR4YRBbwOAwAjCE4TqBAwYwDlXXqy/DDoJUCAAmwxmrAYOxqpECWgQAIri+DM4YqBPQVWXw5iDLwQ1BawJHBQYYAHHQgvCqoXBbQWBXwOALQYAEXwYEBCoRgBLxIFFAwK+F1gvBJgKGBYAoHFlYWCqoUBXAYCB2FbAYlcCAIqBJAICCR4NbW4IxBf4QvBAQIHCFAJgEK4TEGwAuBGgSPBlRHBqyOBd4ZaCAAOr1YfBFwJnDmIYCmJbBQYQpDqprCegcxLwv+PgKMFAALuCAAkxbIIwBlaABFAJZFAAguEXoIACeAYnEGAIGEqoZBAAVWlQuDCIJaDNQUqIYTYBFwbACLYRgEDIVVU4IuEAALDBmINBGAJgDNQIqBLoVWFwjACFgQuD2NbgATBlUAFoogBGIQABQwIADBgimBF4pnBxgtDGgOGgAXCIwRcFEges1g3BwIEBCocr1exdobAEW4ouEAASqCFwISBwAiBqwrBNYj8BleAKQTuFYAVVFxbXCAAOwZQIRCraNFmLUB2OyVwbvFF4MxaQIuKMIVbFwIACUwIACHAatDw2rw1VYA1WrgSBdQIuJ65/BEwJxDAAYFBxgtBFYIIC2ExR4p/BZQJdLF4UxEoLSELwZoHAALvGfYOxwAuM1kAKoQvGLYItHCQMrXw1bLpouBf4K1DF44GFdwS+HmIuQLxAoBBQYtDAAK+G/0rFyIvHEoQKBAga+KwIuSF5IuDXxggBFxtWPYgvFFQWx1YuGXw9WLpwtD2GAF4I2Edw4ACxkrXwoGBFxUqrexxmAqsrldWAQNVGYRgDxhfCw1cCYa+FlZfJFwMrrYXCwJBBUwWBGYoABH4gTEX4xgHFwMqC5QaDGYRCBCZoABwIwGFwJpBC5YzGCaIwFFwQtRACowBOQOBF1IwCaIL2BFcw")); -var img_fix = require("heatshrink").decompress(atob("mEwhH+AH4A/AH4A/AGuJnYv/FzovBGFgvuFwIvCGFQvuFwQvDGFAvuFwYvEGEwvuFwgvFGEgvuFwovGGEQvuFwwvHGEAvuFw4vIGDwvuFxAvJGDgvuFxIvKGDQvuFxQvLGDAvuFxYvMGCwvuFxgvNGCgvuFxovOGCQvuFxwvPGCAvuFx4vQGBwtOCQYvbFRwAJGCwqTGh4uMFS40LEcIA/AH4A/ACQA=")); +var img_nofix = require("heatshrink").decompress(atob("mEwhBC/AH4AS6+sq0AgMrBo8rgICB1mBgIABAoNWAAusDYOBwWBF5IPBldWwAhCGQQJBgOBwNWqsxmIoF64AC1g2ClcGmIvKgGAwGwrcxqtWwItBFYdbw2x2APBG4IqBKgI0CLQIIBDISCBABAlBmOxAAOww1bqtVrY5BBIPVBYMxlYkBKoIFBAAJHBAoI6BQQSwIAANWmJQBAAIyCxmx6xbCBANbFwIhCwuGAAZHCBQKZBSgQvIgNWQQYACDgIHD6tcFwKBBSwIADrgFEGIJiBqASBSBFWrYvGMAIIB2OGJwJdBrYMBwArEAAWAxgwBewQvJwNVF4uMM4IvCquA68rqoqHGgQ3DUIT8BeJNVRAhgCfAWGmPXwExRoIlB2AsB2FbSwSTBAIOwQYLCBSBWFFwgvErYZBXgS+FLgoDCSIRFBwIvLC4WMMoIACqusbIKACEoYCCeAYLDwEAwLBBX5ExXgmG1eGwoCBRwL+BEQVcEYKMCAQxKBqovBC4LvOLYLwC1aoCwqGEIAR1BL4QLEqtWF5RQBF4+M62GF4QnCAAoHBeQILFrmBR5VVKwIvFA4PVw1VR4eAAAIkDA4L3CTIILBwtW1mAL48r1kxc4YADF4KPBF4gpCF4TmCeoYECraOBR5C+DAAjyB1YDB2NV1gPBQQgxDBA8xq1QF5EBV4KOEVIQvBAANbVAMrQoQAKRwREBSAJhBX4y+CLgQACFwewVQJIBmKRD2C4BxlbAwKLBrlbRwQVC1gvGq2FLIWGxiKB1YCBJwUrwRgDeAmMAYQsBrYKBlbkBMIK/Ira2CFgIyBGoOrGoQcB6+BmOAKgIyBFQVbqr0CGwMGXoReHd4aLBRQbuCBAVbJYIcBlcxSYIADYAgRBwARBCQIvGGANV1fVFIiPBTAJeCFwIABwIwBQ4SPCCIJiBKIIuBqAuIF4NWSAKRDAAJIBAAQuDAAKuBmIKBrcxqoCBDwJvCgwuJSAYtEFwMAwOBqEBFgY1D1mBqxZBFgOBBIJsBMYKOJgEBJQJdFgBaDDAIDBUIJWBFAZoEGwMxwvWwC/BMBVWWwK6BrcBEAowBJwLNCwpTBKgIABqqSBDgPV6uGL5TADFwS4GGAUGc4WMfYQABwuFAYJ5CPwOGTQIvJIgOMdQQuHXoWGL4WwGgQzCFgOr1Y8BDwKPKd4XWFxTeCLoYyEFQI6EL4IvBL5MrwGGwC7GLwkBToIlFEwKHBBAqtCRxMBwFVFxkxV4IvLX4QGBq1QF5UGgAuKlYuBKo7oCdobuDq2BFxLJBFxrlCFwwnBFgSOEXxTeBFxdVKAbuEK4erFwgEBriOKqGBFxHXFwerfoOAMAKGEXwmwxmGrdVRxMALxSMBDQNcqtWPgICBGYOFMIaaBCAIRBqAPBF5ILBRg8BgFcFYeBA4IGCA4IoCHoYsBwItKF4UrSAq7BLAgXIwErgIQDwArLGBQuBDYIZPLQIsQGAqSBLoQbUGCquDF1IA/AH4AKA==")); +var img_fix = require("heatshrink").decompress(atob("mEwhBC/AH4A/AH4A/AE0rg4vtq8PF1kHxM7gJesF4Jgrg+IF4M6MFReBF4JgqXoIvDMFJeCF4RgoLwYvDnZgmLwYvEMEpeEF4jBlmYvIMEheFF4pgjXogvGMEReGF407MEBeGF45gfg+IF5rBfLw4vHMDxeIF5BgdLxAvIMDkHFxAvJMDZeJF5JgaLxQvKnZgYLxQvLMC5eLF5bBXmYvWMCxeMF5hgVXpYvNMCheNF5s7MCReNF5xgRg+IFZNersylcHhEPmjBbLw1er1XlkHIhI0CnRgUmQqEKwKnRgIzBiBpBnUICpszryCCFiIyGM4TBRAH4A/AH4A/AH4AFA")); // https://github.com/Leaflet/Leaflet/blob/master/src/geo/projection/Projection.SphericalMercator.js function project(latlong) { From 3e55bc973ca9c95cb4887eec26bd9650e3af13a1 Mon Sep 17 00:00:00 2001 From: RenaudG <34276398+renaudgweb@users.noreply.github.com> Date: Tue, 21 Apr 2020 15:38:52 +0200 Subject: [PATCH 55/73] Update osmpoi.html --- apps/osmpoi/osmpoi.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/osmpoi/osmpoi.html b/apps/osmpoi/osmpoi.html index 58a182721..651e34e7a 100644 --- a/apps/osmpoi/osmpoi.html +++ b/apps/osmpoi/osmpoi.html @@ -141,7 +141,7 @@ }); document.getElementById("upload").addEventListener("click", function() { var app = `var features = ${JSON.stringify(features)}; -var img_nofix = require("heatshrink").decompress(atob("mEwhBC/AH4AS6+sq0AgMrBo8rgICB1mBgIABAoNWAAusDYOBwWBF5IPBldWwAhCGQQJBgOBwNWqsxmIoF64AC1g2ClcGmIvKgGAwGwrcxqtWwItBFYdbw2x2APBG4IqBKgI0CLQIIBDISCBABAlBmOxAAOww1bqtVrY5BBIPVBYMxlYkBKoIFBAAJHBAoI6BQQSwIAANWmJQBAAIyCxmx6xbCBANbFwIhCwuGAAZHCBQKZBSgQvIgNWQQYACDgIHD6tcFwKBBSwIADrgFEGIJiBqASBSBFWrYvGMAIIB2OGJwJdBrYMBwArEAAWAxgwBewQvJwNVF4uMM4IvCquA68rqoqHGgQ3DUIT8BeJNVRAhgCfAWGmPXwExRoIlB2AsB2FbSwSTBAIOwQYLCBSBWFFwgvErYZBXgS+FLgoDCSIRFBwIvLC4WMMoIACqusbIKACEoYCCeAYLDwEAwLBBX5ExXgmG1eGwoCBRwL+BEQVcEYKMCAQxKBqovBC4LvOLYLwC1aoCwqGEIAR1BL4QLEqtWF5RQBF4+M62GF4QnCAAoHBeQILFrmBR5VVKwIvFA4PVw1VR4eAAAIkDA4L3CTIILBwtW1mAL48r1kxc4YADF4KPBF4gpCF4TmCeoYECraOBR5C+DAAjyB1YDB2NV1gPBQQgxDBA8xq1QF5EBV4KOEVIQvBAANbVAMrQoQAKRwREBSAJhBX4y+CLgQACFwewVQJIBmKRD2C4BxlbAwKLBrlbRwQVC1gvGq2FLIWGxiKB1YCBJwUrwRgDeAmMAYQsBrYKBlbkBMIK/Ira2CFgIyBGoOrGoQcB6+BmOAKgIyBFQVbqr0CGwMGXoReHd4aLBRQbuCBAVbJYIcBlcxSYIADYAgRBwARBCQIvGGANV1fVFIiPBTAJeCFwIABwIwBQ4SPCCIJiBKIIuBqAuIF4NWSAKRDAAJIBAAQuDAAKuBmIKBrcxqoCBDwJvCgwuJSAYtEFwMAwOBqEBFgY1D1mBqxZBFgOBBIJsBMYKOJgEBJQJdFgBaDDAIDBUIJWBFAZoEGwMxwvWwC/BMBVWWwK6BrcBEAowBJwLNCwpTBKgIABqqSBDgPV6uGL5TADFwS4GGAUGc4WMfYQABwuFAYJ5CPwOGTQIvJIgOMdQQuHXoWGL4WwGgQzCFgOr1Y8BDwKPKd4XWFxTeCLoYyEFQI6EL4IvBL5MrwGGwC7GLwkBToIlFEwKHBBAqtCRxMBwFVFxkxV4IvLX4QGBq1QF5UGgAuKlYuBKo7oCdobuDq2BFxLJBFxrlCFwwnBFgSOEXxTeBFxdVKAbuEK4erFwgEBriOKqGBFxHXFwerfoOAMAKGEXwmwxmGrdVRxMALxSMBDQNcqtWPgICBGYOFMIaaBCAIRBqAPBF5ILBRg8BgFcFYeBA4IGCA4IoCHoYsBwItKF4UrSAq7BLAgXIwErgIQDwArLGBQuBDYIZPLQIsQGAqSBLoQbUGCquDF1IA/AH4AKA==")); +var img_nofix = require("heatshrink").decompress(atob("mEwhBC/AH4A/AGnXwMrgMrBg4KBgOBwIOBldWwNWAAmBCIOB1kBF5mBlVVCwInBqwzBAQIcBEQNVqtcFwIRB64AD1gPBlcGGYIAMFIOG2FbrdcFgVWrgHBw2x2Owqss1h0Bq0slcsGoIIClR8IQQ2BrYjBEgOGwwrC2AIB6uwlVWEgMxqo6BAAcxq2s1hsBGB1b2AAExg1CGAUxRQNWlQ9BAA1blQOCqzBMQ4KQBAAYFBF4aYBD4NVNoQAIGAJhOBoIvFxhgBAgOrmJdJwAwGeoRgMqyQGdYReBJoMqZAIBBAQ1cAgOwrZxCeZlWrmMF5ExPgIuEXYiRHMAOBL5oVDGYItB6uGqxeBFBCPDBQcqMAQuKlgvBXAWMw2rDIOxraOBLwaMEwAHCBQhQBF5jvGLoIZB6wvBwKwBLopABXgIAFq2BF5krqy+FF4OxF5ItBIgJaBBQlcCYLUBFxMBq1VRwRfEX4IvCqqCBRISSFSAQEBqumL5krwNc6orBAARMBAYOAJQIvBAB0xWAIvMXwIqBFweMAgSrB1kxwCLCABVbXwKPMgCOBFoYABLwQGBmIaBmKyCR5UxwJeBGIK/KQAOw1ereQIsCLwOMYAPXlQnBF4VcMoIFBXwdbWAKOBR5mAdgerw+G1YuBBIJgBwMxrdcGQQrCqo3C2AvBFwOBgLvMRoRdCw6XElRNBwMqmNVFoVbwDtEFwKiBXxZgCXwgECJoStB64ABGASICBoWGqsqFwUrlYuLgA9BdIex6orBlcxgwuD1gABegIyBAAaJBHgMGLpgvDraJFlgnCqwuB0wqBwIyCwIACHIdVMgOBGB1cRoQuBFQQABGAOmmLjCLAWmGQQsBFoJJBBYJgPEIIuGGAUAWwQOBwzABFYLEC6p5Cra/NF4Nb2GMFw4ABlYvCxgxCAAYrB1b2CqrANd4YuJF4YAExg2BBIIEBBAS/OF4SuBFxFWlQkELYZmBBAmGLxsAldcLpVWgxXCF44EDAANcF55hBFxSbBKwooCBQIABBASOOlcrFxuxFw+MFoYACmJQBXxouK2PV6pWEFQWx1aVGRx4uIwLqBDoNVqtWquAGIhnBGgOGwFVmOsgIvN1hdHgFbrcxq2BAwIDCmNbwwACBwI8BwMsRxodBMA2BZAWmDYJMFlgmCVAIPJGCIFBwJ3OwIpQGBCSBAYJ2OADYsCAQIupAH4A/AH4AoA")); var img_fix = require("heatshrink").decompress(atob("mEwhBC/AH4A/AH4A/AE0rg4vtq8PF1kHxM7gJesF4Jgrg+IF4M6MFReBF4JgqXoIvDMFJeCF4RgoLwYvDnZgmLwYvEMEpeEF4jBlmYvIMEheFF4pgjXogvGMEReGF407MEBeGF45gfg+IF5rBfLw4vHMDxeIF5BgdLxAvIMDkHFxAvJMDZeJF5JgaLxQvKnZgYLxQvLMC5eLF5bBXmYvWMCxeMF5hgVXpYvNMCheNF5s7MCReNF5xgRg+IFZNersylcHhEPmjBbLw1er1XlkHIhI0CnRgUmQqEKwKnRgIzBiBpBnUICpszryCCFiIyGM4TBRAH4A/AH4A/AH4AFA")); // https://github.com/Leaflet/Leaflet/blob/master/src/geo/projection/Projection.SphericalMercator.js From 00c37da578024838586fbbb0b78e91da12e2b93b Mon Sep 17 00:00:00 2001 From: RenaudG <34276398+renaudgweb@users.noreply.github.com> Date: Tue, 21 Apr 2020 15:45:31 +0200 Subject: [PATCH 56/73] Update osmpoi.html --- apps/osmpoi/osmpoi.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/osmpoi/osmpoi.html b/apps/osmpoi/osmpoi.html index 651e34e7a..0096b78a0 100644 --- a/apps/osmpoi/osmpoi.html +++ b/apps/osmpoi/osmpoi.html @@ -141,7 +141,7 @@ }); document.getElementById("upload").addEventListener("click", function() { var app = `var features = ${JSON.stringify(features)}; -var img_nofix = require("heatshrink").decompress(atob("mEwhBC/AH4A/AGnXwMrgMrBg4KBgOBwIOBldWwNWAAmBCIOB1kBF5mBlVVCwInBqwzBAQIcBEQNVqtcFwIRB64AD1gPBlcGGYIAMFIOG2FbrdcFgVWrgHBw2x2Owqss1h0Bq0slcsGoIIClR8IQQ2BrYjBEgOGwwrC2AIB6uwlVWEgMxqo6BAAcxq2s1hsBGB1b2AAExg1CGAUxRQNWlQ9BAA1blQOCqzBMQ4KQBAAYFBF4aYBD4NVNoQAIGAJhOBoIvFxhgBAgOrmJdJwAwGeoRgMqyQGdYReBJoMqZAIBBAQ1cAgOwrZxCeZlWrmMF5ExPgIuEXYiRHMAOBL5oVDGYItB6uGqxeBFBCPDBQcqMAQuKlgvBXAWMw2rDIOxraOBLwaMEwAHCBQhQBF5jvGLoIZB6wvBwKwBLopABXgIAFq2BF5krqy+FF4OxF5ItBIgJaBBQlcCYLUBFxMBq1VRwRfEX4IvCqqCBRISSFSAQEBqumL5krwNc6orBAARMBAYOAJQIvBAB0xWAIvMXwIqBFweMAgSrB1kxwCLCABVbXwKPMgCOBFoYABLwQGBmIaBmKyCR5UxwJeBGIK/KQAOw1ereQIsCLwOMYAPXlQnBF4VcMoIFBXwdbWAKOBR5mAdgerw+G1YuBBIJgBwMxrdcGQQrCqo3C2AvBFwOBgLvMRoRdCw6XElRNBwMqmNVFoVbwDtEFwKiBXxZgCXwgECJoStB64ABGASICBoWGqsqFwUrlYuLgA9BdIex6orBlcxgwuD1gABegIyBAAaJBHgMGLpgvDraJFlgnCqwuB0wqBwIyCwIACHIdVMgOBGB1cRoQuBFQQABGAOmmLjCLAWmGQQsBFoJJBBYJgPEIIuGGAUAWwQOBwzABFYLEC6p5Cra/NF4Nb2GMFw4ABlYvCxgxCAAYrB1b2CqrANd4YuJF4YAExg2BBIIEBBAS/OF4SuBFxFWlQkELYZmBBAmGLxsAldcLpVWgxXCF44EDAANcF55hBFxSbBKwooCBQIABBASOOlcrFxuxFw+MFoYACmJQBXxouK2PV6pWEFQWx1aVGRx4uIwLqBDoNVqtWquAGIhnBGgOGwFVmOsgIvN1hdHgFbrcxq2BAwIDCmNbwwACBwI8BwMsRxodBMA2BZAWmDYJMFlgmCVAIPJGCIFBwJ3OwIpQGBCSBAYJ2OADYsCAQIupAH4A/AH4AoA")); +var img_nofix = require("heatshrink").decompress(atob("mEwhBC/AH4A/AH4A/AC2swMllcrBQoHBktWwIEBlYEBqwAEgAICF6FWldbrgDBAIMrFIIhBrlbAAIIBwOsAAgsClcxF6ErrmG2GGw1cqsxrmAwuG2OxxkxFoOCq1VFANVLgIyBPI4vLq2F2OwAAQrCAgPVw0xEgVVMoQ7BwsxmOm1iUCMCIuD2GM2AvC2IuDFQIACwADCrZrCGCOBqovI2NcEAIuBTwQAHlZhCL6FVYAKQG2NV1i3BZYIpDrZiFlb1BYSFWwAvG6tbwOCmIuFF4YAC2FVwOBMCFWraBCRwReDBYIpELQOAAQQ5CqpgBF57RBFYK+C2IcBw4vBEQIwDrYEDrlbGYOMmMr64vQd4hcBX4VcF4LsGOIYGCxhMBYAKORGAhhBF4TtBAAzvFwuAwIvPlbuBXIQAE2BMBHgIoBE4QvEricBqtWF4KPOF4KICAAReCd4WBdoYAJmKPCF50lrhYCYIuxreBwUxR5RrBrmCwIABF54pCFwrkBJoMxFAKGBF4lcFwNbR4JxBX6GGFYeHSoOGSQJgBGARVBFoIqCMIWMlS+ClbvRMIbFEJ4PXwMrmIqBAARjDleB67ABFxowCYAgDBQQVbFwIAB00xGAQMDA4OCNoJdOAAWBYAex6uGNAIcBFwSvB1mCq1VFYMxqwICA4IvRDgKKDw0qwQrBPgIuBX4IoCAAmBDILQCF6AwBwBgBFwgwCldVTQKJBqtcwB1BSgXV6uAXyAvCrYuHAAMrrYuBGIQABwoGBOgWxF6SEBFwWmFwpgBF4IADxgyC2IFCR6Z5BLpHX1krLoQADLYQHEqrvRWQMrFxKOEF4eMxgyBGgVWkovRgCMH1kqZIInBLwwtCRwZfQqxdLEYQuFAQYHCraORq2BXZPVKwIABEoIGBFoYCCRwNWRyIuIquGrgfBldWwGAwqMBFYVbrlcqovSL42sksrwCsBD4QDBkoyBqsxFQINBmItRL4UrGAZdBLIIABCQ8lgAsBH4IsSGA4uBDq4wTq0xmIuqAH4A/AH4A/AH4AHA=")); var img_fix = require("heatshrink").decompress(atob("mEwhBC/AH4A/AH4A/AE0rg4vtq8PF1kHxM7gJesF4Jgrg+IF4M6MFReBF4JgqXoIvDMFJeCF4RgoLwYvDnZgmLwYvEMEpeEF4jBlmYvIMEheFF4pgjXogvGMEReGF407MEBeGF45gfg+IF5rBfLw4vHMDxeIF5BgdLxAvIMDkHFxAvJMDZeJF5JgaLxQvKnZgYLxQvLMC5eLF5bBXmYvWMCxeMF5hgVXpYvNMCheNF5s7MCReNF5xgRg+IFZNersylcHhEPmjBbLw1er1XlkHIhI0CnRgUmQqEKwKnRgIzBiBpBnUICpszryCCFiIyGM4TBRAH4A/AH4A/AH4AFA")); // https://github.com/Leaflet/Leaflet/blob/master/src/geo/projection/Projection.SphericalMercator.js From 9d678772943b6e19cdfa53113b18933f31524911 Mon Sep 17 00:00:00 2001 From: Purple-Tentacle <59914607+Purple-Tentacle@users.noreply.github.com> Date: Tue, 21 Apr 2020 16:04:56 +0200 Subject: [PATCH 57/73] ActivePedom 0.03 --- apps/activepedom/app.js | 44 ++++++++++++++++++++++++++++++++------ apps/activepedom/widget.js | 26 ++++++++++++++-------- 2 files changed, 55 insertions(+), 15 deletions(-) diff --git a/apps/activepedom/app.js b/apps/activepedom/app.js index f966530d0..0680e2d1a 100644 --- a/apps/activepedom/app.js +++ b/apps/activepedom/app.js @@ -1,8 +1,31 @@ (() => { +//Graph module, as long as modules are not added by the app loader +Modules.addCached("graph",function(){exports.drawAxes=function(b,c,a){function h(a){return e+m*(a-t)/x}function l(a){return f+g-g*(a-n)/u}var k=a.padx||0,d=a.pady||0,t=-k,w=c.length+k-1,n=(void 0!==a.miny?a.miny:a.miny=c.reduce(function(a,b){return Math.min(a,b)},c[0]))-d;c=(void 0!==a.maxy?a.maxy:a.maxy=c.reduce(function(a,b){return Math.max(a,b)},c[0]))+d;a.gridy&&(d=a.gridy,n=d*Math.floor(n/d),c=d*Math.ceil(c/d));var e=a.x||0,f=a.y||0,m=a.width||b.getWidth()-(e+1),g=a.height||b.getHeight()-(f+1);a.axes&&(null!==a.ylabel&& + (e+=6,m-=6),null!==a.xlabel&&(g-=6));a.title&&(f+=6,g-=6);a.axes&&(b.drawLine(e,f,e,f+g),b.drawLine(e,f+g,e+m,f+g));a.title&&(b.setFontAlign(0,-1),b.drawString(a.title,e+m/2,f-6));var x=w-t,u=c-n;u||(u=1);if(a.gridx){b.setFontAlign(0,-1,0);var v=a.gridx;for(d=Math.ceil((t+k)/v)*v;d<=w-k;d+=v){var r=h(d),p=a.xlabel?a.xlabel(d):d;b.setPixel(r,f+g-1);var q=b.stringWidth(p)/2;null!==a.xlabel&&r>q&&b.getWidth()>r+q&&b.drawString(p,r,f+g+2)}}if(a.gridy)for(b.setFontAlign(0,0,1),d=n;d<=c;d+=a.gridy)k=l(d), + p=a.ylabel?a.ylabel(d):d,b.setPixel(e+1,k),q=b.stringWidth(p)/2,null!==a.ylabel&&k>q&&b.getHeight()>k+q&&b.drawString(p,e-5,k+1);b.setFontAlign(-1,-1,0);return{x:e,y:f,w:m,h:g,getx:h,gety:l}};exports.drawLine=function(b,c,a){a=a||{};a=exports.drawAxes(b,c,a);var h=!0,l;for(l in c)h?b.moveTo(a.getx(l),a.gety(c[l])):b.lineTo(a.getx(l),a.gety(c[l])),h=!1;return a};exports.drawBar=function(b,c,a){a=a||{};a.padx=1;a=exports.drawAxes(b,c,a);for(var h in c)b.fillRect(a.getx(h-.5)+1,a.gety(c[h]),a.getx(h+ + .5)-1,a.gety(0));return a}}); + const storage = require("Storage"); +const SETTINGS_FILE = 'activepedom.settings.json'; var history = 86400000; // 28800000=8h 43200000=12h //86400000=24h +//return setting +function setting(key) { +//define default settings +const DEFAULTS = { + 'cMaxTime' : 1100, + 'cMinTime' : 240, + 'stepThreshold' : 30, + 'intervalResetActive' : 30000, + 'stepSensitivity' : 80, + 'stepGoal' : 10000, + 'stepLength' : 75, +}; +if (!settings) { loadSettings(); } +return (key in settings) ? settings[key] : DEFAULTS[key]; +} + //Convert ms to time function getTime(t) { date = new Date(t); @@ -58,8 +81,8 @@ function drawGraph() { filename = filename = "activepedom-" + now.getFullYear() + month + now.getDate() + ".data"; var csvFile = storage.open(filename, "r"); times = getArrayFromCSV(csvFile, 0); - first = getDate(times[0]) + " " + getTime(times[0]); - last = getDate (times[times.length-1]) + " " + getTime(times[times.length-1]); + first = getDate(times[0]) + " " + getTime(times[0]); //first entry in datafile + last = getDate (times[times.length-1]) + " " + getTime(times[times.length-1]); //last entry in datafile //free memory csvFile = undefined; times = undefined; @@ -67,21 +90,24 @@ function drawGraph() { //steps var csvFile = storage.open(filename, "r"); steps = getArrayFromCSV(csvFile, 1); + first = first + " " + steps[0] + "/" + setting('stepGoal'); + last = last + " " + steps[steps.length-1] + "/" + setting('stepGoal'); + //define y-axis grid labels stepsLastEntry = steps[steps.length-1]; if (stepsLastEntry < 1000) gridyValue = 100; - if (stepsLastEntry >= 1000 && stepsLastEntry < 10000) gridyValue = 500; + if (stepsLastEntry >= 1000 && stepsLastEntry < 10000) gridyValue = 1000; if (stepsLastEntry > 10000) gridyValue = 5000; //draw drawMenu(); - g.drawString("First: " + first, 40, 30); - g.drawString(" Last: " + last, 40, 40); + g.drawString("First: " + first, 10, 30); + g.drawString(" Last: " + last, 10, 40); require("graph").drawLine(g, steps, { //title: "Steps Counted", axes : true, gridy : gridyValue, - y : 50, //offset on screen + y : 60, //offset on screen x : 5, //offset on screen }); //free memory from big variables @@ -128,6 +154,12 @@ setWatch(function() { //BTN4 setWatch(function() { //BTN5 }, BTN5, {edge:"rising", debounce:50, repeat:true}); +//load settings +let settings; +function loadSettings() { +settings = storage.readJSON(SETTINGS_FILE, 1) || {}; +} + drawMenu(); })(); \ No newline at end of file diff --git a/apps/activepedom/widget.js b/apps/activepedom/widget.js index 7879b2056..c6bd410ce 100644 --- a/apps/activepedom/widget.js +++ b/apps/activepedom/widget.js @@ -35,16 +35,24 @@ now = new Date(); month = now.getMonth() + 1; if (month < 10) month = "0" + month; - filename = filename = "activepedom-" + now.getFullYear() + month + now.getDate() + ".data"; + filename = filename = "activepedom" + now.getFullYear() + month + now.getDate() + ".data"; dataFile = s.open(filename,"a"); - if (dataFile) dataFile.write([ - now.getTime(), - stepsCounted, - active, - stepsTooShort, - stepsTooLong, - stepsOutsideTime, - ].join(",")+"\n"); + if (dataFile) { + if (dataFile.getLength() == 0) { + stepsToWrite = 0; + } + else { + stepsToWrite = stepsCounted; + } + dataFile.write([ + now.getTime(), + stepsToWrite, + active, + stepsTooShort, + stepsTooLong, + stepsOutsideTime, + ].join(",")+"\n"); + } dataFile = undefined; } From 8dd71947bdc0f791717add161121d053e423e91c Mon Sep 17 00:00:00 2001 From: Purple-Tentacle <59914607+Purple-Tentacle@users.noreply.github.com> Date: Tue, 21 Apr 2020 16:32:15 +0200 Subject: [PATCH 58/73] Fix typo --- apps/activepedom/app.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/activepedom/app.js b/apps/activepedom/app.js index 0680e2d1a..0a9b3b93f 100644 --- a/apps/activepedom/app.js +++ b/apps/activepedom/app.js @@ -78,7 +78,7 @@ function drawGraph() { now = new Date(); month = now.getMonth() + 1; if (month < 10) month = "0" + month; - filename = filename = "activepedom-" + now.getFullYear() + month + now.getDate() + ".data"; + filename = filename = "activepedom" + now.getFullYear() + month + now.getDate() + ".data"; var csvFile = storage.open(filename, "r"); times = getArrayFromCSV(csvFile, 0); first = getDate(times[0]) + " " + getTime(times[0]); //first entry in datafile @@ -162,4 +162,4 @@ settings = storage.readJSON(SETTINGS_FILE, 1) || {}; drawMenu(); -})(); \ No newline at end of file +})(); From 8272b19bb6517b96950502ff3f422cab8e6fecea Mon Sep 17 00:00:00 2001 From: Paul Cockrell Date: Tue, 21 Apr 2020 19:38:02 +0100 Subject: [PATCH 59/73] Finish BuffGym app --- apps/buffgym/buffgym-exercise.js | 115 ++---- apps/buffgym/buffgym-icon.js | 2 +- apps/buffgym/buffgym-program-a.json | 33 ++ apps/buffgym/buffgym-program-b.json | 33 ++ apps/buffgym/buffgym-program-index.json | 10 + apps/buffgym/buffgym-program.js | 62 ++- apps/buffgym/buffgym-programs.json | 1 - apps/buffgym/buffgym-programs.json.unminified | 101 ----- apps/buffgym/buffgym-set.js | 42 +- apps/buffgym/buffgym.app.js | 373 ++++++++++-------- apps/buffgym/buffgym.png | Bin 1800 -> 7576 bytes 11 files changed, 363 insertions(+), 409 deletions(-) create mode 100644 apps/buffgym/buffgym-program-a.json create mode 100644 apps/buffgym/buffgym-program-b.json create mode 100644 apps/buffgym/buffgym-program-index.json delete mode 100644 apps/buffgym/buffgym-programs.json delete mode 100644 apps/buffgym/buffgym-programs.json.unminified mode change 100644 => 100755 apps/buffgym/buffgym.png diff --git a/apps/buffgym/buffgym-exercise.js b/apps/buffgym/buffgym-exercise.js index 99d658571..68e49be84 100644 --- a/apps/buffgym/buffgym-exercise.js +++ b/apps/buffgym/buffgym-exercise.js @@ -1,116 +1,76 @@ -const STARTED = 1; -const RESTING = 2; -const COMPLETED = 3; -const ONE_SECOND = 1000; - exports = class Exercise { - constructor(params /*{title, weight, unit, restPeriod}*/) { - const DEFAULTS = { - title: "Unknown", - weight: 0, - unit: "Kg", - restPeriod: 90, - weightIncrement: 2.5, - }; - const p = Object.assign({}, DEFAULTS, params); - - this._title = p.title; - this._weight = p.weight; - this._unit = p.unit; - this._originalRestPeriod = p.restPeriod; // Used when reseting _restPeriod - this._restPeriod = p.restPeriod; - this._weightIncrement = p.weightIncrement; - this._started = new Date(); - this._completed = false; - this._sets = []; + constructor(params) { + this.title = params.title; + this.weight = params.weight; + this.unit = params.unit; + this.restPeriod = params.restPeriod; + this.completed = false; + this.sets = []; this._restTimeout = null; this._restInterval = null; this._state = null; - } - - get title() { - return this._title; + this._originalRestPeriod = params.restPeriod; + this._weightIncrement = params.weightIncrement || 2.5; } get humanTitle() { - return `${this._title} ${this._weight}${this._unit}`; + return `${this.title} ${this.weight}${this.unit}`; } get subTitle() { - const totalSets = this._sets.length; - const uncompletedSets = this._sets.filter((set) => !set.isCompleted()).length; + const totalSets = this.sets.length; + const uncompletedSets = this.sets.filter((set) => !set.isCompleted()).length; const currentSet = (totalSets - uncompletedSets) + 1; return `Set ${currentSet} of ${totalSets}`; } - get restPeriod() { - return this._restPeriod; - } - decRestPeriod() { - this._restPeriod--; - } - - get weight() { - return this._weight; - } - - get unit() { - return this._unit; - } - - get started() { - return this._started; + this.restPeriod--; } addSet(set) { - this._sets.push(set); + this.sets.push(set); } - addSets(sets) { - sets.forEach(set => this.addSet(set)); - } - - get currentSet() { - return this._sets.filter(set => !set.isCompleted())[0]; + currentSet() { + return this.sets.filter(set => !set.isCompleted())[0]; } isLastSet() { - return this._sets.filter(set => !set.isCompleted()).length === 1; + return this.sets.filter(set => !set.isCompleted()).length === 1; } isCompleted() { - return !!this._completed; + return !!this.completed; } canSetCompleted() { - return this._sets.filter(set => set.isCompleted()).length === this._sets.length; + return this.sets.filter(set => set.isCompleted()).length === this.sets.length; } setCompleted() { if (!this.canSetCompleted()) throw "All sets must be completed"; - if (this.canProgress) this._weight += this._weightIncrement; - this._completed = true; + if (this.canProgress()) this.weight += this._weightIncrement; + this.completed = true; } - get canProgress() { + canProgress() { let completedRepsTotalSum = 0; let targetRepsTotalSum = 0; - - const completedRepsTotal = this._sets.forEach(set => completedRepsTotalSum += set.reps); - const targetRepsTotal = this._sets.forEach(set => targetRepsTotalSum += set.maxReps); + this.sets.forEach(set => completedRepsTotalSum += set.reps); + this.sets.forEach(set => targetRepsTotalSum += set.maxReps); return (targetRepsTotalSum - completedRepsTotalSum) === 0; } startRestTimer(program) { this._restTimeout = setTimeout(() => { - this.next(); - }, ONE_SECOND * this._restPeriod); + this.next(program); + }, 1000 * this.restPeriod); this._restInterval = setInterval(() => { program.emit("redraw"); - }, ONE_SECOND); + }, 1000 ); } resetRestTimer() { @@ -118,7 +78,7 @@ exports = class Exercise { clearInterval(this._restInterval); this._restTimeout = null; this._restInterval = null; - this._restPeriod = this._originalRestPeriod; + this.restPeriod = this._originalRestPeriod; } isRestTimerRunning() { @@ -129,52 +89,51 @@ exports = class Exercise { clearWatch(); setWatch(() => { - this.currentSet.incReps(); + this.currentSet().incReps(); program.emit("redraw"); }, BTN1, {repeat: true}); setWatch(program.next.bind(program), BTN2, {repeat: false}); setWatch(() => { - this.currentSet.decReps(); + this.currentSet().decReps(); program.emit("redraw"); }, BTN3, {repeat: true}); } setupRestingButtons(program) { clearWatch(); - setWatch(program.next.bind(program), BTN2, {repeat: true}); + setWatch(program.next.bind(program), BTN2, {repeat: false}); } next(program) { - global.poo = this; + const STARTED = 1; + const RESTING = 2; + const COMPLETED = 3; + switch(this._state) { case null: - console.log("XXX 1 moving null -> STARTED"); this._state = STARTED; this.setupStartedButtons(program); break; case STARTED: - console.log("XXX 2 moving STARTED -> RESTING"); this._state = RESTING; this.startRestTimer(program); this.setupRestingButtons(program); break; case RESTING: this.resetRestTimer(); - this.currentSet.setCompleted(); + this.currentSet().setCompleted(); if (this.canSetCompleted()) { - console.log("XXX 3b moving RESTING -> COMPLETED"); this._state = COMPLETED; this.setCompleted(); } else { - console.log("XXX 3a moving RESTING -> null"); this._state = null; } // As we are changing state and require it to be reprocessed // invoke the next step of program - program.next(program); + program.next(); break; default: throw "Exercise: Attempting to move to an unknown state"; diff --git a/apps/buffgym/buffgym-icon.js b/apps/buffgym/buffgym-icon.js index 949b0e45b..31764acbb 100644 --- a/apps/buffgym/buffgym-icon.js +++ b/apps/buffgym/buffgym-icon.js @@ -1 +1 @@ -require("heatshrink").decompress(atob("mEwwhC/AFEEolAC6lN7vdDCcECwPd6guVGCYuDC4cCBQMikQXQJAMjkECmcyIx4XDmUjmYvLC4XUDARHBIoIWLgATCGQdA7tEonQC5ouDDYg0BOxgSEAggwKRwgUCC6ZIDSwoXNogWDDgNCAgIWIkUEoUk6kiCgMkokipsiBIQXIki2CAgNCAoYADC5Eic4Mic4ICCAIIJCC5MzAAcykYGEAAIXOABAXTmUzGoIXVAIIXLB4SICDIovjO76PZbYR3PDI4XiI6530MIh3SC6R33C/oAOC48CCxsgC44A/ADY=")) +require("heatshrink").decompress(atob("mEwxH+ACPI5AUSADAtB5vNGFQtBAIfNF95hoF4wwoF5AwmF5BhmXYbAEF/6QbF1QwIF04qB54ADAwIwoF4oRKBoIvsB4gvZ58kkgCDFxoxaF5wuHGDQcMF5IwXDZwLDGDmlDIWlkgJDSwIABCRAwPDQohCFgIABDQIOCFwYABr4RCCQIvQDYguEAAwtFF5owJDZAvHFw4vFOYQvKFAowMBxIvFMQwvPAB4wFUQ4vJGDYvUGC4vNdgyuEGDIsNFwYwGNAgAPExAvMGIdfTIovfTpYvrfRCOkZ44ugF44NGF05gUFyQvKGIoueGKIufGJ4uhG5oupGItfr4vvAAgvlGAQvt/wrEF9oEGF841IF9QGHX0oGIAD8kAAYJOFzwEBBQoMFACA=")); \ No newline at end of file diff --git a/apps/buffgym/buffgym-program-a.json b/apps/buffgym/buffgym-program-a.json new file mode 100644 index 000000000..7ebaf3741 --- /dev/null +++ b/apps/buffgym/buffgym-program-a.json @@ -0,0 +1,33 @@ +{ + "title": "Program A", + "exercises": [ + { + "title": "Squats", + "weight": 40, + "unit": "Kg", + "sets": [5, 5, 5, 5, 5], + "restPeriod": 90 + }, + { + "title": "Overhead press", + "weight": 20, + "unit": "Kg", + "sets": [5, 5, 5, 5, 5], + "restPeriod": 90 + }, + { + "title": "Deadlift", + "weight": 20, + "unit": "Kg", + "sets": [5], + "restPeriod": 90 + }, + { + "title": "Pullups", + "weight": 0, + "unit": "Kg", + "sets": [10, 10, 10], + "restPeriod": 90 + } + ] +} \ No newline at end of file diff --git a/apps/buffgym/buffgym-program-b.json b/apps/buffgym/buffgym-program-b.json new file mode 100644 index 000000000..b93348621 --- /dev/null +++ b/apps/buffgym/buffgym-program-b.json @@ -0,0 +1,33 @@ +{ + "title": "Program B", + "exercises": [ + { + "title": "Squats", + "weight": 40, + "unit": "Kg", + "sets": [5, 5, 5, 5, 5], + "restPeriod": 90 + }, + { + "title": "Bench press", + "weight": 20, + "unit": "Kg", + "sets": [5, 5, 5, 5, 5], + "restPeriod": 90 + }, + { + "title": "Row", + "weight": 20, + "unit":"Kg", + "sets": [5, 5, 5, 5, 5], + "restPeriod": 90 + }, + { + "title": "Tricep extension", + "weight": 20, + "unit": "Kg", + "sets": [10, 10, 10], + "restPeriod": 90 + } + ] +} \ No newline at end of file diff --git a/apps/buffgym/buffgym-program-index.json b/apps/buffgym/buffgym-program-index.json new file mode 100644 index 000000000..3bb51f1b5 --- /dev/null +++ b/apps/buffgym/buffgym-program-index.json @@ -0,0 +1,10 @@ +[ + { + "title": "Program A", + "file": "buffgym-program-a.json" + }, + { + "title": "Program B", + "file": "buffgym-program-b.json" + } +] \ No newline at end of file diff --git a/apps/buffgym/buffgym-program.js b/apps/buffgym/buffgym-program.js index 956827f56..68a069da5 100644 --- a/apps/buffgym/buffgym-program.js +++ b/apps/buffgym/buffgym-program.js @@ -1,68 +1,56 @@ exports = class Program { constructor(params) { - const DEFAULTS = { - title: "Unknown", - trainDay: "", // Day of week - }; - const p = Object.assign({}, DEFAULTS, params); - - this._title = p.title; - this._trainDay = p.trainDay; - this._exercises = []; - + this.title = params.title; + this.exercises = []; + this.completed = false; this.on("redraw", redraw.bind(null, this)); } - get title() { - return `${this._title} - ${this._trainDay}`; - } - - addExercise(exercise) { - this._exercises.push(exercise); - } - addExercises(exercises) { - exercises.forEach(exercise => this.addExercise(exercise)); + exercises.forEach(exercise => this.exercises.push(exercise)); } currentExercise() { - return ( - this._exercises - .filter(exercise => !exercise.isCompleted())[0] - ); + return this.exercises.filter(exercise => !exercise.isCompleted())[0]; } canComplete() { - return ( - this._exercises - .filter(exercise => exercise.isCompleted()) - .length === this._exercises.length - ); + return this.exercises.filter(exercise => exercise.isCompleted()).length === this.exercises.length; } setCompleted() { if (!this.canComplete()) throw "All exercises must be completed"; - this._completed = true; + this.completed = true; } isCompleted() { - return !!this._completed; + return !!this.completed; + } + + toJSON() { + return { + title: this.title, + exercises: this.exercises.map(exercise => { + return { + title: exercise.title, + weight: exercise.weight, + unit: exercise.unit, + sets: exercise.sets.map(set => set.maxReps), + restPeriod: exercise.restPeriod, + }; + }), + }; } // State machine next() { - console.log("XXX Program.next"); - const exercise = this.currentExercise(); - - // All exercises are completed so mark the - // Program as comleted if (this.canComplete()) { this.setCompleted(); this.emit("redraw"); - return; } - exercise.next(this); + // Call current exercise state machine + this.currentExercise().next(this); } } \ No newline at end of file diff --git a/apps/buffgym/buffgym-programs.json b/apps/buffgym/buffgym-programs.json deleted file mode 100644 index 7551c7a47..000000000 --- a/apps/buffgym/buffgym-programs.json +++ /dev/null @@ -1 +0,0 @@ -[{"title":"Program A","exercises":[{"title":"Squats","weight":40,"unit":"Kg","sets":[5,5,5,5,5]},{"title":"Overhead press","weight":20,"unit":"Kg","sets":[5,5,5,5,5]},{"title":"Deadlift","weight":20,"unit":"Kg","sets":[5]},{"title":"Pullups","weight":0,"unit":"Kg","sets":[10,10,10]}]},{"title":"Program B","exercises":[{"title":"Squats","weight":40,"unit":"Kg","sets":[5,5,5,5,5]},{"title":"Bench press","weight":20,"unit":"Kg","sets":[5,5,5,5,5]},{"title":"Row","weight":20,"unit":"Kg","sets":[5,5,5,5,5]},{"title":"Tricep extension","weight":20,"unit":"Kg","sets":[10,10,10]}]}] \ No newline at end of file diff --git a/apps/buffgym/buffgym-programs.json.unminified b/apps/buffgym/buffgym-programs.json.unminified deleted file mode 100644 index cd005eeab..000000000 --- a/apps/buffgym/buffgym-programs.json.unminified +++ /dev/null @@ -1,101 +0,0 @@ -[ - { - "title": "Program A", - "exercises": [ - { - "title": "Squats", - "weight": 40, - "unit": "Kg", - "sets": [ - 5, - 5, - 5, - 5, - 5 - ] - }, - { - "title": "Overhead press", - "weight": 20, - "unit": "Kg", - "sets": [ - 5, - 5, - 5, - 5, - 5 - ] - }, - { - "title": "Deadlift", - "weight": 20, - "unit": "Kg", - "sets": [ - 5 - ] - }, - { - "title": "Pullups", - "weight": 0, - "unit": "Kg", - "sets": [ - 10, - 10, - 10 - ] - } - ] - }, - { - "title": "Program B", - "exercises": [ - { - "title": "Squats", - "weight": 40, - "unit": "Kg", - "sets": [ - 5, - 5, - 5, - 5, - 5 - ] - }, - { - "title": "Bench press", - "weight": 20, - "unit": "Kg", - "sets": [ - 5, - 5, - 5, - 5, - 5 - ] - }, - { - "title": "Row", - "weight": 20, - "unit":"Kg", - "sets": [ - 5, - 5, - 5, - 5, - 5 - ] - - }, - { - "title": "Tricep extension", - "weight": 20, - "unit": "Kg", - "sets": [ - 10, - 10, - 10 - ] - } - ] - } -] \ No newline at end of file diff --git a/apps/buffgym/buffgym-set.js b/apps/buffgym/buffgym-set.js index aed6df260..4bd12d7ec 100644 --- a/apps/buffgym/buffgym-set.js +++ b/apps/buffgym/buffgym-set.js @@ -1,46 +1,28 @@ exports = class Set { constructor(maxReps) { - this._minReps = 0; - this._maxReps = maxReps; - this._reps = 0; - this._completed = false; - } - - get title() { - return this._title; - } - - get weight() { - return this._weight; + this.minReps = 0; + this.maxReps = maxReps; + this.reps = 0; + this.completed = false; } isCompleted() { - return !!this._completed; + return !!this.completed; } setCompleted() { - this._completed = true; - } - - get reps() { - return this._reps; - } - - get maxReps() { - return this._maxReps; + this.completed = true; } incReps() { - if (this._completed) return; - if (this._reps >= this._maxReps) return; - - this._reps++; + if (this.completed) return; + if (this.reps >= this.maxReps) return; + this.reps++; } decReps() { - if (this._completed) return; - if (this._reps <= this._minReps) return; - - this._reps--; + if (this.completed) return; + if (this.reps <= this.minReps) return; + this.reps--; } } \ No newline at end of file diff --git a/apps/buffgym/buffgym.app.js b/apps/buffgym/buffgym.app.js index e1ab3e66b..eeabd5c29 100755 --- a/apps/buffgym/buffgym.app.js +++ b/apps/buffgym/buffgym.app.js @@ -1,177 +1,135 @@ +Bangle.setLCDMode("120x120"); + const W = g.getWidth(); const H = g.getHeight(); const RED = "#d32e29"; const PINK = "#f05a56"; const WHITE = "#ffffff"; -const Set = require("buffgym-set.js"); -const Exercise = require("buffgym-exercise.js"); -const Program = require("buffgym-program.js"); - -function centerStringX(str) { - return (W - g.stringWidth(str)) / 2; -} - -function iconIncrement() { - const img = require("heatshrink").decompress(atob("ikUxH+AA3XAAgNHCJIVMBYXQ5PC4XJ6AUJCIQQBAAoVCCQwjCAA/JCgglHA4IpJBYwTHA4RMJCY5oDJo4THKIQKET5IMGCaY7TMaKLTWajbTFJIlICgoVBFYXJYQYSGCggAGCRAVIBgw")); - return img; -} - -function iconDecrement() { - const img = require("heatshrink").decompress(atob("ikUxH+AA3XAAgNHCJIVMBYXQ5PC4XJ6AUJCIQQBAAoVCCQwjCAA/JCgglKFJADBCRYABCYQmOFAhNMKIw6FTw4LHCaY7TMaKLTWajbTFJglFCgoVBFYXJYQYSGCggAGCRAVIBgw=")); - return img; -} - -function iconOk() { - const img = require("heatshrink").decompress(atob("ikUxH+AA3XAAgNHCJIVMBYXQ5PC4XJ6AUJCIQQBAAoVCCQwjCAA/JCgglKFJADBCJQxCCYQmMIwZoDJpQMCKIg6KBYwTGFQgeHHYouCCRI7EMYTXFRhILEK5SfFRgYSIborbSbpglFCgoVBFYXJYQYSGCggAGCRAVIBgwA==")); - return img; -} - function drawMenu(params) { + const hs = require("heatshrink"); + const incImg = hs.decompress(atob("gsFwMAkM+oUA")); + const decImg = hs.decompress(atob("gsFwIEBnwCBA")); + const okImg = hs.decompress(atob("gsFwMAhGFo0A")); const DEFAULT_PARAMS = { showBTN1: false, showBTN2: false, showBTN3: false, }; const p = Object.assign({}, DEFAULT_PARAMS, params); - if (p.showBTN1) g.drawImage(iconIncrement(), W - 30, 10); - if (p.showBTN2) g.drawImage(iconOk(), W - 30, 110); - if (p.showBTN3) g.drawImage(iconDecrement(), W - 30, 210); + if (p.showBTN1) g.drawImage(incImg, W - 10, 10); + if (p.showBTN2) g.drawImage(okImg, W - 10, 60); + if (p.showBTN3) g.drawImage(decImg, W - 10, 110); } -function clearScreen() { - g.setColor(RED); - g.fillRect(0,0,W,H); -} - -function drawTitle(exercise) { - const title = exercise.humanTitle; - - g.setFont("Vector",20); - g.setColor(WHITE); - g.drawString(title, centerStringX(title), 5); -} - -function drawReps(exercise) { - const set = exercise.currentSet; +function drawSet(exercise) { + const set = exercise.currentSet(); if (set.isCompleted()) return; + g.clear(); + + // Draw exercise title g.setColor(PINK); - g.fillCircle(W / 2, H / 2, 50); + g.fillRect(15, 0, W - 15, 18); + g.setFontAlign(0, -1); + g.setFont("6x8", 1); g.setColor(WHITE); - g.setFont("Vector", 40); - g.drawString(set.reps, centerStringX(set.reps), (H - 45) / 2); - g.setFont("Vector", 15); - const note = `of ${set.maxReps}`; - g.drawString(note, centerStringX(note), (H / 2) + 25); -} - -function drawSets(exercise) { - const sets = exercise.subTitle; - + g.drawString(exercise.title, W / 2, 5); + g.setFont("6x8", 1); + g.drawString(exercise.weight + " " + exercise.unit, W / 2, 27); + // Draw completed reps counter + g.setFontAlign(0, 0); + g.setColor(PINK); + g.fillRect(15, 42, W - 15, 80); g.setColor(WHITE); - g.setFont("Vector", 15); - g.drawString(sets, centerStringX(sets), H - 25); -} + g.setFont("6x8", 5); + g.drawString(set.reps, (W / 2) + 2, (H / 2) + 1); + g.setFont("6x8", 1); + const note = `Target reps: ${set.maxReps}`; + g.drawString(note, W / 2, H - 24); + // Draw sets monitor + g.drawString(exercise.subTitle, W / 2, H - 12); -function drawSetProgress(exercise) { - drawTitle(exercise); - drawReps(exercise); - drawSets(exercise); drawMenu({showBTN1: true, showBTN2: true, showBTN3: true}); + + g.flip(); } -function drawStartNextExercise() { - const title = "Good work"; - const msg = "No need to rest\nmove straight on\nto the next exercise"; - - g.setColor(WHITE); - g.setFont("Vector", 35); - g.drawString(title, centerStringX(title), 10); - g.setFont("Vector", 15); - g.drawString(msg, 30, 150); - drawMenu({showBTN1: false, showBTN2: true, showBTN3: false}); -} - -function drawProgramCompleted() { +function drawProgDone() { const title1 = "You did"; const title2 = "GREAT!"; const msg = "That's the program\ncompleted. Now eat\nsome food and\nget plenty of rest."; clearWatch(); setWatch(Bangle.showLauncher, BTN2, {repeat: false}); - - g.setColor(WHITE); - g.setFont("Vector", 35); - g.drawString(title1, centerStringX(title1), 10); - g.setFont("Vector", 40); - g.drawString(title2, centerStringX(title2), 50); - g.setFont("Vector", 15); - g.drawString(msg, 30, 150); - drawMenu({showBTN1: false, showBTN2: true, showBTN3: false}); -} - -/* -function drawExerciseCompleted(program) { - const exercise = program.currentExercise(); - const title = exercise.canProgress? - "WELL DONE!" : - "NOT BAD!"; - const msg = exercise.canProgress? - `You weight is automatically increased\nfor ${exercise.title} to ${exercise.weight}${exercise.unit}` : - "It looks like you struggled\non a few sets, your weight will\nstay the same"; - const action = "Move straight on to the next exercise"; - - clearScreen(); - g.setColor(WHITE); - g.setFont("Vector", 20); - g.drawString(title, centerStringX(title), 10); - g.setFont("Vector", 10); - g.drawString(msg, centerStringX(msg), 180); - g.drawString(action, centerStringX(action), 210); drawMenu({showBTN2: true}); - clearWatch(); - setWatch(() => { - init(program); - }, BTN2, {repeat: false}); + g.setFontAlign(0, -1); + g.setColor(WHITE); + g.setFont("6x8", 2); + g.drawString(title1, W / 2, 10); + g.drawString(title2, W / 2, 30); + g.setFont("6x8", 1); + g.drawString(msg, (W / 2) + 3, 70); + g.flip(); +} + +function drawSetComp() { + const title = "Good work"; + const msg = "No need to rest\nmove straight on\nto the next\nexercise.Your\nweight has been\nincreased for\nnext time!"; + + g.clear(); + drawMenu({showBTN2: true}); + + g.setFontAlign(0, -1); + g.setColor(WHITE); + g.setFont("6x8", 2); + g.drawString(title, W / 2, 10); + g.setFont("6x8", 1); + g.drawString(msg, (W / 2) - 2, 45); + + g.flip(); } -*/ function drawRestTimer(program) { const exercise = program.currentExercise(); const motivation = "Take a breather.."; - clearScreen(); - drawMenu({showBTN2: true}); - - g.setColor(PINK); - g.fillCircle(W / 2, H / 2, 50); - g.setColor(WHITE); - g.setFont("Vector", 15); - g.drawString(motivation, centerStringX(motivation), 25); - g.setFont("Vector", 40); - g.drawString(exercise.restPeriod, centerStringX(exercise.restPeriod), (H - 45) / 2); - exercise.decRestPeriod(); if (exercise.restPeriod <= 0) { exercise.resetRestTimer(); - redraw(program); + program.next(); + + return; } + + g.clear(); + drawMenu({showBTN2: true}); + g.setFontAlign(0, -1); + g.setColor(PINK); + g.fillRect(15, 42, W - 15, 80); + g.setColor(WHITE); + g.setFont("6x8", 1); + g.drawString("Have a short\nrest period.", W / 2, 10); + g.setFont("6x8", 5); + g.drawString(exercise.restPeriod, (W / 2) + 2, (H / 2) - 19); + g.flip(); + + exercise.decRestPeriod(); } function redraw(program) { const exercise = program.currentExercise(); - - clearScreen(); + g.clear(); if (program.isCompleted()) { - drawProgramCompleted(program); + saveProg(program); + drawProgDone(program); return; } if (exercise.isRestTimerRunning()) { if (exercise.isLastSet()) { - drawStartNextExercise(program); + drawSetComp(program); } else { drawRestTimer(program); } @@ -179,48 +137,141 @@ function redraw(program) { return; } - drawSetProgress(exercise); + drawSet(exercise); } -function init(program) { - clearWatch(); - program.next(); -} +function drawProgMenu(programs, selProgIdx) { + g.clear(); + g.setFontAlign(0, -1); + g.setColor(WHITE); + g.setFont("6x8", 2); + g.drawString("BuffGym", W / 2, 10); -// Setup training program. This should come from file - -// Squats -function buildPrograms() { - const programsJSON = require("Storage").readJSON("buffgym-programs.json", 1); - - if (!programsJSON) throw "No programs JSON found"; - - const programs = []; - - programsJSON.forEach(programJSON => { - const program = new Program({ - title: programJSON.title, - }); - const exercises = programJSON.exercises.map(exerciseJSON => { - const exercise = new Exercise({ - title: exerciseJSON.title, - weight: exerciseJSON.weight, - unit: exerciseJSON.unit, - }); - exerciseJSON.sets.forEach(setJSON => { - exercise.addSet(new Set(setJSON)); - }); - - return exercise; - }); - program.addExercises(exercises); - programs.push(program); + g.setFont("6x8", 1); + g.setFontAlign(-1, -1); + let selectedProgram = programs[selProgIdx].title; + let yPos = 50; + programs.forEach(program => { + g.setColor("#f05a56"); + g.fillRect(0, yPos, W, yPos + 11); + g.setColor("#ffffff"); + if (selectedProgram === program.title) { + g.drawRect(0, yPos, W - 1, yPos + 11); + } + g.drawString(program.title, 10, yPos + 2); + yPos += 15; }); - - return programs; + g.flip(); } -// For this spike, just run the first program, what will -// really happen is the user picks a program to do from -// some menu on a start page. -init(buildPrograms()[0]); \ No newline at end of file +function setupMenu() { + clearWatch(); + const progs = getProgIndex(); + let selProgIdx = 0; + drawProgMenu(progs, selProgIdx); + + setWatch(()=>{ + selProgIdx--; + if (selProgIdx< 0) selProgIdx = 0; + drawProgMenu(progs, selProgIdx); + }, BTN1, {repeat: true}); + + setWatch(()=>{ + const prog = buildProg(progs[selProgIdx].file); + prog.next(); + }, BTN2, {repeat: false}); + + setWatch(()=>{ + selProgIdx++; + if (selProgIdx > progs.length - 1) selProgIdx = progs.length - 1; + drawProgMenu(progs, selProgIdx); + }, BTN3, {repeat: true}); +} + +function drawSplash() { + g.reset(); + g.setBgColor(RED); + g.clear(); + g.setColor(WHITE); + g.setFontAlign(0,-1); + g.setFont("6x8", 2); + g.drawString("BuffGym", W / 2, 10); + g.setFont("6x8", 1); + g.drawString("5x5", W / 2, 42); + g.drawString("training app", W / 2, 55); + g.drawRect(19, 38, 100, 99); + const img = require("heatshrink").decompress(atob("lkdxH+AB/I5ASQACwpB5vNFkwpBAIfNFdZZkFYwskFZAsiFZBZiVYawEFf6ETFUwsIFUYmB54ADAwIskFYoRKBoIroB4grV58kkgCDFRotWFZwqHFiwYMFZIsTC5wLDFjGlCoWlkgJDRQIABCRAsLCwodCFAIABCwIOCFQYABr4RCCQIrMC4gqEAAwpFFZosFC5ArHFQ4rFNYQrGEgosMBxIrFLQwrLAB4sFSw4rFFjYrQFi4rNbASeEFjIoJFQYsGMAgAPEQgAIGwosCRoorbA=")); + g.drawImage(img, 40, 70); + g.flip(); + + let flasher = false; + let bgCol, txtCol; + const i = setInterval(() => { + if (flasher) { + bgCol = WHITE; + txtCol = RED; + } else { + bgCol = RED; + txtCol = WHITE; + } + flasher = !flasher; + g.setColor(bgCol); + g.fillRect(0, 108, W, 120); + g.setColor(txtCol); + g.drawString("Press btn to begin", W / 2, 110); + g.flip(); + }, 250); + + setWatch(()=>{ + clearInterval(i); + setupMenu(); + }, BTN1, {repeat: false}); + + setWatch(()=>{ + clearInterval(i); + setupMenu(); + }, BTN2, {repeat: false}); + + setWatch(()=>{ + clearInterval(i); + setupMenu(); + }, BTN3, {repeat: false}); +} + +function getProgIndex() { + const progIdx = require("Storage").readJSON("buffgym-program-index.json"); + return progIdx; +} + +function buildProg(fName) { + const Set = require("buffgym-set.js"); + const Exercise = require("buffgym-exercise.js"); + const Program = require("buffgym-program.js"); + const progJSON = require("Storage").readJSON(fName); + const prog = new Program({ + title: progJSON.title, + }); + const exercises = progJSON.exercises.map(exerciseJSON => { + const exercise = new Exercise({ + title: exerciseJSON.title, + weight: exerciseJSON.weight, + unit: exerciseJSON.unit, + restPeriod: exerciseJSON.restPeriod, + }); + exerciseJSON.sets.forEach(setJSON => { + exercise.addSet(new Set(setJSON)); + }); + + return exercise; + }); + prog.addExercises(exercises); + + return prog; +} + +function saveProg(program) { + const fName = getProgIndex().find(prog => prog.title === program.title).file; + require("Storage").writeJSON(fName, program.toJSON()); +} + +drawSplash(); \ No newline at end of file diff --git a/apps/buffgym/buffgym.png b/apps/buffgym/buffgym.png old mode 100644 new mode 100755 index 93a29a4a686f172e5e6dbd2ecb2a1d3edf4751c0..9bde64cc4b4a6cbea919ae5d61fe2f01694da589 GIT binary patch literal 7576 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 Date: Tue, 21 Apr 2020 20:10:56 +0100 Subject: [PATCH 60/73] Add README --- apps/buffgym/README.md | 43 +++++++++++++++++++++++++++++++++ apps/buffgym/buffgym-scrn1.png | Bin 0 -> 4141 bytes apps/buffgym/buffgym-scrn2.png | Bin 0 -> 2801 bytes apps/buffgym/buffgym-scrn3.png | Bin 0 -> 3569 bytes apps/buffgym/buffgym-scrn4.png | Bin 0 -> 3299 bytes apps/buffgym/buffgym-scrn5.png | Bin 0 -> 4500 bytes apps/buffgym/buffgym-scrn6.png | Bin 0 -> 3912 bytes 7 files changed, 43 insertions(+) create mode 100644 apps/buffgym/README.md create mode 100755 apps/buffgym/buffgym-scrn1.png create mode 100755 apps/buffgym/buffgym-scrn2.png create mode 100755 apps/buffgym/buffgym-scrn3.png create mode 100755 apps/buffgym/buffgym-scrn4.png create mode 100755 apps/buffgym/buffgym-scrn5.png create mode 100755 apps/buffgym/buffgym-scrn6.png diff --git a/apps/buffgym/README.md b/apps/buffgym/README.md new file mode 100644 index 000000000..e9e217828 --- /dev/null +++ b/apps/buffgym/README.md @@ -0,0 +1,43 @@ +# BuffGym + +This gym training assistant trains you on the famous [Stronglifts 5x5 workout](https://stronglifts.com/5x5) program. + +## Usage + +When you start the app it will wait on a splash screen until you are ready to start the work out. Press any of the buttons to start + +![](buffgym-scrn1.png) + +You are then presented with the programs menu, use BTN1 to move up the list, and BTN3 to move down the list. Once you have made your selection, press BTN2 to select the program. + +![](buffgym-scrn2.png) + +You will now begin moving through the exercises in the program. You will see the exercise information on the display. +1. At the top is the exercise name, e.g 'Squats' +2. Next is the weight you must train +3. In the center is where you record the number of *reps* you completed (more on that shortly) +4. Below the *reps* value, is the target reps you must try to reach. +5. Below the target reps is the current set you are training, out of the total sets for the exercise. +6. The *reps* value is used to store what you achieved for the current set, you enter this after you have trained on your current set. To alter this value, use BTN1 to increase the value (it will stop at the maximum required reps) and BTN3 to decreas the value to a minimum of 0 (this is the default value). Pressing BTN2 will confirm your reps + +![](buffgym-scrn3.png) + +You will then be presented with a rest timer screen, it counts down and automatically moves to the next exercise when it reaches 0. You can cancel the timer early if you wish by pressing BTN2. If it is the last set of an exercise, you don't need to rest, so it lets you know you have completed all the sets in the exercise and can start the next exercise. + +![](buffgym-scrn4.png) +![](buffgym-scrn5.png) + +Once all exercises are done, you are presented with a pat-on-the-back screen to tell you how awesome you are. + +![](buffgym-scrn6.png) + +## Features + +* If you successfully complete all reps and sets for an exercise, it will automatically update your weights for next time +* Has a neat rest timer to make sure you are training optimally +* Doesn't require a mobile phone, most 'smart watches' are just a visual presentation of the mobile phone app, this runs purley on the watch. So why not leave your phone and its distractions out of the gym! +* Clear and simple user interface + +## Created by + +[Paul Cockrell](https://github.com/paulcockrell) April 2020. \ No newline at end of file diff --git a/apps/buffgym/buffgym-scrn1.png b/apps/buffgym/buffgym-scrn1.png new file mode 100755 index 0000000000000000000000000000000000000000..07b79386f1503317acee9ff894d8dcf4c0035bc4 GIT binary patch literal 4141 zcmdT|c{r5)yPtWC%w(Gq$}UAOue7|D>`FpP$_&DoLVCr}Vx91eB`=lHB9%}-^;X6f z#*!I^67oaJzKoF=F&axVgE9P`>0IZWf6uwDbIx_0Kc4lvzxREAzxVz5d_T{VcIxCY z+081OVKA7ilcW7<=sGVxkei^hHRk(W7)<`Blf9jLG;S_;{}r`EGDjyv$OlP)=0yqh zwnmLsl7xCoBX$n!6+C#PjxC|(n0PR(!WfRe&Ir3Ea4c~3Gs@n`Tb2jV19usE2wLE% zqY7Yy)WWO40aXQChN?2TM;ipc!;v8_FnE}c<>^!y@VAs!*?u^Jc6q^39Y8+R02v<; z==l%LIuX#oSlIu_Ks^Cta@eCkqqHmEmtQbZcegRx434l=Ti|UfkTfx05AX@mLu#?w z3=f>e7fiT*XpThIVC8Qq4NNanFWx;-i{gYbs*;&OAG!@c<>^^83@#{^a+Y3;G~(3Z z@;|^qpj|0bkocIs!CDN_)PT$H)dn8r5q4}j1x$x!3Af7q!W6ciLi)I1_jjuLggfSBaM5GG@C z!2JI9mP=%C%RHuQ4=Gwz1}@lIHwQiM1J+Yu3N=fK1q70NGzMg%CU}A&%2J?fW%ok) zgh5_GKb^ND)Gr<&!nN>YMm7P`F1^Q5Mg4xwTwjls4%{(DTlJ?p)cNY`M9G0!8}FyV zHi%mwcXh{ru+IzSg9_%y#=t4w=edaQhME0im$;!IXIVc_pq}DkJF~`IqX{X?`VE7# z$cHG-V+Jz1%6?^gTkq3COQu0(KW>gopJ>fU1?l!JLkCHZ7$wqbfQEr%*fl7IFMySu zqEF1@&_kk%{LAze1C4@yXhIH*2DB|BH~R?={ODIq`AJ{L5vdz9LHMkE0nG(}^nSMI z3*B1+|NR(TDc+%FX(|cC95qoc6GY=k0j8g(QMKmvg{j#M>1?agx8Tnb;*xr(-};UL zX~wWEa@pjZk)}~XSe$sa+>WS9DWfdbWh?32nF>3!b-F=EK-|mV>(EenPISnDrJX>d2i7ic`2Z3H; zCW_{DWB@<~=W% za#ynA>Pk2rY0TPl5hq<(|B#&yRSP78{wY`=f43zXI$Wc@$8knUz!~h<@42|vbA*7F zflJ+V|24e&6$4$i<4xPI5GMkQf}X1!FQzE)Rw>JMMILMrjQaju*R|I(*jK#{g3?$Z z-CPRcQ+dyQ;z={)Tw=cD^&U61#kiw4e1AZTv^Jt5_T9pmcemoxkHZZ7$v=Vvzm zCF;Umpx!%U{CMm29EYEJwDgHh74^8C>i6+(YhcqNzfS z{OM~`7wmc+c5-|MiFi=y5rd#ccL zt~e4i;k{HoBP=2W@fQ2~gG(2WGSWY_y;W2L;w8*h0TO5-F*bvc8q!8!_ zrxjhQ62dGm3B6)smllR7*D;opHnHk(Rg||XL4Yb&!4|7tj$d2x zvY1j%5T9Ai3|h&^C^d^7(|%%g_9yc&QPV4=eECnsIc2W38xaw*D-|5G4K%LIdKqO? zO4m<_w4~-oiGCnBlAtIb<*B!JF&+nxnZv9PF7(7RBM_Y3d@VlGOpxL4KCH!Z3rHg> zBOWpu4`Bb#Tj9UfWkc7DjIt>Sv7*JdD`~+m$Y2uh6@>7jYo>@N89(*$V(^oT6Jmd2 z%UruU-i!DqcOJbzG`%G}(_h@L5p~)uLUIXAOdTA3w)uqoxQ2ot?sL2gi@z~;CQd~3 z?G%(91mv)9#B|a`K$_huX@4VzN!>?_u0#4Py}Y!#^kgt;xe#Iy1I`Wb-Sk^E3WSUr z3T^4hJHYyMz}D3C6!6Hv;yPd(F1$iOMxStk@In;FPZ=#oT;IiDzppy&&OJhS78>D0 zNCErrL%m%qMjv*-@C2iS-Rkmnc=u~D3d^2PneSxP(#WI#=^|bsd@0gPWZ$6XrdB?ZIZKzXO?j}p=o|?4_rU+du`E2bJK_+Qdqg+fBZh6!p6wOt ztk*z&Ur|~di5&Rw-IOBc)tSg6j8UX7T#WSrOsDw=H|>KlamMxxYn*1ExI|e~H^48a zm@@8SKE1lC6`I{{6Z%TopJU_^dHqbPtSV4-`Rk5>Ruo*-ZucW?mew!2cD^e7Enp0x zVH{($;lo~774Y7>S}cFFh3eov-6ng7st$DSjIodd_GGvZk0rYh90>sg93bb*1H{ zkT*Q0@#`$sE)ezpZN9QMHl7)mWd&f9PxguT5QEVU{Z}ERSNXK^DU9e*jkr_3>^3%i zirIrS!zv@xCiuU$fE9vKSiXc`-iF#LZ+N(&fi@gh>qD5DUtEp7>bsI)c9XX4FOGD^ z5I2M_c2SU3{52I!#R71t1u+!+y5PMo=Ej4ax)TfcJX)TIE(Pmd6)K!(F823+zSFfpK86d5LI$ZlVpPfb1H)!7ys3$HjQ+p2lod~+%Wj`}oE7o;b=$y6 z^RUFZUHnzQO|C35s(x9JP8mb(#D}pXhjj3ojNW_O;ldg5R`EpOi5=It+@(A6Mk5zm zMUTm-2Oh#(gg9LXMzzIl6bEzulLp)`=?J6IA$SBGF4scdQ+%p-7iQQXVRje)B#v6j z+p+x9a7oDi;@s+j*Dd?(IAab}#XZX9P3(qr(HY6Y#6W4!In&rti?re>L>~>3ZB=~d zbakNW1l}M7GAX9tJs-s{cRo>mze8%%q4ow*l~i%za;>H$UUeE-)%26-dY^{h-NL9z(RHH_Auyc*_L0u)v$oP^?aFL! za@X87Dd|&`_k8Io0+$boTg>XjNA{Jb?LZRr-C&1DNt2H0p5iO5-nrQ{sEvojO7Ziu zBwIU3-QnFFQ2-V|4mfYNKyHJyqO?-VeXajJll=M(p~!}^KN1bv8ba~0R;`H&?&kIxJJgn*vzB((k#J1uEf~k&Ew+iX3t)oUJj7+nZ}mONf9DYq+&QR+%>&3Krg* zY^A7VyU_|RL&Ta>X*gf8VY3x`c_^v4yc*!+SPsM9O9aWQQ`ya9kF&GM=BcI|71p6k zAJZ>QUK!A4-SFh!eY6Xc6Qk^LL{Uk=oaUX=9)D2chW8YNwYjfV zL`(+JUsQf@1Ijbfqs;NEY%v zc!wEDd894#a~5*F54)w4V;_Wa5m_L%)ZpYfIK}ClAt*@yTdqgdRncXxbgec8i)djU z&Yvqu=F+vig?_x7|40E<57TY4Y@meFK&#}Bs2cheul#fOb4^R6zLr*X8`OU6TJ7`o zwWYDk>%Gf{0_VnaU*lv9vinBo zkS4rgOStraH;kiQCIOEaFN)oS@Sz^~W}F2B^3roUv|w<;Gx3M_Nzi+`L)vkbd;$iy hi4+|YO(E8$#taEfv#|m%=r;h&>F7!OlEe7Ke*rU?*>?Z{ literal 0 HcmV?d00001 diff --git a/apps/buffgym/buffgym-scrn2.png b/apps/buffgym/buffgym-scrn2.png new file mode 100755 index 0000000000000000000000000000000000000000..ec70fb79110bb029f286b66194fea8be4fe50e28 GIT binary patch literal 2801 zcmeHJT~t%q6~6c81_G&qM!*3faZNQ;$Kps?APU64A}vE?AV8rImeMlH@MAS3CI33M zqYDUQDJ}(*ahQUVhJb>^0Lf)hfhARHF+@}#%M1uyNPv(Z5<+@yANtg{K6I_l!#U^S z?C(4KoW1wA&(%{YiJN?beE|U2lyvg=r`Wpmeh|E{Ii4|h9RPe)Nym?*bMh7^KED3l zz!vc;_?1rXtTOE$w@lwq zGKKDX&lXDA&&3fCZ7Sa+4ZI@|=0SMw5pGLAEXyFI`s&)}D#jzyc76FHFaLGp$ zBzp328kK@P1H>Uj!ctZA$O|7rTjYNM##{No;WRU|Lp>I|u*1ZR6BHdN$@?({8NTXy zlg~mjB*FtX%CCq38Si+8_vcmz^}<;yqL0PNaStoji_YG9IxR&ea1QmAiIGaV1VJmR zrBma^%)CUUa^Aj*LOl++A+)U#_kw>UPVITS_{hBk^>B!I&c{przYj7z_NIw~a0xue zu(!%p_h;W^R&T5ygKytgXpdYUH?rMn+78XiZ*%FLG99l;Ni1_j{4Cx3o9;eFehV(! zidHixm{xAD)T^mQ$!l@PR`lk|Om65SL>L>%psBr+MQQD1J+TcSE|KBG;{Kq9`F*FN zc%9%JsVQfwSDQWcoZg``hQAX-?i2RCZi*pKhx1gc!weZ$JVl1p*;Nj0(!%*%vz^%!Aa3~-}7^U>M(7v z(iM6lnx=DhTTq*F;9pcWxFk-DcPxDA96YJOWf#-!0cx&Lr*%~uXP05sUbRg?&!-#4 zhz)>pQvv%T7-+~4$#G-+!RP!VoJHYk;TzNXUWrbR&%%80gPiWMQKeHapJwH%+tB^KBMlz(>hx@?mh39_RmaohvYJt2rt7&? zIe@lyRe(uK_PcK9#<0-K1YPv20X$hMbku4#l?EdnnnP1MJF(0Xu`7M*Qn_sVoL8pz z%IvZnb9!s6O^v;@AH9}ZW@EBLL-g9}@<)I&uWebmtE@BV%c8j#54IRy4TTc%a7=%I z;jeU7I0gCOYoJijats8Y0r(h8+9&zxG*RMO6t%{OP&U(i3%M%-Br8QJ6p}v%h!UrQ zVA!<2fwr51+?1Vz8X@TL6Xij1GEEejpo4#khdH&(3(!r`ds3fDU&2zjb_PCxv9G6- zwg>ndQUy*xeL1)qxrr%N)5AP?b6{4W!Hg?S(HAaWX5Zg# zI+LK1p&E5PpbXRuIUwFwRWY34VO)>(ny2FHhZ~;33i?bA0_YI2j@`k($*))LDqj2>rsu%SaG+Tkeg$b4Fn) z^{(r0IvWf3A@aw&C>JgXG0g8nC#fDZhO6z=I13FX;uC5ATPf;8SgIFz1sc#R#g8lN z@SMj5lI^2i_Y=c|je8(yoljMlK2qKn&n$l~9>hDwUl&`=SRR`nHjY`s#ah^rD(}jI z%sUO4Kbks2R=m9f30}JIgp`h(cVbrUl8oh3ASjp}$gyz=geC4mBjYeuEM)a^ojVMp z4|9DM;1}RnS!8-v^*&_vS{+{qf*Ma)cHd<@?C7g6owEn|8(ii)0f)0NT+dpa;NJ$- zeoK=~A#cC)?|-r|pKv?-@Q!nbu0Kl@rS;|LFzvNwLL<&Ir^&C|?fIqd1#~b*r_Ss0 zEF_f7BrcW&AQ$gL>%qxj%1Et~gl{Do6x3f@kIgEx5+}6mc-^lVmV2$4#!`h){!HRv zorvIT0k%w~%XwkK!p)4OWXj&C0W%-^Ry^yqyH{A0J6E`{8gZ;gFs6)`bGI_%>bqyC zNMam_=jg>3M%y8*yVwH+R#J>RP`%PR!|bJ{>*X7|L)T2!k_5X1t9kB zL@e3M=Hv_#b0k literal 0 HcmV?d00001 diff --git a/apps/buffgym/buffgym-scrn3.png b/apps/buffgym/buffgym-scrn3.png new file mode 100755 index 0000000000000000000000000000000000000000..0888fc507c229f1eb1b757770531a56ffa63b63e GIT binary patch literal 3569 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 DipYXY literal 0 HcmV?d00001 diff --git a/apps/buffgym/buffgym-scrn4.png b/apps/buffgym/buffgym-scrn4.png new file mode 100755 index 0000000000000000000000000000000000000000..3078d25dce7b2b114c17804571e16c858aaf2d7f GIT binary patch literal 3299 zcmeH~X;4#H7RSTO6M|w4FcAR*aRC((5k#D@7(g}`pxJ^5Bx<)oY(bHL>^zsYU2#Ag zv;`S)5E3BTfRF@8zy)PT36Uibki||Q1n2+)N#@zse3+@44>M&=)lAKY_g=lKbN}bu zbL#)Qb+7n%xvyMqupEIvtn~EQ>kEHnpC6Pu{B{iZH3NarqI>Rj@;?_gk>ix1`$lK) zWkdP-W$r^BYp*O@5xMhNSKbbZ)m2$x%pI!Pz(6wNw)=3?IWw%z^T(4>Q7Ywg6&?YZ zXeK#}OxkV~tdn^mAbk*JegFaKIobzbMgZ1GOi(rg*q(H*9IXZ(SI0lGR0G52W#Kpg z)vQIN905?(vcV1lh{@JZ%1c9&p?l;a3sg)UKaX;pgH zx-?!h0$gpH##>=*RN{hw?yCKLLLI2mcwj)FSXy!oP8B>nw8%cGLM7?_`cl$t)>xb@ zr1dqSLU8^xg+(4Sm>O7HHcJz%#mhn;=`pPtn?L`Z;a2m~k&b|aV^hF|)3Ko~+=RTc z;Ro`m_k!-Sr#-4aO-|9MW3*SaXH+?3j9i0;Qgxk0>G?xC>d@9@4W-*RovsL#=gf`c zxa>^(QZlwyOs)yzGo#r|W*6sNuCRmQO%$_8A%UEmJT7;2{A?OqBVSxe7bGWF7(rWy z+E}&sd1Bl@0JKp(wx*ujwAaEPy8GZUitF>#zc5^Jv~*KN^fif_1%REr6qvgbO7?MeGbio^Q`lkR&Xm>MpOTA7Vg0 zFZ~4p&M{2#1oyBzHorGLv8LzoNfl$bx|m0L0JY_I(A5YWWihq0BmEGphC1L*xoanj84gDQ zx)`FU&ZW>X82!q7ahfxi99MIq&e*_3RF~O9dm`?kWj$F5;rY(Fe0{}> zGsBFO`ayJYZc-Euc(9aAfhT~c4Nx#un+n(qBglG>VV|b3QBTw z7)p3<>(h9b_gs>q(ST}wJN6fjvW}G?bU&xuikTwK0vCnQI7m zCs<}yT;gToP!q&F*e`bFK`Wp)D7@@j4QD&dM|dXaZC%b3D*$ER4Yi{|*o##z*D5gC z*AaksEWR8G!OoSoAKeC;Zh#g4_hc}-^Aj_@-);`q06u^z%K1MUz4ai9)Xjf#&V!qc zU03QtISMytYOvh^Gy_l}+Cv1;6y}evF}lR*pM>lSRn2bm`y>$@5DI5cKD^E|y)~OH zR8Oc>+*4PF4&odWn@>6Ghh}u{jc1)0=V-dEp-ujjW;h zP*twCd&m*oh)}txQ$dd}puy5x8VWDmF<29qDz(R!2a{U%=eTzm0}PFi!H>~_5tKd! zYo_z8kAxmyG(!}T!GcfeJw<<85U{(V^j;QW73fBxxeW-4E-=yMcHYA4u#DdvWAtv< zly(p3d-EHOtu~fYWna8m_?LJouMgtukD!zqAtxeJkxx&mf= z$Les|c25ZTeGm&tDyzo@)mT63pAy2w&@~f7NWYgOLO0`raym?;JbE_$w6uEl_|(g# zEx+x49#%h&{2-00tnS~b#dH%Lx!8i3Bic4)H3=0HKaqf03nFEE8==Lao%XVSd0Z-I zL>|8CKN7bFJ3rAdH}^wIigLZptL;zwklT(#nMco69u7lR9NPleZFbz?f?J|?23q-X zV|-bU7X04p3qr6}iDSv-@MazCX+C`WIreS5S(bllWUH$YFrXD;@fb~C8y=Revv(vz z+;*LH)kSpGN6aP^7Abwt7l!yMgh@uIBoNEZocHV$_ADj{q%B&}e4?Vp-6?I|A{4H;f1YvGMVi}Mg~3So(G&#HW_pibrn}>1h@G89CPi_>{uy7st0LT*=&_Ufis<^!u7w) zF1k{{$d;>#d3^f{&wp7?4;zFte}`W(&NS$R4Nb63d41$7nE2nJMaCM`Mil<^d4kP4 z3XCz+TQ7)sCj_M1S){3^s|JH+qdK4opzh~+9YkfLV4`f?f$@M31CSQs%-f5A8Fd9B zo<{(i3jK5eQ=k|1{gA5`_{?QdiF#eu|B09E2|~2v1k9 Ky`|2S^M3`WxUwt& literal 0 HcmV?d00001 diff --git a/apps/buffgym/buffgym-scrn5.png b/apps/buffgym/buffgym-scrn5.png new file mode 100755 index 0000000000000000000000000000000000000000..b34a5b124aba6acacdcd671c2401563958faa509 GIT binary patch literal 4500 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 HT+Y7%cOZEH literal 0 HcmV?d00001 From a49397ed3dac75b38e3fd3537fe080d2a661a5a4 Mon Sep 17 00:00:00 2001 From: Paul Cockrell Date: Tue, 21 Apr 2020 20:11:32 +0100 Subject: [PATCH 61/73] Disable emulator --- apps.json | 1 + 1 file changed, 1 insertion(+) diff --git a/apps.json b/apps.json index 4eeee4e32..139192339 100644 --- a/apps.json +++ b/apps.json @@ -1302,6 +1302,7 @@ "description": "BuffGym is the famous 5x5 workout program for the BangleJS", "tags": "tool,outdoors", "type": "app", + "allow_emulator": false, "storage": [ {"name":"buffgym"}, {"name":"buffgym.app.js", "url": "buffgym.app.js"}, From 5f19c8bd80688b8f78c139b7185b5e19b2812f5d Mon Sep 17 00:00:00 2001 From: jeffmer Date: Tue, 21 Apr 2020 20:22:26 +0100 Subject: [PATCH 62/73] Update apps.json --- apps.json | 1 + 1 file changed, 1 insertion(+) diff --git a/apps.json b/apps.json index 0b7001a5e..8df240cf6 100644 --- a/apps.json +++ b/apps.json @@ -297,6 +297,7 @@ "version":"0.01", "description": "Displays GPS Course and Speed, + Directions to waypoint and waypoint recording", "tags": "tool,outdoors,gps", + "readme": "README.md", "storage": [ {"name":"gpsnav.app.js","url":"app.js"}, {"name":"waypoints.json","url":"waypoints.json","evaluate":false}, From b5fd14b4fb39e313544758f35950d9068f738fe0 Mon Sep 17 00:00:00 2001 From: Paul Cockrell Date: Tue, 21 Apr 2020 20:45:02 +0100 Subject: [PATCH 63/73] Add training programs to apps file --- apps.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps.json b/apps.json index 139192339..4b51a4689 100644 --- a/apps.json +++ b/apps.json @@ -1309,7 +1309,9 @@ {"name":"buffgym-set.js","url":"buffgym-set.js"}, {"name":"buffgym-exercise.js","url":"buffgym-exercise.js"}, {"name":"buffgym-program.js","url":"buffgym-program.js"}, - {"name":"buffgym-programs.json","url":"buffgym-programs.json"}, + {"name":"buffgym-program-a.json","url":"buffgym-program-a.json"}, + {"name":"buffgym-program-b.json","url":"buffgym-program-b.json"}, + {"name":"buffgym-program-index.json","url":"buffgym-program-index.json"}, {"name":"buffgym.img","url":"buffgym-icon.js","evaluate":true} ] } From 7e305033814aa2946c68686d82e94f85e70cbf6f Mon Sep 17 00:00:00 2001 From: Paul Cockrell Date: Tue, 21 Apr 2020 20:46:30 +0100 Subject: [PATCH 64/73] Add readme to apps.json --- apps.json | 1 + 1 file changed, 1 insertion(+) diff --git a/apps.json b/apps.json index 4b51a4689..d800050ee 100644 --- a/apps.json +++ b/apps.json @@ -1303,6 +1303,7 @@ "tags": "tool,outdoors", "type": "app", "allow_emulator": false, + "readme": "README.md", "storage": [ {"name":"buffgym"}, {"name":"buffgym.app.js", "url": "buffgym.app.js"}, From 14e209b020c0eca0e54fc591c378c8a52f1fab4b Mon Sep 17 00:00:00 2001 From: Paul Cockrell Date: Tue, 21 Apr 2020 20:47:45 +0100 Subject: [PATCH 65/73] Add tags to buffgym app in apps.json --- apps.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps.json b/apps.json index d800050ee..96f758c07 100644 --- a/apps.json +++ b/apps.json @@ -1300,7 +1300,7 @@ "icon": "buffgym.png", "version":"0.01", "description": "BuffGym is the famous 5x5 workout program for the BangleJS", - "tags": "tool,outdoors", + "tags": "tools,outdoors,gym,exercise", "type": "app", "allow_emulator": false, "readme": "README.md", From bb9747da0924adbef19929b29c833bdc707fd70d Mon Sep 17 00:00:00 2001 From: Paul Cockrell Date: Tue, 21 Apr 2020 20:51:15 +0100 Subject: [PATCH 66/73] Add app comments --- apps/buffgym/buffgym.app.js | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/apps/buffgym/buffgym.app.js b/apps/buffgym/buffgym.app.js index eeabd5c29..4dc6ffd5a 100755 --- a/apps/buffgym/buffgym.app.js +++ b/apps/buffgym/buffgym.app.js @@ -1,3 +1,14 @@ +/** + * BangleJS Stronglifts 5x5 training aid + * + * Original Author: Paul Cockrell https://github.com/paulcockrell + * Created: April 2020 + * + * Inspired by: + * - Stronglifts 5x5 training program https://stronglifts.com/5x5/ + * - Stronglifts smart watch app + */ + Bangle.setLCDMode("120x120"); const W = g.getWidth(); From 94bb31889cba0b31be983a6dcfda7d506c367fa0 Mon Sep 17 00:00:00 2001 From: Paul Cockrell Date: Tue, 21 Apr 2020 21:14:18 +0100 Subject: [PATCH 67/73] Update apps.json --- apps.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps.json b/apps.json index 96f758c07..65f0090b3 100644 --- a/apps.json +++ b/apps.json @@ -1300,7 +1300,7 @@ "icon": "buffgym.png", "version":"0.01", "description": "BuffGym is the famous 5x5 workout program for the BangleJS", - "tags": "tools,outdoors,gym,exercise", + "tags": "tool,outdoors,gym,exercise", "type": "app", "allow_emulator": false, "readme": "README.md", From 26d8855ea20bba5d7833fe331d4696f15d602e98 Mon Sep 17 00:00:00 2001 From: Richard de Boer Date: Tue, 21 Apr 2020 23:13:04 +0200 Subject: [PATCH 68/73] locale: Measure temperature in Kelvin Because that is what Gadgetbridge sends for the weather --- apps.json | 2 +- apps/locale/ChangeLog | 1 + apps/locale/locale.html | 4 ++-- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/apps.json b/apps.json index 1cacc920e..95a845f54 100644 --- a/apps.json +++ b/apps.json @@ -65,7 +65,7 @@ { "id": "locale", "name": "Languages", "icon": "locale.png", - "version":"0.06", + "version":"0.07", "description": "Translations for different countries", "tags": "tool,system,locale,translate", "type": "locale", diff --git a/apps/locale/ChangeLog b/apps/locale/ChangeLog index 3d983150d..a3cc0c9a3 100644 --- a/apps/locale/ChangeLog +++ b/apps/locale/ChangeLog @@ -6,3 +6,4 @@ Add correct scaling for speed/distance/temperature 0.06: Remove translations if not required Ensure 'on' is always supplied for translations +0.07: Measure temperature in Kelvin diff --git a/apps/locale/locale.html b/apps/locale/locale.html index 21bf37f29..936d2e9f0 100644 --- a/apps/locale/locale.html +++ b/apps/locale/locale.html @@ -112,8 +112,8 @@ exports = { name : "en_GB", currencySym:"£", `${js(locale.currency_symbol)} + n.toFixed(2)`: `n.toFixed(2) + ${js(locale.currency_symbol)}`; var temperature; - if (locale.temperature=='°C') temperature="t"; - else if (locale.temperature=='°F') temperature="(t*9/5)+32"; + if (locale.temperature=='°C') temperature="(t-273.15)"; + else if (locale.temperature=='°F') temperature="((t-273.15)*9/5)+32"; else throw new Error("Unknown temperature unit "+locale.temperature); var localeModule = `var l = ${JSON.stringify({ From 319307cdd1831b27a94b6a9150cf24e24379ae22 Mon Sep 17 00:00:00 2001 From: Richard de Boer Date: Tue, 21 Apr 2020 23:18:21 +0200 Subject: [PATCH 69/73] weather: Show Gadgetbridge weather reports Based on http://forum.espruino.com/comments/15194626/, where NebbishHacker did most of the actual work :-) --- apps.json | 17 ++++ apps/weather/app.js | 54 +++++++++++ apps/weather/icon.js | 1 + apps/weather/icon.png | Bin 0 -> 1173 bytes apps/weather/lib.js | 176 ++++++++++++++++++++++++++++++++++++ apps/weather/readme.md | 16 ++++ apps/weather/screenshot.png | Bin 0 -> 4039 bytes apps/weather/widget.js | 40 ++++++++ 8 files changed, 304 insertions(+) create mode 100644 apps/weather/app.js create mode 100644 apps/weather/icon.js create mode 100644 apps/weather/icon.png create mode 100644 apps/weather/lib.js create mode 100644 apps/weather/readme.md create mode 100644 apps/weather/screenshot.png create mode 100644 apps/weather/widget.js diff --git a/apps.json b/apps.json index 95a845f54..3921e8ae1 100644 --- a/apps.json +++ b/apps.json @@ -348,6 +348,23 @@ {"name":"files.img","url":"files-icon.js","evaluate":true} ] }, + { "id": "weather", + "name": "Weather", + "icon": "icon.png", + "version":"0.01", + "description": "Show Gadgetbridge weather report", + "readme": "readme.md", + "tags": "widget,outdoors", + "storage": [ + {"name":"weather.app.js","url":"app.js"}, + {"name":"weather.wid.js","url":"widget.js"}, + {"name":"weather","url":"lib.js"}, + {"name":"weather.img","url":"icon.js","evaluate":true} + ], + "data": [ + {"name": "weather.json"} + ] + }, { "id": "widbat", "name": "Battery Level Widget", "icon": "widget.png", diff --git a/apps/weather/app.js b/apps/weather/app.js new file mode 100644 index 000000000..fdf28f0e0 --- /dev/null +++ b/apps/weather/app.js @@ -0,0 +1,54 @@ +(() => { + function draw(w) { + g.reset(); + g.setColor(0).fillRect(0, 24, 239, 239); + + require('weather').drawIcon(w.txt, 65, 90, 55); + const locale = require("locale"); + + g.setColor(-1); + + const temp = locale.temp(w.temp).match(/^(\D*\d*)(.*)$/); + let width = g.setFont("Vector", 40).stringWidth(temp[1]); + width += g.setFont("Vector", 20).stringWidth(temp[2]); + g.setFont("Vector", 40).setFontAlign(-1, -1, 0); + g.drawString(temp[1], 180-width/2, 70); + g.setFont("Vector", 20).setFontAlign(1, -1, 0); + g.drawString(temp[2], 180+width/2, 70); + + g.setFont("6x8", 1); + g.setFontAlign(-1, 0, 0); + g.drawString("Humidity", 135, 130); + g.drawString("Wind", 135, 142); + g.setFontAlign(1, 0, 0); + g.drawString(w.hum+"%", 225, 130); + g.drawString(locale.speed(w.wind), 225, 142); + + g.setFont("6x8", 2).setFontAlign(0, 0, 0); + g.drawString(w.loc, 120, 170); + + g.setFont("6x8", 1).setFontAlign(0, 0, 0); + g.drawString(w.txt.charAt(0).toUpperCase()+w.txt.slice(1), 120, 190); + + g.flip(); + } + + const _GB = global.GB; + global.GB = (event) => { + if (event.t==="weather") draw(event); + if (_GB) setTimeout(_GB, 0, event); + }; + + Bangle.loadWidgets(); + Bangle.drawWidgets(); + + const weather = require('weather').load(); + if (weather) { + draw(weather); + } else { + E.showMessage('Weather unknown\n\nIs Gadgetbridge\nconnected?'); + } + + // Show launcher when middle button pressed + setWatch(Bangle.showLauncher, BTN2, {repeat: false, edge: 'falling'}) +})() diff --git a/apps/weather/icon.js b/apps/weather/icon.js new file mode 100644 index 000000000..18ca2b0c9 --- /dev/null +++ b/apps/weather/icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwwhC/AE8N6AXV7vdFyoXBGCQUBAAoXp73u93tC6YWBAAIXSFwQwDRiAWDGASSBmYABIx5IDgYXCmC7KCoYRBnvUCwQwKC4gSEAAgwKC5gwKCwPjC6inBC6owBC6wVKPBXd6YXMDBAuNJJQXWfwZITC/6QIBw073ezR6m73anOJAwuHeBAYFIw4WJAAsL3YQOAAxeBCiWIC4e72AJChGACpMIxAXBIwIwEBIIXKBgouDEIYuLC4ghEC6ELLoYXPU4YXFLxQNBBgcLEQqqQFwYA/AH4AYA==")) diff --git a/apps/weather/icon.png b/apps/weather/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..bbfc0ace0b8d25c4afefcb336ea04df799a70f22 GIT binary patch literal 1173 zcmV;G1Zw+fgKelF z+6!B~5F)8y)e1%MqEWnPiWg$RgkaGND+=ED(@M!jy(#RCC2ci@HZ&m;H8wSEeq1-3 zna_*eO*h%I$(hL}OJN@v*!|9#@4WBKnQzV+C{Un)Z={DV>E%eib@(DFUXn-NOejAm zNe^8p4lfCJt4`j{fhJF^Xh3?ARSnST?;@FEt!47{!1jEGWkFpPY~BdvcO+sr|AoPp7;j(Z^c9nYrv8 zkRG}g{?t`1FFr+i3Dj4?(4UDMy&OqZr_)1HX<73JfL%aC@{G&CN!PWHJ+npq?bSfm z3XxGNw?6LPs7g_(j(pdPtX6NkmEpEmb0c6>eVOf?QhKnNuV{Lt@F=40(L-~ zBr4U6#P%`av@$0Zg!qTMN57+X49^FVjkbLQP)KEm&RPQbv6&-%R5y%N$)W|^G z3HAX4eumxfNt%QZOugspBgMdEG}xzWFfy>SLB*_~-Ht~Sp@@Yn(5USLDV>K=tk6T&Gr@s zpI_!oxJY!Hg>_~@60*CA@DI5jXU)oJfI#||^z>SYhgIBx&7a<=4-nV|vaT9J`>ZY?00000NkvXXu0mjfi9tF% literal 0 HcmV?d00001 diff --git a/apps/weather/lib.js b/apps/weather/lib.js new file mode 100644 index 000000000..f87984fe5 --- /dev/null +++ b/apps/weather/lib.js @@ -0,0 +1,176 @@ +exports = { + save: weather => { + let json = require('Storage').readJSON('weather.json')||{} + json.weather = Object.assign({}, weather) // don't mutate GB events + delete json.weather.t // don't save the event type (if present) + require('Storage').write('weather.json', json) + }, + load: () => { + let json = require('Storage').readJSON('weather.json')||{} + return json.weather + }, + drawIcon: (cond, x, y, r) => { + function drawSun(x, y, r) { + g.setColor("#FF7700"); + g.fillCircle(x, y, r); + } + + function drawCloud(x, y, r, c) { + const u = r/12; + if (c==null) c = "#EEEEEE"; + g.setColor(c); + g.fillCircle(x-8*u, y+3*u, 4*u); + g.fillCircle(x-4*u, y-2*u, 5*u); + g.fillCircle(x+4*u, y+0*u, 4*u); + g.fillCircle(x+9*u, y+4*u, 3*u); + g.fillPoly([ + x-8*u, y+7*u, + x-8*u, y+3*u, + x-4*u, y-2*u, + x+4*u, y+0*u, + x+9*u, y+4*u, + x+9*u, y+7*u, + ]); + } + + function drawBrokenClouds(x, y, r) { + drawCloud(x+1/8*r, y-1/8*r, 7/8*r, "#777777"); + drawCloud(x-1/8*r, y+1/8*r, 7/8*r); + } + + function drawFewClouds(x, y, r) { + drawSun(x+3/8*r, y-1/8*r, 5/8*r); + drawCloud(x-1/8*r, y+1/8*r, 7/8*r); + } + + function drawRainLines(x, y, r) { + g.setColor("#FFFFFF"); + const y1 = y+1/2*r; + const y2 = y+1*r; + g.fillPoly([ + x-6/12*r+1, y1, + x-8/12*r+1, y2, + x-7/12*r, y2, + x-5/12*r, y1, + ]); + g.fillPoly([ + x-2/12*r+1, y1, + x-4/12*r+1, y2, + x-3/12*r, y2, + x-1/12*r, y1, + ]); + g.fillPoly([ + x+2/12*r+1, y1, + x+0/12*r+1, y2, + x+1/12*r, y2, + x+3/12*r, y1, + ]); + } + + function drawShowerRain(x, y, r) { + drawFewClouds(x, y-1/3*r, r); + drawRainLines(x, y, r); + } + + function drawRain(x, y, r) { + drawBrokenClouds(x, y-1/3*r, r); + drawRainLines(x, y, r); + } + + function drawThunderstorm(x, y, r) { + function drawLightning(x, y, r) { + g.setColor("#FF7700"); + g.fillPoly([ + x-2/6*r, y-r, + x-4/6*r, y+1/6*r, + x-1/6*r, y+1/6*r, + x-3/6*r, y+1*r, + x+3/6*r, y-1/6*r, + x+0/6*r, y-1/6*r, + x+3/6*r, y-r, + ]); + } + + drawBrokenClouds(x, y-1/3*r, r); + drawLightning(x-1/12*r, y+1/2*r, 1/2*r); + } + + function drawSnow(x, y, r) { + function rotatePoints(points, pivotX, pivotY, angle) { + for(let i = 0; i {}; + condition = condition.toLowerCase(); + if (condition.includes("thunderstorm")) return drawThunderstorm; + if (condition.includes("freezing")||condition.includes("snow")|| + condition.includes("sleet")) { + return drawSnow; + } + if (condition.includes("drizzle")|| + condition.includes("shower")) { + return drawRain; + } + if (condition.includes("rain")) return drawShowerRain; + if (condition.includes("clear")) return drawSun; + if (condition.includes("few clouds")) return drawFewClouds; + if (condition.includes("scattered clouds")) return drawCloud; + if (condition.includes("clouds")) return drawBrokenClouds; + return drawMist; + } + + chooseIcon(cond)(x, y, r) + }, +} diff --git a/apps/weather/readme.md b/apps/weather/readme.md new file mode 100644 index 000000000..a326b67dd --- /dev/null +++ b/apps/weather/readme.md @@ -0,0 +1,16 @@ +# Weather + +Shows Gadgetbridge weather reports. + +This adds a widget with a weather pictogram and the temperature. +You can view the full report through the app: +![Screenshot](screenshot.png) + +## Setup + +See [this guide](https://codeberg.org/Freeyourgadget/Gadgetbridge/wiki/Weather) +to setup Gadgetbridge weather reporting. + +## Controls + +BTN2: opens the launcher diff --git a/apps/weather/screenshot.png b/apps/weather/screenshot.png new file mode 100644 index 0000000000000000000000000000000000000000..ce79b3b646bfebdad6c29f57779c018ce0ce457e GIT binary patch literal 4039 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 Fe*nCRR)+up literal 0 HcmV?d00001 diff --git a/apps/weather/widget.js b/apps/weather/widget.js new file mode 100644 index 000000000..7488b7657 --- /dev/null +++ b/apps/weather/widget.js @@ -0,0 +1,40 @@ +(() => { + function draw() { + const w = require('weather').load() + if (!w) return; + g.reset(); + g.setColor(0).fillRect(this.x, this.y, this.x+this.width, this.y+24) + if (w.txt) { + require('weather').drawIcon(w.txt, this.x+10, this.y+8, 8); + } + if (w.temp) { + let t = require('locale').temp(w.temp); // applies conversion + t = t.substr(0, t.length-2); // but we have no room for units + g.setFontAlign(0, 1); // center horizontally at bottom of widget + g.setFont('6x8', 1); + g.setColor(-1) + g.drawString(t, this.x+10, this.y+24) + } + } + + function update(weather) { + require('weather').save(weather); + if (!WIDGETS["weather"].width) { + WIDGETS["weather"].width = 20 + Bangle.drawWidgets() + } else if (Bangle.isLCDOn()) { + WIDGETS["weather"].draw() + } + } + + const _GB = global.GB; + global.GB = (event) => { + if (event.t==="weather") update(event); + if (_GB) setTimeout(_GB, 0, event); + }; + + WIDGETS["weather"] = {area: "tl", width: 20, draw: draw}; + if (!require('weather').load()) { + WIDGETS["weather"].width = 0 + } +})(); From 06fc54f83171cf175af359e2113cc239e24cad4c Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Wed, 22 Apr 2020 08:56:50 +0100 Subject: [PATCH 70/73] oops - fix sanity check errors --- apps.json | 3 +-- apps/buffgym/buffgym-icon.js | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/apps.json b/apps.json index 70fb6cac7..84b8fb643 100644 --- a/apps.json +++ b/apps.json @@ -1332,7 +1332,6 @@ "allow_emulator": false, "readme": "README.md", "storage": [ - {"name":"buffgym"}, {"name":"buffgym.app.js", "url": "buffgym.app.js"}, {"name":"buffgym-set.js","url":"buffgym-set.js"}, {"name":"buffgym-exercise.js","url":"buffgym-exercise.js"}, @@ -1438,7 +1437,7 @@ { "id": "osmpoi", "name": "POI Compass", "icon": "app.png", - "version":"0.01", + "version":"0.02", "description": "Uploads all the points of interest in an area onto your watch, same as Beer Compass with more p.o.i.", "tags": "tool,outdoors,gps", "custom": "osmpoi.html", diff --git a/apps/buffgym/buffgym-icon.js b/apps/buffgym/buffgym-icon.js index 31764acbb..523ed35b6 100644 --- a/apps/buffgym/buffgym-icon.js +++ b/apps/buffgym/buffgym-icon.js @@ -1 +1 @@ -require("heatshrink").decompress(atob("mEwxH+ACPI5AUSADAtB5vNGFQtBAIfNF95hoF4wwoF5AwmF5BhmXYbAEF/6QbF1QwIF04qB54ADAwIwoF4oRKBoIvsB4gvZ58kkgCDFxoxaF5wuHGDQcMF5IwXDZwLDGDmlDIWlkgJDSwIABCRAwPDQohCFgIABDQIOCFwYABr4RCCQIvQDYguEAAwtFF5owJDZAvHFw4vFOYQvKFAowMBxIvFMQwvPAB4wFUQ4vJGDYvUGC4vNdgyuEGDIsNFwYwGNAgAPExAvMGIdfTIovfTpYvrfRCOkZ44ugF44NGF05gUFyQvKGIoueGKIufGJ4uhG5oupGItfr4vvAAgvlGAQvt/wrEF9oEGF841IF9QGHX0oGIAD8kAAYJOFzwEBBQoMFACA=")); \ No newline at end of file +require("heatshrink").decompress(atob("mEwxH+ACPI5AUSADAtB5vNGFQtBAIfNF95hoF4wwoF5AwmF5BhmXYbAEF/6QbF1QwIF04qB54ADAwIwoF4oRKBoIvsB4gvZ58kkgCDFxoxaF5wuHGDQcMF5IwXDZwLDGDmlDIWlkgJDSwIABCRAwPDQohCFgIABDQIOCFwYABr4RCCQIvQDYguEAAwtFF5owJDZAvHFw4vFOYQvKFAowMBxIvFMQwvPAB4wFUQ4vJGDYvUGC4vNdgyuEGDIsNFwYwGNAgAPExAvMGIdfTIovfTpYvrfRCOkZ44ugF44NGF05gUFyQvKGIoueGKIufGJ4uhG5oupGItfr4vvAAgvlGAQvt/wrEF9oEGF841IF9QGHX0oGIAD8kAAYJOFzwEBBQoMFACA=")) From 6d07882eae4bb6a8b4d17c7bdac38c9ec6cbe0af Mon Sep 17 00:00:00 2001 From: Richard de Boer Date: Wed, 22 Apr 2020 10:59:00 +0200 Subject: [PATCH 71/73] Revert "locale: Measure temperature in Kelvin" This reverts commit 26d8855e --- apps.json | 2 +- apps/locale/ChangeLog | 1 - apps/locale/locale.html | 4 ++-- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/apps.json b/apps.json index 3921e8ae1..3a76c645b 100644 --- a/apps.json +++ b/apps.json @@ -65,7 +65,7 @@ { "id": "locale", "name": "Languages", "icon": "locale.png", - "version":"0.07", + "version":"0.06", "description": "Translations for different countries", "tags": "tool,system,locale,translate", "type": "locale", diff --git a/apps/locale/ChangeLog b/apps/locale/ChangeLog index a3cc0c9a3..3d983150d 100644 --- a/apps/locale/ChangeLog +++ b/apps/locale/ChangeLog @@ -6,4 +6,3 @@ Add correct scaling for speed/distance/temperature 0.06: Remove translations if not required Ensure 'on' is always supplied for translations -0.07: Measure temperature in Kelvin diff --git a/apps/locale/locale.html b/apps/locale/locale.html index 936d2e9f0..21bf37f29 100644 --- a/apps/locale/locale.html +++ b/apps/locale/locale.html @@ -112,8 +112,8 @@ exports = { name : "en_GB", currencySym:"£", `${js(locale.currency_symbol)} + n.toFixed(2)`: `n.toFixed(2) + ${js(locale.currency_symbol)}`; var temperature; - if (locale.temperature=='°C') temperature="(t-273.15)"; - else if (locale.temperature=='°F') temperature="((t-273.15)*9/5)+32"; + if (locale.temperature=='°C') temperature="t"; + else if (locale.temperature=='°F') temperature="(t*9/5)+32"; else throw new Error("Unknown temperature unit "+locale.temperature); var localeModule = `var l = ${JSON.stringify({ From c3940972b58039afc7a60df46a49b512f3ab3b54 Mon Sep 17 00:00:00 2001 From: Richard de Boer Date: Wed, 22 Apr 2020 11:00:16 +0200 Subject: [PATCH 72/73] weather: Convert Gadgetbridge temperature from Kelvin to Celsius --- apps/weather/app.js | 2 +- apps/weather/widget.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/weather/app.js b/apps/weather/app.js index fdf28f0e0..8493144f7 100644 --- a/apps/weather/app.js +++ b/apps/weather/app.js @@ -8,7 +8,7 @@ g.setColor(-1); - const temp = locale.temp(w.temp).match(/^(\D*\d*)(.*)$/); + const temp = locale.temp(w.temp-273.15).match(/^(\D*\d*)(.*)$/); let width = g.setFont("Vector", 40).stringWidth(temp[1]); width += g.setFont("Vector", 20).stringWidth(temp[2]); g.setFont("Vector", 40).setFontAlign(-1, -1, 0); diff --git a/apps/weather/widget.js b/apps/weather/widget.js index 7488b7657..e02591543 100644 --- a/apps/weather/widget.js +++ b/apps/weather/widget.js @@ -8,7 +8,7 @@ require('weather').drawIcon(w.txt, this.x+10, this.y+8, 8); } if (w.temp) { - let t = require('locale').temp(w.temp); // applies conversion + let t = require('locale').temp(w.temp-273.15); // applies conversion t = t.substr(0, t.length-2); // but we have no room for units g.setFontAlign(0, 1); // center horizontally at bottom of widget g.setFont('6x8', 1); From bf5bf91967eb37d703533ce775f57aa8b31696f8 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Wed, 22 Apr 2020 13:17:31 +0100 Subject: [PATCH 73/73] mclock: Improve performance, attempt to remove occasional glitch when LCD on (fix #279) --- apps.json | 2 +- apps/mclock/ChangeLog | 1 + apps/mclock/clock-morphing.js | 107 ++++++++++++++++++++-------------- 3 files changed, 66 insertions(+), 44 deletions(-) diff --git a/apps.json b/apps.json index 837b94669..65b681390 100644 --- a/apps.json +++ b/apps.json @@ -108,7 +108,7 @@ { "id": "mclock", "name": "Morphing Clock", "icon": "clock-morphing.png", - "version":"0.03", + "version":"0.04", "description": "7 segment clock that morphs between minutes and hours", "tags": "clock", "type":"clock", diff --git a/apps/mclock/ChangeLog b/apps/mclock/ChangeLog index e6a689e9e..4bc1ea352 100644 --- a/apps/mclock/ChangeLog +++ b/apps/mclock/ChangeLog @@ -1,2 +1,3 @@ 0.02: Modified for use with new bootloader and firmware 0.03: Added Locale based date +0.04: Improve performance, attempt to remove occasional glitch when LCD on (fix #279) diff --git a/apps/mclock/clock-morphing.js b/apps/mclock/clock-morphing.js index ce30ad033..e9365db52 100644 --- a/apps/mclock/clock-morphing.js +++ b/apps/mclock/clock-morphing.js @@ -1,14 +1,15 @@ var locale = require("locale"); +var CHARW = 34; // how tall are digits? +var CHARP = 2; // how chunky are digits? +var Y = 50; // start height // Offscreen buffer -var buf = Graphics.createArrayBuffer(240,86,1,{msb:true}); -function flip() { - g.setColor(1,1,1); - g.drawImage({width:buf.getWidth(),height:buf.getHeight(),buffer:buf.buffer},0,50); -} +var buf = Graphics.createArrayBuffer(CHARW+CHARP*2,CHARW*2 + CHARP*2,1,{msb:true}); +var bufimg = {width:buf.getWidth(),height:buf.getHeight(),buffer:buf.buffer}; // The last time that we displayed var lastTime = " "; // If animating, this is the interval's id var animInterval; +var timeInterval; /* Get array of lines from digit d to d+1. n is the amount (0..1) @@ -49,7 +50,7 @@ const DIGITS = { [0,1,1,1], [1,1,1,2], [1-n,2,1,2]], -"5": (n,maxFive)=>maxFive ? [ // 5 -> 0 +"5to0": n=>[ // 5 -> 0 [0,0,0,1], [0,0,1,0], [n,1,1,1], @@ -57,7 +58,8 @@ const DIGITS = { [0,2,1,2], [0,2,0,2], [1,1-n,1,1], -[0,1,0,1+n]] : [ // 5 -> 6 +[0,1,0,1+n]], +"5to6": n=>[ // 5 -> 6 [0,0,0,1], [0,0,1,0], [0,1,1,1], @@ -109,59 +111,66 @@ const DIGITS = { /* Draw a transition between lastText and thisText. 'n' is the amount - 0..1 */ -function draw(lastText,thisText,n) { - buf.clear(); - var x = 1; // x offset - const p = 2; // padding around digits - var y = p; // y offset - const s = 34; // character size +function drawDigits(lastText,thisText,n) { + const p = CHARP; // padding around digits + const s = CHARW; // character size + var x = 0; // x offset + g.reset(); for (var i=0;i{ + if (c[0]!=c[2]) // horiz + buf.fillRect(p+c[0]*s,c[1]*s,p+c[2]*s,2*p+c[3]*s); + else if (c[1]!=c[3]) // vert + buf.fillRect(c[0]*s,p+c[1]*s,2*p+c[2]*s,p+c[3]*s); + }); + g.drawImage(bufimg,x,Y); } - var l = DIGITS[ch](chn,lastCh==5 && thisCh==0); - l.forEach(c=>{ - if (c[0]!=c[2]) // horiz - buf.fillRect(x+c[0]*s,y+c[1]*s-p,x+c[2]*s,y+c[3]*s+p); - else if (c[1]!=c[3]) // vert - buf.fillRect(x+c[0]*s-p,y+c[1]*s,x+c[2]*s+p,y+c[3]*s); - }); if (thisCh==":") x-=4; x+=s+p+7; } - y += 2*s; +} +function drawSeconds() { + var x = (CHARW + CHARP + 6)*5; + var y = Y + 2*CHARW + CHARP; var d = new Date(); - buf.setFont("6x8"); - buf.setFontAlign(-1,-1); - buf.drawString(("0"+d.getSeconds()).substr(-2), x, y-8); + g.reset(); + g.setFont("6x8"); + g.setFontAlign(-1,-1); + g.drawString(("0"+d.getSeconds()).substr(-2), x, y-8, true); // date - buf.setFontAlign(0,-1); + g.setFontAlign(0,-1); var date = locale.date(d,false); - buf.drawString(date, buf.getWidth()/2, y+8); - flip(); + g.drawString(date, g.getWidth()/2, y+8, true); } /* Show the current time, and animate if needed */ function showTime() { - if (!Bangle.isLCDOn()) return; if (animInterval) return; // in animation - quit var d = new Date(); var t = (" "+d.getHours()).substr(-2)+":"+ ("0"+d.getMinutes()).substr(-2); var l = lastTime; // same - don't animate - if (t==l) { - draw(t,l,0); + if (t==l || l==" ") { + drawDigits(l,t,0); + drawSeconds(); + lastTime = t; return; } var n = 0; @@ -170,23 +179,35 @@ function showTime() { if (n>=1) { n=1; clearInterval(animInterval); - animInterval=0; + animInterval = undefined; } - draw(l,t,n); + drawDigits(l,t,n); }, 20); lastTime = t; } Bangle.on('lcdPower',function(on) { - if (on) + if (animInterval) { + clearInterval(animInterval); + animInterval = undefined; + } + if (timeInterval) { + clearInterval(timeInterval); + timeInterval = undefined; + } + if (on) { showTime(); + timeInterval = setInterval(showTime, 1000); + } else { + lastTime = " "; + } }); g.clear(); Bangle.loadWidgets(); Bangle.drawWidgets(); // Update time once a second -setInterval(showTime, 1000); +timeInterval = setInterval(showTime, 1000); showTime(); // Show launcher when middle button pressed