diff --git a/apps/accellog/ChangeLog b/apps/accellog/ChangeLog index 94241c7a7..45469da5c 100644 --- a/apps/accellog/ChangeLog +++ b/apps/accellog/ChangeLog @@ -3,3 +3,4 @@ 0.03: Exit as first menu option, dont show decimal places for seconds 0.04: Localisation, change Exit->Back to allow back-arrow to appear on 2v13 firmware 0.05: Add max G values during recording, record actual G values and magnitude to CSV +0.06: Convert Yes/No On/Off in settings to checkboxes diff --git a/apps/accellog/app.js b/apps/accellog/app.js index 147f7503f..ee82f435f 100644 --- a/apps/accellog/app.js +++ b/apps/accellog/app.js @@ -26,8 +26,7 @@ function showMenu() { viewLogs(); }, /*LANG*/"Log raw data" : { - value : logRawData, - format : v => v?/*LANG*/"Yes":/*LANG*/"No", + value : !!logRawData, onchange : v => { logRawData=v; } }, }; diff --git a/apps/accellog/metadata.json b/apps/accellog/metadata.json index 903c57903..907828c7f 100644 --- a/apps/accellog/metadata.json +++ b/apps/accellog/metadata.json @@ -2,7 +2,7 @@ "id": "accellog", "name": "Acceleration Logger", "shortName": "Accel Log", - "version": "0.05", + "version": "0.06", "description": "Logs XYZ acceleration data to a CSV file that can be downloaded to your PC", "icon": "app.png", "tags": "outdoor", diff --git a/apps/activityreminder/ChangeLog b/apps/activityreminder/ChangeLog index 3811425ac..76f0945c8 100644 --- a/apps/activityreminder/ChangeLog +++ b/apps/activityreminder/ChangeLog @@ -8,3 +8,4 @@ 0.08: Use default Bangle formatter for booleans 0.09: New app screen (instead of showing settings or the alert) and some optimisations 0.10: Add software back button via setUI +0.11: Add setting to unlock screen diff --git a/apps/activityreminder/alert.js b/apps/activityreminder/alert.js index 96a9b76c4..8b359a073 100644 --- a/apps/activityreminder/alert.js +++ b/apps/activityreminder/alert.js @@ -26,6 +26,12 @@ if (!(storage.readJSON('setting.json', 1) || {}).quiet) { Bangle.buzz(400); } + + if ((storage.readJSON('activityreminder.s.json', 1) || {}).unlock) { + Bangle.setLocked(false); + Bangle.setLCDPower(1); + } + setTimeout(load, 20000); } @@ -34,4 +40,4 @@ Bangle.drawWidgets(); run(); -})(); \ No newline at end of file +})(); diff --git a/apps/activityreminder/metadata.json b/apps/activityreminder/metadata.json index a7fb0c487..a5df15a26 100644 --- a/apps/activityreminder/metadata.json +++ b/apps/activityreminder/metadata.json @@ -3,7 +3,7 @@ "name": "Activity Reminder", "shortName":"Activity Reminder", "description": "A reminder to take short walks for the ones with a sedentary lifestyle", - "version":"0.10", + "version":"0.11", "icon": "app.png", "type": "app", "tags": "tool,activity", diff --git a/apps/activityreminder/settings.js b/apps/activityreminder/settings.js index 051c0dcd8..28082a8a0 100644 --- a/apps/activityreminder/settings.js +++ b/apps/activityreminder/settings.js @@ -75,7 +75,14 @@ settings.tempThreshold = v; activityreminder.writeSettings(settings); } - } + }, + 'Unlock on alarm': { + value: !!settings.unlock, + onchange: v => { + settings.unlock = v; + activityreminder.writeSettings(settings); + } + }, }; return mainMenu; diff --git a/apps/android/settings.js b/apps/android/settings.js index 0abb32249..1cfc8927c 100644 --- a/apps/android/settings.js +++ b/apps/android/settings.js @@ -12,7 +12,7 @@ var mainmenu = { "" : { "title" : "Android" }, "< Back" : back, - /*LANG*/"Connected" : { value : NRF.getSecurityStatus().connected?"Yes":"No" }, + /*LANG*/"Connected" : { value : NRF.getSecurityStatus().connected?/*LANG*/"Yes":/*LANG*/"No" }, /*LANG*/"Find Phone" : () => E.showMenu({ "" : { "title" : /*LANG*/"Find Phone" }, "< Back" : ()=>E.showMenu(mainmenu), diff --git a/apps/backswipe/README.md b/apps/backswipe/README.md index 1611263bb..21aa357b3 100644 --- a/apps/backswipe/README.md +++ b/apps/backswipe/README.md @@ -10,6 +10,12 @@ Standard # of drag handlers: 0-10 (Default: 0, must be changed for backswipe to Standard # of handlers settings are used to fine tune when backswipe should trigger the back function. E.g. when using a keyboard that works on drags, we don't want the backswipe to trigger when we just wanted to select a letter. This might not be able to cover all cases however. +To get an indication for standard # of handlers `Bangle["#onswipe"]` and `Bangle["#ondrag"]` can be entered in the [Espruino Web IDE](https://www.espruino.com/ide) console field. They return `undefined` if no handler is active, a function if one is active, or a list of functions if multiple are active. Calling this on the clock app is a good start. + +## TODO + +- Possibly add option to tweak standard # of handlers on per app basis. + ## Creator Kedlub diff --git a/apps/blescanner/ChangeLog b/apps/blescanner/ChangeLog new file mode 100644 index 000000000..5560f00bc --- /dev/null +++ b/apps/blescanner/ChangeLog @@ -0,0 +1 @@ +0.01: New App! diff --git a/apps/blescanner/app-icon.js b/apps/blescanner/app-icon.js new file mode 100644 index 000000000..a08a17ae4 --- /dev/null +++ b/apps/blescanner/app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwwhC/AH4ARkQAHBwsBiIACiAHBgQXIkAXJiIuKGAwWEC4cjmYABn//AAMyC63yC653FC6HwC5aQBC5ybIC44WChGAWxMgC44rCxGIZxYXFIoYXBGAQNCAAQXILYYXBGAUDBoK0EC5AsBC4QwEC5wAEC853BhAWDI6CPCFwp3OX4ouCC8xHXCAJ3VX94XCwBHVGIiPTU4oNCAAQWBX5gDBgQRCAAoXGGAUIFwQXHkAXHJIgABCw4IBC5sAiIAEiAgHAAQXLHBAYIC+6wJQYIADgIXGGBJ3FC4iOBAH4A/ACAA==")) diff --git a/apps/blescanner/app.js b/apps/blescanner/app.js new file mode 100644 index 000000000..7cbf80d7e --- /dev/null +++ b/apps/blescanner/app.js @@ -0,0 +1,41 @@ +E.showMessage("Scanning..."); +var devices = []; + +setInterval(function() { + NRF.findDevices(function(devs) { + devs.forEach(dev=>{ + var existing = devices.find(d=>d.id==dev.id); + if (existing) { + existing.timeout = 0; + existing.rssi = (existing.rssi*3 + dev.rssi)/4; + } else { + dev.timeout = 0; + dev.new = 0; + devices.push(dev); + } + }); + devices.forEach(d=>{d.timeout++;d.new++}); + devices = devices.filter(dev=>dev.timeout<8); + devices.sort((a,b)=>b.rssi - a.rssi); + g.clear(1).setFont("12x20"); + var wasNew = false; + devices.forEach((d,y)=>{ + y*=20; + var n = d.name; + if (!n) n=d.id.substr(0,22); + if (d.new<4) { + g.fillRect(0,y,g.getWidth(),y+19); + g.setColor(g.theme.bg); + if (d.rssi > -70) wasNew = true; + } else { + g.setColor(g.theme.fg); + } + g.setFontAlign(-1,-1); + g.drawString(n,0,y); + g.setFontAlign(1,-1); + g.drawString(0|d.rssi,g.getWidth()-1,y); + }); + g.flip(); + Bangle.setLCDBrightness(wasNew); + }, 1200); +}, 1500); diff --git a/apps/blescanner/app.png b/apps/blescanner/app.png new file mode 100644 index 000000000..8665f24ad Binary files /dev/null and b/apps/blescanner/app.png differ diff --git a/apps/blescanner/metadata.json b/apps/blescanner/metadata.json new file mode 100644 index 000000000..54cde3ede --- /dev/null +++ b/apps/blescanner/metadata.json @@ -0,0 +1,14 @@ +{ "id": "blescanner", + "name": "BLE Scanner", + "shortName":"BLE Scan", + "version":"0.01", + "description": "Scans for bluetooth devices nearby and shows their names on the screen ordered by signal strength. The most recently discovered items are highlighted.", + "icon": "app.png", + "screenshots" : [ { "url":"screenshot.png" } ], + "tags": "tool,bluetooth", + "supports" : ["BANGLEJS2"], + "storage": [ + {"name":"blescanner.app.js","url":"app.js"}, + {"name":"blescanner.img","url":"app-icon.js","evaluate":true} + ] +} diff --git a/apps/blescanner/screenshot.png b/apps/blescanner/screenshot.png new file mode 100644 index 000000000..55bd44a52 Binary files /dev/null and b/apps/blescanner/screenshot.png differ diff --git a/apps/btadv/README.md b/apps/btadv/README.md new file mode 100644 index 000000000..7b1afcefe --- /dev/null +++ b/apps/btadv/README.md @@ -0,0 +1,16 @@ +# Bluetooth Advert + +This app advertises and exports (over Bluetooth) live data from the bangle's sensors: + +- Heart Rate +- Accelerometer readings +- Pressure +- GPS information +- Magnetic flux + +Swipe in any direction to access settings, and tap a setting to toggle it. +Hit back to return to the details screen, which shows sensor data being exported. + +# TypeScript + +This app is written in TypeScript, see [typescript/README.md](/typescript/README.md) for more info diff --git a/apps/btadv/app.js b/apps/btadv/app.js index 7f9300923..ced701d79 100644 --- a/apps/btadv/app.js +++ b/apps/btadv/app.js @@ -1,15 +1,5 @@ "use strict"; -var __assign = (this && this.__assign) || function () { - __assign = Object.assign || function(t) { - for (var s, i = 1, n = arguments.length; i < n; i++) { - s = arguments[i]; - for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) - t[p] = s[p]; - } - return t; - }; - return __assign.apply(this, arguments); -}; +var __assign = Object.assign; var Layout = require("Layout"); Bangle.loadWidgets(); Bangle.drawWidgets(); diff --git a/apps/btadv/app.ts b/apps/btadv/app.ts index b3a25305c..15128e484 100644 --- a/apps/btadv/app.ts +++ b/apps/btadv/app.ts @@ -1,3 +1,6 @@ +// ts helpers: +const __assign = Object.assign; + const Layout = require("Layout") as Layout_.Layout; Bangle.loadWidgets(); diff --git a/apps/bthrm/bthrm.js b/apps/bthrm/bthrm.js index b07e7bd37..246b539d4 100644 --- a/apps/bthrm/bthrm.js +++ b/apps/bthrm/bthrm.js @@ -96,7 +96,7 @@ function draw(){ if (!isNaN(bt.battery)) layout.btBattery.label = bt.battery + "%"; if (bt.rr) layout.btRR.label = bt.rr.join(","); if (!isNaN(bt.location)) layout.btLocation.label = BODY_LOCS[bt.location]; - if (bt.contact !== undefined) layout.btContact.label = bt.contact ? "Yes":"No"; + if (bt.contact !== undefined) layout.btContact.label = bt.contact ? /*LANG*/"Yes":/*LANG*/"No"; if (!isNaN(bt.energy)) layout.btEnergy.label = bt.energy.toFixed(0) + "kJ"; } else { layout.bt.label = "--"; diff --git a/apps/clkinfostopw/README.md b/apps/clkinfostopw/README.md index bfac58dab..e92eee3ef 100644 --- a/apps/clkinfostopw/README.md +++ b/apps/clkinfostopw/README.md @@ -9,3 +9,7 @@ Tap to start, tap again to pause. Tap again to restart ## Requests [Contact Rob](https://www.github.com/bobrippling) for features/bugs + +# TypeScript + +This app is written in TypeScript, see [typescript/README.md](/typescript/README.md) for more info diff --git a/apps/clockcal/ChangeLog b/apps/clockcal/ChangeLog index 27d4fc7f4..4c8c13366 100644 --- a/apps/clockcal/ChangeLog +++ b/apps/clockcal/ChangeLog @@ -4,3 +4,4 @@ 0.04: Use default Bangle formatter for booleans 0.05: Improved colors (connected vs disconnected) 0.06: Tell clock widgets to hide. +0.07: Convert Yes/No On/Off in settings to checkboxes diff --git a/apps/clockcal/metadata.json b/apps/clockcal/metadata.json index 872211495..03f5c3df2 100644 --- a/apps/clockcal/metadata.json +++ b/apps/clockcal/metadata.json @@ -1,7 +1,7 @@ { "id": "clockcal", "name": "Clock & Calendar", - "version": "0.06", + "version": "0.07", "description": "Clock with Calendar", "readme":"README.md", "icon": "app.png", diff --git a/apps/clockcal/settings.js b/apps/clockcal/settings.js index d4cc4df68..4d8be6fbd 100644 --- a/apps/clockcal/settings.js +++ b/apps/clockcal/settings.js @@ -16,7 +16,7 @@ actions = ["[ignore]","[calend.]","[AI:music]","[AI:messg]"]; require("Storage").list(RegExp(".app.js")).forEach(element => actions.push(element.replace(".app.js",""))); - + function writeSettings() { require('Storage').writeJSON(FILE, settings); } @@ -106,18 +106,11 @@ writeSettings(); } }, - 'Load deafauls?': { - value: 0, - min: 0, max: 1, - format: v => ["No", "Yes"][v], - onchange: v => { - if (v == 1) { - settings = defaults; - writeSettings(); - load(); - } - } - }, + 'Load defaults': () => { + settings = defaults; + writeSettings(); + load(); + } }; // Show the menu E.showMenu(menu); diff --git a/apps/cscsensor/ChangeLog b/apps/cscsensor/ChangeLog index a98be5c0f..5264e8d42 100644 --- a/apps/cscsensor/ChangeLog +++ b/apps/cscsensor/ChangeLog @@ -6,3 +6,4 @@ 0.06: Now read wheel rev as well as cadence sensor Improve connection code 0.07: Make Bangle.js 2 compatible +0.08: Convert Yes/No On/Off in settings to checkboxes diff --git a/apps/cscsensor/metadata.json b/apps/cscsensor/metadata.json index 4006789ef..ba250c914 100644 --- a/apps/cscsensor/metadata.json +++ b/apps/cscsensor/metadata.json @@ -2,7 +2,7 @@ "id": "cscsensor", "name": "Cycling speed sensor", "shortName": "CSCSensor", - "version": "0.07", + "version": "0.08", "description": "Read BLE enabled cycling speed and cadence sensor and display readings on watch", "icon": "icons8-cycling-48.png", "tags": "outdoors,exercise,ble,bluetooth", diff --git a/apps/cscsensor/settings.js b/apps/cscsensor/settings.js index d7a7d565d..4fac5d0c1 100644 --- a/apps/cscsensor/settings.js +++ b/apps/cscsensor/settings.js @@ -23,17 +23,17 @@ } } const menu = { - '': { 'title': 'Cycle speed sensor' }, + '': { 'title': /*LANG*/'Cycle speed sensor' }, '< Back': back, - 'Wheel circ.(mm)': { + /*LANG*/'Wheel circ.(mm)': { value: s.wheelcirc, min: 800, max: 2400, step: 5, onchange: save('wheelcirc'), }, - 'Reset total distance': function() { - E.showPrompt("Zero total distance?", {buttons: {"No":false, "Yes":true}}).then(function(v) { + /*LANG*/'Reset total distance': function() { + E.showPrompt(/*LANG*/"Zero total distance?", {buttons: {/*LANG*/"No":false, /*LANG*/"Yes":true}}).then(function(v) { if (v) { s['totaldist'] = 0; storage.write(SETTINGS_FILE, s); diff --git a/apps/f9lander/ChangeLog b/apps/f9lander/ChangeLog index a13f2a313..b5a33bd2e 100644 --- a/apps/f9lander/ChangeLog +++ b/apps/f9lander/ChangeLog @@ -1,2 +1,3 @@ 0.01: New App! 0.02: Add lightning +0.03: Convert Yes/No On/Off in settings to checkboxes diff --git a/apps/f9lander/metadata.json b/apps/f9lander/metadata.json index 1db777099..e53805ee0 100644 --- a/apps/f9lander/metadata.json +++ b/apps/f9lander/metadata.json @@ -1,7 +1,7 @@ { "id": "f9lander", "name": "Falcon9 Lander", "shortName":"F9lander", - "version":"0.02", + "version":"0.03", "description": "Land a rocket booster", "icon": "f9lander.png", "screenshots" : [ { "url":"f9lander_screenshot1.png" }, { "url":"f9lander_screenshot2.png" }, { "url":"f9lander_screenshot3.png" }], diff --git a/apps/f9lander/settings.js b/apps/f9lander/settings.js index 0f9fba302..9d85da394 100644 --- a/apps/f9lander/settings.js +++ b/apps/f9lander/settings.js @@ -2,7 +2,6 @@ /** * @param {function} back Use back() to return to settings menu */ -const boolFormat = v => v ? /*LANG*/"On" : /*LANG*/"Off"; (function(back) { const SETTINGS_FILE = 'f9settings.json' // initialize with default settings... @@ -27,8 +26,7 @@ const boolFormat = v => v ? /*LANG*/"On" : /*LANG*/"Off"; '': { 'title': 'OpenWind' }, '< Back': back, 'Lightning': { - value: settings.lightning, - format: boolFormat, + value: !!settings.lightning, onchange: save('lightning'), } } diff --git a/apps/fileman/fileman.app.js b/apps/fileman/fileman.app.js index 6a3c5598d..5baae298b 100644 --- a/apps/fileman/fileman.app.js +++ b/apps/fileman/fileman.app.js @@ -7,7 +7,7 @@ var m; var files; function delete_file(fn) { - E.showPrompt("Delete\n"+fn+"?", {buttons: {"No":false, "Yes":true}}).then(function(v) { + E.showPrompt(/*LANG*/"Delete\n"+fn+"?", {buttons: {/*LANG*/"No":false, /*LANG*/"Yes":true}}).then(function(v) { if (v) { if (fn.charCodeAt(fn.length-1)==1) { var fh = STOR.open(fn.substr(0, fn.length-1), "r"); diff --git a/apps/gbridge/settings.js b/apps/gbridge/settings.js index cf6c84c73..ae63bb0f9 100644 --- a/apps/gbridge/settings.js +++ b/apps/gbridge/settings.js @@ -24,22 +24,22 @@ var mainmenu = { "" : { "title" : "Gadgetbridge" }, "< Back" : back, - "Connected" : { value : NRF.getSecurityStatus().connected?"Yes":"No" }, - "Show Icon" : { + /*LANG*/"Connected" : { value : NRF.getSecurityStatus().connected?/*LANG*/"Yes":/*LANG*/"No" }, + /*LANG*/"Show Icon" : { value: settings().showIcon, onchange: setIcon }, - "Find Phone" : function() { E.showMenu(findPhone); }, - "Record HRM" : { + /*LANG*/"Find Phone" : function() { E.showMenu(findPhone); }, + /*LANG*/"Record HRM" : { value: !!settings().hrm, onchange: v => updateSetting('hrm', v) - } + } }; var findPhone = { "" : { "title" : "-- Find Phone --" }, - "On" : _=>gb({t:"findPhone",n:true}), - "Off" : _=>gb({t:"findPhone",n:false}), + /*LANG*/"On" : _=>gb({t:"findPhone",n:true}), + /*LANG*/"Off" : _=>gb({t:"findPhone",n:false}), "< Back" : function() { E.showMenu(mainmenu); }, }; diff --git a/apps/gipy/ChangeLog b/apps/gipy/ChangeLog index f913c9e58..bfb2f4282 100644 --- a/apps/gipy/ChangeLog +++ b/apps/gipy/ChangeLog @@ -73,3 +73,5 @@ * Display current and next segment in red so that you know where to go. * Avoid angles flickering at low speed at the cost of less refresh. * Splash screen while waiting for gps signal. + +0.17: Convert Yes/No On/Off in settings to checkboxes diff --git a/apps/gipy/metadata.json b/apps/gipy/metadata.json index 97d18f5fe..f0581d578 100644 --- a/apps/gipy/metadata.json +++ b/apps/gipy/metadata.json @@ -2,7 +2,7 @@ "id": "gipy", "name": "Gipy", "shortName": "Gipy", - "version": "0.16", + "version": "0.17", "description": "Follow gpx files using the gps. Don't get lost in your bike trips and hikes.", "allow_emulator":false, "icon": "gipy.png", diff --git a/apps/gipy/settings.js b/apps/gipy/settings.js index af9cbef22..d43a557f6 100644 --- a/apps/gipy/settings.js +++ b/apps/gipy/settings.js @@ -19,8 +19,7 @@ "< Back": () => back(), "keep gps alive": { value: !!settings.keep_gps_alive, // !! converts undefined to false - format: (v) => (v ? "Yes" : "No"), - onchange: (v) => { + onchange: v => { settings.keep_gps_alive = v; writeSettings(); }, diff --git a/apps/homework/app.js b/apps/homework/app.js index 3d9be31c9..a6ad331f0 100644 --- a/apps/homework/app.js +++ b/apps/homework/app.js @@ -46,8 +46,8 @@ var mainMenu = { "Reset Homework": function() { E.showPrompt("Are you sure you want to delete homework.txt?", { buttons: { - "No": false, - "Yes": true + /*LANG*/"No": false, + /*LANG*/"Yes": true } }).then(function(v) { if (v) { diff --git a/apps/info/info.app.js b/apps/info/info.app.js index ade3f3ebb..d97f780da 100644 --- a/apps/info/info.app.js +++ b/apps/info/info.app.js @@ -21,11 +21,11 @@ var screens = [ name: "Hardware", items: [ {name: "Battery", fun: () => E.getBattery() + "%"}, - {name: "Charge?", fun: () => Bangle.isCharging() ? "Yes" : "No"}, + {name: "Charge?", fun: () => Bangle.isCharging() ? /*LANG*/"Yes" : /*LANG*/"No"}, {name: "TempInt.", fun: () => locale.temp(parseInt(E.getTemperature()))}, - {name: "Bluetooth", fun: () => NRF.getSecurityStatus().connected ? "Conn" : "NoConn"}, - {name: "GPS", fun: () => Bangle.isGPSOn() ? "On" : "Off"}, - {name: "Compass", fun: () => Bangle.isCompassOn() ? "On" : "Off"}, + {name: "Bluetooth", fun: () => NRF.getSecurityStatus().connected ? /*LANG*/"Conn" : /*LANG*/"NoConn"}, + {name: "GPS", fun: () => Bangle.isGPSOn() ? /*LANG*/"On" : /*LANG*/"Off"}, + {name: "Compass", fun: () => Bangle.isCompassOn() ? /*LANG*/"On" : /*LANG*/"Off"}, ] }, { @@ -160,4 +160,4 @@ Bangle.on('lock', function(isLocked) { }); Bangle.loadWidgets(); -Bangle.drawWidgets(); \ No newline at end of file +Bangle.drawWidgets(); diff --git a/apps/kbtouch/ChangeLog b/apps/kbtouch/ChangeLog index 17e824c00..5bd2159e6 100644 --- a/apps/kbtouch/ChangeLog +++ b/apps/kbtouch/ChangeLog @@ -1,2 +1,3 @@ 0.01: New App! 0.02: Introduced settings to customize the layout and functionality of the keyboard. +0.03: Convert Yes/No On/Off in settings to checkboxes diff --git a/apps/kbtouch/metadata.json b/apps/kbtouch/metadata.json index 89d121d63..8d7434e44 100644 --- a/apps/kbtouch/metadata.json +++ b/apps/kbtouch/metadata.json @@ -1,6 +1,6 @@ { "id": "kbtouch", "name": "Touch keyboard", - "version":"0.02", + "version":"0.03", "description": "A library for text input via onscreen keyboard", "icon": "app.png", "type":"textinput", diff --git a/apps/kbtouch/settings.js b/apps/kbtouch/settings.js index 871cc5d32..227efaf2d 100644 --- a/apps/kbtouch/settings.js +++ b/apps/kbtouch/settings.js @@ -8,13 +8,13 @@ if (settings.speedScaling===undefined) settings.speedScaling=24; return settings; } - + function updateSetting(setting, value) { let settings = require('Storage').readJSON("kbtouch.settings.json", true) || {}; settings[setting] = value; require('Storage').writeJSON("kbtouch.settings.json", settings); } - + var mainmenu = { "" : { "title" : /*LANG*/"Touch Keyboard" }, "< Back" : back, @@ -25,22 +25,16 @@ onchange: v => updateSetting("textSize", v) }, /*LANG*/'Offset keyboard': { - value: settings().offsetKeyboard, - min: 0, max: 1, - format: v => [/*LANG*/"No",/*LANG*/"Yes"][v], - onchange: v => updateSetting("offsetKeyboard", v) + value: !!settings().offsetKeyboard, + onchange: v => updateSetting("offsetKeyboard", v?1:0) }, /*LANG*/'Loop around': { - value: settings().loopAround, - min: 0, max: 1, - format: v => [/*LANG*/"No",/*LANG*/"Yes"][v], - onchange: v => updateSetting("loopAround", v) + value: !!settings().loopAround, + onchange: v => updateSetting("loopAround", v?1:0) }, /*LANG*/'One-to-one input and release to select': { - value: settings().oneToOne, - min: 0, max: 1, - format: v => [/*LANG*/"No",/*LANG*/"Yes"][v], - onchange: v => updateSetting("oneToOne", v) + value: !!settings().oneToOne, + onchange: v => updateSetting("oneToOne", v?1:0) }, /*LANG*/'Speed scaling': { value: settings().speedScaling, @@ -49,10 +43,8 @@ onchange: v => updateSetting("speedScaling", v) } ///*LANG*/'Release to select': { - // value: 1|settings().fontSize, - // min: 0, max: 1, - // format: v => [/*LANG*/"No",/*LANG*/"Yes"][v], - // onchange: v => updateSetting("releaseToSelect", v) + // value: !!(1|settings().fontSize), + // onchange: v => updateSetting("releaseToSelect", v?1:0) //} }; E.showMenu(mainmenu); diff --git a/apps/marioclock/marioclock-app.js b/apps/marioclock/marioclock-app.js index 6289a2568..ee6371f4e 100644 --- a/apps/marioclock/marioclock-app.js +++ b/apps/marioclock/marioclock-app.js @@ -73,7 +73,7 @@ let lastTemp = 0; const phone = { get status() { - return NRF.getSecurityStatus().connected ? "Yes" : "No"; + return NRF.getSecurityStatus().connected ? /*LANG*/"Yes" : /*LANG*/"No"; }, message: null, messageTimeout: null, diff --git a/apps/messagegui/ChangeLog b/apps/messagegui/ChangeLog index d061e6642..f314c72d3 100644 --- a/apps/messagegui/ChangeLog +++ b/apps/messagegui/ChangeLog @@ -87,3 +87,4 @@ 0.62: Remove '.show' field, tidyup and fix .open if fast load not enabled 0.63: Fix messages app loading on clock without fast load 0.64: Ensure we don't get 'undefined' as the message body +0.65: Make sure messages are saved if not in the clock app (fix #2460) diff --git a/apps/messagegui/lib.js b/apps/messagegui/lib.js index a9436a77b..54d79866a 100644 --- a/apps/messagegui/lib.js +++ b/apps/messagegui/lib.js @@ -29,7 +29,7 @@ exports.listener = function(type, msg) { } const appSettings = require("Storage").readJSON("messages.settings.json", 1) || {}; - let loadMessages = (Bangle.CLOCK || event.important); // should we load the messages app? + let loadMessages = (Bangle.CLOCK || msg.important); // should we load the messages app? if (type==="music") { if (Bangle.CLOCK && msg.state && msg.title && appSettings.openMusic) loadMessages = true; else return; diff --git a/apps/messagegui/metadata.json b/apps/messagegui/metadata.json index 3504122f9..1e22f7304 100644 --- a/apps/messagegui/metadata.json +++ b/apps/messagegui/metadata.json @@ -2,7 +2,7 @@ "id": "messagegui", "name": "Message UI", "shortName": "Messages", - "version": "0.64", + "version": "0.65", "description": "Default app to display notifications from iOS and Gadgetbridge/Android", "icon": "app.png", "type": "app", diff --git a/apps/messageicons/ChangeLog b/apps/messageicons/ChangeLog index 1dd1f3d9e..f420615cb 100644 --- a/apps/messageicons/ChangeLog +++ b/apps/messageicons/ChangeLog @@ -3,3 +3,4 @@ 0.03: Fix icons broken in 0v02 (#2386) Store all icons in a separate binary file (much faster lookup) 0.04: Add message icon for 'clock' +0.05: Add message icon for 'jira' diff --git a/apps/messageicons/icons.img b/apps/messageicons/icons.img index 104168357..66ecb53f8 100644 Binary files a/apps/messageicons/icons.img and b/apps/messageicons/icons.img differ diff --git a/apps/messageicons/icons/generate.js b/apps/messageicons/icons/generate.js index e857032af..b77cfc26e 100755 --- a/apps/messageicons/icons/generate.js +++ b/apps/messageicons/icons/generate.js @@ -87,6 +87,7 @@ exports.getColor = function(msg,options) { if (st.iconColorMode == 'mono') return options.default; const s = (("string"=== typeof msg) ? msg : (msg.src || "")).toLowerCase(); return { + // This file is generated by /icons/generate.js. If you need to modify its content, you should do it there instead. // generic colors, using B2-safe colors // DO NOT USE BLACK OR WHITE HERE, just leave the declaration out and then the theme's fg color will be used "airbnb": "#ff385c", // https://news.airbnb.com/media-assets/category/brand/ @@ -107,6 +108,7 @@ exports.getColor = function(msg,options) { "google home": "#fbbc05", // "home assistant": "#41bdf5", // ha-blue is #41bdf5, but that's the background "instagram": "#ff0069", // https://about.instagram.com/brand/gradient + "jira": "#0052cc", //https://atlassian.design/resources/logo-library "lieferando": "#ff8000", "linkedin": "#0a66c2", // https://brand.linkedin.com/ "messenger": "#0078ff", diff --git a/apps/messageicons/icons/icon_names.json b/apps/messageicons/icons/icon_names.json index f7a743e85..7c09cd397 100644 --- a/apps/messageicons/icons/icon_names.json +++ b/apps/messageicons/icons/icon_names.json @@ -42,6 +42,7 @@ { "app":"google play store", "icon":"google play store.png" }, { "app":"home assistant", "icon":"home assistant.png" }, { "app":"instagram", "icon":"instagram.png" }, + { "app":"jira", "icon":"jira.png" }, { "app":"kalender", "icon":"kalender.png" }, { "app":"keep notes", "icon":"google keep.png" }, { "app":"lieferando", "icon":"lieferando.png" }, diff --git a/apps/messageicons/icons/jira.png b/apps/messageicons/icons/jira.png new file mode 100644 index 000000000..fe3d83b6a Binary files /dev/null and b/apps/messageicons/icons/jira.png differ diff --git a/apps/messageicons/lib.js b/apps/messageicons/lib.js index 314840c13..f7efa2d16 100644 --- a/apps/messageicons/lib.js +++ b/apps/messageicons/lib.js @@ -2,7 +2,7 @@ exports.getImage = function(msg) { if (msg.img) return atob(msg.img); let s = (("string"=== typeof msg) ? msg : (msg.src || "")).toLowerCase(); if (msg.id=="music") s="music"; - let match = ",default|0,airbnb|1,alarm|2,alarmclockreceiver|2,amazon shopping|3,bibel|4,bitwarden|5,1password|5,lastpass|5,dashlane|5,bring|6,calendar|7,etar|7,chat|8,chrome|9,clock|2,corona-warn|10,bmo|11,desjardins|11,rbc mobile|11,nbc|11,rabobank|11,scotiabank|11,td (canada)|11,discord|12,drive|13,element|14,facebook|15,messenger|16,firefox|17,firefox beta|17,firefox nightly|17,f-droid|5,neo store|5,aurora droid|5,github|18,gitlab|19,gmx|20,google|21,google home|22,google play store|23,home assistant|24,instagram|25,kalender|26,keep notes|27,lieferando|28,linkedin|29,maps|30,organic maps|30,osmand|30,mastodon|31,fedilab|31,tooot|31,tusky|31,mattermost|32,n26|33,netflix|34,news|35,cbc news|35,rc info|35,reuters|35,ap news|35,la presse|35,nbc news|35,nextbike|36,nina|37,outlook mail|38,paypal|39,phone|40,plex|41,pocket|42,post & dhl|43,proton mail|44,reddit|45,sync pro|45,sync dev|45,boost|45,infinity|45,slide|45,signal|46,skype|47,slack|48,snapchat|49,starbucks|50,steam|51,teams|52,telegram|53,telegram foss|53,threema|54,tiktok|55,to do|56,opentasks|56,tasks|56,transit|57,twitch|58,twitter|59,uber|60,lyft|60,vlc|61,warnapp|62,whatsapp|63,wordfeud|64,youtube|65,newpipe|65,zoom|66,meet|66,music|67,sms message|0,mail|0,gmail|0,".match(new RegExp(`,${s}\\|(\\d+)`)) + let match = ",default|0,airbnb|1,alarm|2,alarmclockreceiver|2,amazon shopping|3,bibel|4,bitwarden|5,1password|5,lastpass|5,dashlane|5,bring|6,calendar|7,etar|7,chat|8,chrome|9,clock|2,corona-warn|10,bmo|11,desjardins|11,rbc mobile|11,nbc|11,rabobank|11,scotiabank|11,td (canada)|11,discord|12,drive|13,element|14,facebook|15,messenger|16,firefox|17,firefox beta|17,firefox nightly|17,f-droid|5,neo store|5,aurora droid|5,github|18,gitlab|19,gmx|20,google|21,google home|22,google play store|23,home assistant|24,instagram|25,jira|26,kalender|27,keep notes|28,lieferando|29,linkedin|30,maps|31,organic maps|31,osmand|31,mastodon|32,fedilab|32,tooot|32,tusky|32,mattermost|33,n26|34,netflix|35,news|36,cbc news|36,rc info|36,reuters|36,ap news|36,la presse|36,nbc news|36,nextbike|37,nina|38,outlook mail|39,paypal|40,phone|41,plex|42,pocket|43,post & dhl|44,proton mail|45,reddit|46,sync pro|46,sync dev|46,boost|46,infinity|46,slide|46,signal|47,skype|48,slack|49,snapchat|50,starbucks|51,steam|52,teams|53,telegram|54,telegram foss|54,threema|55,tiktok|56,to do|57,opentasks|57,tasks|57,transit|58,twitch|59,twitter|60,uber|61,lyft|61,vlc|62,warnapp|63,whatsapp|64,wordfeud|65,youtube|66,newpipe|66,zoom|67,meet|67,music|68,sms message|0,mail|0,gmail|0,".match(new RegExp(`,${s}\\|(\\d+)`)) return require("Storage").read("messageicons.img", (match===null)?0:match[1]*76, 76); }; @@ -13,6 +13,7 @@ exports.getColor = function(msg,options) { if (st.iconColorMode == 'mono') return options.default; const s = (("string"=== typeof msg) ? msg : (msg.src || "")).toLowerCase(); return { + // This file is generated by /icons/generate.js. If you need to modify its content, you should do it there instead. // generic colors, using B2-safe colors // DO NOT USE BLACK OR WHITE HERE, just leave the declaration out and then the theme's fg color will be used "airbnb": "#ff385c", // https://news.airbnb.com/media-assets/category/brand/ @@ -33,6 +34,7 @@ exports.getColor = function(msg,options) { "google home": "#fbbc05", // "home assistant": "#41bdf5", // ha-blue is #41bdf5, but that's the background "instagram": "#ff0069", // https://about.instagram.com/brand/gradient + "jira": "#0052cc", //https://atlassian.design/resources/logo-library "lieferando": "#ff8000", "linkedin": "#0a66c2", // https://brand.linkedin.com/ "messenger": "#0078ff", diff --git a/apps/messageicons/metadata.json b/apps/messageicons/metadata.json index 0d1db227b..13f218508 100644 --- a/apps/messageicons/metadata.json +++ b/apps/messageicons/metadata.json @@ -1,7 +1,7 @@ { "id": "messageicons", "name": "Message Icons", - "version": "0.04", + "version": "0.05", "description": "Library containing a list of icons and colors for apps", "icon": "app.png", "type": "module", diff --git a/apps/neonx/ChangeLog b/apps/neonx/ChangeLog index e78686a00..b055d6a15 100644 --- a/apps/neonx/ChangeLog +++ b/apps/neonx/ChangeLog @@ -3,4 +3,5 @@ 0.03: Optional show lock status via color 0.04: Ensure that widgets are always hidden in fullscreen mode 0.05: Better lock/unlock animation -0.06: Use widget_utils. +0.06: Use widget_utils +0.07: Convert Yes/No On/Off in settings to checkboxes diff --git a/apps/neonx/metadata.json b/apps/neonx/metadata.json index c273cb05a..edd0e76b8 100644 --- a/apps/neonx/metadata.json +++ b/apps/neonx/metadata.json @@ -2,7 +2,7 @@ "id": "neonx", "name": "Neon X & IO X Clock", "shortName": "Neon X Clock", - "version": "0.06", + "version": "0.07", "description": "Pebble Neon X & Neon IO X for Bangle.js", "icon": "neonx.png", "type": "clock", diff --git a/apps/neonx/neonx.settings.js b/apps/neonx/neonx.settings.js index 68e156dae..8edaf5c50 100644 --- a/apps/neonx/neonx.settings.js +++ b/apps/neonx/neonx.settings.js @@ -25,11 +25,9 @@ "" : { "title":"Neon X & IO"}, "< Back": back, "Neon IO X": { - value: 0 | neonXSettings.io, - min: 0, max: 1, - format: v => v ? "On" : "Off", + value: !!neonXSettings.io, onchange: v => { - neonXSettings.io = v; + neonXSettings.io = v?1:0; updateSettings(); } }, @@ -43,27 +41,23 @@ } }, "Date on touch": { - value: 0 | neonXSettings.showDate, - min: 0, max: 1, - format: v => v ? "On" : "Off", + value: !!neonXSettings.showDate, onchange: v => { - neonXSettings.showDate = v; + neonXSettings.showDate = v?1:0; updateSettings(); } }, 'Fullscreen': { - value: false | neonXSettings.fullscreen, - format: () => (neonXSettings.fullscreen ? 'Yes' : 'No'), - onchange: () => { - neonXSettings.fullscreen = !neonXSettings.fullscreen; + value: !!neonXSettings.fullscreen, + onchange: v => { + neonXSettings.fullscreen = v; updateSettings(); }, }, 'Show lock': { - value: false | neonXSettings.showLock, - format: () => (neonXSettings.showLock ? 'Yes' : 'No'), - onchange: () => { - neonXSettings.showLock = !neonXSettings.showLock; + value: !!neonXSettings.showLock, + onchange: v => { + neonXSettings.showLock = v; updateSettings(); }, }, diff --git a/apps/numerals/ChangeLog b/apps/numerals/ChangeLog index 57818c180..d6703a96b 100644 --- a/apps/numerals/ChangeLog +++ b/apps/numerals/ChangeLog @@ -7,4 +7,5 @@ 0.07: Add date on touch and some improvements (see settings and readme) 0.08: Add new draw styles, tidy up draw functionality 0.09: Tweak for faster rendering -0.10: Enhance for use with Bangle2, insert new draw mode 'thickfill' \ No newline at end of file +0.10: Enhance for use with Bangle2, insert new draw mode 'thickfill' +0.11: Convert Yes/No On/Off in settings to checkboxes diff --git a/apps/numerals/metadata.json b/apps/numerals/metadata.json index 6ba850d86..6a1adc810 100644 --- a/apps/numerals/metadata.json +++ b/apps/numerals/metadata.json @@ -2,7 +2,7 @@ "id": "numerals", "name": "Numerals Clock", "shortName": "Numerals Clock", - "version": "0.10", + "version": "0.11", "description": "A simple big numerals clock", "icon": "numerals.png", "type": "clock", diff --git a/apps/numerals/numerals.settings.js b/apps/numerals/numerals.settings.js index ae321322a..b4d5d4286 100644 --- a/apps/numerals/numerals.settings.js +++ b/apps/numerals/numerals.settings.js @@ -30,10 +30,8 @@ onchange: v=> { numeralsSettings.drawMode=dm[v]; updateSettings();} }, "Date on touch": { - value: 0|numeralsSettings.showDate, - min:0,max:1, - format: v=>v?"On":"Off", - onchange: v=> { numeralsSettings.showDate=v; updateSettings();} + value: !!numeralsSettings.showDate, + onchange: v=> { numeralsSettings.showDate=v?1:0; updateSettings();} }, "< back": back }; diff --git a/apps/powermanager/ChangeLog b/apps/powermanager/ChangeLog index 06f38d399..ee31195b2 100644 --- a/apps/powermanager/ChangeLog +++ b/apps/powermanager/ChangeLog @@ -4,3 +4,8 @@ 0.04: Remove calibration with current voltage (Calibrate->Auto) as it is now handled by settings app Allow automatic calibration on every charge longer than 3 hours 0.05: Add back button to settings menu. +0.06: Allow logging of some things using power + Add widget for live monitoring of power use +0.07: Convert Yes/No On/Off in settings to checkboxes +0.08: Fix the wrapping of intervals/timeouts with parameters + Fix the widget drawing if widgets are hidden and Bangle.setLCDBrightness is called \ No newline at end of file diff --git a/apps/powermanager/README.md b/apps/powermanager/README.md index 88b3c370a..804e986e7 100644 --- a/apps/powermanager/README.md +++ b/apps/powermanager/README.md @@ -7,6 +7,26 @@ Features: * Force monotonic battery percentage or voltage * Automatic calibration on charging uninterrupted longer than 3 hours (reloads of the watch reset the timer). + +## Widget + +The widget shows an approximate current power use. There is a power gauge showing the estimation of the currently used power and the currently active sensor with the biggest power draw. +G for GPS, H for pulse sensor and C for compass. + +## Logging + +You can switch on logging in the options to diagnose unexpected power use. Currently the logging can capture the code running from timeouts and intervals and the power up and down of some devices. The captured times are probably not perfect but should be good enough to indicate problems. + +Do not use trace logging for extended time, it uses a lot of storage and can fill up the flash quite quick. + +### TODO + +* Wrap functions given as strings to setTimeout/setInterval +* Handle eval in setTimeout/setInterval +* Track functions executed as event handlers +* Track buzzer +* Modify browser interface to estimate power use like widget does + ## Internals Battery calibration offset is set by writing `batFullVoltage` in setting.json @@ -14,6 +34,10 @@ Battery calibration offset is set by writing `batFullVoltage` in setting.json ## TODO * Optionally keep battery history and show as graph +* Capture some more stuff in logging + * Event driven code execution + * Buzzer + * Better tracking of display on time ## Creator diff --git a/apps/powermanager/boot.js b/apps/powermanager/boot.js index 2bc2aaa35..f3e3f718f 100644 --- a/apps/powermanager/boot.js +++ b/apps/powermanager/boot.js @@ -3,11 +3,116 @@ require('Storage').readJSON("powermanager.default.json", true) || {}, require('Storage').readJSON("powermanager.json", true) || {} ); - + + if (settings.log) { + let logFile = require('Storage').open("powermanager.log","a"); + let def = require('Storage').readJSON("powermanager.def.json", true) || {}; + if (!def.start) def.start = Date.now(); + if (!def.deferred) def.deferred = {}; + let hw = require('Storage').readJSON("powermanager.hw.json", true) || {}; + if (!hw.start) hw.start = Date.now(); + if (!hw.power) hw.power = {}; + + const saveEvery = 1000 * 60 * 5; + const TO_WRAP = ["GPS","Compass","Barometer","HRM","LCD"]; + + let save = ()=>{ + let defExists = require("Storage").read("powermanager.def.json")!==undefined; + if (!(!defExists && def.saved)){ + def.saved = Date.now(); + require('Storage').writeJSON("powermanager.def.json", def); + } + let hwExists = require("Storage").read("powermanager.hw.json")!==undefined; + if (!(!hwExists && hw.saved)){ + hw.saved = Date.now(); + require('Storage').writeJSON("powermanager.hw.json", hw); + } + } + + setInterval(save, saveEvery); + + E.on("kill", ()=>{ + for (let c of TO_WRAP){ + if (lastPowerOn[c] && Bangle["is"+c+"On"]()){ + hw.power[c] += Date.now() - lastPowerOn[c]; + } + } + save(); + }); + + + let logPower = (type, oldstate, state, app) => { + logFile.write("p," + type + ',' + (oldstate?1:0) + ',' + (state?1:0) + ',' + app + "\n"); + }; + let logDeferred = (type, duration, source) => { + logFile.write(type + ',' + duration + ',' + source.replace(/\n/g, " ").replace(/,/g,"") + "\n"); + }; + + let lastPowerOn = {}; + + for (let c of TO_WRAP){ + let functionName = "set" + c + "Power"; + let checkName = "is" + c + "On"; + let type = c + ""; + lastPowerOn[type] = (!lastPowerOn[type] && Bangle[checkName]()) ? Date.now() : undefined; + + lastPowerOn[type] = Date.now(); + + Bangle[functionName] = ((o) => (a,b) => { + let oldstate = Bangle[checkName](); + let result = o(a,b); + if (!lastPowerOn[type] && result) { + //switched on, store time + lastPowerOn[type] = Date.now(); + } else if (lastPowerOn[type] && !result){ + //switched off + hw.power[type] += Date.now() - lastPowerOn[type]; + lastPowerOn[type] = undefined; + } + + if (settings.logDetails) logPower(type, oldstate, result, b); + return result; + })(Bangle[functionName]); + } + + let functions = {}; + let wrapDeferred = ((o,t) => (a) => { + if (a == eval || typeof a == "string") { + return o.apply(this, arguments); + } else { + let wrapped = a; + if (!a.__wrapped){ + wrapped = ()=>{ + let start = Date.now(); + let result = a.apply(undefined, arguments.slice(2)); // function arguments for deferred calls start at index 2, first is function, second is time + let end = Date.now()-start; + let f = a.toString().substring(0,100); + if (settings.logDetails) logDeferred(t, end, f); + if (!def.deferred[f]) def.deferred[f] = 0; + def.deferred[f] += end; + return result; + }; + //copy over properties of functions + for (let p in a){ + wrapped[p] = a[p]; + } + //mark function as wrapped + wrapped.__wrapped = true; + } + let newArgs = arguments.slice(); + newArgs[0] = wrapped; + return o.apply(this, newArgs); + } + }); + + global.setTimeout = wrapDeferred(global.setTimeout, "t"); + global.setInterval = wrapDeferred(global.setInterval, "i"); + } + if (settings.warnEnabled){ var chargingInterval; - function handleCharging(charging){ + let handleCharging = (charging) => { if (charging){ if (chargingInterval) clearInterval(chargingInterval); chargingInterval = setInterval(()=>{ @@ -20,12 +125,12 @@ clearInterval(chargingInterval); chargingInterval = undefined; } - } + }; Bangle.on("charging",handleCharging); handleCharging(Bangle.isCharging()); } - + if (settings.forceMonoPercentage){ var p = (E.getBattery()+E.getBattery()+E.getBattery()+E.getBattery())/4; var op = E.getBattery; @@ -56,4 +161,4 @@ if (!charging) chargeStart = undefined; }); } -})(); +})(); \ No newline at end of file diff --git a/apps/powermanager/default.json b/apps/powermanager/default.json index 6c929dc38..457f79610 100644 --- a/apps/powermanager/default.json +++ b/apps/powermanager/default.json @@ -2,5 +2,6 @@ "warnEnabled": false, "warn": 96, "forceMonoVoltage": false, - "forceMonoPercentage": false + "forceMonoPercentage": false, + "log": false } diff --git a/apps/powermanager/interface.html b/apps/powermanager/interface.html new file mode 100644 index 000000000..7a00af993 --- /dev/null +++ b/apps/powermanager/interface.html @@ -0,0 +1,268 @@ + +
+ + + + + + + + + diff --git a/apps/powermanager/metadata.json b/apps/powermanager/metadata.json index 456831aa9..5487c2278 100644 --- a/apps/powermanager/metadata.json +++ b/apps/powermanager/metadata.json @@ -2,17 +2,25 @@ "id": "powermanager", "name": "Power Manager", "shortName": "Power Manager", - "version": "0.05", + "version": "0.08", "description": "Allow configuration of warnings and thresholds for battery charging and display.", "icon": "app.png", "type": "bootloader", "tags": "tool", "supports": ["BANGLEJS2"], "readme": "README.md", + "interface": "interface.html", "storage": [ {"name":"powermanager.boot.js","url":"boot.js"}, {"name":"powermanager.settings.js","url":"settings.js"}, + {"name":"powermanager.wid.js","url":"widget.js"}, {"name":"powermanager","url":"lib.js"}, {"name":"powermanager.default.json","url":"default.json"} + ], + "data": [ + {"name":"powermanager.hw.json"}, + {"name":"powermanager.def.json"}, + {"name":"powermanager.json"}, + {"name":"powermanager.log"} ] } diff --git a/apps/powermanager/settings.js b/apps/powermanager/settings.js index fe4719275..fa186bfac 100644 --- a/apps/powermanager/settings.js +++ b/apps/powermanager/settings.js @@ -24,6 +24,9 @@ 'title': 'Power Manager' }, "< Back" : back, + 'Widget': function() { + E.showMenu(submenu_widget); + }, 'Monotonic percentage': { value: !!settings.forceMonoPercentage, onchange: v => { @@ -41,6 +44,9 @@ }, 'Calibrate': function() { E.showMenu(submenu_calibrate); + }, + 'Logging': function() { + E.showMenu(submenu_logging); } }; @@ -100,7 +106,6 @@ }, 'Enabled': { value: !!settings.warnEnabled, - format: v => settings.warnEnabled ? "On" : "Off", onchange: v => { writeSettings("warnEnabled", v); } @@ -117,5 +122,61 @@ } }; + var submenu_logging = { + '': { + title: "Logging", + back: function() { + E.showMenu(mainmenu); + }, + }, + 'Enabled': { + value: !!settings.log, + onchange: v => { + writeSettings("log", v); + } + }, + 'Trace': { + value: !!settings.logDetails, + onchange: v => { + writeSettings("logDetails", v); + } + } + } + + var submenu_widget = { + '': { + title: "Widget", + back: function() { + E.showMenu(mainmenu); + }, + }, + 'Enabled': { + value: !!settings.widget, + onchange: v => { + writeSettings("widget", v); + } + }, + 'Refresh': { + min: 0.5, + max: 60, + step: 0.5, + value: settings.refreshUnlocked || 1, + format: v => v + "s", + onchange: v => { + writeSettings("refreshUnlocked", v); + } + }, + 'Refresh locked': { + min: 5, + max: 120, + step: 5, + value: settings.refreshLocked || 60, + format: v => v + "s", + onchange: v => { + writeSettings("refreshLocked", v); + } + } + } + E.showMenu(mainmenu); }) diff --git a/apps/powermanager/widget.js b/apps/powermanager/widget.js new file mode 100644 index 000000000..3147c40ac --- /dev/null +++ b/apps/powermanager/widget.js @@ -0,0 +1,116 @@ +/* run widgets in their own function scope so they don't interfere with +currently-running apps */ +(() => { + const s = require("Storage").readJSON("powermanager.json") || {}; + + if (!s.widget) return; + + const SYSTICKMAX = peek32(0xE000E014); + const SYSTICKWAIT = SYSTICKMAX/64000; // 64 MHz clock rate, Systick counting down on every non idle clock + + const GU = require("graphics_utils"); + const APPROX_IDLE = 0.3; + const APPROX_HIGH_BW_BLE = 0.5; + const APPROX_COMPASS = process.HWVERSION == 2 ? 5.5 : 2; + const APPROX_HRM = process.HWVERSION == 2 ? 1 : 2.5; + const APPROX_CPU = 3; + const APPROX_GPS = process.HWVERSION == 2 ? 25 : 30; + const APPROX_TOUCH = 2.5; + const APPROX_BACKLIGHT = process.HWVERSION == 2 ? 16 : 40; + const MAX = APPROX_IDLE + APPROX_HIGH_BW_BLE + APPROX_COMPASS + APPROX_HRM + APPROX_CPU + APPROX_GPS + APPROX_TOUCH + APPROX_BACKLIGHT; + + let settings = require("Storage").readJSON("setting.json") || {}; + + let brightnessSetting = settings.brightness || 1; + Bangle.setLCDBrightness = ((o) => (a) => { + brightnessSetting = a; + WIDGETS.powermanager.draw(WIDGETS.powermanager); + return o(a); + })(Bangle.setLCDBrightness); + + let brightness = () => { + return process.HWVERSION == 2 ? (brightnessSetting * APPROX_BACKLIGHT) : (brightnessSetting * 0.9 * 33 + 7); + }; + + function doDraw(w, cpu){ + g.reset(); + + let current = APPROX_IDLE + cpu * APPROX_CPU; + let mostExpensive = "P"; + + if (!Bangle.isLocked()) current += APPROX_TOUCH + brightness(); + if (Bangle.isCompassOn()) { + current += APPROX_COMPASS; + mostExpensive = "C"; + } + if (Bangle.isHRMOn()) { + current += APPROX_HRM; + mostExpensive = "H"; + } + if (Bangle.isGPSOn()) { + current += APPROX_GPS; + mostExpensive = "G"; + } + + current = current / MAX; + + g.clearRect(w.x, w.y, w.x + 23, w.y + 23); + + g.setColor(g.theme.fg); + + g.setFont6x15(); + g.setFontAlign(0, 0); + g.drawString(mostExpensive, w.x + 12, w.y + 15); + let end = 135 + (current * (405 - 135)); + g.setColor(current > 0.7 ? "#f00" : (current > 0.3 ? "#ff0" : "#0f0")); + GU.fillArc(g, w.x + 12, w.y + 12, 9, 12, GU.degreesToRadians(135), GU.degreesToRadians(end), GU.degreesToRadians(30)); + + g.setColor(g.theme.fg); + let endCpu = 135 + (cpu * (405 - 135)); + GU.fillArc(g, w.x + 12, w.y + 12, 5.5, 8, GU.degreesToRadians(135), GU.degreesToRadians(endCpu), GU.degreesToRadians(30)); + } + let sTimeout; + let s2Timeout; + let systickDiff; + function draw(w) { + let nextRefresh = Bangle.isLocked() ? ((s.refreshLocked || 60) * 1000 ): ((s.refreshUnlocked || 1) * 1000) + + if (s2Timeout) clearTimeout(s2Timeout); + if (sTimeout) clearTimeout(sTimeout); + + let t,systickNow; + sTimeout = setTimeout(()=>{ + systickNow = peek32(0xE000E018); + t = Date.now(); + }, nextRefresh - SYSTICKWAIT - 100); + + s2Timeout = setTimeout(() => { + let tLater = Date.now(); + let systickLater = peek32(0xE000E018); + systickDiff = systickLater - systickNow; + if (systickDiff < 0) systickDiff += SYSTICKMAX; + }, nextRefresh - 100); + + doDraw(w, systickDiff ? (1 - systickDiff/SYSTICKMAX) : 0); + + if (w.timeoutId !== undefined) { + clearTimeout(w.timeoutId); + } + w.timeoutId = setTimeout(() => { + w.timeoutId = undefined; + w.draw(w); + }, nextRefresh); + } + + // add your widget + WIDGETS.powermanager = { + area: "tl", + width: 24, + draw: draw + }; + + Bangle.on("lock", ()=>{WIDGETS.powermanager.draw(WIDGETS.powermanager);}); + + // conserve memory + delete settings; +})(); \ No newline at end of file diff --git a/apps/recorder/ChangeLog b/apps/recorder/ChangeLog index c4d1fa8c1..c3e20ed34 100644 --- a/apps/recorder/ChangeLog +++ b/apps/recorder/ChangeLog @@ -25,3 +25,4 @@ 0.19: Fix track plotting code 0.20: Automatic translation of some more strings. 0.21: Speed report now uses speed units from locale +0.22: Convert Yes/No On/Off in settings to checkboxes diff --git a/apps/recorder/app.js b/apps/recorder/app.js index 8ac3ff627..972a9580d 100644 --- a/apps/recorder/app.js +++ b/apps/recorder/app.js @@ -56,7 +56,6 @@ function showMainMenu() { '< Back': ()=>{load();}, /*LANG*/'RECORD': { value: !!settings.recording, - format: v=>v?/*LANG*/"On":/*LANG*/"Off", onchange: v => { setTimeout(function() { E.showMenu(); diff --git a/apps/recorder/metadata.json b/apps/recorder/metadata.json index 45d588d99..60abeadef 100644 --- a/apps/recorder/metadata.json +++ b/apps/recorder/metadata.json @@ -2,7 +2,7 @@ "id": "recorder", "name": "Recorder", "shortName": "Recorder", - "version": "0.21", + "version": "0.22", "description": "Record GPS position, heart rate and more in the background, then download to your PC.", "icon": "app.png", "tags": "tool,outdoors,gps,widget", diff --git a/apps/run/ChangeLog b/apps/run/ChangeLog index 95945be78..3638407ef 100644 --- a/apps/run/ChangeLog +++ b/apps/run/ChangeLog @@ -13,3 +13,4 @@ 0.12: Fix for recorder not stopping at end of run. Bug introduced in 0.11 0.13: Revert #1578 (stop duplicate entries) as with 2v12 menus it causes other boxes to be wiped (fix #1643) 0.14: Fix Bangle.js 1 issue where after the 'overwrite track' menu, the start/stop button stopped working +0.15: Keep run state between runs (allowing you to exit and restart the app) diff --git a/apps/run/app.js b/apps/run/app.js index 4038b8c1a..a56fce31c 100644 --- a/apps/run/app.js +++ b/apps/run/app.js @@ -41,6 +41,13 @@ var statIDs = [settings.B1,settings.B2,settings.B3,settings.B4,settings.B5,setti var exs = ExStats.getStats(statIDs, settings); // --------------------------- +function setStatus(running) { + layout.button.label = running ? "STOP" : "START"; + layout.status.label = running ? "RUN" : "STOP"; + layout.status.bgCol = running ? "#0f0" : "#f00"; + layout.render(); +} + // Called to start/stop running function onStartStop() { var running = !exs.state.active; @@ -77,12 +84,9 @@ function onStartStop() { } else { exs.stop(); } - layout.button.label = running ? "STOP" : "START"; - layout.status.label = running ? "RUN" : "STOP"; - layout.status.bgCol = running ? "#0f0" : "#f00"; // if stopping running, don't clear state // so we can at least refer to what we've done - layout.render(); + setStatus(running); }); } @@ -105,13 +109,14 @@ for (var i=0;i