diff --git a/apps/a_clock_timer/ChangeLog b/apps/a_clock_timer/ChangeLog index 262f30295..cfb53c432 100644 --- a/apps/a_clock_timer/ChangeLog +++ b/apps/a_clock_timer/ChangeLog @@ -1,3 +1,4 @@ 0.01: Beta version for Bangle 2 (2021/11/28) 0.02: Shows night time on the map (2022/12/28) 0.03: Add 1 minute timer with upper taps (2023/01/05) +1.00: Page to set up custom time zones (2023/01/06) \ No newline at end of file diff --git a/apps/a_clock_timer/README.md b/apps/a_clock_timer/README.md index 3fcc00b28..4e199344a 100644 --- a/apps/a_clock_timer/README.md +++ b/apps/a_clock_timer/README.md @@ -8,11 +8,11 @@ * Bottom Left tap: decrease by 5 minutes * Short buzz at T-30, T-20, T-10 ; Double buzz at T * Other time zones - * Currently hardcoded to Paris and Tokyo (this will be customizable in a future version) + * Showing Paris and Tokyo by default, but you can customize this using the dedicated configuration page on the app store * World Map * The map shows day and night on Earth and the position of the Sun (yellow line) -![](screenshot.png) +![](screenshot-1.png) ![](screenshot.png) ## Creator [@alainsaas](https://github.com/alainsaas) diff --git a/apps/a_clock_timer/app.js b/apps/a_clock_timer/app.js index 441229842..b01cec59b 100644 --- a/apps/a_clock_timer/app.js +++ b/apps/a_clock_timer/app.js @@ -89,6 +89,7 @@ function showWelcomeMessage() { } // time +var offsets = require("Storage").readJSON("a_clock_timer.settings.json") || [ ["PAR",1], ["TYO",9] ]; var drawTimeout; function getGmt() { @@ -119,7 +120,7 @@ function draw() { g.setColor('#ff0').drawLine(x_sun, g.getHeight()-IMAGEHEIGHT, x_sun, g.getHeight()); g.reset(); - var x_night_start = 176 - (((gmtHours-6)%24) / 24 * 176 + 4); + var x_night_start = (176 - (((gmtHours-6)%24) / 24 * 176 + 4)) % 176; var x_night_end = 176 - (((gmtHours+6)%24) / 24 * 176 + 4); g.setColor('#000'); for (let x = x_night_start; x < (x_night_end < x_night_start ? 176 : x_night_end); x+=2) { @@ -138,8 +139,8 @@ function draw() { g.setFont("Michroma36").drawString(locale.time(date,1), g.getWidth()/2, 46); g.setFont("6x8"); g.drawString(locale.date(new Date(),1), 125, 68); - g.drawString("PAR "+locale.time(getTimeFromTimezone(1),1), 125, 80); - g.drawString("TYO "+locale.time(getTimeFromTimezone(9),1), 125, 88); + g.drawString(offsets[0][0]+" "+locale.time(getTimeFromTimezone(offsets[0][1]),1), 125, 80); + g.drawString(offsets[1][0]+" "+locale.time(getTimeFromTimezone(offsets[1][1]),1), 125, 88); queueNextDraw(); } diff --git a/apps/a_clock_timer/custom.html b/apps/a_clock_timer/custom.html new file mode 100644 index 000000000..b62226340 --- /dev/null +++ b/apps/a_clock_timer/custom.html @@ -0,0 +1,58 @@ + + + + + +

You can set the 2 additional timezones displayed by the clock.

+ + + + + +
NameUTC Offset (Hours)
+

Click

+ + + + diff --git a/apps/a_clock_timer/metadata.json b/apps/a_clock_timer/metadata.json index 4e7a36b8a..6507857f1 100644 --- a/apps/a_clock_timer/metadata.json +++ b/apps/a_clock_timer/metadata.json @@ -1,17 +1,19 @@ { "id": "a_clock_timer", "name": "A Clock with Timer", - "version": "0.03", + "version": "1.00", "description": "A Clock with Timer, Map and Time Zones", "icon": "app.png", - "screenshots": [{"url":"screenshot.png"}], + "screenshots": [{"url":"screenshot.png"},{"url":"screenshot-1.png"}], "type": "clock", "tags": "clock", "supports": ["BANGLEJS2"], "allow_emulator": true, "readme": "README.md", + "custom": "custom.html", "storage": [ {"name":"a_clock_timer.app.js","url":"app.js"}, {"name":"a_clock_timer.img","url":"app-icon.js","evaluate":true} - ] + ], + "data": [{"name":"a_clock_timer.settings.json"}] } diff --git a/apps/a_clock_timer/screenshot-1.png b/apps/a_clock_timer/screenshot-1.png new file mode 100644 index 000000000..ede6439de Binary files /dev/null and b/apps/a_clock_timer/screenshot-1.png differ diff --git a/apps/a_clock_timer/screenshot.png b/apps/a_clock_timer/screenshot.png index 5dcdf406e..893daa9d0 100644 Binary files a/apps/a_clock_timer/screenshot.png and b/apps/a_clock_timer/screenshot.png differ diff --git a/apps/barclock/ChangeLog b/apps/barclock/ChangeLog index 88f4eaf00..96ee0141e 100644 --- a/apps/barclock/ChangeLog +++ b/apps/barclock/ChangeLog @@ -14,3 +14,4 @@ 0.14: Use ClockFace_menu.addItems 0.15: Add Power saving option 0.16: Support Fast Loading +0.17: Hide widgets instead of not loading them at all diff --git a/apps/barclock/metadata.json b/apps/barclock/metadata.json index 785c228b0..010852083 100644 --- a/apps/barclock/metadata.json +++ b/apps/barclock/metadata.json @@ -1,7 +1,7 @@ { "id": "barclock", "name": "Bar Clock", - "version": "0.16", + "version": "0.17", "description": "A simple digital clock showing seconds as a bar", "icon": "clock-bar.png", "screenshots": [{"url":"screenshot.png"},{"url":"screenshot_pm.png"}], diff --git a/apps/barclock/settings.js b/apps/barclock/settings.js index 7b88b7021..04f0a38ba 100644 --- a/apps/barclock/settings.js +++ b/apps/barclock/settings.js @@ -1,5 +1,10 @@ (function(back) { let s = require("Storage").readJSON("barclock.settings.json", true) || {}; + // migrate "don't load widgets" to "hide widgets" + if (!("hideWidgets" in s) && ("loadWidgets" in s) && !s.loadWidgets) { + s.hideWidgets = 1; + } + delete s.loadWidgets; function save(key, value) { s[key] = value; @@ -19,7 +24,7 @@ }; let items = { showDate: s.showDate, - loadWidgets: s.loadWidgets, + hideWidgets: s.hideWidgets, }; // Power saving for Bangle.js 1 doesn't make sense (no updates while screen is off anyway) if (process.env.HWVERSION>1) { diff --git a/apps/bwclk/ChangeLog b/apps/bwclk/ChangeLog index 6a71769f3..33cd7ef63 100644 --- a/apps/bwclk/ChangeLog +++ b/apps/bwclk/ChangeLog @@ -27,4 +27,5 @@ 0.26: Use clkinfo.addInteractive instead of a custom implementation 0.27: Clean out some leftovers in the remove function after switching to clkinfo.addInteractive that would cause ReferenceError. -0.28: Option to show (1) time only and (2) week of year. \ No newline at end of file +0.28: Option to show (1) time only and (2) week of year. +0.29: use setItem of clockInfoMenu to change the active item \ No newline at end of file diff --git a/apps/bwclk/app.js b/apps/bwclk/app.js index 67ed86552..c2518361b 100644 --- a/apps/bwclk/app.js +++ b/apps/bwclk/app.js @@ -327,9 +327,7 @@ Bangle.on('lock', lockListenerBw); let charging = function(charging){ // Jump to battery - clockInfoMenu.menuA = 0; - clockInfoMenu.menuB = 2; - clockInfoMenu.redraw(); + clockInfoMenu.setItem(0, 2); drawTime(); } Bangle.on('charging', charging); diff --git a/apps/bwclk/metadata.json b/apps/bwclk/metadata.json index 7c5d285e3..a29102bdf 100644 --- a/apps/bwclk/metadata.json +++ b/apps/bwclk/metadata.json @@ -1,7 +1,7 @@ { "id": "bwclk", "name": "BW Clock", - "version": "0.28", + "version": "0.29", "description": "A very minimalistic clock.", "readme": "README.md", "icon": "app.png", diff --git a/apps/cogclock/ChangeLog b/apps/cogclock/ChangeLog index f4bfe77a5..403cd2258 100644 --- a/apps/cogclock/ChangeLog +++ b/apps/cogclock/ChangeLog @@ -1,3 +1,4 @@ 0.01: New clock 0.02: Use ClockFace library, add settings 0.03: Use ClockFace_menu.addSettingsFile +0.04: Hide widgets instead of not loading them at all diff --git a/apps/cogclock/metadata.json b/apps/cogclock/metadata.json index 29000b589..d404275ee 100644 --- a/apps/cogclock/metadata.json +++ b/apps/cogclock/metadata.json @@ -1,7 +1,7 @@ { "id": "cogclock", "name": "Cog Clock", - "version": "0.03", + "version": "0.04", "description": "A cross-shaped clock inside a cog", "icon": "icon.png", "screenshots": [{"url":"screenshot.png"}], diff --git a/apps/cogclock/settings.js b/apps/cogclock/settings.js index a91b033d0..fb1dd761c 100644 --- a/apps/cogclock/settings.js +++ b/apps/cogclock/settings.js @@ -4,7 +4,7 @@ /*LANG*/"< Back": back, }; require("ClockFace_menu").addSettingsFile(menu, "cogclock.settings.json", [ - "showDate", "loadWidgets" + "showDate", "hideWidgets" ]); E.showMenu(menu); }); diff --git a/apps/dtlaunch/ChangeLog b/apps/dtlaunch/ChangeLog index b353459b9..e0bd76eb0 100644 --- a/apps/dtlaunch/ChangeLog +++ b/apps/dtlaunch/ChangeLog @@ -25,4 +25,6 @@ facilitate 'fast switching' of apps where available. widgets would still be loaded when they weren't supposed to. 0.21: Bangle 2: Call Bangle.drawWidgets() early on so that the widget field immediately follows the correct theme. +0.22: Bangle 2: Change to not automatically marking the first app on a page +when moving pages. Add caching for faster startups. diff --git a/apps/dtlaunch/app-b2.js b/apps/dtlaunch/app-b2.js index e1ce6d8d1..2070f1147 100644 --- a/apps/dtlaunch/app-b2.js +++ b/apps/dtlaunch/app-b2.js @@ -13,20 +13,25 @@ }, require('Storage').readJSON("dtlaunch.json", true) || {}); let s = require("Storage"); - var apps = s.list(/\.info$/).map(app=>{ - let a=s.readJSON(app,1); - return a && { - name:a.name, type:a.type, icon:a.icon, sortorder:a.sortorder, src:a.src - };}).filter( - app=>app && (app.type=="app" || (app.type=="clock" && settings.showClocks) || (app.type=="launch" && settings.showLaunchers) || !app.type)); - - apps.sort((a,b)=>{ - let n=(0|a.sortorder)-(0|b.sortorder); - if (n) return n; // do sortorder first - if (a.nameb.name) return 1; - return 0; - }); + // Borrowed caching from Icon Launcher, code by halemmerich. + let launchCache = s.readJSON("launch.cache.json", true)||{}; + let launchHash = require("Storage").hash(/\.info/); + if (launchCache.hash!=launchHash) { + launchCache = { + hash : launchHash, + apps : s.list(/\.info$/) + .map(app=>{var a=s.readJSON(app,1);return a&&{name:a.name,type:a.type,icon:a.icon,sortorder:a.sortorder,src:a.src};}) + .filter(app=>app && (app.type=="app" || (app.type=="clock" && settings.showClocks) || !app.type)) + .sort((a,b)=>{ + var n=(0|a.sortorder)-(0|b.sortorder); + if (n) return n; // do sortorder first + if (a.nameb.name) return 1; + return 0; + }) }; + s.writeJSON("launch.cache.json", launchCache); + } + let apps = launchCache.apps; apps.forEach(app=>{ if (app.icon) app.icon = s.read(app.icon); // should just be a link to a memory area @@ -90,7 +95,7 @@ let swipeListenerDt = function(dirLeftRight, dirUpDown){ updateTimeoutToClock(); - selected = 0; + selected = -1; oldselected=-1; if(settings.swipeExit && dirLeftRight==1) Bangle.showClock(); if (dirUpDown==-1||dirLeftRight==-1){ @@ -154,3 +159,4 @@ updateTimeoutToClock(); } // end of app scope + diff --git a/apps/dtlaunch/metadata.json b/apps/dtlaunch/metadata.json index d1aa6f679..b19d59e49 100644 --- a/apps/dtlaunch/metadata.json +++ b/apps/dtlaunch/metadata.json @@ -1,7 +1,7 @@ { "id": "dtlaunch", "name": "Desktop Launcher", - "version": "0.21", + "version": "0.22", "description": "Desktop style App Launcher with six (four for Bangle 2) apps per page - fast access if you have lots of apps installed.", "screenshots": [{"url":"shot1.png"},{"url":"shot2.png"},{"url":"shot3.png"}], "icon": "icon.png", diff --git a/apps/health/ChangeLog b/apps/health/ChangeLog index fb97552b1..7ea528ca6 100644 --- a/apps/health/ChangeLog +++ b/apps/health/ChangeLog @@ -18,3 +18,5 @@ 0.17: Add automatic translation of bar chart labels 0.18: Show step goal in daily step chart 0.19: Can show notification when daily step goal is reached +0.20: Fix the settings page, it would not update settings correctly. +0.21: Update boot.min.js. diff --git a/apps/health/boot.js b/apps/health/boot.js index 0f4e6c832..74ac7c894 100644 --- a/apps/health/boot.js +++ b/apps/health/boot.js @@ -105,7 +105,7 @@ function handleStepGoalNotification() { if (!settings.stepGoalNotificationDate || settings.stepGoalNotificationDate < now) { // notification not yet shown today? Bangle.buzz(200, 0.5); require("notify").show({ - title : /*LANG*/ settings.stepGoal + " steps", + title : settings.stepGoal + /*LANG*/ " steps", body : /*LANG*/ "You reached your step goal!", icon : atob("DAyBABmD6BaBMAsA8BCBCBCBCA8AAA==") }); diff --git a/apps/health/boot.min.js b/apps/health/boot.min.js index 963da9c6b..f255f271e 100644 --- a/apps/health/boot.min.js +++ b/apps/health/boot.min.js @@ -1,5 +1,5 @@ -function l(){var a=require("Storage").readJSON("health.json",1)||{},d=Bangle.getHealthStatus("day").steps;a.stepGoalNotification&&0=a.stepGoal&&(d=(new Date(Date.now())).toISOString().split("T")[0],!a.stepGoalNotificationDate||a.stepGoalNotificationDate=a.stepGoal&&(d=(new Date(Date.now())).toISOString().split("T")[0],!a.stepGoalNotificationDate||a.stepGoalNotificationDate=b;b++)setTimeout(function(){Bangle.setHRMPower(1,"health");setTimeout(function(){Bangle.setHRMPower(0,"health")},2E5*b+6E4)},2E5*b)};Bangle.on("health",d);Bangle.on("HRM",function(b){80>8,c.steps&255,c.bpm,Math.min(c.movement/8,255))}var b=new Date(Date.now()-59E4);a&&0k;k++)e=g.substr(h,4),"\u00ff\u00ff\u00ff\u00ff"!=e&&(a.steps+=(e.charCodeAt(0)<<8)+e.charCodeAt(1),a.movement+=e.charCodeAt(2),a.movCnt++,e=e.charCodeAt(2),a.bpm+=e,e&&a.bpmCnt++),h-=4;a.bpmCnt&&(a.bpm/= -a.bpmCnt);a.movCnt&&(a.movement/=a.movCnt);require("Storage").write(b,d(a),f,17988)}}) \ No newline at end of file +a.bpmCnt);a.movCnt&&(a.movement/=a.movCnt);require("Storage").write(b,d(a),f,17988)}}) diff --git a/apps/health/metadata.json b/apps/health/metadata.json index 704101138..482d72ec4 100644 --- a/apps/health/metadata.json +++ b/apps/health/metadata.json @@ -2,7 +2,7 @@ "id": "health", "name": "Health Tracking", "shortName": "Health", - "version": "0.19", + "version": "0.21", "description": "Logs health data and provides an app to view it", "icon": "app.png", "tags": "tool,system,health", diff --git a/apps/health/settings.js b/apps/health/settings.js index e7b0a7c15..4fb0f9e93 100644 --- a/apps/health/settings.js +++ b/apps/health/settings.js @@ -5,6 +5,9 @@ stepGoalNotification: false }, require("Storage").readJSON("health.json", true) || {}); + function setSettings() { + require("Storage").writeJSON("health.json", settings); + } E.showMenu({ "": { title: /*LANG*/"Health Tracking" }, @@ -22,7 +25,7 @@ ][v], onchange: v => { settings.hrm = v; - setSettings(settings); + setSettings(); } }, @@ -33,7 +36,7 @@ step: 250, onchange: v => { settings.stepGoal = v; - setSettings(settings); + setSettings(); } }, /*LANG*/"Step Goal Notification": { @@ -45,8 +48,4 @@ } } }); - - function setSettings(settings) { - require("Storage").writeJSON("health.json", settings); - } }) diff --git a/apps/messagelist/ChangeLog b/apps/messagelist/ChangeLog index 759f68777..8db873bb9 100644 --- a/apps/messagelist/ChangeLog +++ b/apps/messagelist/ChangeLog @@ -1 +1,2 @@ -0.01: New app! \ No newline at end of file +0.01: New app! +0.02: Fix music updates while app is already open diff --git a/apps/messagelist/app.js b/apps/messagelist/app.js index ebd5d4217..3e71f9544 100644 --- a/apps/messagelist/app.js +++ b/apps/messagelist/app.js @@ -85,9 +85,9 @@ } const setUI = function(options, cb) { + delete Bangle.uiRemove; // don't clear out things when switching UI within the app options = Object.assign({remove: () => uiRemove()}, options); Bangle.setUI(options, cb); - Bangle.on("message", onMessage); }; const remove = function(msg) { @@ -1161,48 +1161,49 @@ idx = MESSAGES.findIndex(m => m.src && m.src.toLowerCase().startsWith("alarm")); if (idx>=0) alarm = MESSAGES.splice(idx, 1)[0]; }; - if (MESSAGES!==undefined) { // only if loading MESSAGES worked - g.reset().clear(); - Bangle.loadWidgets(); - require("messages").toggleWidget(false); - Bangle.drawWidgets(); - findSpecials(); // sets global vars for special messages - // any message we asked to show? - const showIdx = MESSAGES.findIndex(m => m.show); - // any new text messages? - const newIdx = MESSAGES.findIndex(m => m.new); - // figure out why the app was loaded - if (showIdx>=0) show(showIdx); - else if (call && call.new) showCall(); - else if (alarm && alarm.new) showAlarm(); - else if (map && map.new) showMap(); - else if (music && music.new && settings().openMusic) { - if (settings().alwaysShowMusic===undefined) { - // if not explicitly disabled, enable this the first time we see music - let s = settings(); - s.alwaysShowMusic = true; - require("Storage").writeJSON("messages.settings.json", s); - } - showMusic(); + // Internal setUI suppresses Bangle.uiRemove between internal screens, so we + // need to call setUI to run uiRemove from previous app when fast-loaded. + Bangle.setUI(); + Bangle.loadWidgets(); + require("messages").toggleWidget(false); + Bangle.drawWidgets(); + findSpecials(); // sets global vars for special messages + // any message we asked to show? + const showIdx = MESSAGES.findIndex(m => m.show); + // any new text messages? + const newIdx = MESSAGES.findIndex(m => m.new); + + // figure out why the app was loaded + if (showIdx>=0) show(showIdx); + else if (call && call.new) showCall(); + else if (alarm && alarm.new) showAlarm(); + else if (map && map.new) showMap(); + else if (music && music.new && settings().openMusic) { + if (settings().alwaysShowMusic===undefined) { + // if not explicitly disabled, enable this the first time we see music + let s = settings(); + s.alwaysShowMusic = true; + require("Storage").writeJSON("messages.settings.json", s); } - // check for new message last: Maybe we already showed it, but timed out before - // if that happened, and we're loading for e.g. music now, we want to show the music screen - else if (newIdx>=0) { - showMessage(newIdx); - // auto-loaded for message(s): auto-close after timeout - let unreadTimeoutSecs = settings().unreadTimeout; - if (unreadTimeoutSecs===undefined) unreadTimeoutSecs = 60; - if (unreadTimeoutSecs) { - unreadTimeout = setTimeout(load, unreadTimeoutSecs*1000); - } - } else if (MESSAGES.length) { // not autoloaded, but we have messages to show - back = "main"; // prevent "back" from loading clock - showMessage(); - } else showMain(); - - // stop buzzing, auto-close timeout on input - ["touch", "drag", "swipe"].forEach(l => Bangle.on(l, clearUnreadStuff)); - (B2 ? [BTN1] : [BTN1, BTN2, BTN3]).forEach(b => watches.push(setWatch(clearUnreadStuff, b, false))); + showMusic(); } + // check for new message last: Maybe we already showed it, but timed out before + // if that happened, and we're loading for e.g. music now, we want to show the music screen + else if (newIdx>=0) { + showMessage(newIdx); + // auto-loaded for message(s): auto-close after timeout + let unreadTimeoutSecs = settings().unreadTimeout; + if (unreadTimeoutSecs===undefined) unreadTimeoutSecs = 60; + if (unreadTimeoutSecs) { + unreadTimeout = setTimeout(load, unreadTimeoutSecs*1000); + } + } else if (MESSAGES.length) { // not autoloaded, but we have messages to show + back = "main"; // prevent "back" from loading clock + showMessage(); + } else showMain(); + + // stop buzzing, auto-close timeout on input + ["touch", "drag", "swipe"].forEach(l => Bangle.on(l, clearUnreadStuff)); + (B2 ? [BTN1] : [BTN1, BTN2, BTN3]).forEach(b => watches.push(setWatch(clearUnreadStuff, b, false))); } \ No newline at end of file diff --git a/apps/messagelist/metadata.json b/apps/messagelist/metadata.json index 7947e2db4..72404263f 100644 --- a/apps/messagelist/metadata.json +++ b/apps/messagelist/metadata.json @@ -1,7 +1,7 @@ { "id": "messagelist", "name": "Message List", - "version": "0.01", + "version": "0.02", "description": "Display notifications from iOS and Gadgetbridge/Android as a list", "icon": "app.png", "type": "app", diff --git a/apps/mixdiganclock/ChangeLog b/apps/mixdiganclock/ChangeLog new file mode 100644 index 000000000..5354e44a7 --- /dev/null +++ b/apps/mixdiganclock/ChangeLog @@ -0,0 +1,3 @@ +0.01: fork from miclock, Added compatib with b widgets, devices(dynamic x,y) and themes(dynamic colors) +0.02: Code refactored, change colors in real time +0.03: Hour point size can be modified on real time. \ No newline at end of file diff --git a/apps/mixdiganclock/README.md b/apps/mixdiganclock/README.md new file mode 100644 index 000000000..aa860b4d4 --- /dev/null +++ b/apps/mixdiganclock/README.md @@ -0,0 +1,58 @@ +# Mix Digital & Analog Clock +A dual and simultaneous Analog and Digital Clock, also shows day, month and year. +Color are automatically set depending on the configured Theme or device, bunt also change on realtime through touching the right side. + +Compatible with BangleJS1,BangleJS2,and EMSCRIPTENx emulators + +## Pictures: + +Bangle JS1 + +![](photo_mixdigan_bjs1.jpg) + +Screenshot emulator BJS2 + +![](ss_mixdigan_ems2.png) + +Screenshot emulator BJS1 + +![](ss_mixdigan_ems.png) + + +SS emulator -color change +![](ss_mixdigan_ems_2.png) + +SS emulator -color change +![](ss_mixdigan_ems2_2.png) + +SS emulator -color change +![](ss_mixdigan_ems2_3.png) + +## Usage + +Open and see + +## Features + +Compatibility with devices +Dynamic Colours and positions +Support for bottom widgets + + +## Controls + +Exit : BTN2 (BJS1) +Exit/launcher : left area +Change Color : right area +Increase Hour Points : swipe right +Decrease Hour Points : swipe left + + +## Coming soon +A better color combination + +## Support + +This app is so basic that probably the easiest is to just edit the code ;) + +Otherwise you can contact me [here](https://github.com/dapgo/my_espruino_smartwatch_things) \ No newline at end of file diff --git a/apps/mixdiganclock/app-icon.js b/apps/mixdiganclock/app-icon.js new file mode 100644 index 000000000..8663b48d0 --- /dev/null +++ b/apps/mixdiganclock/app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEw4X/AAN994JB8noH+cFqtVqALHr5IB+oWHKgX/DAwWCDA8BA4IvBB4NABYcH/4KBAAP/6ALDj4WCDAX0BYd/6tVq2VqtX/ouECgILCEgIwCgP9BYt/BYUHFwQLDr48CBZcfHQILEq5ICBZd/LgQLDqpUCBbYAEC4+a1WlBaYjLBZNaIwIBBEYwLNy2WC6KbBC4qnFC4oLDZYILFa4oLJfYYADfYcB/4LF/4LCKgLkCcQRSCJAX1BYdfIwQ8CEgn/HQQwDDAVfFwgABA4IAC+oKEgEFBYdQBYoYDCwwYCF4IWHAFgA=")) \ No newline at end of file diff --git a/apps/mixdiganclock/metadata.json b/apps/mixdiganclock/metadata.json new file mode 100644 index 000000000..8fae2dd8f --- /dev/null +++ b/apps/mixdiganclock/metadata.json @@ -0,0 +1,17 @@ +{ + "id": "mixdiganclock", + "name": "Mix Dig&Anal Clock", + "version": "0.03", + "description": "A dual Analog and Digital Clock, based in Mixed Clock, but with more compatibility, change of colors, thicker clock hands... ", + "icon": "mixdiganclock.png", + "type": "clock", + "tags": "clock", + "screenshots": [{"url":"pic_mixdigan_bjs1.jpg"}], + "supports": ["BANGLEJS","BANGLEJS"], + "readme": "README.md", + "allow_emulator": true, + "storage": [ + {"name":"mixdiganclock.app.js","url":"mixdiganclock.app.js"}, + {"name":"mixdiganclock.img","url":"app-icon.js","evaluate":true} + ] +} diff --git a/apps/mixdiganclock/mixdiganclock.app.js b/apps/mixdiganclock/mixdiganclock.app.js new file mode 100644 index 000000000..bd36c0f32 --- /dev/null +++ b/apps/mixdiganclock/mixdiganclock.app.js @@ -0,0 +1,230 @@ +/*fork of miclock, dynamic x,y, colors on realtime, +compatible with BJS1, BJS2 and bottom widgets +*/ +var locale = require("locale"); +var v_mode_debug=0; //, 0=no, 1 min, 2 prone detail +var v_model=process.env.BOARD; +var LastDrawDay; // to notice a change and repaint static texts +//RGB565 0x White , black, 'Orange',blue,red, olive,... +var a_colors= [0xFFFF,0x0000, 0xFD20, 0x001F,0xF800,0x7be0,0x780F,0x07E0]; //new Array(0xFFFF +var Radius= []; //new Array(); +var TxtPosition=[]; +var v_bfont_size; +var v_vfont_size; +var v_color1; +var v_color2; +var v_color3; +var v_color_erase; +var v_count_col; +var rect = Bangle.appRect; +var v_center_x; +var v_center_y; +if (v_mode_debug>0) console.log("a_colors.length "+a_colors.length); + +g.clear(); +//show the exit button +//Bangle.setUI(); +Bangle.setUI("clock"); //implies center button for launcher +/*{ + mode : "custom", + back : Bangle.showLauncher +});*/ + +Bangle.loadWidgets(); + + + +function setVariables() { +// different values depending on loaded widgets or not, so after load widgets + rect = Bangle.appRect; + v_center_x = g.getWidth()/2; + v_center_y = g.getHeight()/2; //vertical middle + //if (v_mode_debug>1) console.log(v_model+" center x, y "+v_center_x+" , "+v_center_y+" Max y,y2"+rect.y+" ,"+rect.y2); + TxtPosition = { + "x1": 3, "x2": g.getWidth()-3, + "y1": rect.y+17, "y2": rect.y2-6, + "x_HH": g.getWidth()/2 ,"y_mm": v_center_y+32 + }; + + //emuls EMSCRIPTEN,EMSCRIPTEN2 + v_count_col=2; //1st=0 1st compatible color (dark/light theme) + v_color_erase=g.getBgColor(); + if (v_model=='BANGLEJS'||v_model=='EMSCRIPTEN') { + Radius = { "center": 7, "hour": 50, "min": 70, "dots": 88,"circleH":6,"circleM":2 }; + v_bfont_size=3; + v_vfont_size=35; + v_color1=2; // orange + v_color2=4; + v_color3=0; //white , for hands PEND replace hardcoded by logic + }else{ + Radius = { "center": 5, "hour": 35, "min": 50, "dots": 60, "circleH":5,"circleM":2 }; + v_bfont_size=2; + v_vfont_size=22; + v_color1=3; // blue + v_color2=1; + v_color3=1; //opposite to bg, for hands PEND replace hardcoded by logic + } + if (v_mode_debug>0) console.log("set vars for: "+v_model); +} + + +function rotatePoint(x, y, d) { + rad = -1 * d / 180 * Math.PI; + var sin = Math.sin(rad); + var cos = Math.cos(rad); + xn = ((v_center_x + x * cos - y * sin) + 0.5) | 0; + yn = ((v_center_y + x * sin - y * cos) + 0.5) | 0; + p = [xn, yn]; + return p; +} + +//no need to repaint +function drawStaticRing(v_colorparam){ + // draw hour and minute dots + if (v_mode_debug>0) console.log("color: "+v_colorparam); + //g.setColor(a_colors[v_color1]); + g.setColor(v_colorparam); + + for (i = 0; i < 60; i++) { + // ? 2 : 4; + radius = (i % 5) ? Radius.circleM : Radius.circleH; + point = rotatePoint(0, Radius.dots, i * 6); + //if (v_mode_debug>1) console.log("point"+point); + g.fillCircle(point[0], point[1], radius); + } +} + +//no need to repaint every min +function drawDailyTxt(){ + var date = new Date(); + var isEn = locale.name.startsWith("en"); + var dateArray = date.toString().split(" "); + LastDrawDay=locale.dow(date,true); + var hour = date.getHours(); + + if (v_mode_debug>1) { + console.log("full date "+date.toString()); + console.log("locale time "+locale.time(date,true)); + console.log("LastDrawDay "+LastDrawDay); + console.log("locale new day "+(locale.dow(date,true))); + } + g.setColor(a_colors[v_color2]); + //small size then bitmap + g.setFont("4x6", v_bfont_size); //6x8 + g.setFontAlign(-1, 0); + g.drawString(locale.dow(date,true) + ' ',TxtPosition.x1 , TxtPosition.y1, true); + g.drawString(isEn?(' ' + dateArray[2]):locale.month(date,true), TxtPosition.x1, TxtPosition.y2, true); + g.setFontAlign(1, 0); + g.drawString(isEn?locale.month(date,true):(' ' + dateArray[2]), TxtPosition.x2, TxtPosition.y1, true); + g.drawString(dateArray[3], TxtPosition.x2, TxtPosition.y2, true); +} + + +function drawMixedClock() { + var date = new Date(); + var dateArray = date.toString().split(" "); + //var isEn = locale.name.startsWith("en"); + var point = []; + var minute = date.getMinutes(); + var hour = date.getHours(); + var radius; + //Call function only after a change of day + if (LastDrawDay!=locale.dow(date,true)) drawDailyTxt(); + //ERASE previous hands + // erase last MINutes hand + g.setColor(v_color_erase); + point = rotatePoint(0, Radius.min, (minute - 1) * 6); + g.drawLine(v_center_x, v_center_y, point[0], point[1]); + //to increase thicknes + g.drawLine(v_center_x+1, v_center_y, point[0]+1, point[1]); + // erase last two HOUR hands ¿2? + g.setColor(v_color_erase); + p = rotatePoint(0, Radius.hour, hour % 12 * 30 + (minute - 2) / 2 | 0); + g.drawLine(v_center_x, v_center_y, p[0], p[1]); + //to increase thicknes + g.drawLine(v_center_x+1, v_center_y, p[0]+1, p[1]); + + point = rotatePoint(0, Radius.hour, hour % 12 * 30 + (minute - 1) / 2 | 0); + g.drawLine(v_center_x, v_center_y, point[0], point[1]); + //to increase thicknes + g.drawLine(v_center_x+1, v_center_y, point[0]+1, point[1]); + + // here time DIGITs are draw under hands + + // draw new MINute hand + point = rotatePoint(0, Radius.min, minute * 6); + g.setColor(a_colors[v_color3]); + g.drawLine(v_center_x, v_center_y, point[0], point[1]); + //to increase thicknes + g.drawLine(v_center_x+1, v_center_y, point[0]+1, point[1]); + // draw new HOUR hand + point = rotatePoint(0, Radius.hour, hour % 12 * 30 + date.getMinutes() / 2 | 0); + g.setColor(a_colors[v_color3]); + g.drawLine(v_center_x, v_center_y, point[0], point[1]); + //to increase thicknes + g.drawLine(v_center_x+1, v_center_y, point[0]+1, point[1]); + + // draw DIGITs of time above hands for better UX + //g.setFont("6x8", 3); 3 bigger size + g.setFontVector(v_vfont_size); + g.setColor(a_colors[v_color2]); + g.setFontAlign(0, 0); + //by default 24H, to use format config 12H 24H read from locale + g.drawString(dateArray[4].substr(0, 5), TxtPosition.x_HH, TxtPosition.y_mm, true); + // the central point requires redrawing because hands draw over it + g.setColor(a_colors[v_color1]); + g.fillCircle(v_center_x, v_center_y, Radius.center); +} +function UserInput(){ + Bangle.on('touch', function(button){ + switch(button){ + case 1: + Bangle.showLauncher(); + break; + case 2: + //testing to improve + if (v_mode_debug>0) console.log("v_count_col/total: "+v_count_col+"/"+a_colors.length); + if (v_count_col0) console.log("paint on color: "+v_count_col); + drawStaticRing(a_colors[v_color1]); + drawDailyTxt(); + break; + case 3: + //console.log("Touch 3 aka 1+2 not for emul");//center 1+2 + break; + } + }); + Bangle.on('swipe', dir => { + if(dir == 1) { + drawStaticRing(v_color_erase); + if (Radius.circleH<13) Radius.circleH++; + if (v_mode_debug>0) console.log("radio: "+Radius.circleH); + drawStaticRing(a_colors[v_color1]); + } + else { + drawStaticRing(v_color_erase); + if (Radius.circleH>1) Radius.circleH--; + if (v_mode_debug>0) console.log("radio: "+Radius.circleH); + drawStaticRing(a_colors[v_color1]); + } + }); +} +Bangle.on('lcdPower', function(on) { + if (on) + drawMixedClock(); +}); + +setVariables(); +Bangle.drawWidgets(); +UserInput(); + +setInterval(drawMixedClock, 5E3); +drawStaticRing(a_colors[v_color1]); +drawDailyTxt(); //1st time +drawMixedClock(); diff --git a/apps/mixdiganclock/mixdiganclock.info b/apps/mixdiganclock/mixdiganclock.info new file mode 100644 index 000000000..f9057ef5a --- /dev/null +++ b/apps/mixdiganclock/mixdiganclock.info @@ -0,0 +1 @@ +{"id":"mixdiganclock","name":"Mix Dig&Anal","type":"clock","src":"mixdiganclock.app.js","icon":"mixdiganclock.img","version":"0.02","tags":"clock","files":"mixdiganclock.info,mixdiganclock.app.js,mixdiganclock.img"} \ No newline at end of file diff --git a/apps/mixdiganclock/mixdiganclock.png b/apps/mixdiganclock/mixdiganclock.png new file mode 100644 index 000000000..9881aed85 Binary files /dev/null and b/apps/mixdiganclock/mixdiganclock.png differ diff --git a/apps/mixdiganclock/pic_mixdigan_bjs1.jpg b/apps/mixdiganclock/pic_mixdigan_bjs1.jpg new file mode 100644 index 000000000..eeb23a8ee Binary files /dev/null and b/apps/mixdiganclock/pic_mixdigan_bjs1.jpg differ diff --git a/apps/mixdiganclock/ss_mixdigan_ems.png b/apps/mixdiganclock/ss_mixdigan_ems.png new file mode 100644 index 000000000..0c4b6fab1 Binary files /dev/null and b/apps/mixdiganclock/ss_mixdigan_ems.png differ diff --git a/apps/mixdiganclock/ss_mixdigan_ems2.png b/apps/mixdiganclock/ss_mixdigan_ems2.png new file mode 100644 index 000000000..fee8b8ef3 Binary files /dev/null and b/apps/mixdiganclock/ss_mixdigan_ems2.png differ diff --git a/apps/mixdiganclock/ss_mixdigan_ems2_2.png b/apps/mixdiganclock/ss_mixdigan_ems2_2.png new file mode 100644 index 000000000..3dc16fa36 Binary files /dev/null and b/apps/mixdiganclock/ss_mixdigan_ems2_2.png differ diff --git a/apps/mixdiganclock/ss_mixdigan_ems2_3.png b/apps/mixdiganclock/ss_mixdigan_ems2_3.png new file mode 100644 index 000000000..c61b67fdd Binary files /dev/null and b/apps/mixdiganclock/ss_mixdigan_ems2_3.png differ diff --git a/apps/mixdiganclock/ss_mixdigan_ems_2.png b/apps/mixdiganclock/ss_mixdigan_ems_2.png new file mode 100644 index 000000000..94c1c5d78 Binary files /dev/null and b/apps/mixdiganclock/ss_mixdigan_ems_2.png differ diff --git a/apps/saclock/ChangeLog b/apps/saclock/ChangeLog new file mode 100644 index 000000000..88c983c2c --- /dev/null +++ b/apps/saclock/ChangeLog @@ -0,0 +1,2 @@ +0.01: New App! +0.02: Hide widgets instead of not loading them at all \ No newline at end of file diff --git a/apps/saclock/metadata.json b/apps/saclock/metadata.json index 558e28066..6ad55b0fe 100644 --- a/apps/saclock/metadata.json +++ b/apps/saclock/metadata.json @@ -1,7 +1,7 @@ { "id": "saclock", "name": "Simple analog clock", "shortName":"Analog clock", - "version":"0.01", + "version":"0.02", "description": "A very basic analog clock", "screenshots": [{"url":"screenshot.png"}], "icon": "icon.png", diff --git a/apps/saclock/settings.js b/apps/saclock/settings.js index 3b98f6a13..30ea95321 100644 --- a/apps/saclock/settings.js +++ b/apps/saclock/settings.js @@ -4,7 +4,7 @@ /*LANG*/"< Back": back, }; require("ClockFace_menu").addSettingsFile(menu, "saclock.settings.json", [ - "loadWidgets" + "hideWidgets" ]); E.showMenu(menu); }); diff --git a/apps/sched/ChangeLog b/apps/sched/ChangeLog index b24ba9266..6813345b7 100644 --- a/apps/sched/ChangeLog +++ b/apps/sched/ChangeLog @@ -19,3 +19,4 @@ 0.16: Improve support for date timezone 0.17: Fix midnight in local timezone (alarms wouldn't always fire as expected in timezone != 0) 0.18: Update clock_info to avoid a redraw +0.19: Update clock_info to refresh periodically on active alarms/timers diff --git a/apps/sched/clkinfo.js b/apps/sched/clkinfo.js index 439784039..b778bf970 100644 --- a/apps/sched/clkinfo.js +++ b/apps/sched/clkinfo.js @@ -49,6 +49,52 @@ return val; } + /* + * Returns the array [interval, switchTimeout] + * `interval` is the refresh rate (hourly or per minute) + * `switchTimeout` is the time before the refresh rate should change (or expiration) + */ + function getRefreshIntervals(a) { + const minute = 60 * 1000; + const halfhour = 30 * minute; + const hour = 2 * halfhour; + let msecs = alarm.getTimeToAlarm(a); + if(typeof msecs == "undefined" || msecs == 0) + return []; + if(msecs > hour) { //refresh every half an hour + let remain = (msecs+minute) % halfhour; + if(remain < 27 * minute && remain != 0) //first align period (some tolerance) + return [ halfhour, remain ]; + return [ halfhour, msecs - hour ]; + } else { //refresh every minute + //alarms just need the progress bar refreshed, no need every minute + if(!a.timer) return []; + return [ minute, msecs ]; + } + } + + function _doInterval(interval) { + return setTimeout(()=>{ + this.emit("redraw"); + this.interval = setInterval(()=>{ + this.emit("redraw"); + }, interval); + }, interval); + } + function _doSwitchTimeout(a, switchTimeout) { + return setTimeout(()=>{ + this.emit("redraw"); + clearInterval(this.interval); + this.interval = undefined; + var tmp = getRefreshIntervals(a); + var interval = tmp[0]; + var switchTimeout = tmp[1]; + if(!interval) return; + this.interval = _doInterval.call(this, interval); + this.switchTimeout = _doSwitchTimeout.call(this, a, switchTimeout); + }, switchTimeout); + } + var img = iconAlarmOn; //get only alarms not created by other apps var alarmItems = { @@ -63,8 +109,20 @@ hasRange: true, get: () => ({ text: getAlarmText(a), img: getAlarmIcon(a), v: getAlarmValue(a), min:0, max:getAlarmMax(a)}), - show: function() {}, - hide: function () {}, + show: function() { + var tmp = getRefreshIntervals(a); + var interval = tmp[0]; + var switchTimeout = tmp[1]; + if(!interval) return; + this.interval = _doInterval.call(this, interval); + this.switchTimeout = _doSwitchTimeout.call(this, a, switchTimeout); + }, + hide: function() { + clearInterval(this.interval); + clearTimeout(this.switchTimeout); + this.interval = undefined; + this.switchTimeout = undefined; + }, run: function() { } })), }; diff --git a/apps/sched/metadata.json b/apps/sched/metadata.json index a99e62089..9ffc28524 100644 --- a/apps/sched/metadata.json +++ b/apps/sched/metadata.json @@ -1,7 +1,7 @@ { "id": "sched", "name": "Scheduler", - "version": "0.18", + "version": "0.19", "description": "Scheduling library for alarms and timers", "icon": "app.png", "type": "scheduler", diff --git a/apps/tempmonitor/CSV_IDE_view.png b/apps/tempmonitor/CSV_IDE_view.png new file mode 100644 index 000000000..50725455b Binary files /dev/null and b/apps/tempmonitor/CSV_IDE_view.png differ diff --git a/apps/tempmonitor/CSV_excel_view.png b/apps/tempmonitor/CSV_excel_view.png new file mode 100644 index 000000000..b903515e8 Binary files /dev/null and b/apps/tempmonitor/CSV_excel_view.png differ diff --git a/apps/tempmonitor/ChangeLog b/apps/tempmonitor/ChangeLog index 2d9536fb9..99fe6a77d 100644 --- a/apps/tempmonitor/ChangeLog +++ b/apps/tempmonitor/ChangeLog @@ -1 +1,2 @@ 0.01: 1st version: saves values to csv +0.02: added HTML interface diff --git a/apps/tempmonitor/README.md b/apps/tempmonitor/README.md index 094a47868..a956f0e0f 100644 --- a/apps/tempmonitor/README.md +++ b/apps/tempmonitor/README.md @@ -17,6 +17,13 @@ Screenshot BJS1 ![](ss_emul_bjs1.png) +Screenshot data file content + +![](file_interface.png) + +![](CSV_IDE_view.png) + +![](CSV_excel_view.png) ## Usage diff --git a/apps/tempmonitor/file_interface.png b/apps/tempmonitor/file_interface.png new file mode 100644 index 000000000..2179d7d1e Binary files /dev/null and b/apps/tempmonitor/file_interface.png differ diff --git a/apps/tempmonitor/interface.html b/apps/tempmonitor/interface.html new file mode 100644 index 000000000..02d1fed91 --- /dev/null +++ b/apps/tempmonitor/interface.html @@ -0,0 +1,67 @@ + + + + + +
+ + + + + + \ No newline at end of file diff --git a/apps/tempmonitor/metadata.json b/apps/tempmonitor/metadata.json index bba8c6095..dafb70f27 100644 --- a/apps/tempmonitor/metadata.json +++ b/apps/tempmonitor/metadata.json @@ -1,12 +1,14 @@ { "id": "tempmonitor", "name": "Temperature monitor", - "version": "0.01", + "version": "0.02", "description": "Displays the current temperature and stores in a CSV file", "icon": "app.png", "tags": "tool", + "interface": "interface.html", "supports": ["BANGLEJS", "BANGLEJS2"], - "screenshots": [{"url":"photo_banglejs1.jpg"}], + "readme": "README.md", + "screenshots": [{"url":"ss_emul_bjs2.png"}], "allow_emulator": true, "storage": [ {"name":"tempmonitor.app.js","url":"tempmonitor.app.js"}, diff --git a/apps/tempmonitor/photo_banglejs1.jpg b/apps/tempmonitor/photo_banglejs1.jpg index 58c64b01c..7352e619a 100644 Binary files a/apps/tempmonitor/photo_banglejs1.jpg and b/apps/tempmonitor/photo_banglejs1.jpg differ diff --git a/apps/tempmonitor/ss_emul_bjs1.png b/apps/tempmonitor/ss_emul_bjs1.png index 1865ebc85..da7a53bd1 100644 Binary files a/apps/tempmonitor/ss_emul_bjs1.png and b/apps/tempmonitor/ss_emul_bjs1.png differ diff --git a/apps/tempmonitor/tempmonitor.app.js b/apps/tempmonitor/tempmonitor.app.js index 36b4bb654..62a4fee67 100644 --- a/apps/tempmonitor/tempmonitor.app.js +++ b/apps/tempmonitor/tempmonitor.app.js @@ -1,14 +1,14 @@ // Temperature monitor that saves a log of measures -// Version 001 standalone for developer -// PEND -//test with small savefreq +// standalone ver for developer, to remove testing lines +// delimiter ; (excel) or , (oldscool) +{ var v_mode_debug=0; //, 0=no, 1 min, 2 prone detail //var required for drawing with dynamic screen var rect = Bangle.appRect; var history = []; var readFreq=5000; //ms //PEND add to settings -var saveFreq=30000; //ms -var v_saveToFile='Y'; //Y save //N +var saveFreq=60000; //ms 1min +var v_saveToFile= new Boolean(true); //true save //false //with upload file º is not displayed properly //with upload RAM º is displayed var v_t_symbol="";//ºC @@ -68,10 +68,10 @@ function saveToFile() { var strlastSaveTime=new String(); strlastSaveTime=a.toISOString(); //strlastSaveTime=strlastSaveTime.concat(a.getFullYear(),a.getMonth()+1,a.getDate(),a.getHours(),a.getMinutes());; - if (v_mode_debug==1) console.log("saving="+strlastSaveTime+","+lastMeasure); - - if (v_saveToFile=='Y'){ - require("Storage").open(filename,"a").write(strlastSaveTime+","+lastMeasure+"\n"); + if (v_mode_debug==1) console.log("saving="+strlastSaveTime+";"+a.getHours()+":"+a.getMinutes()+";"+lastMeasure); + if (v_saveToFile==true){ + //write(strlastSaveTime+";"+ + require("Storage").open(filename,"a").write((a.getMonth()+1)+";"+a.getDate()+";"+a.getHours()+":"+a.getMinutes()+";"+lastMeasure+"\n"); //(getTime()+","); v_saved_entries=v_saved_entries+1; } @@ -127,11 +127,12 @@ setInterval(function() { drawTemperature(); }, readFreq); //ms -if (v_saveToFile=="Y") { +if (v_saveToFile==true) { setInterval(function() { saveToFile(); }, saveFreq); //ms } setTimeout(ClearScreen, 3500); setTimeout(drawGraph,4000); -setTimeout(drawTemperature,4500); \ No newline at end of file +setTimeout(drawTemperature,4500); +} \ No newline at end of file diff --git a/apps/terminalclock/ChangeLog b/apps/terminalclock/ChangeLog index 75d1a760e..268e0427c 100644 --- a/apps/terminalclock/ChangeLog +++ b/apps/terminalclock/ChangeLog @@ -5,3 +5,5 @@ 0.05: Add altitude display (only Bangle.js 2) 0.06: Add power related settings to control the HR and pressure(altitude) sensor from the watchface 0.07: Use ClockFace module and rework the settings to be able to personnalize the order of the lines +0.08: Hide widgets instead of not loading them at all + Use Clockface_menu for widgets and power saving settings diff --git a/apps/terminalclock/app.js b/apps/terminalclock/app.js index b60a32094..515ad8f66 100644 --- a/apps/terminalclock/app.js +++ b/apps/terminalclock/app.js @@ -32,7 +32,8 @@ const clock = new ClockFace({ this.unlock_precision = 1; if (this.HRMinConfidence === undefined) this.HRMinConfidence = 50; if (this.PowerOnInterval === undefined) this.PowerOnInterval = 15; - if (this.powerSaving===undefined) this.powerSaving = true; + if (this.powerSave===undefined) this.powerSave = this.powerSaving; // migrate old setting + if (this.powerSave===undefined) this.powerSave = true; ["L2", "L3", "L4", "L5", "L6", "L7", "L8", "L9"].forEach(k => { if (this[k]===undefined){ if(k == "L2") this[k] = "Date"; @@ -55,7 +56,7 @@ const clock = new ClockFace({ }); // set the services (HRM, pressure sensor, etc....) - if(!this.powerSaving){ + if(!this.powerSave){ turnOnServices(); } else{ setInterval(turnOnServices, this.PowerOnInterval*60000); // every PowerOnInterval min @@ -156,7 +157,7 @@ function turnOnServices(){ if(clock.showAltitude){ Bangle.setBarometerPower(true, "terminalclock"); } - if(clock.powerSaving){ + if(clock.powerSave){ setTimeout(function () { turnOffServices(); }, 45000); @@ -194,7 +195,7 @@ Clock related functions but not in the ClockFace module ---------------------------------------------------- */ function unlock(){ - if(clock.powerSaving){ + if(clock.powerSave){ turnOnServices(); } clock.precision = clock.unlock_precision; diff --git a/apps/terminalclock/metadata.json b/apps/terminalclock/metadata.json index a8682f9a8..8403a3b4d 100644 --- a/apps/terminalclock/metadata.json +++ b/apps/terminalclock/metadata.json @@ -3,7 +3,7 @@ "name": "Terminal Clock", "shortName":"Terminal Clock", "description": "A terminal cli like clock displaying multiple sensor data", - "version":"0.07", + "version":"0.08", "icon": "app.png", "type": "clock", "tags": "clock", diff --git a/apps/terminalclock/settings.js b/apps/terminalclock/settings.js index f347e8ee3..80f6248ed 100644 --- a/apps/terminalclock/settings.js +++ b/apps/terminalclock/settings.js @@ -2,11 +2,8 @@ var FILE = "terminalclock.json"; // Load settings var settings = Object.assign({ - // ClockFace lib - loadWidgets: true, // TerminalClock specific HRMinConfidence: 50, - powerSaving: true, PowerOnInterval: 15, L2: 'Date', L3: 'HR', @@ -17,6 +14,18 @@ L8: 'Empty', L9: 'Empty', }, require('Storage').readJSON(FILE, true) || {}); + // ClockFace lib: migrate "don't load widgets" to "hide widgets" + if (!("hideWidgets" in settings)) { + if (("loadWidgets" in settings) && !settings.loadWidgets) settings.hideWidgets = 1; + else settings.hideWidgets = 0; + } + delete settings.loadWidgets; + // ClockFace lib: migrate `powerSaving` to `powerSave` + if (!("powerSave" in settings)) { + if ("powerSaving" in settings) settings.powerSave = settings.powerSaving; + else settings.powerSave = true; + } + delete settings.powerSaving; function writeSettings() { require('Storage').writeJSON(FILE, settings); @@ -63,25 +72,16 @@ writeSettings(); } }, - 'Show widgets': { - value: settings.loadWidgets, - onchange: v => { - settings.loadWidgets = v; - writeSettings(); - } - }, - 'Power saving': { - value: settings.powerSaving, - onchange: v => { - settings.powerSaving = v; - writeSettings(); - setTimeout(function() { - E.showMenu(getMainMenu()); - },0); - } - } }; - if(settings.powerSaving){ + const save = (key, v) => { + settings[key] = v; + writeSettings(); + }; + require("ClockFace_menu").addItems(mainMenu, save, { + hideWidgets: settings.hideWidgets, + powerSave: settings.powerSave, + }); + if(settings.powerSave){ mainMenu['Power on interval'] = { value: settings.PowerOnInterval, min: 3, max: 60, diff --git a/apps/widclk/widget.js b/apps/widclk/widget.js index 7c281f761..a31bd4772 100644 --- a/apps/widclk/widget.js +++ b/apps/widclk/widget.js @@ -6,7 +6,7 @@ WIDGETS["wdclk"]={area:"tl",width:Bangle.CLOCK?0:52/* g.stringWidth("00:00") */, this.width = Bangle.CLOCK?0:52; return setTimeout(Bangle.drawWidgets,1); // widget changed size - redraw } - if (!this.width) return; // if size not right, return + if (!this.width) return; // if not visible, return g.reset().setFontCustom(atob("AAAAAAAAAAIAAAQCAQAAAd0BgMBdwAAAAAAAdwAB0RiMRcAAAERiMRdwAcAQCAQdwAcERiMRBwAd0RiMRBwAAEAgEAdwAd0RiMRdwAcERiMRdwAFAAd0QiEQdwAdwRCIRBwAd0BgMBAAABwRCIRdwAd0RiMRAAAd0QiEQAAAAAAAAAA="), 32, atob("BgAAAAAAAAAAAAAAAAYCAAYGBgYGBgYGBgYCAAAAAAAABgYGBgYG"), 512+9); var time = require("locale").time(new Date(),1); g.drawString(time, this.x, this.y+3, true); // 5 * 6*2 = 60 diff --git a/apps/widclkbttm/README.md b/apps/widclkbttm/README.md index 5e386a757..a8379e288 100644 --- a/apps/widclkbttm/README.md +++ b/apps/widclkbttm/README.md @@ -1,5 +1,9 @@ # Digital clock widget (bottom widget area) -This very basic widget clock allows to test the unfrequently used widget bottom area. +This very basic widget clock shows time inside apps that respect the bottom widget area, also allows to test this unfrequently used area. + +Note that it will not be displayed when a clock app is been shown + +Compatible with BangleJS1,BangleJS2,and EMSCRIPTENx emulators forked from https://github.com/espruino/BangleApps/tree/master/apps/widclk @@ -10,14 +14,17 @@ Example of usage ![](widTextBottom_ss1.jpg) +Screenshot emulator bangle.js2 + +![](ss_bjs2.jpg) + ## Usage Upload the widget file -Open an app that supports displaying widgets - +Open an app (not a clock/watchface) that supports displaying widgets (included the bottom one) @@ -25,4 +32,4 @@ Open an app that supports displaying widgets This app is so basic that probably the easiest is to just edit the code ;) -Otherwise you can contact me [here](https://github.com/dapgo) \ No newline at end of file +Otherwise you can contact me [here](https://github.com/dapgo/my_espruino_smartwatch_things) \ No newline at end of file diff --git a/apps/widclkbttm/metadata.json b/apps/widclkbttm/metadata.json index 2bcd6bc58..4b14ef9c6 100644 --- a/apps/widclkbttm/metadata.json +++ b/apps/widclkbttm/metadata.json @@ -3,11 +3,12 @@ "name": "Digital clock (Bottom) widget", "shortName": "Digital clock Bottom Widget", "version": "0.05", - "description": "Displays time in the bottom of the screen (may not be compatible with some apps)", + "description": "Displays time HH:mm in the bottom of the screen (may not be compatible with some apps)", "icon": "widclkbttm.png", "type": "widget", "tags": "widget", "supports": ["BANGLEJS","BANGLEJS2"], + "screenshots": [{"url":"ss_bjs1.png"}], "readme": "README.md", "storage": [ {"name":"widclkbttm.wid.js","url":"widclkbttm.wid.js"} diff --git a/apps/widclkbttm/ss_bjs1.png b/apps/widclkbttm/ss_bjs1.png new file mode 100644 index 000000000..b1b2f553a Binary files /dev/null and b/apps/widclkbttm/ss_bjs1.png differ diff --git a/apps/widclkbttm/ss_bjs2.png b/apps/widclkbttm/ss_bjs2.png new file mode 100644 index 000000000..a7c557c53 Binary files /dev/null and b/apps/widclkbttm/ss_bjs2.png differ diff --git a/apps/widclkbttm/widclkbttm.wid.js b/apps/widclkbttm/widclkbttm.wid.js index 2278b5380..50142a5b9 100644 --- a/apps/widclkbttm/widclkbttm.wid.js +++ b/apps/widclkbttm/widclkbttm.wid.js @@ -1,9 +1,9 @@ WIDGETS["wdclkbttm"]={area:"br",width:Bangle.CLOCK?0:60,draw:function() { if (!Bangle.CLOCK == !this.width) { // if we're the wrong size for if we have a clock or not... - this.width = Bangle.CLOCK?0:60; + this.width = Bangle.CLOCK?0:60; return setTimeout(Bangle.drawWidgets,1); // widget changed size - redraw } - if (!this.width) return; // if size not right, return + if (!this.width) return; // if not visible, return g.reset().setFont("6x8", 2).setFontAlign(-1, 0); var time = require("locale").time(new Date(),1); g.drawString(time, this.x, this.y+11, true); // 5 * 6*2 = 60 diff --git a/apps/widhwbttm/ChangeLog b/apps/widhwbttm/ChangeLog index 23192b302..7d3aafc41 100644 --- a/apps/widhwbttm/ChangeLog +++ b/apps/widhwbttm/ChangeLog @@ -1,2 +1,3 @@ 0.01: 1st ver, inspired in some code from widclkbttm (Digital clock bttom widget) 0.02: Correction, intervals, dynamic color and font size depending on device +0.03: minor corrections, and color depending on theme diff --git a/apps/widhwbttm/README.md b/apps/widhwbttm/README.md index 2427ff818..85f7af47f 100644 --- a/apps/widhwbttm/README.md +++ b/apps/widhwbttm/README.md @@ -2,8 +2,9 @@ A basic HW/performance monitor widget that shows on real time some technical info, such as free mem, free storage, trash mem, files, FW version. Also allows to test the unfrequently used widget bottom area. Compatible with BangleJS1,BangleJS2,and EMSCRIPTENx emulators +Dynamic Color dependant on Theme color bg -forked from widclkbttm (Digital clock bttom widget) +forked from my widclkbttm (Digital clock bttom widget) ## Photo @@ -13,6 +14,8 @@ Example of usage ![](widhwbttm.ss1.jpg) ![](widhwbttm.ss2.jpg) +Screenshot emulator +![](screenshot_ems2.png) diff --git a/apps/widhwbttm/metadata.json b/apps/widhwbttm/metadata.json index f455e90a7..8a6957a46 100644 --- a/apps/widhwbttm/metadata.json +++ b/apps/widhwbttm/metadata.json @@ -2,12 +2,13 @@ "id": "widhwbttm", "name": "HW stats (Bottom) widget", "shortName": "Digital clock Bottom Widget", - "version": "0.02", - "description": "Displays technical info and mem stats in the bottom of the screen (may not be compatible with some apps)", + "version": "0.03", + "description": "Displays technical info, such as model, ver, temperatura or mem stats in the bottom of the screen (may not be compatible with some apps)", "icon": "widhwbttm.png", "type": "widget", "tags": "widget", "supports": ["BANGLEJS","BANGLEJS2"], + "screenshots": [{"url":"screenshot.png"}], "readme": "README.md", "storage": [ {"name":"widhwbttm.wid.js","url":"widhwbttm.wid.js"} diff --git a/apps/widhwbttm/screenshot.png b/apps/widhwbttm/screenshot.png new file mode 100644 index 000000000..de648d399 Binary files /dev/null and b/apps/widhwbttm/screenshot.png differ diff --git a/apps/widhwbttm/screenshot_ems2.png b/apps/widhwbttm/screenshot_ems2.png new file mode 100644 index 000000000..d0c753946 Binary files /dev/null and b/apps/widhwbttm/screenshot_ems2.png differ diff --git a/apps/widhwbttm/widhwbttm.wid.js b/apps/widhwbttm/widhwbttm.wid.js index ec7b568a0..551e2005b 100644 --- a/apps/widhwbttm/widhwbttm.wid.js +++ b/apps/widhwbttm/widhwbttm.wid.js @@ -1,57 +1,59 @@ (function() { - let intervalRef = null; - var v_switch; // show stats + let intervalRef = null; + var v_count; // show stats var v_str_hw=new String(); - if (process.env.BOARD=='BANGLEJS'||process.env.BOARD=='EMSCRIPTEN') var v_font_size=16; - else var v_font_size=14; - if (v_switch == null || v_switch == '') v_switch=0; - function draw(){ - if (Bangle.CLOCK) return; + //if (process.env.BOARD=='BANGLEJS'||process.env.BOARD=='EMSCRIPTEN') var v_bfont_size=2; + var v_bfont_size=2; + if (g.theme.dark==true) var v_color=0xFFFF; //white + else var v_color=0x0000; //black + if (v_count == null || v_count == '') v_count=0; - if (v_switch==0) { - // var v_hw=process.env.VERSION; - v_str_hw="V "+process.env.VERSION.substr(0,6); - v_switch++; - } else if (v_switch==1) { + function draw(){ + // if (Bangle.CLOCK) return; //to remove from a clock + if (v_count==0) { + v_str_hw=process.env.VERSION.substr(0,6); + v_count++; + } else if (v_count==1) { v_str_hw=process.env.BOARD.substr(0,3)+".."+process.env.BOARD.substr(process.env.BOARD.length-3,3); - v_switch++; - } - else if (v_switch==2) { + v_count++; + } else if (v_count==2) { v_str_hw="Bat "+E.getBattery()+"%"; - v_switch++; - } + v_count++; + } + else if (v_count==3 && process.env.BOARD.substr(0,6)=='BANGLE') { + v_str_hw="Tmp "+E.getTemperature(); + v_count++; + } else { // text prefix has to be 4char stor=require("Storage").getStats(); - if (v_switch==3) { + if (v_count==4) { v_str_hw="Fre "+process.memory().free; //+"/"+process.memory().total; - v_switch++; + v_count++; } - else if (v_switch==4) { - v_str_hw="Sto "+stor.freeBytes; - v_switch++; - } else if (v_switch==5) { - v_str_hw="Tra "+stor.trashBytes; - v_switch++; - } else if (v_switch==6) { + else if (v_count==5) { + v_str_hw="Sto "+stor.freeBytes; + v_count++; + } else if (v_count==6) { + v_str_hw="Tra "+stor.trashBytes; + v_count++; + } else if (v_count==7) { v_str_hw="Fil "+stor.fileCount; - v_switch=0; - } - // 4 char are prefix - if (v_str_hw.length>7) { - //replace 3 digits by k - //substring betw x and y - v_str_hw=v_str_hw.substr(0,v_str_hw.length-3)+"k"; - } - } //else storage - g.reset().setFontVector(v_font_size).setFontAlign(-1, 0); - //clean a longer previous string, care with br widgets - g.drawString(" ", this.x, this.y+11, true); - g.drawString(v_str_hw, this.x, this.y+11, true); - } //end draw + v_count=0; + } + // 4 char are prefix + if (v_str_hw.length>7) { + //replace 3 digits by k + v_str_hw=v_str_hw.substr(0,v_str_hw.length-3)+"k"; + } + } //end else storage + g.reset().setColor(v_color).setFont("6x8",v_bfont_size).setFontAlign(-1, 0); + //clean a longer previous string, care with br widgets + g.drawString(" ", this.x, this.y+11, true); + g.drawString(v_str_hw, this.x, this.y+11, true); + } //end draw -WIDGETS["wdhwbttm"]={area:"bl",width:60,draw:draw}; -//{area:"bl",width:Bangle.CLOCK?0:60,draw:draw}; +WIDGETS["wdhwbttm"]={area:"bl",width:100,draw:draw}; if (Bangle.isLCDOn) intervalRef = setInterval(()=>WIDGETS["wdhwbttm"].draw(), 10*1000); })() diff --git a/modules/ClockFace.js b/modules/ClockFace.js index bf64d418a..10dfb9e43 100644 --- a/modules/ClockFace.js +++ b/modules/ClockFace.js @@ -41,17 +41,12 @@ function ClockFace(options) { this[k] = settings[k]; }); } - // these default to true - ["showDate", "loadWidgets"].forEach(k => { - if (this[k]===undefined) this[k] = true; - }); + // showDate defaults to true + if (this.showDate===undefined) this.showDate = true; + // if (old) setting was to not load widgets, default to hiding them + if (this.hideWidgets===undefined && this.loadWidgets===false) this.hideWidgets = 1; + let s = require("Storage").readJSON("setting.json",1)||{}; - if ((global.__FILE__===undefined || global.__FILE__===s.clock) - && s.clockHasWidgets!==this.loadWidgets) { - // save whether we can Fast Load - s.clockHasWidgets = this.loadWidgets; - require("Storage").writeJSON("setting.json", s); - } // use global 24/12-hour setting if not set by clock-settings if (!('is12Hour' in this)) this.is12Hour = !!(s["12hour"]); } @@ -92,7 +87,9 @@ ClockFace.prototype.start = function() { .CLOCK is set by Bangle.setUI('clock') but we want to load widgets so we can check appRect and *then* call setUI. see #1864 */ Bangle.CLOCK = 1; - if (this.loadWidgets) Bangle.loadWidgets(); + Bangle.loadWidgets(); + const widget_util = ["show", "hide", "swipeOn"][this.hideWidgets|0]; + require("widget_utils")[widget_util](); if (this.init) this.init.apply(this); const uiRemove = this._remove ? () => this.remove() : undefined; if (this._upDown) { @@ -133,6 +130,7 @@ ClockFace.prototype.resume = function() { }; ClockFace.prototype.remove = function() { this._removed = true; + require("widget_utils").show(); if (this._timeout) clearTimeout(this._timeout); Bangle.removeListener("lcdPower", this._onLcd); if (this._remove) this._remove.apply(this); diff --git a/modules/ClockFace.md b/modules/ClockFace.md index f123d38c0..36452cf85 100644 --- a/modules/ClockFace.md +++ b/modules/ClockFace.md @@ -140,7 +140,7 @@ For example: // now clock.showDate === false; clock.foo === 123; - clock.loadWidgets === true; // default when not in settings file + clock.hideWidgets === 0; // default when not in settings file clock.is12Hour === ??; // not in settings file: uses global setting clock.start(); @@ -152,13 +152,14 @@ The following properties are automatically set on the clock: * `is12Hour`: `true` if the "Time Format" setting is set to "12h", `false` for "24h". * `paused`: `true` while the clock is paused. (You don't need to check this inside your `draw()` code) * `showDate`: `true` (if not overridden through the settings file.) -* `loadWidgets`: `true` (if not overridden through the settings file.) - If set to `false` before calling `start()`, the clock won't call `Bangle.loadWidgets();` for you. - Best is to add a setting for this, but if you never want to load widgets, you could do this: +* `hideWidgets`: `0` (if not overridden through the settings file.) + If set to `1` before calling `start()`, the clock calls `require("widget_utils")hide();` for you. + (Bangle.js 2 only: `2` for swipe-down) + Best is to add a setting for this, but if you never want to show widgets, you could do this: ```js var ClockFace = require("ClockFace"); var clock = new ClockFace({draw: function(){/*...*/}}); - clock.loadWidgets = false; // prevent loading of widgets + clock.hideWidgets = 1; // hide widgets clock.start(); ``` @@ -200,7 +201,7 @@ let menu = { }; require("ClockFace_menu").addItems(menu, save, { showDate: settings.showDate, - loadWidgets: settings.loadWidgets, + hideWidgets: settings.hideWidgets, }); E.showMenu(menu); @@ -213,7 +214,7 @@ let menu = { /*LANG*/"< Back": back, }; require("ClockFace_menu").addSettingsFile(menu, ".settings.json", [ - "showDate", "loadWidgets", "powerSave", + "showDate", "hideWidgets", "powerSave", ]); E.showMenu(menu); diff --git a/modules/ClockFace_menu.js b/modules/ClockFace_menu.js index a1dd76fee..e78246f43 100644 --- a/modules/ClockFace_menu.js +++ b/modules/ClockFace_menu.js @@ -10,13 +10,12 @@ exports.addItems = function(menu, callback, items) { let value = items[key]; const label = { showDate:/*LANG*/"Show date", - loadWidgets:/*LANG*/"Load widgets", + hideWidgets:/*LANG*/"Widgets", powerSave:/*LANG*/"Power saving", }[key]; switch(key) { // boolean options which default to true case "showDate": - case "loadWidgets": if (value===undefined) value = true; // fall through case "powerSave": @@ -25,6 +24,17 @@ exports.addItems = function(menu, callback, items) { value: !!value, onchange: v => callback(key, v), }; + break; + + case "hideWidgets": + let options = [/*LANG*/"Show",/*LANG*/"Hide"]; + if (process.env.HWVERSION===2) options.push(/*LANG*/"Swipe"); + menu[label] = { + value: value|0, + min: 0, max: options.length-1, + format: v => options[v|0], + onchange: v => callback(key, v), + }; } }); }; @@ -39,6 +49,12 @@ exports.addItems = function(menu, callback, items) { exports.addSettingsFile = function(menu, settingsFile, items) { let s = require("Storage").readJSON(settingsFile, true) || {}; + // migrate "don't load widgets" to "hide widgets" + if (!("hideWidgets" in s) && ("loadWidgets" in s) && !s.loadWidgets) { + s.hideWidgets = 1; + } + delete s.loadWidgets; + function save(key, value) { s[key] = value; require("Storage").writeJSON(settingsFile, s); diff --git a/modules/Layout.js b/modules/Layout.js index f8e27b66b..4cf8752a3 100644 --- a/modules/Layout.js +++ b/modules/Layout.js @@ -267,7 +267,7 @@ Layout.prototype.layout = function (l) { }); } }; - cb[l.type](l); + if (cb[l.type]) cb[l.type](l); }; Layout.prototype.debug = function(l,c) { if (!l) l = this._l; diff --git a/modules/Layout.min.js b/modules/Layout.min.js index 19e60f7a0..959657228 100644 --- a/modules/Layout.min.js +++ b/modules/Layout.min.js @@ -1,14 +1,14 @@ -function p(d,h){function b(e){"ram";e.id&&(a[e.id]=e);e.type||(e.type="");e.c&&e.c.forEach(b)}this._l=this.l=d;this.options=h||{};this.lazy=this.options.lazy||!1;this.physBtns=1;let f;if(2!=process.env.HWVERSION){this.physBtns=3;f=[];function e(l){"ram";"btn"==l.type&&f.push(l);l.c&&l.c.forEach(e)}e(d);f.length&&(this.physBtns=0,this.buttons=f,this.selectedButton=-1)}if(this.options.btns)if(d=this.options.btns,this.physBtns>=d.length){this.b=d;let e=Math.floor(Bangle.appRect.h/this.physBtns); -for(2d.length;)d.push({label:""});this._l.width=g.getWidth()-8;this._l={type:"h",filly:1,c:[this._l,{type:"v",pad:1,filly:1,c:d.map(l=>(l.type="txt",l.font="6x8",l.height=e,l.r=1,l))}]}}else this._l.width=g.getWidth()-32,this._l={type:"h",c:[this._l,{type:"v",c:d.map(e=>(e.type="btn",e.filly=1,e.width=32,e.r=1,e))}]},f&&f.push.apply(f,this._l.c[1].c);this.setUI();var a=this;b(this._l);this.updateNeeded=!0}function t(d,h,b,f,a){var e= -null==d.bgCol?a:g.toColor(d.bgCol);if(e!=a||"txt"==d.type||"btn"==d.type||"img"==d.type||"custom"==d.type){var l=d.c;delete d.c;var k="H"+E.CRC32(E.toJS(d));l&&(d.c=l);delete h[k]||((f[k]=[d.x,d.y,d.x+d.w-1,d.y+d.h-1]).bg=null==a?g.theme.bg:a,b&&(b.push(d),b=null))}if(d.c)for(var c of d.c)t(c,h,b,f,e)}p.prototype.setUI=function(){Bangle.setUI();let d;this.buttons&&(Bangle.setUI({mode:"updown",back:this.options.back,remove:this.options.remove},h=>{var b=this.selectedButton,f=this.buttons.length;if(void 0=== -h&&this.buttons[b])return this.buttons[b].cb();this.buttons[b]&&(delete this.buttons[b].selected,this.render(this.buttons[b]));b=(b+f+h)%f;this.buttons[b]&&(this.buttons[b].selected=1,this.render(this.buttons[b]));this.selectedButton=b}),d=!0);!this.options.back&&!this.options.remove||d||Bangle.setUI({mode:"custom",back:this.options.back,remove:this.options.remove});if(this.b){function h(b,f){.75=b.x&&f.y>=b.y&&f.x<=b.x+b.w&&f.y<=b.y+b.h&&(2==f.type&&b.cbl?b.cbl(f):b.cb&&b.cb(f));b.c&&b.c.forEach(a=>h(a,f))}Bangle.touchHandler=(b,f)=>h(this._l,f);Bangle.on("touch", -Bangle.touchHandler)}};p.prototype.render=function(d){function h(c){"ram";b.reset();void 0!==c.col&&b.setColor(c.col);void 0!==c.bgCol&&b.setBgColor(c.bgCol).clearRect(c.x,c.y,c.x+c.w-1,c.y+c.h-1);f[c.type](c)}d||(d=this._l);this.updateNeeded&&this.update();var b=g,f={"":function(){},txt:function(c){"ram";if(c.wrap){var m=b.setFont(c.font).setFontAlign(0,-1).wrapString(c.label,c.w),n=c.y+(c.h-b.getFontHeight()*m.length>>1);b.drawString(m.join("\n"),c.x+(c.w>>1),n)}else b.setFont(c.font).setFontAlign(0, -0,c.r).drawString(c.label,c.x+(c.w>>1),c.y+(c.h>>1))},btn:function(c){"ram";var m=c.x+(0|c.pad),n=c.y+(0|c.pad),q=c.w-(c.pad<<1),r=c.h-(c.pad<<1);m=[m,n+4,m+4,n,m+q-5,n,m+q-1,n+4,m+q-1,n+r-5,m+q-5,n+r-1,m+4,n+r-1,m,n+r-5,m,n+4];n=c.selected?b.theme.bgH:b.theme.bg2;b.setColor(n).fillPoly(m).setColor(c.selected?b.theme.fgH:b.theme.fg2).drawPoly(m);void 0!==c.col&&b.setColor(c.col);c.src?b.setBgColor(n).drawImage("function"==typeof c.src?c.src():c.src,c.x+c.w/2,c.y+c.h/2,{scale:c.scale||void 0,rotate:.5* -Math.PI*(c.r||0)}):b.setFont(c.font||"6x8:2").setFontAlign(0,0,c.r).drawString(c.label,c.x+c.w/2,c.y+c.h/2)},img:function(c){"ram";b.drawImage("function"==typeof c.src?c.src():c.src,c.x+c.w/2,c.y+c.h/2,{scale:c.scale||void 0,rotate:.5*Math.PI*(c.r||0)})},custom:function(c){"ram";c.render(c)},h:function(c){"ram";c.c.forEach(h)},v:function(c){"ram";c.c.forEach(h)}};if(this.lazy){this.rects||(this.rects={});var a=this.rects.clone(),e=[];t(d,a,e,this.rects,null);for(var l in a)delete this.rects[l];d= -Object.keys(a).map(c=>a[c]).reverse();for(var k of d)b.setBgColor(k.bg).clearRect.apply(g,k);e.forEach(h)}else h(d)};p.prototype.forgetLazyState=function(){this.rects={}};p.prototype.layout=function(d){var h={h:function(b){"ram";var f=b.x+(0|b.pad),a=0,e=b.c&&b.c.reduce((k,c)=>k+(0|c.fillx),0);e||(f+=b.w-b._w>>1,e=1);var l=f;b.c.forEach(k=>{k.x=0|l;f+=k._w;a+=0|k.fillx;l=f+Math.floor(a*(b.w-b._w)/e);k.w=0|l-k.x;k.h=0|(k.filly?b.h-(b.pad<<1):k._h);k.y=0|b.y+(0|b.pad)+((1+(0|k.valign))*(b.h-(b.pad<< -1)-k.h)>>1);if(k.c)h[k.type](k)})},v:function(b){"ram";var f=b.y+(0|b.pad),a=0,e=b.c&&b.c.reduce((k,c)=>k+(0|c.filly),0);e||(f+=b.h-b._h>>1,e=1);var l=f;b.c.forEach(k=>{k.y=0|l;f+=k._h;a+=0|k.filly;l=f+Math.floor(a*(b.h-b._h)/e);k.h=0|l-k.y;k.w=0|(k.fillx?b.w-(b.pad<<1):k._w);k.x=0|b.x+(0|b.pad)+((1+(0|k.halign))*(b.w-(b.pad<<1)-k.w)>>1);if(k.c)h[k.type](k)})}};h[d.type](d)};p.prototype.debug=function(d,h){d||(d=this._l);h=h||1;g.setColor(h&1,h&2,h&4).drawRect(d.x+h-1,d.y+h-1,d.x+d.w-h,d.y+d.h-h); -d.pad&&g.drawRect(d.x+d.pad-1,d.y+d.pad-1,d.x+d.w-d.pad,d.y+d.h-d.pad);h++;d.c&&d.c.forEach(b=>this.debug(b,h))};p.prototype.update=function(){function d(a){"ram";b[a.type](a);if(a.r&1){var e=a._w;a._w=a._h;a._h=e}a._w=Math.max(a._w+(a.pad<<1),0|a.width);a._h=Math.max(a._h+(a.pad<<1),0|a.height)}delete this.updateNeeded;var h=g,b={txt:function(a){"ram";a.font.endsWith("%")&&(a.font="Vector"+Math.round(h.getHeight()*a.font.slice(0,-1)/100));if(a.wrap)a._h=a._w=0;else{var e=g.setFont(a.font).stringMetrics(a.label); -a._w=e.width;a._h=e.height}},btn:function(a){"ram";a.font&&a.font.endsWith("%")&&(a.font="Vector"+Math.round(h.getHeight()*a.font.slice(0,-1)/100));var e=a.src?h.imageMetrics("function"==typeof a.src?a.src():a.src):h.setFont(a.font||"6x8:2").stringMetrics(a.label);a._h=16+e.height;a._w=20+e.width},img:function(a){"ram";var e=h.imageMetrics("function"==typeof a.src?a.src():a.src),l=a.scale||1;a._w=e.width*l;a._h=e.height*l},"":function(a){"ram";a._w=0;a._h=0},custom:function(a){"ram";a._w=0;a._h=0}, -h:function(a){"ram";a.c.forEach(d);a._h=a.c.reduce((e,l)=>Math.max(e,l._h),0);a._w=a.c.reduce((e,l)=>e+l._w,0);null==a.fillx&&a.c.some(e=>e.fillx)&&(a.fillx=1);null==a.filly&&a.c.some(e=>e.filly)&&(a.filly=1)},v:function(a){"ram";a.c.forEach(d);a._h=a.c.reduce((e,l)=>e+l._h,0);a._w=a.c.reduce((e,l)=>Math.max(e,l._w),0);null==a.fillx&&a.c.some(e=>e.fillx)&&(a.fillx=1);null==a.filly&&a.c.some(e=>e.filly)&&(a.filly=1)}},f=this._l;d(f);delete b;f.fillx||f.filly?(f.w=Bangle.appRect.w,f.h=Bangle.appRect.h, -f.x=Bangle.appRect.x,f.y=Bangle.appRect.y):(f.w=f._w,f.h=f._h,f.x=Bangle.appRect.w-f.w>>1,f.y=Bangle.appRect.y+(Bangle.appRect.h-f.h>>1));this.layout(f)};p.prototype.clear=function(d){d||(d=this._l);g.reset();void 0!==d.bgCol&&g.setBgColor(d.bgCol);g.clearRect(d.x,d.y,d.x+d.w-1,d.y+d.h-1)};exports=p \ No newline at end of file +function p(d,h){function b(e){"ram";e.id&&(a[e.id]=e);e.type||(e.type="");e.c&&e.c.forEach(b)}this._l=this.l=d;this.options=h||{};this.lazy=this.options.lazy||!1;this.physBtns=1;let f;if(2!=process.env.HWVERSION){this.physBtns=3;f=[];function e(l){"ram";"btn"==l.type&&f.push(l);l.c&&l.c.forEach(e)}e(d);f.length&&(this.physBtns=0,this.buttons=f,this.selectedButton=-1)}if(this.options.btns)if(d=this.options.btns,this.physBtns>=d.length){this.b=d;let e=Math.floor(Bangle.appRect.h/ +this.physBtns);for(2d.length;)d.push({label:""});this._l.width=g.getWidth()-8;this._l={type:"h",filly:1,c:[this._l,{type:"v",pad:1,filly:1,c:d.map(l=>(l.type="txt",l.font="6x8",l.height=e,l.r=1,l))}]}}else this._l.width=g.getWidth()-32,this._l={type:"h",c:[this._l,{type:"v",c:d.map(e=>(e.type="btn",e.filly=1,e.width=32,e.r=1,e))}]},f&&f.push.apply(f,this._l.c[1].c);this.setUI();var a=this;b(this._l);this.updateNeeded=!0}function t(d, +h,b,f,a){var e=null==d.bgCol?a:g.toColor(d.bgCol);if(e!=a||"txt"==d.type||"btn"==d.type||"img"==d.type||"custom"==d.type){var l=d.c;delete d.c;var k="H"+E.CRC32(E.toJS(d));l&&(d.c=l);delete h[k]||((f[k]=[d.x,d.y,d.x+d.w-1,d.y+d.h-1]).bg=null==a?g.theme.bg:a,b&&(b.push(d),b=null))}if(d.c)for(var c of d.c)t(c,h,b,f,e)}p.prototype.setUI=function(){Bangle.setUI();let d;this.buttons&&(Bangle.setUI({mode:"updown",back:this.options.back,remove:this.options.remove},h=>{var b=this.selectedButton,f=this.buttons.length; +if(void 0===h&&this.buttons[b])return this.buttons[b].cb();this.buttons[b]&&(delete this.buttons[b].selected,this.render(this.buttons[b]));b=(b+f+h)%f;this.buttons[b]&&(this.buttons[b].selected=1,this.render(this.buttons[b]));this.selectedButton=b}),d=!0);!this.options.back&&!this.options.remove||d||Bangle.setUI({mode:"custom",back:this.options.back,remove:this.options.remove});if(this.b){function h(b,f){.75=b.x&&f.y>=b.y&&f.x<=b.x+b.w&&f.y<=b.y+b.h&&(2==f.type&&b.cbl?b.cbl(f):b.cb&&b.cb(f));b.c&&b.c.forEach(a=>h(a,f))}Bangle.touchHandler= +(b,f)=>h(this._l,f);Bangle.on("touch",Bangle.touchHandler)}};p.prototype.render=function(d){function h(c){"ram";b.reset();void 0!==c.col&&b.setColor(c.col);void 0!==c.bgCol&&b.setBgColor(c.bgCol).clearRect(c.x,c.y,c.x+c.w-1,c.y+c.h-1);f[c.type](c)}d||(d=this._l);this.updateNeeded&&this.update();var b=g,f={"":function(){},txt:function(c){"ram";if(c.wrap){var m=b.setFont(c.font).setFontAlign(0,-1).wrapString(c.label,c.w),n=c.y+(c.h-b.getFontHeight()*m.length>>1);b.drawString(m.join("\n"),c.x+(c.w>> +1),n)}else b.setFont(c.font).setFontAlign(0,0,c.r).drawString(c.label,c.x+(c.w>>1),c.y+(c.h>>1))},btn:function(c){"ram";var m=c.x+(0|c.pad),n=c.y+(0|c.pad),q=c.w-(c.pad<<1),r=c.h-(c.pad<<1);m=[m,n+4,m+4,n,m+q-5,n,m+q-1,n+4,m+q-1,n+r-5,m+q-5,n+r-1,m+4,n+r-1,m,n+r-5,m,n+4];n=c.selected?b.theme.bgH:b.theme.bg2;b.setColor(n).fillPoly(m).setColor(c.selected?b.theme.fgH:b.theme.fg2).drawPoly(m);void 0!==c.col&&b.setColor(c.col);c.src?b.setBgColor(n).drawImage("function"==typeof c.src?c.src():c.src,c.x+ +c.w/2,c.y+c.h/2,{scale:c.scale||void 0,rotate:.5*Math.PI*(c.r||0)}):b.setFont(c.font||"6x8:2").setFontAlign(0,0,c.r).drawString(c.label,c.x+c.w/2,c.y+c.h/2)},img:function(c){"ram";b.drawImage("function"==typeof c.src?c.src():c.src,c.x+c.w/2,c.y+c.h/2,{scale:c.scale||void 0,rotate:.5*Math.PI*(c.r||0)})},custom:function(c){"ram";c.render(c)},h:function(c){"ram";c.c.forEach(h)},v:function(c){"ram";c.c.forEach(h)}};if(this.lazy){this.rects||(this.rects={});var a=this.rects.clone(),e=[];t(d,a,e,this.rects, +null);for(var l in a)delete this.rects[l];d=Object.keys(a).map(c=>a[c]).reverse();for(var k of d)b.setBgColor(k.bg).clearRect.apply(g,k);e.forEach(h)}else h(d)};p.prototype.forgetLazyState=function(){this.rects={}};p.prototype.layout=function(d){var h={h:function(b){"ram";var f=b.x+(0|b.pad),a=0,e=b.c&&b.c.reduce((k,c)=>k+(0|c.fillx),0);e||(f+=b.w-b._w>>1,e=1);var l=f;b.c.forEach(k=>{k.x=0|l;f+=k._w;a+=0|k.fillx;l=f+Math.floor(a*(b.w-b._w)/e);k.w=0|l-k.x;k.h=0|(k.filly?b.h-(b.pad<<1):k._h);k.y=0| +b.y+(0|b.pad)+((1+(0|k.valign))*(b.h-(b.pad<<1)-k.h)>>1);if(k.c)h[k.type](k)})},v:function(b){"ram";var f=b.y+(0|b.pad),a=0,e=b.c&&b.c.reduce((k,c)=>k+(0|c.filly),0);e||(f+=b.h-b._h>>1,e=1);var l=f;b.c.forEach(k=>{k.y=0|l;f+=k._h;a+=0|k.filly;l=f+Math.floor(a*(b.h-b._h)/e);k.h=0|l-k.y;k.w=0|(k.fillx?b.w-(b.pad<<1):k._w);k.x=0|b.x+(0|b.pad)+((1+(0|k.halign))*(b.w-(b.pad<<1)-k.w)>>1);if(k.c)h[k.type](k)})}};if(h[d.type])h[d.type](d)};p.prototype.debug=function(d,h){d||(d=this._l);h=h||1;g.setColor(h& +1,h&2,h&4).drawRect(d.x+h-1,d.y+h-1,d.x+d.w-h,d.y+d.h-h);d.pad&&g.drawRect(d.x+d.pad-1,d.y+d.pad-1,d.x+d.w-d.pad,d.y+d.h-d.pad);h++;d.c&&d.c.forEach(b=>this.debug(b,h))};p.prototype.update=function(){function d(a){"ram";b[a.type](a);if(a.r&1){var e=a._w;a._w=a._h;a._h=e}a._w=Math.max(a._w+(a.pad<<1),0|a.width);a._h=Math.max(a._h+(a.pad<<1),0|a.height)}delete this.updateNeeded;var h=g,b={txt:function(a){"ram";a.font.endsWith("%")&&(a.font="Vector"+Math.round(h.getHeight()*a.font.slice(0,-1)/100)); +if(a.wrap)a._h=a._w=0;else{var e=g.setFont(a.font).stringMetrics(a.label);a._w=e.width;a._h=e.height}},btn:function(a){"ram";a.font&&a.font.endsWith("%")&&(a.font="Vector"+Math.round(h.getHeight()*a.font.slice(0,-1)/100));var e=a.src?h.imageMetrics("function"==typeof a.src?a.src():a.src):h.setFont(a.font||"6x8:2").stringMetrics(a.label);a._h=16+e.height;a._w=20+e.width},img:function(a){"ram";var e=h.imageMetrics("function"==typeof a.src?a.src():a.src),l=a.scale||1;a._w=e.width*l;a._h=e.height*l}, +"":function(a){"ram";a._w=0;a._h=0},custom:function(a){"ram";a._w=0;a._h=0},h:function(a){"ram";a.c.forEach(d);a._h=a.c.reduce((e,l)=>Math.max(e,l._h),0);a._w=a.c.reduce((e,l)=>e+l._w,0);null==a.fillx&&a.c.some(e=>e.fillx)&&(a.fillx=1);null==a.filly&&a.c.some(e=>e.filly)&&(a.filly=1)},v:function(a){"ram";a.c.forEach(d);a._h=a.c.reduce((e,l)=>e+l._h,0);a._w=a.c.reduce((e,l)=>Math.max(e,l._w),0);null==a.fillx&&a.c.some(e=>e.fillx)&&(a.fillx=1);null==a.filly&&a.c.some(e=>e.filly)&&(a.filly=1)}},f=this._l; +d(f);delete b;f.fillx||f.filly?(f.w=Bangle.appRect.w,f.h=Bangle.appRect.h,f.x=Bangle.appRect.x,f.y=Bangle.appRect.y):(f.w=f._w,f.h=f._h,f.x=Bangle.appRect.w-f.w>>1,f.y=Bangle.appRect.y+(Bangle.appRect.h-f.h>>1));this.layout(f)};p.prototype.clear=function(d){d||(d=this._l);g.reset();void 0!==d.bgCol&&g.setBgColor(d.bgCol);g.clearRect(d.x,d.y,d.x+d.w-1,d.y+d.h-1)};exports=p \ No newline at end of file diff --git a/modules/clock_info.js b/modules/clock_info.js index e1323780d..b28271e9c 100644 --- a/modules/clock_info.js +++ b/modules/clock_info.js @@ -299,6 +299,23 @@ exports.addInteractive = function(menu, options) { options.redraw = function() { drawItem(menu[options.menuA].items[options.menuB]); }; + options.setItem = function (menuA, menuB) { + if (!menu[menuA] || !menu[menuA].items[menuB] || (options.menuA == menuA && options.menuB == menuB)) { + // menuA or menuB did not exist or did not change + return false; + } + + const oldMenuItem = menu[options.menuA].items[options.menuB]; + if (oldMenuItem) { + menuHideItem(oldMenuItem); + oldMenuItem.removeAllListeners("draw"); + } + options.menuA = menuA; + options.menuB = menuB; + menuShowItem(menu[options.menuA].items[options.menuB]); + + return true; + } return options; }; diff --git a/package-lock.json b/package-lock.json index e981abdb8..5e531b4a6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -987,9 +987,9 @@ "dev": true }, "json5": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", - "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", "dev": true, "requires": { "minimist": "^1.2.0"