From 3f1ded53ede093c29023a96541eb0738d3f04f25 Mon Sep 17 00:00:00 2001 From: Erik Andresen Date: Tue, 2 May 2023 19:33:29 +0200 Subject: [PATCH 01/78] calendar: Read day names from locale --- apps/calendar/calendar.js | 65 ++++----------------------------------- 1 file changed, 6 insertions(+), 59 deletions(-) diff --git a/apps/calendar/calendar.js b/apps/calendar/calendar.js index 6aab1aecd..ffe3084e6 100644 --- a/apps/calendar/calendar.js +++ b/apps/calendar/calendar.js @@ -55,65 +55,12 @@ if (settings.ndColors === true) { } function getDowLbls(locale) { - let dowLbls; - //TODO: Find some clever way to generate this programmatically from locale lib - switch (locale) { - case "de_AT": - case "de_CH": - case "de_DE": - if (startOnSun) { - dowLbls = ["So", "Mo", "Di", "Mi", "Do", "Fr", "Sa"]; - } else { - dowLbls = ["Mo", "Di", "Mi", "Do", "Fr", "Sa", "So"]; - } - break; - case "nl_NL": - if (startOnSun) { - dowLbls = ["zo", "ma", "di", "wo", "do", "vr", "za"]; - } else { - dowLbls = ["ma", "di", "wo", "do", "vr", "za", "zo"]; - } - break; - case "fr_BE": - case "fr_CH": - case "fr_FR": - if (startOnSun) { - dowLbls = ["Di", "Lu", "Ma", "Me", "Je", "Ve", "Sa"]; - } else { - dowLbls = ["Lu", "Ma", "Me", "Je", "Ve", "Sa", "Di"]; - } - break; - case "sv_SE": - if (startOnSun) { - dowLbls = ["Di", "Lu", "Ma", "Me", "Je", "Ve", "Sa"]; - } else { - dowLbls = ["Lu", "Ma", "Me", "Je", "Ve", "Sa", "Di"]; - } - break; - case "it_CH": - case "it_IT": - if (startOnSun) { - dowLbls = ["Do", "Lu", "Ma", "Me", "Gi", "Ve", "Sa"]; - } else { - dowLbls = ["Lu", "Ma", "Me", "Gi", "Ve", "Sa", "Do"]; - } - break; - case "oc_FR": - if (startOnSun) { - dowLbls = ["dg", "dl", "dm", "dc", "dj", "dv", "ds"]; - } else { - dowLbls = ["dl", "dm", "dc", "dj", "dv", "ds", "dg"]; - } - break; - default: - if (startOnSun) { - dowLbls = ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"]; - } else { - dowLbls = ["Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"]; - } - break; - } - return dowLbls; + let days = startOnSun ? [0, 1, 2, 3, 4, 5, 6] : [1, 2, 3, 4, 5, 6, 0]; + const d = new Date(); + return days.map(i => { + d.setDate(d.getDate() + (i + 7 - d.getDay()) % 7); + return require("locale").dow(d, 1); + }); } function sameDay(d1, d2) { From aa6d7cdbe197f8c8dde64699372f8c445aa7583f Mon Sep 17 00:00:00 2001 From: Erik Andresen Date: Tue, 2 May 2023 20:03:58 +0200 Subject: [PATCH 02/78] calendar: Display holidays --- apps/calendar/ChangeLog | 1 + apps/calendar/calendar.js | 47 ++++++++++++++++++++++--------------- apps/calendar/metadata.json | 2 +- 3 files changed, 30 insertions(+), 20 deletions(-) diff --git a/apps/calendar/ChangeLog b/apps/calendar/ChangeLog index 27e1e2517..c7902e263 100644 --- a/apps/calendar/ChangeLog +++ b/apps/calendar/ChangeLog @@ -13,3 +13,4 @@ 0.12: Mark dated events on a day 0.13: Switch to swipe left/right for month and up/down for year selection Display events for current month on touch +0.14: Add support for holidays diff --git a/apps/calendar/calendar.js b/apps/calendar/calendar.js index ffe3084e6..92e3428ba 100644 --- a/apps/calendar/calendar.js +++ b/apps/calendar/calendar.js @@ -36,7 +36,12 @@ const events = (require("Storage").readJSON("sched.json",1) || []).filter(a => a date.setHours(time.h); date.setMinutes(time.m); date.setSeconds(time.s); - return {date: date, msg: a.msg}; + return {date: date, msg: a.msg, type: "e"}; +}); +// add holidays +(require("Storage").readJSON("calendar.holiday.json",1) || []).forEach(h => { + const date = new Date(h.date); + events.push({date: date, msg: h.name, type: "h"}); }); events.sort((a,b) => a.date - b.date); @@ -167,6 +172,27 @@ function drawCalendar(date) { const y1 = y * rowH + headerH + rowH; const x2 = x * colW + colW; const y2 = y * rowH + headerH + rowH + rowH; + + if (eventsThisMonth.length > 0) { + // Display events for this day + eventsThisMonth.forEach((ev, idx) => { + if (sameDay(ev.date, curDay)) { + if (ev.type === "e") { // alarm/event + const hour = ev.date.getHours() + ev.date.getMinutes()/60.0; + const slice = hour/24*(eventsPerDay-1); // slice 0 for 0:00 up to eventsPerDay for 23:59 + const height = (y2-2) - (y1+2); // height of a cell + const sliceHeight = height/eventsPerDay; + const ystart = (y1+2) + slice*sliceHeight; + g.setColor(bgEvent).fillRect(x1+1, ystart, x2-2, ystart+sliceHeight); + } else if (ev.type === "h") { // holiday + g.setColor(bgColorWeekend).fillRect(x1+1, y1+1, x2-1, y2-1); + } + + eventsThisMonth.splice(idx, 1); // this event is no longer needed + } + }); + } + if (isToday) { g.setColor(red); g.drawRect(x1, y1, x2, y2); @@ -178,23 +204,6 @@ function drawCalendar(date) { ); } - if (eventsThisMonth.length > 0) { - // Display events for this day - g.setColor(bgEvent); - eventsThisMonth.forEach((ev, idx) => { - if (sameDay(ev.date, curDay)) { - const hour = ev.date.getHours() + ev.date.getMinutes()/60.0; - const slice = hour/24*(eventsPerDay-1); // slice 0 for 0:00 up to eventsPerDay for 23:59 - const height = (y2-2) - (y1+2); // height of a cell - const sliceHeight = height/eventsPerDay; - const ystart = (y1+2) + slice*sliceHeight; - g.fillRect(x1+1, ystart, x2-2, ystart+sliceHeight); - - eventsThisMonth.splice(idx, 1); // this event is no longer needed - } - }); - } - require("Font8x12").add(Graphics); g.setFont("8x12", fontSize); g.setColor(day < 50 ? fgOtherMonth : fgSameMonth); @@ -236,7 +245,7 @@ function setUI() { const menu = events.filter(ev => ev.date.getFullYear() === date.getFullYear() && ev.date.getMonth() === date.getMonth()).map(e => { const dateStr = require("locale").date(e.date, 1); const timeStr = require("locale").time(e.date, 1); - return { title: `${dateStr} ${timeStr}` + (e.msg ? " " + e.msg : "") }; + return { title: `${dateStr} ${e.type === "e" ? timeStr : ""}` + (e.msg ? " " + e.msg : "") }; }); if (menu.length === 0) { menu.push({title: /*LANG*/"No events"}); diff --git a/apps/calendar/metadata.json b/apps/calendar/metadata.json index 87599e3f4..bf5c67b09 100644 --- a/apps/calendar/metadata.json +++ b/apps/calendar/metadata.json @@ -1,7 +1,7 @@ { "id": "calendar", "name": "Calendar", - "version": "0.13", + "version": "0.14", "description": "Simple calendar", "icon": "calendar.png", "screenshots": [{"url":"screenshot_calendar.png"}], From 8650595ca42879087f496b40f81dcd7ddebcdcc9 Mon Sep 17 00:00:00 2001 From: Erik Andresen Date: Tue, 2 May 2023 22:30:47 +0200 Subject: [PATCH 03/78] calendar: Add interface.html for holidays --- apps/calendar/interface.html | 186 +++++++++++++++++++++++++++++++++++ apps/calendar/metadata.json | 3 +- 2 files changed, 188 insertions(+), 1 deletion(-) create mode 100644 apps/calendar/interface.html diff --git a/apps/calendar/interface.html b/apps/calendar/interface.html new file mode 100644 index 000000000..b70b26f9c --- /dev/null +++ b/apps/calendar/interface.html @@ -0,0 +1,186 @@ + + + + + + + + + +

Holidays

+ +
+ +
+ + + + + + + + + + + +
DateHoliday
+ +
+
+
+
+ +
+
+ +
+
+
+
+ + + + + diff --git a/apps/calendar/metadata.json b/apps/calendar/metadata.json index bf5c67b09..b7e40a1fd 100644 --- a/apps/calendar/metadata.json +++ b/apps/calendar/metadata.json @@ -9,10 +9,11 @@ "supports": ["BANGLEJS","BANGLEJS2"], "readme": "README.md", "allow_emulator": true, + "interface": "interface.html", "storage": [ {"name":"calendar.app.js","url":"calendar.js"}, {"name":"calendar.settings.js","url":"settings.js"}, {"name":"calendar.img","url":"calendar-icon.js","evaluate":true} ], - "data": [{"name":"calendar.json"}] + "data": [{"name":"calendar.json"}, {"name":"calendar.holiday.json"}] } From 2d752832b734aa85052c63211f7e9ea8be53a7b6 Mon Sep 17 00:00:00 2001 From: Erik Andresen Date: Tue, 2 May 2023 22:31:21 +0200 Subject: [PATCH 04/78] sched/interface: fix date format --- apps/sched/interface.html | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/apps/sched/interface.html b/apps/sched/interface.html index 366e597a2..f1ace7d0c 100644 --- a/apps/sched/interface.html +++ b/apps/sched/interface.html @@ -3,7 +3,7 @@ - + -

Holidays

+

Holidays

- +
+ + diff --git a/apps/calendar/metadata.json b/apps/calendar/metadata.json index b7e40a1fd..44a68d879 100644 --- a/apps/calendar/metadata.json +++ b/apps/calendar/metadata.json @@ -15,5 +15,5 @@ {"name":"calendar.settings.js","url":"settings.js"}, {"name":"calendar.img","url":"calendar-icon.js","evaluate":true} ], - "data": [{"name":"calendar.json"}, {"name":"calendar.holiday.json"}] + "data": [{"name":"calendar.json"}, {"name":"calendar.days.json"}] } From d4116f80d56b8ff1a9f8651d274cac0a06c7fd01 Mon Sep 17 00:00:00 2001 From: Erik Andresen Date: Thu, 4 May 2023 21:27:20 +0200 Subject: [PATCH 07/78] calendar: Change color for holidays --- apps/calendar/calendar.js | 8 ++++++-- apps/calendar/interface.html | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/apps/calendar/calendar.js b/apps/calendar/calendar.js index 7977b0196..d7c43eb1f 100644 --- a/apps/calendar/calendar.js +++ b/apps/calendar/calendar.js @@ -16,6 +16,7 @@ const white = "#ffffff"; const red = "#d41706"; const blue = "#0000ff"; const yellow = "#ffff00"; +const cyan = "#00ffff"; let bgColor = color4; let bgColorMonth = color1; let bgColorDow = color2; @@ -23,6 +24,7 @@ let bgColorWeekend = color3; let fgOtherMonth = gray1; let fgSameMonth = white; let bgEvent = blue; +let bgOtherEvent = "#ff8800"; const eventsPerDay=6; // how much different events per day we can display const date = new Date(); @@ -60,6 +62,7 @@ if (settings.ndColors === true) { fgOtherMonth = blue; fgSameMonth = black; bgEvent = color2; + bgOtherEvent = cyan; } function getDowLbls(locale) { @@ -163,10 +166,11 @@ function drawCalendar(date) { week2AfterMonth.setDate(week2AfterMonth.getDate() + 14); events.forEach(ev => { if (ev.repeat === "y") { - ev.date.setFullYear(date.getFullYear()); + ev.date.setFullYear(ev.date.getMonth() < 6 ? week2AfterMonth.getFullYear() : weekBeforeMonth.getFullYear()); } }); const eventsThisMonth = events.filter(ev => ev.date > weekBeforeMonth && ev.date < week2AfterMonth); + eventsThisMonth.sort((a,b) => a.date - b.date); let i = 0; for (y = 0; y < rowN - 1; y++) { for (x = 0; x < colN; x++) { @@ -197,7 +201,7 @@ function drawCalendar(date) { g.setColor(bgColorWeekend).fillRect(x1+1, y1+1, x2-1, y2-1); break; case "o": // other - g.setColor("#88ff00").fillRect(x1+1, y1+1, x2-1, y2-1); + g.setColor(bgOtherEvent).fillRect(x1+1, y1+1, x2-1, y2-1); break; } diff --git a/apps/calendar/interface.html b/apps/calendar/interface.html index 509a6bebd..280a96c0b 100644 --- a/apps/calendar/interface.html +++ b/apps/calendar/interface.html @@ -160,7 +160,7 @@ function renderHoliday(holiday) { } function addHoliday() { - const holiday = {date: formatDate(new Date())}; + const holiday = {date: formatDate(new Date()), type: 'h'}; renderHoliday(holiday); holidays.push(holiday); render(); From 42700ea24d0de4e188d9e3702ef28509b8a1eaa6 Mon Sep 17 00:00:00 2001 From: stweedo <108593831+stweedo@users.noreply.github.com> Date: Fri, 5 May 2023 12:09:58 -0500 Subject: [PATCH 08/78] v0.02 of Shadow Clock with settings menu --- apps/shadowclk/ChangeLog | 1 + apps/shadowclk/README.md | 25 ++++ apps/shadowclk/app-icon.js | 2 +- apps/shadowclk/app.js | 146 ++++++++++++-------- apps/shadowclk/app.png | Bin 8844 -> 2377 bytes apps/shadowclk/custom.html | 231 ++++++++++++++++++++++++++++++++ apps/shadowclk/icon.png | Bin 0 -> 446 bytes apps/shadowclk/metadata.json | 34 +++-- apps/shadowclk/screenshot-1.png | Bin 2704 -> 3510 bytes apps/shadowclk/screenshot.png | Bin 2676 -> 3505 bytes apps/shadowclk/settings.js | 58 ++++++++ 11 files changed, 430 insertions(+), 67 deletions(-) create mode 100644 apps/shadowclk/README.md create mode 100644 apps/shadowclk/custom.html create mode 100644 apps/shadowclk/icon.png create mode 100644 apps/shadowclk/settings.js diff --git a/apps/shadowclk/ChangeLog b/apps/shadowclk/ChangeLog index 5560f00bc..5a654d5a1 100644 --- a/apps/shadowclk/ChangeLog +++ b/apps/shadowclk/ChangeLog @@ -1 +1,2 @@ 0.01: New App! +0.02: New 'Settings Menu' to choose your favorite color and switch between light or dark themes diff --git a/apps/shadowclk/README.md b/apps/shadowclk/README.md new file mode 100644 index 000000000..15455f003 --- /dev/null +++ b/apps/shadowclk/README.md @@ -0,0 +1,25 @@ +# Shadow Clock + +Shadow Clock uses the "Londrina" font in a user selectable color and surrounds it in the "Londrina Shadow" font to create a visually appealing way to show the time in a clear, easily readable manner. On the Bangle.js 2, the time can be read easily even if the screen is locked and unlit. + +## Usage + +* Install Shadow Clock through the Bangle.js app loader. +* Configure it through the default Bangle.js configuration mechanism +(Settings app, "Apps" menu, "Shadow Clock" submenu). +* If you like it, make it your default watch face +(Settings app, "System" menu, "Clock" submenu, select "Shadow Clock"). + +## Configuration + +Anton Clock is configured by the standard settings mechanism of Bangle.js's operating system: +Open the `Settings` app, then the `Apps` submenu and below it the `Shadow Clock` menu. +You configure Shadow Clock by selecting a `Light` or `Dark` system wide theme and then selecting the color of the clock numbers. + +## Compatibility + +Shadow Clock should be compatible with with Bangle.js 1, however it was built and tested with Bangle.js 2 + +## Creator + +[stweedo](https://github.com/stweedo) diff --git a/apps/shadowclk/app-icon.js b/apps/shadowclk/app-icon.js index 3e3eee97f..afbb8269a 100644 --- a/apps/shadowclk/app-icon.js +++ b/apps/shadowclk/app-icon.js @@ -1 +1 @@ -require("heatshrink").decompress(atob("mEwhHXAH4A/AH4A/AH4A/AH4A/AH4A/AFGsAAQOUA4OBDBYfHo8jAAOBByOssgICkdkF6AWEF5IOHxAHDAAVALx4VEF5AOHA4oAD0ovNoEjo6BCF5AOHF4ccp9dAoVdFxh2CioUCa44OIwIFCirwBjgFBqyNPqxJCEAOIKwOIBxYJChwfBwIABJQ7dHnIkCEAsVBxovDdiMcVYIgHFQgOJR4WIxBdMCoccshUCkdkRYJ6DBxIvDAAlkF5wWLBxQKJOAIvTroOOBQkcmU5aoYAKhwACjiqDqwOOTQQqDGwQvMAAawCcoOsAAQOL642DBAI0EAB1AC4QfBJIU5BxQ2DAAp5FF6ZJFF4xgFAAMOOwyPKjkcCgWsAoMyBxQAB1k5BAMcZAQuPDIS6EYBAIRAHKHCAIhPLAoWswIMEL6OBDIgYGHA4qCCwIKBDIgvPDggnIAw7lBF4J4KR5gVJKgZDDIgQCDMITvXXA47EHxD2aFQhOCBAY8DRiiWLD4aEBMYzuCLzgvEEQK4BFAQCDB4TACF7QA/AH4A/AH4A/AAQA==")) +require("heatshrink").decompress(atob("mEwxH+64Afq17AAlWq2sBYOtB4Urq2BFzeBwONAAeyHAQvCrPX1g3BlYvb02BjwADF4QmBwdZF4MrleBgAvlgAwBgqQBlcAF72HF46PBwaPDwK/dVoLpBAAwMBweDFTYA/AH4A/AH4A/AF2lAAOsBRIAF6AMDp9Wp+lFyNWkYABitWFwoKCAAsHBgMyBAkVwIuO6EVCod6F50A6+BBI0VMRxGEF6BfBIwZqHABRGCo5EIF4cOgEHAAUA0scBYQDDCAIvMhx7CCYTfDAYIvDK4McNoaODh1PPgcO1jsNiskOYQTBh0cjlW1iDHfwJfDjmeoDKEABSlCgAlCF4QJGcgwPEfQ5eMFQIvDRYIfClesioADEgcrSAguEwJeNh1AAgQkBwOlkkkQoOBvQACIgRAB685F4wJBF5oAGp4UJ1i6CeQK/Dg4ECZYQvTComsnNdrp+B0rADlaKD1l6X52BgAACJIgvEFIcO0sOF4cAAgeISgYvLMg8HKoOBAAIvEAAsOL4bwGFxyuDg/QGoYZBT5AKBXQYvVCYUH1gvFqwjGTwWBGA0AOwIAN6EOhytBAwIFBh1PAoN6g8VskVmUAZoelBQVABQIuPMAS6DfYWBMgI9CwMrq2lDA2Bq1PFqLpCHBAWKMIJGBAgRDEABiKBlYTDAYcA1gKBqwgFlYMBLoIaBCIKZDABh+BDIQVBC4WsF4YOBGAmsBQSgCAIIvQFYIiBKwReDFQI3DEIlWFIIsBCwIABF6JhClZhBZQo8BAYIOBIoh0CBIJ5DAH4AEPYKBDWwSGCAoKIDAoIwcEwJ/CRYICCFoI8BQ4YKBMDhWBEwIjBYQcAAYQKBZIRfdAIJVCQgLkDAYJjCcX4A/AH4A/AFwA==")) diff --git a/apps/shadowclk/app.js b/apps/shadowclk/app.js index c18363f72..e69225035 100644 --- a/apps/shadowclk/app.js +++ b/apps/shadowclk/app.js @@ -1,63 +1,93 @@ // Clock with large colored digits using the "Londrina" font and a slightly larger "Londrina Shadow" font on top Graphics.prototype.setFontLondrinaSolid = function() { - // Actual height 59 (64 - 6) - return this.setFontCustom( - E.toString(require('heatshrink').decompress(atob('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'))), - 46, - atob("DyEqHigoJikpJygqEQ=="), - 81|65536 - ); -}; - -Graphics.prototype.setFontLondrinaShadow = function() { - // Actual height 63 (67 - 5) - return this.setFontCustom( - E.toString(require('heatshrink').decompress(atob('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'))), - 46, - atob("DyEqHigoJikpJygqEQ=="), - 81|65536 - ); -}; - -(function() { - let drawTimeout; - - // Actually draw the watch face - function draw() { - const x = g.getWidth() / 2; - const y = g.getHeight() / 2; - g.reset().clearRect(Bangle.appRect); - const date = new Date(); - var hour = String(date.getHours()).padStart(2, '0'); - if (hour[0] === '0') hour = hour[1]; - var minutes = String(date.getMinutes()).padStart(2, '0'); - const timeStr = hour + ':' + minutes; - - g.setFontAlign(0, 0).setFont("LondrinaSolid").setColor(0, 1, 1).drawString(timeStr, x - 1, y); - g.reset().setFontAlign(0, 0).setFont("LondrinaShadow").drawString(timeStr, x - 1, y); - - const locale = require("locale"); - const dateStr = locale.date(date, 0).toUpperCase() + "\n" + - locale.dow(date, 0).toUpperCase(); - g.setFontAlign(0, 0).setFont("6x8", 2).drawString(dateStr, x, y + 48); - - if (drawTimeout) clearTimeout(drawTimeout); - drawTimeout = setTimeout(() => { - drawTimeout = undefined; - draw(); - }, 60000 - (Date.now() % 60000)); - } - - Bangle.setUI({ - mode: "clock", - remove: function() { + // Actual height 59 (64 - 6) + return this.setFontCustom( + E.toString(require('heatshrink').decompress(atob('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'))), + 46, + atob("DyEqHigoJikpJygqEQ=="), + 81 | 65536 + ); + }; + + Graphics.prototype.setFontLondrinaShadow = function() { + // Actual height 63 (67 - 5) + return this.setFontCustom( + E.toString(require('heatshrink').decompress(atob('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'))), + 46, + atob("DyEqHigoJikpJygqEQ=="), + 81 | 65536 + ); + }; + + Graphics.prototype.setFontDotGothic16 = function() { + // Actual height 20 (19 - 0) + return this.setFontCustom( + E.toString(require('heatshrink').decompress(atob('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'))), + 32, + atob("CgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoA"), + 20|65536 + ); + }; + + const storage = require('Storage'); + + var settings = Object.assign({ + // default values + color: "#0ff", + theme: "light", + }, storage.readJSON("shadowclk.json", true) || {}); + + (function() { + let drawTimeout; + + function draw() { + const x = g.getWidth() / 2; + const y = g.getHeight() / 2; + g.reset().clearRect(Bangle.appRect); + const date = new Date(); + var hour = String(date.getHours()).padStart(2, '0'); + if (hour[0] === '0') hour = hour[1]; + var minutes = String(date.getMinutes()).padStart(2, '0'); + const timeStr = hour + ':' + minutes; + var color = settings.color; + g.setFontAlign(0, 0).setFont("LondrinaSolid").setColor(color).drawString(timeStr, x - 1, y); + g.reset().setFontAlign(0, 0).setFont("LondrinaShadow").drawString(timeStr, x - 1, y); + + const locale = require("locale"); + const dayOfMonth = date.getDate(); + const month = locale.month(date, 1).slice(0, 1).toUpperCase() + locale.month(date, 1).slice(1).toLowerCase(); + const year = date.getFullYear(); + var dayOfMonthStr = dayOfMonth.toString(); + if (dayOfMonth === 1 || dayOfMonth === 21 || dayOfMonth === 31) { + dayOfMonthStr += "st"; + } else if (dayOfMonth === 2 || dayOfMonth === 22) { + dayOfMonthStr += "nd"; + } else if (dayOfMonth === 3 || dayOfMonth === 23) { + dayOfMonthStr += "rd"; + } else { + dayOfMonthStr += "th"; + } + const dayOfWeek = locale.dow(date, 0).slice(0, 1).toUpperCase() + locale.dow(date, 0).slice(1).toLowerCase(); + const dateStr = month + " " + dayOfMonthStr + ", " + year + "\n" + dayOfWeek; + g.setFontAlign(0, 0).setFont("DotGothic16").drawString(dateStr, x, y + 48); + if (drawTimeout) clearTimeout(drawTimeout); - drawTimeout = undefined; + drawTimeout = setTimeout(() => { + drawTimeout = undefined; + draw(); + }, 60000 - (Date.now() % 60000)); } - }); - - Bangle.loadWidgets(); - draw(); - setTimeout(Bangle.drawWidgets, 0); -})(); + + Bangle.setUI({ + mode: "clock", + remove: function() { + if (drawTimeout) clearTimeout(drawTimeout); + drawTimeout = undefined; + } + }); + Bangle.loadWidgets(); + draw(); + setTimeout(Bangle.drawWidgets, 0); + applySettings(); + })(); \ No newline at end of file diff --git a/apps/shadowclk/app.png b/apps/shadowclk/app.png index 9d02ed5b4bbb2e4c5002d1b3b2c10c84ae0b9866..c50f7ed61dafde3e84b71fa223a687f8a80dbed9 100644 GIT binary patch delta 2367 zcmV-F3BdM@MadG7BYyw^b5ch_0Itp)=>Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi z!~g&e!~vBn4jTXf2;NCVK~!i%?U{K@l~)?ZAH)@L!yQfCM&r_;RTSwThB{G4py1Nt z*3@d$U>vD+X*+dcTsuyqq1H>)!G)^RqLrYyRESnB?iNL5+$`lPn-EkYIXO8ntuVpU-P5SClF#sp;ra9D2n`KI-@biy z{V%@&J$nLm>jG|hd3mB5e0+S+rArsgojX@|dR-*MC*aPLJ8&Q6j%o$fj9Q?8A&{Xd zgJ%OzJ%R1pw}0!ly?cQjJAh@&SV&7tlZc22$;il%L4yXV4SB8XPS`D`9VUT;kiuZ0 zckkZv=ux(;T`LkEF7oN8=6d+~`H8>3zr@7EsH0@AeT}FIL?=Ys4BHxxFj!Dy^Y!gz z#u?1$AR_h z)&1ceIC0{HBqb%`#fukc(xeHdPMvBz@_N{{YZscdhP$9R863=shU7#Q#FCgrrdhq;Kq%pRkNnj;&7{1 z4}L*GMt@65o<4nw)cAPRtX0dXDUDKCT>}E()vA?I104JDN5rmOi`sSS;CVp-LPA3D zmybRIYS%V;I6+OIEFx#mrpD*UEzx9>$SG4)Qz;I{#+K~sEP8v36csTi(v!c1hYw5l z`SMFKMMW{^oHCElJ=#h0{rrrQLG|jWU*Bx6*nd+~?NWK*_-G%%MB^rP~ zapAMibiTFzYrxg()~%aSD1-Ok2bwko+Oz>Wbu!1cZGr38abW9KpnG?tqd|H)z*V;; z$A8z?$d$(B1jegXHjc_IUfg1?TtOdye{-Izh}*YOl$~uZ+cSDJpxSt`-N%lFiDlv7 zd3eM_ik%HN3ozlhJTG4$DGK%4I9kQTH1d8S(2wslU_%UmVBmm zZOPBgWv(=;y)@a`LXV;N2k36dp?&+TKlt|B#S@^BZmnm(n+Fb9%g*A)jdF4Se&(28 zzT9yi+vt3q9ZR7hixvS&1}olt6KOyFgc|wz=Cb11Gc=_n(%idePU#T&zx5VgQh$y^ zNtHEgtWmj9zyEITr}*FljQ;pzosE9-1bFmF=N&>xwLLD*D3r$G1XB9Ax^PyO~=EU{Hw&6;7IdI{tNha>%aUVolGdnMxO z(?%;fco68)1$oM|wj<}l1tgCdgKZ;5Adx!YZ)eURorCiG^;e#U=0-0#KpRMrvT2jGpQ}hw z8tm`yxXnJg7^d?U8*UyyE`Lywc^xT6?_a;J+pun3aedP!P0V%i@z%c1q8b!sd##;2 z9k*LzPL5EOGUu3b9d@^(BEZMTC=r^t&nQYYHWDP~{(YU!<~`u$(|LQe@TD0&Yw~3M z>?TSpDlpw$FruhDt81Z=L9ihIEVcglyRGO_OPSky)mM%4V zIi}nW&DleT@E;ml)s%$d%7yWgDxS~|+CgdJPI=ymI-pmtUbcZ-0{s$B!MuHR_IW;o%rcVNfP|8ZOwxOR0#9i_@tq($mxB_U+q7 zscb?+Lv^}m&mKugNYMGPurQr&-MUqd9I?LKbw-&Js9wFgPW$!iC)ciB6ZJje0i}=P z)~#DQwczgVuKREoBr`Kp#*Q5;SyWDr=-$1%PSqMl(^#B0Z+~9#(Nt+tQj!cAGDHe! z{JEmcOU!|TKaN8@Lh42AOgb17Cr;E~R#vZGZS+zWb2deLE$tJln30izlP6DN@#4j} zVK48=W-7bOmoMwDE`50PI?+#1b%zfh)-Q3}(0`~~x32z8SClz{4jnq+?Afzu*RCBd zUAjc8`3y~=NPk4oW>?Wdj~+d=Bd$C(HK+jt2IyDf^XU{tMMdGhA)zd6*suZT&Yi;w zYHF@BJZKv&Teb{Elz3gKk?T;)bN8*%&Ix5sKz%=mr!&%k2Af)S<@2iV3GLgr*RSI( z+@rA<92~4KtLi&v&Kz0+&Ge;DOia`RwMDHy&pD3q(toN6CMPGO9-XF@v}AdgDAcA< zaW~hy;ED>pUeC?V)hqVu)hivNckV1ain@(QM#8B8Cr_R%g@uK>Z$+ul4p^W_1x2csOkQ4ITKXs` zPBCG^1RAk!7&&qzz0>u2mDQyV2ne8CupfK(?#04|3$cja-v~n~R)qg+0*xCtM$48h zwd82sy0yN zaB^>EX>4U6ba`-PAZ2)IW&i+q+U=WJc3d|SME|jhUIOM}IT+9B9rW`1240aSB}$g; z{_<(jVwGxm56Fy+i~wM>|MTx-{>7i%YBe#Hnp@76Ke5H;J5Q>8{UdpfzCL(|^7)%c1_4k}r&)LuHddx&LzYukU{T3m8a1iovzn1wa{7pPB_owkw zZMTz@FFWnvXS(J*5kJO7w_JC}?fW?0WQfskUwHI>`fy*Xq4?%!P@bZG-0>x}utFtg z({DpUWAN`|areIM-fz0fotNXI-f=OL+Xkz76 zR$XoN?aYQLcHC*_U3T4V_XE~WIPs*DPdW9p)8Di9%IbGNzmYZf%9_8K(&x&1)_B#F z@^%R)I!VeI8S|0qwM7{K&|W#S)y3$QIpxeYv0U;DGATD^Ic1C##_fDM?mc&ZWbT*p zW>Wp7y!k)NoKfoj7nw7p?)$ubk+mhdn>S-m6)L7SP$^Q-RMYg@^ev-d2gLFn{UV^{8e@alNpif?ZXfgfbfm>L!0RjLT9)W5!~ z`SsgAV&&`m!biV&>)xp0cxd@9!6i18Fwt;na9OIiOcM{4IvPD;oV0geX9s9tQfZ@) zTH_cKmb;ht?QLAtq;AqB8J|bvzj@)~BP@_8@tz@rmMV9slQFxoq0kl2V1m}?z4{2I z@k&XlhGYj_rTf?%|H^v~W|g7T($83#aZlS}G*@GWNlt{4#yT@Be{ykVxYK;j2Q9ja zAEWivXN8DjpSo*fESeCy=0L5(o<(~+aI6T1w_b0UmcuyJm;QtR$(c6y%lU?S%mg#d zPpO8~;40tx+&kq^S4Jv#q#uLf4q>0YqHSYjK9NpxD`mT)Un~3CeAK_j@aQ#H>DPPg zlOREaKx=Mhw4GMGpzubrgGMFXU>%;gYHIw z7^M8;J0u9D*ftWrmqTP->D&x9?`sm@#8s`DgO5aEcA`|xime1cVsJGlp}M$9)JawD zEzAPfqc;F?uWrXD25Cp8kav${!d+gUCZqRgJ*4VnC`eW2MS%y6a&x`Q1{k)S$70 zv<;f*Y`CMwx9y&wIh7Xbn2gVFroOA2TyAg;I(zi_q?Nc0cXv?}Hl>~H^*kn-ug{OU z&@D@Iv{Gtkz&9=t#Ilp4M#9;S-bDafNTz{5HTR$E?LOQh4DnN zKsMSaZ5tdO1%SwgZzvT}#pru(&`lnAVE{KTfm^AZJ{JmtW)GTYO`xpzm{#1;0BLlL z-MnR~u$~4n%wT>(g)Zy?tx#i&LOD?uJcx$<*w~Chow*9h)LqQ3xv$J@a~!cKx$t*! z2gL?4G-w$*LDumbztZBEt?dS~ywGtHM38vRo0+NdR9gZjMZvZk;40XbaPD%PU)$qr zJzA?PHBTZy2k7>&g{NjMoQ*tc8FT?uBwn9Z<$B^q^2&V`xH~jd<;c4oI0ffN)O%dK z#dQF40L&Tbw~|DiWGv-{lvS8qeRt$S zPs>j%<^b9FTqxN-qz)n=wMsw$NP)S0jJAUUs(}VDQ2LwUBVGVXnJyy{4vlclYI5H- z9lJ*=3+_k%x4uaa1|<+kAEa7l4Qq*>OWKPu!m!|!E3UB%0%42%JNXi`(v7*2qq8xG zok=C!4YMM>1{nm)d?gpWaz^=H@1h0iFh~pKnZht1`}aZ;BAhY} zIvhvg(9X`zgr6zVJ!w05K^hP-l5jvE7CJn*anl6sYc7Ds_ij^Y4&8ImH#yUG;2)ZP z9wZh6>am$+!vyp}fRYBP#*r!{Mw({x#W+<9S7`1{|D_7>ej}xQH2p==66zQ8+-h_v z7o^tU%X9U-Cg_68%$!s#`Wh%8ypE_QQqgG+L{!NwL`oIv!*A2>?aUGWJW|iFlwGcI zL$K$}$*Tc2dh;9$Vg#4GyNKnP1%f(*aNxQJK+{Vt=rXY1<&21Ca1@`1*r;|?X(f{_ z*1Wny=v8kA?K%sTOsQF%I|_rSS;&qKUw|h?HRslV5D5;!ekj0uQ`*OY1{wrKkgqgf zXr8mN(!de|@`xk~U^7Eo18oUTgRrQBX_E6JYbsFE)Y|G0j{Sl4Hdj^5s3zC@%(MfD zagP$lvat%7h3d_cEpG> zS`|c8@g~NoF#V%?0Plxtxc4mH6^0@98Y5x#AX^BPBB+#SH3%aIjgbjl#=-@+)BVhuj`>;|b z-q|Oh9U6y;`0QMc3o$D)i9We-t|Yzzi;*-E8Z`0&xkjl&6$PP_v9{jxI+$x$VL%e= zL^H@gk!*ESKtVol)(Yl5wVI?gFn_zlEj-Y_-MXr6?=WaQpkVFOb8yknq-zF!a?V&S zata}%rUHG^dg(zZl%aWf5z1wZB9D#W5JE<8%iYfy45-_*IsEkW_?e^iJy?Pa5rVLA zFVdiRPi)G7F9WklyM>~ho$EDlI^BHlLsCt^lH_l%g#b zFRo;hvq~BrNz<$mwWOXL8b%sU;gZ6xy)=g=d1N!5x8GKw#sHcRI6MYdr9~ESGtnfp z%Y*#|vSf0X!qAIbJ)H{I5mut_6)4J!0ZHU7Ic?%p*- z6cF73mj-uXBNri9P(DnAuM>RfeZvHjkMXT^MlHe6p@XuGIm8#N349i`6-%ydAuPO4 z^qEY>Ye(VIiV)?ODMfwBp^*H>>mwn;<+ErdT8l*NlIST6iub{j(#~5Bot^W0YRs?a zCXt)$ev}yn`(tumsd**lV_IH0f#<)>iuvWV{7F{KFQ?^CvSL1_r65;mACR^L^g2bN z0zHHTL>@Jm2OV{nr<(i%6(iR~rDfO5pvVy$BPT7!V+&s0jSezU{#w8Dj@Bj@h!&u$ zH4@fk9g&>!EYe_m!P&4mdPjv;u4mMmeGeNQ5jD>x#THs?snKcRRjXBoc2_e9KSa^x zRE%~Q5Eu9b+z_{%UHu_h3{ubdo8TY;QkQ7FxX}zXOuQwml@M9B(p%_bmEKQJEM?mc zZX?PDJ|6M*!Krnq;PH|{>pwZU-4f%_(ti&DDD63Hnpzhe*>J-i8#KFj#vtYlNox%y z%{P~!6#43Iibh1BqT;n*iJduD6wy3eGl(Pk#(PTmMG`7teDSdu>fgw zYi!eG8(E>I&J4h=YJqPrt>g`ZV5X@DXB#>Z*}e#S(w*toR3-?+;o-_!j=Sxu1~=r! zo?E#1xmct68Ubd5ccTf|4KfcKE|Rq?Y=rC9io69+@Oj(P$pL6VP;f)2TI##&&e4f5*h7Cv0zh_Z-M}0%WW10qPp;}pLS}x-$v;(>^ zJWIP+;-IBf5Ckd$ce}~$sXQVL5BR9=-GxNs>Y@uHkwJe|pIBf%19B(@12m}{{9Xf6 zp(1dAO_iGh1Zc;=2H1gVEdW(v-I8bK|j$7j6>M5K=ZvgPvtbS2PhQ{9llzB(g?*Ynw3n}vfQ-2Fm z<^!g_gp~AIx((pxurlA^>LaY?(+rwJwt9M5shR$lVrZ4;7# z`>sLD9n2i+Nm_Tzd^>AAs7Ng!R;+4iNVL1bwB@~?xEZ?ATg=>3hT#>mK~r%q54v;P zYCoDDa*Vmf0LEPa!Lv97Us%mZq%MTgx^buqCI~&;Qx`gOoc78R@*CcCNEfuDR`oz` z)MYaoAkiRcr*1M%?3>yw0fGIonl|YC2SKAY=DIwG{kN^696_Yyb(eYv(eQv_lH9vi zgsVjYJ`JF1k!rO++vg8D3|5FPg>Lp^%Foii0_9H!O8gg683liww5pr#@tpb6k&L0{ z5%1xY6?2S5^=}YHL5ZW-wETrM%`@awG+*?c(=N1_Bo(z;&EqF%`;3>8G|I)3)X7Sl*+U|&2vyM6}$VjzLhtAX% zLErGgl5Q}BF8Ro4AuhrJQ0SZJ1>~}W8tIww{XE1tU0jV^Ds_VxDx)G)TD2z`mn1|& zM^Poqb>_Htr=}&R8lR;4;E=_538R~H>dd9c4cpUpgCMnWZnV(ub?6Z|qYB^D46+cN z07E#ff@AZBmTSu6-~7xGi3q9KbC>?DigxA@FjO<^;4fA!En-%5*ij2D@C#(DtzD#{ zACIvv4>*Z^(yCEJfH?&F@yIVchIAWRL4=Io$8+SntH&JG29nNQTAjw!!OI;X^1W1N z7DPwfk@WC@>ygh?gO0Ab=kO)t*XF189=a($Uhh&9Sbcz9`XBCZmizqqZ^~i;4r`Q=MMR+b6yS zWmeR=PgQI4cq|O}9Ogj#&)y-Lxm(OJMgzUCT@jr?V*nZb+Y3E?$!c87l`4(qnf+Wi zcBmHbqP1yF{!k5?Jv05uIhl`--DNBq)+|nw7ED;ZmSmdD2r1H@i~x*y*ZJzI)u4jK z*9x2#YCwvIwmgBY0%k$VVro3TqDqkJkVQuCpgoAXj^CZjr=jDd@&DFqJqIXUDoS-g zN6CR2K6g55l+PEquq`MZqUxlu^uvn8Eh7TH_Kb{}ys5)7J=9N81C zSA!Ga2z#a?bwY<)K{GWP(D$JO{E70GNpa;@BB4LX0|hG`jBn!POW?BWDwS&3ySr$hvtIu>g2j>rt?8P^yOQ^ z?#e4v)S=^KxTR%iQoDszY|{elC|Kr=iPInMfP0`t?Cef_DUd3qff0%RL4?dmUb& zK(lspNLY1ZOs92?yA0=0Skosi zF)hw9mVwyCtKB^lroNlQVBMU?yVVV3a1WT7bgb4g7-b(?%GF0| z#~felV0AsG6LCy6WSxi8a-2Lu3u0p$e|uJDknVIfZE@2MwbH0%;$$p^ghsTt`sulC zBg&Evh3Jg54q;m==4y+@SGC}wMKVX+K5>(X}tOw6H=tXjgnc)1vZ5h-H|UyGShRAlgtG zaAEg6A`rFCYBPyyHxCI=+fnTE{@7w6c?u=}jjf^go^i6whG3_kVf`^1q^(0O5u0 z1%f3r*brMdM~5(Qx|mxGQhhEcSJBXXp;L&K`Ku3UgP$IQ8Gt+}#zE)aOADl;o<>~n zW*wC0oVHf4@~0n~-!A?iJpQ9Egh8Mtt@$r;e4*CuGrd;;00D$)LqkwWLqi~Na&Km7 zY-Iodc$|HaJxIeq9K~N#OGPRj>`=rZLv^xHRK!uMP=pGhR%q41 z2R|084ld5RI=Bjg;0K7Si<6>@l=#1-&?3fz<9@um_qclp2(2p9%)SJm>6Vd6CB
zR+d%bbK-G>E=c^yb;ad3&LxKho*6N+nR(&}u~_P1rH5JB(1@pqW2&Z8zL0ZS<-EmN zt2S8Yp8SQOg1)lMb($kcVG&D^AVNU{6;xp%PODCei45&0J^aItUm}-6t_m1A7Epr* z+3|z_!S8O(;^c&z6iNbt7u)_A1%kUkyJ_3s$F|)*0sPOvmEQH&TENUF>CLVdI|9Pn zz{Pb}Q}%$%9U%HtmkrsG{4|AP5qLkNZ^{Ehx4^)f+goQJrw>4ux=P;w2Zz8|iL%!{ z-re8Z+rMWz{rv!3I&z*%6kg^4000JJOGiWi{{a60|De66lK=n!32;bRa{vGf6951U z69E94oEQKA00(qQO+^Ri1p*Hm500{C761SSj!8s8RA}Dqm`hAs*%`-w7h}Lc04HGc za0-Tim;i}J36r!TizIYaO&1xBrp;n9n^ZGpB+^P9Rb6y3m1dDe(@2?g!EPipiYgkU zg4NI&UJ0Rb0?rr%4F<=LU@+zSVr+pg2H!5gJcc~Xqm`oildkSP-#!0x&i|hC-R~hN zilXoaOA>FmBnTu3BnTu3BnTu3BnTu3{67;&j<@48hlA+K%6j_;B_*iU>V3sN_js7F z+nEmrDJv`EXm$1L2Up?{x7Vwb_fpZa42mJQv31DIxJc1Pf=;bHp9$^aN|Z>Lj|R$qid z6dDX`CnAb0%gC}!G#cFz)-yf5b;7PL{?ydO=e4ykISH~13k&!L26j$hVr-0SM~|*H zM3KhsZip?=>xH#*-1_7RKbo5(O_KO?cQ=tpByKDmG|BYT3MSK+%093cOa8!yQJLs?l2>h%D8diO3ro1c#x%S-ABf*^3| z!w+}w2dqOwe0l8HTEoh3)6ys`DgwWM`x;hOR<~LZs0{>gJbM;5cAFRs3=9onTUtWM z$wBY&aG|b_| z73o=7{9C7s8!P1JZ=Lw^WlrYgz}kY7N=vysJj_j_k@VP@@i?--IUE~~=M~p)+S~Vp z{c2+3^?jpJwol&M%fnl@_^a8>FJih^IJ&rEAw^M?hHt*v*jB4m zxqbV#;_-MCuh*;GcQ};$4u>)&Njt*&{eA_PYs--lmX;L8##Zk!{nuabJ{F3})6E_e zC@Lz#U@*`T3{qz_QfD;sle>2bg+g&-wOTEoiQ?7|s#ZgJ`RW~DX^HoHdiEh7*t`fq z*m&G@R0bCpSzKI<8w>E6!2r*nzj)4I5We_=-#0YuJs;59?GTGe+S)LD{4oHzvJCg{ zLsAky9v&v|qmSao0vyWA<6onrTy1UT@42}f1V={rwavz-SFd6;8eh6DA>Q)3BuPBq z^rb2)Do9ODB^r%lv)K>?0hLO{(O3u(2X?b8FE8V8IMzdFolb{Nr$hMOj_sPj8a67>mV1 zb8|D2B;j_uF_}!*?RFLx7HDs8=h34_EN=?GcSXQzwesM>1DsAL!C;U;Ai((eIQjYc z*laeOPA8d}nOiU#jfVRAdPYV@w&=s*Fegr&prWDzo6SZj6hg1p)6vm^TCJwOzJ6U_ zU0sbRibNujy%8`PjhsJ!p3KZlCMG7(Xf!w+4h|kXNOE#AM~)oXM!;^jV>X*PbLPx8 z0s{jB%*@Pi{P=M?J3FbWszRkw;c~e!o6Vd%cMiYbPjPWE27`fMFt|4Ym6eqMl$V#2 zk&(gKvu7zTE(RbkFAt4IvkfE5GNLGAu~@dfo12@%>2xBBB9|^*qQAeNix)2vi9`@Z zk^cUEDl03wbLS4xXcXP%JbFKkSQJGjCnwhe%RrF zLqq8GdNdjhE|-ha($e)^o1UH~KR+Lz&xc;GXKHGSf>^}*-z;pUr>7%H5-BMu$g+&f zr9uz{va+)9`Fymrv~cRwDg1sveSLj&b#)O41h7~v2!cRrYAPm^ z2}zPDDJem#)pF&^75e)6&}cLWf + + + + + + + 3-Bit Color Picker + + + + +
+

3-Bit Color Picker

+
+ +
+ +
+ +
+ + +
+ + + diff --git a/apps/shadowclk/icon.png b/apps/shadowclk/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..447dffb511a6bb298302bfc47555d32ccbb63134 GIT binary patch literal 446 zcmeAS@N?(olHy`uVBq!ia0vp^^*~(B!3HE_b>dlp6icy_X9x!n)NrJ9FfcHddb&7< zRLpsM_af&Z2N4EGQR@xt+Cdv#0<|}>XLraxdA;z&Igt+>I_2_;({JmY-jw5U>+dhd zAF>}0AK@3a_xWQ$EaSF6Z;KdPzR`SQvI{&AuJ-+=7-H;6%r`t@{m;ceX_Wq`l zn;6n~EZeYgefj$7*RN=V-FbI>V`Ny}j30@Q+B@adkQmCh60wS7s)UF<6MJj_nCq)S v_zGhuG>;ayR?YbQGjZErJWj$X^@cebP0l+XkKo@vS% literal 0 HcmV?d00001 diff --git a/apps/shadowclk/metadata.json b/apps/shadowclk/metadata.json index 972f34ad6..1811dd5e6 100644 --- a/apps/shadowclk/metadata.json +++ b/apps/shadowclk/metadata.json @@ -1,16 +1,34 @@ { "id": "shadowclk", "name": "Shadow Clock", - "version": "0.01", - "description": "A simple clock using the Londrina font with color and a shadowed outline. Based on the Anton Clock.", + "version": "0.02", + "description": "A simple clock using the Londrina font in color with a shadowed outline. Based on the Anton Clock.", "icon": "app.png", - "screenshots": [{"url":"screenshot.png"},{"url":"screenshot-1.png"}], + "screenshots": [{ + "url": "screenshot.png" + }, { + "url": "screenshot-1.png" + }], "type": "clock", "tags": "clock", - "supports": ["BANGLEJS","BANGLEJS2"], + "supports": ["BANGLEJS", "BANGLEJS2"], + //"custom": "custom.html", "allow_emulator": true, - "storage": [ - {"name":"shadowclk.app.js","url":"app.js"}, - {"name":"shadowclk.img","url":"app-icon.js","evaluate":true} - ] + "storage": [{ + "name": "shadowclk.app.js", + "url": "app.js" + }, + { + "name": "shadowclk.settings.js", + "url": "settings.js" + }, + { + "name": "shadowclk.img", + "url": "app-icon.js", + "evaluate": true + } + ], + "data": [{ + "name": "shadowclk.json" + }] } diff --git a/apps/shadowclk/screenshot-1.png b/apps/shadowclk/screenshot-1.png index 3f4e0870ee5c007bcc899b98dc9a65e4b58b45b9..2d4933110df1d029b6835f0ef7e84e687d642368 100644 GIT binary patch literal 3510 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 {1&Eb)7-gw?d&bpP>&_Eo{~EDYn%; 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 diff --git a/apps/shadowclk/screenshot.png b/apps/shadowclk/screenshot.png index 5f05672433958d4180c1373c9bf9270f1813ccaa..790294ca3f274cb48a46826bde0b6c6034219cd6 100644 GIT binary patch literal 3505 zcmds)`8(8$`^Mkzx53O{;UtPk<763G z$37&M?A*^z)rvHKJXrOdl{WL0Shs{w%%-OWdx z;~+CpUOVY7sCX4u6?gEpO`-o)$&1kug)?3r`7m=p6Wfy}n9)f{W?c%!n$nZIH+ss9xor3YXMD zG0*d+`_U$sCG0<7NQ;@V)f(^1@;v0gqZNPX_8%Lv(9$D)Whf635V(0A_-9&mhv!RA ztWr`@|H`)o;z#$3By1fu0wa93(3Er~Z*pjJ`w3kRuyFP?`7geuZ|A;~1L{5}22bIP z8)cjN!#=NnO{6Ok9F|DdNnr)W3icdvqr3CVicCXa?>8(u9Y(^vI@^}ChDKut3gWhx z2G^Yz+T9^rjmEK>Kre;A%q_9-k2AED4wwN=E_*U*cuiF;lTd>HD$K%Z-Lao?S zatn3qn60Sj<%OPAb|;tB=w2z)^^6;MP)jE0(GyMRAf%$&mt37G==x|2qf!e-Ix4r2kDD%^gs2!#JE>~m?&L!Lzn$#R z_$9G_FZ}#b8m#+5NBHyWLhi8ZC>&-`p?Nj;yTc@ldIR`x6Z5q*m#X{+>*{p02fQxJQHZ}Pt)Jft6D=P4~I+s`==N7BQnfrcitAo?oBxC&g(&XAR z?$3lT@THS6|3F$ep1G?M3nV$}Cnt55Dc02nEJ59!JFIuxMqUzn>!~fu?do8&MGp*0 zd#E|xhNuhbOY2f$PXL2T8FI7SdpWF@9)|Cfb``q& z;yNy*sf%x;2jN@pI;L23N#S+|=NcB`tjrnh6~l*b_*R=S(_r{2Cngy`lA7Irz7Z8A$a?(P(W- z4RS8TZ-|Of&BDu<);IL#mA=3aJgVxWcRX?!i0*AE)lV%5wW#IAF!kt*bK5r6qiKR~ z!|5YGE}esvlH1#R^q!YYN{iJ0RFg5mRtLQ zs!}mjd9l|TAJvgjf*Txzwzs&5Ega`Ox+us5Zx0~;ni1LDVIHPyv%V1`LZzY;MpYnx zrfq<&{CjS}_}6)GifwpHLGVeKS@6TCQ6yXDh!jHkp=;1CJ^I^Wd{GK#WSzU<_!sxD z=i`U9pvx?hJ89RIEHV!PlH%0}V86-J4W?$u6r%MvkM#)QE+f^mbW1Bvzu%pXJl&(jlaM^ITBtEAhcB@f<$B@$?}?it@=7U{Uz0KwVxgLX2CXU zk-1#z*auG{S~__Yt}=LtXR9;P9QR9=Cy@kGRbhhiUQ1rd#3ZeX6y`NF82Cc9|Bl_? z9))xrjt(Lekd0WKpumj%acL^Xhbfbtz)a~I)_CDQGHO|CiN!P0zfznQoG3jVUp03(ulRmy$*+BS}T635KdE z(%5=6$X!YM(Z-6cx?*^RPL($8+Q*Tx&eDopwu&2;hG5p-o0%y)<$>8+kgA1A&lfM- zTl`y#BRIR&Pa1>dT*!9_;UOAl{xx#rt;cf%E<0DxzsH0cGSl)K!WQ;;WDv=UB0nA` z0oJ3%HGF;67nmqQ@`KLVva(SYLdQvw@IrJ*J)t!5k|$YDkpJ~a&0G53=8GaF z^iu7IYe59qDac#=8UASXGoEApJgFvOYqUT2d2>L;#=U^!tUH&Nv%iB!s)?a3D@Yy! zZ)i0H+wt8V*ck&A#rIyycLtd#+e;9C+yq=@>aDKNpFU$=8S!qaRfZN}${iyR7SHnX z9AcH-n7~DAJ}-9dxQtR()Z$n^hbeDZo@;m8u$!RwI}5dAu}qX@6+m?6tv+k&81m1* zk8dQSjSe5{97mFfN^`#89d&08a}8sEtsjh%O>@)09_PZ9?E>dbHAjYgaItkKA>U@(e1QKW&WolY{tQZa&K6&l-1xlsu?Ejag2cE{{ei!f`#8KO5pXC`rW|*QzLW3a(zPF{{Wg5RM-Fj literal 2676 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 ayYRInTDGC?DC6sm1l&%ab*gm0XZ!=*Lh}az diff --git a/apps/shadowclk/settings.js b/apps/shadowclk/settings.js new file mode 100644 index 000000000..e76467fb0 --- /dev/null +++ b/apps/shadowclk/settings.js @@ -0,0 +1,58 @@ +(function (back) { + // Constants + const LOC = "shadowclk.json"; + const SYS = "setting.json"; + const teletextColors = ["#000", "#f00", "#0f0", "#ff0", "#00f", "#f0f", "#0ff", "#fff"]; + const teletextColorNames = ["Black", "Red", "Green", "Yellow", "Blue", "Magenta", "Cyan", "White"]; + + // Load and set default settings + let appSettings = Object.assign({ + color: teletextColors[6], + theme: 'light', + }, require('Storage').readJSON(LOC, true) || {}); + + // Save settings to storage + function writeSettings() { + require('Storage').writeJSON(LOC, appSettings); + } + + // Switch theme and save to storage + function switchTheme(mode) { + if (mode === g.theme.dark) return; + let s = require("Storage").readJSON(SYS, 1) || {}; + const cl = x => g.setColor(x).getColor(); + s.theme = mode ? { + fg: cl("#fff"), bg: cl("#000"), fg2: cl("#0ff"), bg2: cl("#000"), fgH: cl("#fff"), bgH: cl("#00f"), dark: true + } : { + fg: cl("#000"), bg: cl("#fff"), fg2: cl("#000"), bg2: cl("#cff"), fgH: cl("#000"), bgH: cl("#0ff"), dark: false + }; + require("Storage").writeJSON("setting.json", s); + if (Bangle.CLOCK) load(global.__FILE__); + } + + // Show settings menu + E.showMenu({ + "": { "title": "Shadow Clock" }, + "< Back": () => back(), + 'Theme:': { + value: (appSettings.theme === 'dark'), + format: v => v ? "Dark" : "Light", + onchange: v => { + const newTheme = v ? 'dark' : 'light'; + switchTheme(newTheme === 'dark'); + appSettings.theme = newTheme; + writeSettings(); + } + }, + 'Color:': { + value: teletextColors.indexOf(appSettings.color), + min: 0, + max: 7, + onchange: v => { + appSettings.color = teletextColors[v]; + writeSettings(); + }, + format: v => teletextColorNames[v] + } + }); +}); From 12e5d1abc7ec22a35fbc2b4c46e6eb2e8d1529ca Mon Sep 17 00:00:00 2001 From: stweedo <108593831+stweedo@users.noreply.github.com> Date: Fri, 5 May 2023 12:12:34 -0500 Subject: [PATCH 09/78] Update metadata.json --- apps/shadowclk/metadata.json | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/shadowclk/metadata.json b/apps/shadowclk/metadata.json index 1811dd5e6..56c5be004 100644 --- a/apps/shadowclk/metadata.json +++ b/apps/shadowclk/metadata.json @@ -12,7 +12,6 @@ "type": "clock", "tags": "clock", "supports": ["BANGLEJS", "BANGLEJS2"], - //"custom": "custom.html", "allow_emulator": true, "storage": [{ "name": "shadowclk.app.js", From 196fa38d580407c1071bc6a4eb1b2e28350cb6d9 Mon Sep 17 00:00:00 2001 From: stweedo <108593831+stweedo@users.noreply.github.com> Date: Fri, 5 May 2023 12:14:48 -0500 Subject: [PATCH 10/78] Update metadata.json --- apps/shadowclk/metadata.json | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/shadowclk/metadata.json b/apps/shadowclk/metadata.json index 56c5be004..b07e663ad 100644 --- a/apps/shadowclk/metadata.json +++ b/apps/shadowclk/metadata.json @@ -12,6 +12,7 @@ "type": "clock", "tags": "clock", "supports": ["BANGLEJS", "BANGLEJS2"], + "readme": "README.md", "allow_emulator": true, "storage": [{ "name": "shadowclk.app.js", From 134ef22606e241d30d87093c26a46221466f58e1 Mon Sep 17 00:00:00 2001 From: stweedo <108593831+stweedo@users.noreply.github.com> Date: Fri, 5 May 2023 12:53:38 -0500 Subject: [PATCH 11/78] Update README.md --- apps/shadowclk/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/shadowclk/README.md b/apps/shadowclk/README.md index 15455f003..39994232a 100644 --- a/apps/shadowclk/README.md +++ b/apps/shadowclk/README.md @@ -14,11 +14,11 @@ Shadow Clock uses the "Londrina" font in a user selectable color and surrounds i Anton Clock is configured by the standard settings mechanism of Bangle.js's operating system: Open the `Settings` app, then the `Apps` submenu and below it the `Shadow Clock` menu. -You configure Shadow Clock by selecting a `Light` or `Dark` system wide theme and then selecting the color of the clock numbers. +You configure Shadow Clock by selecting a `Light` or `Dark` system wide theme and then selecting the `color` of the clock numbers. ## Compatibility -Shadow Clock should be compatible with with Bangle.js 1, however it was built and tested with Bangle.js 2 +Shadow Clock should be fully compatible with with Bangle.js 1 and Bangle.js 2. However, it was built and tested with Bangle.js 2 ## Creator From 815110da6033cda272fa12fb830a939f0b5391b5 Mon Sep 17 00:00:00 2001 From: Hugh Barney Date: Fri, 5 May 2023 19:14:54 +0100 Subject: [PATCH 12/78] RAM clkinfo --- apps/clkinfom/ChangeLog | 1 + apps/clkinfom/README.md | 11 +++++++ apps/clkinfom/app.png | Bin 0 -> 206 bytes apps/clkinfom/clkinfo.js | 61 +++++++++++++++++++++++++++++++++++ apps/clkinfom/metadata.json | 15 +++++++++ apps/clkinfom/screenshot.png | Bin 0 -> 2881 bytes 6 files changed, 88 insertions(+) create mode 100644 apps/clkinfom/ChangeLog create mode 100644 apps/clkinfom/README.md create mode 100644 apps/clkinfom/app.png create mode 100644 apps/clkinfom/clkinfo.js create mode 100644 apps/clkinfom/metadata.json create mode 100644 apps/clkinfom/screenshot.png diff --git a/apps/clkinfom/ChangeLog b/apps/clkinfom/ChangeLog new file mode 100644 index 000000000..7f837e50e --- /dev/null +++ b/apps/clkinfom/ChangeLog @@ -0,0 +1 @@ +0.01: First version diff --git a/apps/clkinfom/README.md b/apps/clkinfom/README.md new file mode 100644 index 000000000..baa241fc7 --- /dev/null +++ b/apps/clkinfom/README.md @@ -0,0 +1,11 @@ +# RAM Clock Info + +![](app.png) + +A clock info that displays the % memory used + +## Screenshots + +![](screenshot.png) + +Written by: [Hugh Barney](https://github.com/hughbarney) For support and discussion please post in the [Bangle JS Forum](http://forum.espruino.com/microcosms/1424/) diff --git a/apps/clkinfom/app.png b/apps/clkinfom/app.png new file mode 100644 index 0000000000000000000000000000000000000000..aea4bcbcdc11ffb5143b8a1f78ffc4ebd68609d3 GIT binary patch literal 206 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjoCO|{#S9GG!XV7ZFl!D-MT4h{ zV@SoEw^L7Z9#G(MxPLG;=8S08?LwKOtF595w4IQ-WYIF$v>ew^8e$iBVHuOPV&;-?keS3PnUY&5ksY~o3Uj|^ z+UdA+h-y=57249$uuz1v@1OAf{`mdjd7fXM=kxsXetn)N^Mof>0lXJ1BO{~W;*9c< z)`tJY&R?XtzI~1;EwXVwSVtMwnAW_E40yu@bsR?}F5H_qKYMf+s(pKVB1kW72d}Xg z-d9deTKx#HHb?J+4Yf2cZ2jC=6R$D17#t7KPv`d~exBh^K+dGhm`DKRJNKjS@&my3 z)}{77d;9uwVQQ#meG_;0A~%Kka*L1?IMA31v~vrypI@4J)z2$fAU1bLe0vo5?Fpr3 zg}bRSOHJwGAidX^QJJIWTf~T^=9{j`-7I}=!Wx6~$>2vRhnsh);HB+WE2C(U!bHzV z3OmMkm0V@FjUW9%U?zW_y0t&^`EcsULQVRj-rFlL+*pZ$uLW4SOHW+qzX{j8f3x?k z?&V6J1$YoLNYS-!B!m%8-OaADxcw~E+PMc7hpjEzQ^(_%e^Z%)XdvfzcjjWYc7cC? zJ00Max4s8fo&K3>W{Zy#j596NfHRt!PVd-Ylz>z!26SOp~E-qUVVk{+X#-l zGVOGjSX2nvPsT)`)jE8LA_cig3yEb1WzK^?u}#B2xjosH3=3wm?<*jC&E{Iy&x$1M zxleyr?%9f%#ePKE{#AE0=r>a*BFauRYp$;iT9eZ7v*9!Kg0)BT%}{;oWezt|B{wP0 z%s-rIaosrfTSjZEs~G3AsiC?UG{NcPZ} z+R%ruqQ>QM(p?%L5M)u+Ai$8wy$-#oe*aE?`-q*7L zPahhFBNX#3)}PJSVWYpQ(sh>!h75U)3TJ%J`UuhM!m%2wLW#n!=Y}?3N1cOeEFo^h zsLqUu9ty1VOm)OHHd&X?p`S#4;TrWr($w}uX_|{WHjexas91I-iLPy|No=DBuX`-7 zXssO8PGP(;{H!jVs;u`f7?oERozG98naKtBd!{lZ1_*ki?&YDO*Lu2|lcF7%9hzzp z@G;0&S(5rSXvy0x+_COP;bKevo%|keI6Wu5^@547dFU5qdQK7=N^Vu+g0$`lho7(A zi>s7hUC7($NoRnyUg1vagpA#Sj)-0eliUF96KJq1y9!g8qmB$_?JNoFnOBPCqs-G< z1*OKTD!?){zbcRs=4JgF;rf2nx_-lHkY?bZH1uYT!?sI6&3rOy?&5IQPb@Ws5Q(Jv zUT1pkbKOZUij_GCNiju#b)UG{eRy4W`|bXj6AeZ2T$in+&vK~_=Ay%U^V{*IpF)pY zwOikwrHW~{ZRp-VFdwo@Rk_pN4{JLpOswEhuJzMIC>^1RpwTHde<)3^b9bgtp}tZ@QB7yVg{J!A5&UBC<=iC&<{wk+g& zHDz99YRCL{Qju)SGOqUSjUlq-YLj71Wk=xy?XHRY4+5h%`3bav1^oB~#DEt1(O%^o zT)CV7kDI+@@UeW}hR4Lg)cqQbWL0(ZflnHK*}Ab4N-DD}-T4P{Dl?<+cChsJC3lVGf9nG)B@*S#6%!pIGVnP$)e5#cA{qqa%V>)`&xeA zyMP~`p$O)pG+`5txOTM$>sPKpQ1wg37O$Uq$(tsG3@aY1e-eLjS z+vk5>Y*?hft{I+tde6)CDBFR^x_86AOK&bi^6r)wK{S*PJ7i$?@MBq+QJ7d2PuB6-Pj#YgzB2+w#?+^*2gQvky< z&a09$+g-J5+B{7|I^`|xaW|$H+Ib9~kpoz6~QIu{M0*_neJGHaK_woma-p$0VJx?rN;|#!dE6>{)5ZuLr zrHh)Bk5>oZoDJ^FHtn9ds}Gy8iXj%aiTsQNYJec5&;N!)iu;oWfOM2~hPq2JR5^1Hhm-}K8b4)W zAjL1!RP9k&8jwX{K~V_9E-H@fM*$!<%GHi9|GTx@ ZvIPUXl6 Date: Fri, 5 May 2023 13:32:11 -0500 Subject: [PATCH 13/78] Update settings.js --- apps/shadowclk/settings.js | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/apps/shadowclk/settings.js b/apps/shadowclk/settings.js index e76467fb0..9e976177f 100644 --- a/apps/shadowclk/settings.js +++ b/apps/shadowclk/settings.js @@ -16,6 +16,12 @@ require('Storage').writeJSON(LOC, appSettings); } + // Sync theme with current Bangle.js theme + function syncTheme() { + let sysSettings = require('Storage').readJSON(SYS, 1) || {}; + appSettings.theme = sysSettings.theme && sysSettings.theme.dark ? 'dark' : 'light'; + } + // Switch theme and save to storage function switchTheme(mode) { if (mode === g.theme.dark) return; @@ -30,9 +36,12 @@ if (Bangle.CLOCK) load(global.__FILE__); } + // Sync theme before showing settings menu + syncTheme(); + // Show settings menu E.showMenu({ - "": { "title": "Shadow Clock" }, + "": {"title": "Shadow Clock"}, "< Back": () => back(), 'Theme:': { value: (appSettings.theme === 'dark'), From fc91e7db89d78d5aa3816590f10e6fb593f2a25a Mon Sep 17 00:00:00 2001 From: Rob Pilling Date: Sat, 6 May 2023 11:23:01 +0100 Subject: [PATCH 14/78] stlap: add state and lap data files --- apps/stlap/metadata.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/stlap/metadata.json b/apps/stlap/metadata.json index 1ecdc5b6e..2a814eb0b 100644 --- a/apps/stlap/metadata.json +++ b/apps/stlap/metadata.json @@ -20,5 +20,9 @@ "url": "icon.js", "evaluate": true } + ], + "data": [ + {"name":"stlap.state.json"}, + {"wildcard":"stlap-*.json"} ] } \ No newline at end of file From 8702b3504569a7a0bfd9fd24ba1d5568f30bd41c Mon Sep 17 00:00:00 2001 From: Rob Pilling Date: Sat, 6 May 2023 11:23:16 +0100 Subject: [PATCH 15/78] stlap: no exceptions when STATE_PATH doesn't exist --- apps/stlap/app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/stlap/app.js b/apps/stlap/app.js index 0bd18311f..0c0bb33ca 100644 --- a/apps/stlap/app.js +++ b/apps/stlap/app.js @@ -8,7 +8,7 @@ const BUTTON_ICONS = { reset: heatshrink.decompress(atob("jEYwMA/4BB/+BAQPDAQPnAQIAKv///0///8j///EP//wAQQICBwQUCEhgyCHAQ+CIgI=")) }; -let state = storage.readJSON(STATE_PATH); +let state = storage.readJSON(STATE_PATH, 1); const STATE_DEFAULT = { wasRunning: false, //If the stopwatch was ever running since being reset sessionStart: 0, //When the stopwatch was first started From 16d4dc758875bdef5fc12eef0f906903dcb64c1d Mon Sep 17 00:00:00 2001 From: Rob Pilling Date: Sat, 6 May 2023 11:37:55 +0100 Subject: [PATCH 16/78] stlap: slow down javascript when the user's not watching --- apps/stlap/app.js | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/apps/stlap/app.js b/apps/stlap/app.js index 0c0bb33ca..ad5463180 100644 --- a/apps/stlap/app.js +++ b/apps/stlap/app.js @@ -157,7 +157,7 @@ function firstTimeStart(now, time) { elapsedTime: 0, }; lapFile = 'stlap-' + state.sessionStart + '.json'; - setupTimerInterval(); + setupTimerIntervalFast(); Bangle.buzz(200); drawButtons(); } @@ -201,13 +201,15 @@ function start(now, time) { state.elapsedTime += (state.pausedTime - state.startTime); state.startTime = now; state.running = true; - setupTimerInterval(); + setupTimerIntervalFast(); Bangle.buzz(200); drawTime(); drawButtons(); } Bangle.on("touch", (button, xy) => { + setupTimerIntervalFast(); + //In gesture mode, just turn on the light and then return if (gestureMode) { Bangle.setLCDPower(true); @@ -242,6 +244,8 @@ Bangle.on("touch", (button, xy) => { }); Bangle.on('swipe', direction => { + setupTimerIntervalFast(); + let now = (new Date()).getTime(); let time = getTime(); @@ -272,12 +276,23 @@ setWatch(() => { }, BTN1, { repeat: true }); let timerInterval; +let userWatching = false; + +function setupTimerIntervalFast() { + userWatching = true; + setupTimerInterval(); + + setTimeout(() => { + userWatching = false; + setupTimerInterval(); + }, 5000); +} function setupTimerInterval() { if (timerInterval !== undefined) { clearInterval(timerInterval); } - timerInterval = setInterval(drawTime, 10); + timerInterval = setInterval(drawTime, userWatching ? 10 : 1000); } function stopTimerInterval() { @@ -289,7 +304,7 @@ function stopTimerInterval() { drawTime(); if (state.running) { - setupTimerInterval(); + setupTimerIntervalFast(); } //Save our state when the app is closed @@ -300,5 +315,8 @@ E.on('kill', () => { } }); +// change interval depending of whether the user's looking +Bangle.on("twist", setupTimerIntervalFast); + Bangle.loadWidgets(); Bangle.drawWidgets(); \ No newline at end of file From 7dca61a0d5dbe74debe6608aae030ecbf3dcb852 Mon Sep 17 00:00:00 2001 From: Rob Pilling Date: Sat, 6 May 2023 12:27:21 +0100 Subject: [PATCH 17/78] Fix d888b80ea - correctly bump ratchet launcher's version --- apps/powermanager/ChangeLog | 2 +- apps/ratchet_launch/ChangeLog | 1 + apps/ratchet_launch/metadata.json | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/powermanager/ChangeLog b/apps/powermanager/ChangeLog index d1c288f97..de3fd021c 100644 --- a/apps/powermanager/ChangeLog +++ b/apps/powermanager/ChangeLog @@ -9,4 +9,4 @@ 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 -0.09: Cache the app-launch info \ No newline at end of file +0.09: Accidental version bump \ No newline at end of file diff --git a/apps/ratchet_launch/ChangeLog b/apps/ratchet_launch/ChangeLog index af7f83942..e60ca42d2 100644 --- a/apps/ratchet_launch/ChangeLog +++ b/apps/ratchet_launch/ChangeLog @@ -1 +1,2 @@ 0.01: Initial release +0.02: Cache the app-launch info diff --git a/apps/ratchet_launch/metadata.json b/apps/ratchet_launch/metadata.json index 45057b0b9..7ebe0c4cd 100644 --- a/apps/ratchet_launch/metadata.json +++ b/apps/ratchet_launch/metadata.json @@ -2,7 +2,7 @@ "id": "ratchet_launch", "name": "Ratchet Launcher", "shortName": "Ratchet", - "version": "0.01", + "version": "0.02", "description": "Launcher with discrete scrolling for quicker app selection", "icon": "app.png", "type": "launch", From c2766e8455a8c52697a81278a6dfd59f381997d8 Mon Sep 17 00:00:00 2001 From: stweedo <108593831+stweedo@users.noreply.github.com> Date: Sat, 6 May 2023 06:33:50 -0500 Subject: [PATCH 18/78] Update app.js removed unused function call --- apps/shadowclk/app.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/shadowclk/app.js b/apps/shadowclk/app.js index e69225035..64c86908a 100644 --- a/apps/shadowclk/app.js +++ b/apps/shadowclk/app.js @@ -89,5 +89,4 @@ Graphics.prototype.setFontLondrinaSolid = function() { Bangle.loadWidgets(); draw(); setTimeout(Bangle.drawWidgets, 0); - applySettings(); - })(); \ No newline at end of file + })(); From 10905e98ccb07797e5d353bc530124d9b0a30b88 Mon Sep 17 00:00:00 2001 From: stweedo Date: Sat, 6 May 2023 07:25:34 -0500 Subject: [PATCH 19/78] change menu to match theme switching from settings --- apps/shadowclk/settings.js | 99 ++++++++++++++++++++++---------------- 1 file changed, 58 insertions(+), 41 deletions(-) diff --git a/apps/shadowclk/settings.js b/apps/shadowclk/settings.js index 9e976177f..0315cb10d 100644 --- a/apps/shadowclk/settings.js +++ b/apps/shadowclk/settings.js @@ -1,5 +1,4 @@ (function (back) { - // Constants const LOC = "shadowclk.json"; const SYS = "setting.json"; const teletextColors = ["#000", "#f00", "#0f0", "#ff0", "#00f", "#f0f", "#0ff", "#fff"]; @@ -15,53 +14,71 @@ function writeSettings() { require('Storage').writeJSON(LOC, appSettings); } - - // Sync theme with current Bangle.js theme - function syncTheme() { - let sysSettings = require('Storage').readJSON(SYS, 1) || {}; - appSettings.theme = sysSettings.theme && sysSettings.theme.dark ? 'dark' : 'light'; + + // Colors from 'Ligh BW' and 'Dark BW' themes + function createThemeColors(mode) { + const cl = x => g.setColor(x).getColor(); + return mode ? { + fg: cl("#fff"), bg: cl("#000"), fg2: cl("#fff"), bg2: cl("#004"), fgH: cl("#fff"), bgH: cl("#00f"), dark: true + } : { + fg: cl("#000"), bg: cl("#fff"), fg2: cl("#000"), bg2: cl("#cff"), fgH: cl("#000"), bgH: cl("#0ff"), dark: false + }; } // Switch theme and save to storage function switchTheme(mode) { if (mode === g.theme.dark) return; let s = require("Storage").readJSON(SYS, 1) || {}; - const cl = x => g.setColor(x).getColor(); - s.theme = mode ? { - fg: cl("#fff"), bg: cl("#000"), fg2: cl("#0ff"), bg2: cl("#000"), fgH: cl("#fff"), bgH: cl("#00f"), dark: true - } : { - fg: cl("#000"), bg: cl("#fff"), fg2: cl("#000"), bg2: cl("#cff"), fgH: cl("#000"), bgH: cl("#0ff"), dark: false - }; - require("Storage").writeJSON("setting.json", s); - if (Bangle.CLOCK) load(global.__FILE__); + s.theme = createThemeColors(mode); + require("Storage").writeJSON(SYS, s); + updateTheme(mode); + } + + // Update the current menu with the new theme + function updateTheme(mode) { + let newTheme = createThemeColors(mode); + g.theme = newTheme; + appSettings.theme = mode ? 'dark' : 'light'; + writeSettings(); + delete g.reset; + g._reset = g.reset; + g.reset = function (n) { return g._reset().setColor(newTheme.fg).setBgColor(newTheme.bg); }; + g.clear = function (n) { if (n) g.reset(); return g.clearRect(0, 0, g.getWidth(), g.getHeight()); }; + g.clear(1); + Bangle.drawWidgets(); + showMenu(); } - // Sync theme before showing settings menu - syncTheme(); + // Read the current system theme + function getCurrentTheme() { + let s = require("Storage").readJSON(SYS, 1) || {}; + return s.theme.dark ? 'dark' : 'light'; + } - // Show settings menu - E.showMenu({ - "": {"title": "Shadow Clock"}, - "< Back": () => back(), - 'Theme:': { - value: (appSettings.theme === 'dark'), - format: v => v ? "Dark" : "Light", - onchange: v => { - const newTheme = v ? 'dark' : 'light'; - switchTheme(newTheme === 'dark'); - appSettings.theme = newTheme; - writeSettings(); - } - }, - 'Color:': { - value: teletextColors.indexOf(appSettings.color), - min: 0, - max: 7, - onchange: v => { - appSettings.color = teletextColors[v]; - writeSettings(); + function showMenu() { + appSettings.theme = getCurrentTheme(); + E.showMenu({ + "": { "title": "Shadow Clock" }, + "< Back": () => back(), + 'Theme:': { + value: (appSettings.theme === 'dark'), + format: v => v ? "Dark" : "Light", + onchange: v => { + switchTheme(v); + } }, - format: v => teletextColorNames[v] - } - }); -}); + 'Color:': { + value: teletextColors.indexOf(appSettings.color), + min: 0, + max: 7, + onchange: v => { + appSettings.color = teletextColors[v]; + writeSettings(); + }, + format: v => teletextColorNames[v] + } + }); + } + // Initially show the menu + showMenu(); +}); \ No newline at end of file From 2c896c8567479bbe42ed4a3f0f290ec71f1fc07a Mon Sep 17 00:00:00 2001 From: Rob Pilling Date: Sat, 6 May 2023 17:58:36 +0100 Subject: [PATCH 20/78] stlap: bump version --- apps/stlap/ChangeLog | 3 ++- apps/stlap/metadata.json | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/stlap/ChangeLog b/apps/stlap/ChangeLog index 35ba8b130..0c21e6efd 100644 --- a/apps/stlap/ChangeLog +++ b/apps/stlap/ChangeLog @@ -1,3 +1,4 @@ 0.01: New app! 0.02: Bug fixes -0.03: Submitted to the app loader \ No newline at end of file +0.03: Submitted to the app loader +0.04: Reduce battery consumption when the user's not looking \ No newline at end of file diff --git a/apps/stlap/metadata.json b/apps/stlap/metadata.json index 2a814eb0b..ac846dfd7 100644 --- a/apps/stlap/metadata.json +++ b/apps/stlap/metadata.json @@ -1,7 +1,7 @@ { "id": "stlap", "name": "Stopwatch", - "version": "0.03", + "version": "0.04", "description": "A stopwatch that remembers its state, with a lap timer and a gesture mode (enable by swiping)", "icon": "icon.png", "type": "app", From 62a5be694cc9c09eeab78f1e09762469e53583c3 Mon Sep 17 00:00:00 2001 From: stweedo <108593831+stweedo@users.noreply.github.com> Date: Sun, 7 May 2023 01:15:28 -0500 Subject: [PATCH 21/78] Update app.js Remove fonts when switching UI --- apps/shadowclk/app.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/shadowclk/app.js b/apps/shadowclk/app.js index 64c86908a..56f8bb196 100644 --- a/apps/shadowclk/app.js +++ b/apps/shadowclk/app.js @@ -84,6 +84,9 @@ Graphics.prototype.setFontLondrinaSolid = function() { remove: function() { if (drawTimeout) clearTimeout(drawTimeout); drawTimeout = undefined; + delete Graphics.prototype.setFontLondrinaSolid; + delete Graphics.prototype.setFontLondrinaShadow; + delete Graphics.prototype.setFontDotGothic16; } }); Bangle.loadWidgets(); From 6ef609d1d5582d51e4a1862bcda8fcb5e68b20a4 Mon Sep 17 00:00:00 2001 From: stweedo <108593831+stweedo@users.noreply.github.com> Date: Sun, 7 May 2023 01:24:06 -0500 Subject: [PATCH 22/78] Update app.js --- apps/shadowclk/app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/shadowclk/app.js b/apps/shadowclk/app.js index 56f8bb196..d21d5de06 100644 --- a/apps/shadowclk/app.js +++ b/apps/shadowclk/app.js @@ -92,4 +92,4 @@ Graphics.prototype.setFontLondrinaSolid = function() { Bangle.loadWidgets(); draw(); setTimeout(Bangle.drawWidgets, 0); - })(); + }); From d61aca2e62e5f662ab8b4b71ef1de3069824bd34 Mon Sep 17 00:00:00 2001 From: stweedo <108593831+stweedo@users.noreply.github.com> Date: Sun, 7 May 2023 02:07:58 -0500 Subject: [PATCH 23/78] Update app.js changed const to let which fixed launcher bug --- apps/shadowclk/app.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/shadowclk/app.js b/apps/shadowclk/app.js index d21d5de06..bc0c07256 100644 --- a/apps/shadowclk/app.js +++ b/apps/shadowclk/app.js @@ -30,7 +30,7 @@ Graphics.prototype.setFontLondrinaSolid = function() { ); }; - const storage = require('Storage'); + let storage = require('Storage'); var settings = Object.assign({ // default values @@ -92,4 +92,4 @@ Graphics.prototype.setFontLondrinaSolid = function() { Bangle.loadWidgets(); draw(); setTimeout(Bangle.drawWidgets, 0); - }); + })(); From e88198dd1197aeb75e0ef3cd7aef90029bbbdcbe Mon Sep 17 00:00:00 2001 From: stweedo <108593831+stweedo@users.noreply.github.com> Date: Sun, 7 May 2023 02:12:20 -0500 Subject: [PATCH 24/78] Update README.md --- apps/shadowclk/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/shadowclk/README.md b/apps/shadowclk/README.md index 39994232a..8b8dd2302 100644 --- a/apps/shadowclk/README.md +++ b/apps/shadowclk/README.md @@ -14,7 +14,7 @@ Shadow Clock uses the "Londrina" font in a user selectable color and surrounds i Anton Clock is configured by the standard settings mechanism of Bangle.js's operating system: Open the `Settings` app, then the `Apps` submenu and below it the `Shadow Clock` menu. -You configure Shadow Clock by selecting a `Light` or `Dark` system wide theme and then selecting the `color` of the clock numbers. +You configure Shadow Clock by selecting a `Light` or `Dark` system wide theme and then selecting the `Color` of the clock numbers. ## Compatibility From 21d6c8846c18bebf576d89b1960fe511b8ef7661 Mon Sep 17 00:00:00 2001 From: dapgo Date: Sun, 7 May 2023 13:16:09 +0200 Subject: [PATCH 25/78] Cosmetic and UX improvements IMO the UX and legibility have been improved --- apps/wohrm/ChangeLog | 1 + apps/wohrm/README.md | 6 ++++ apps/wohrm/app.js | 28 ++++++++++-------- apps/wohrm/bangle2-workout-HRM-screenshot.png | Bin 0 -> 2437 bytes apps/wohrm/metadata.json | 2 +- 5 files changed, 23 insertions(+), 14 deletions(-) create mode 100644 apps/wohrm/bangle2-workout-HRM-screenshot.png diff --git a/apps/wohrm/ChangeLog b/apps/wohrm/ChangeLog index 2ca405365..8cdb24153 100644 --- a/apps/wohrm/ChangeLog +++ b/apps/wohrm/ChangeLog @@ -9,3 +9,4 @@ 0.09: Ported to Bangle.js2 Home returns to clock, instead of menu Add settings +0.10: Increased(font sizes and bg height for current HR), BJS2 (added support for bottom widgets) diff --git a/apps/wohrm/README.md b/apps/wohrm/README.md index 87b1a65da..d35feb253 100644 --- a/apps/wohrm/README.md +++ b/apps/wohrm/README.md @@ -30,3 +30,9 @@ Pressing middle button will switch off the HRM of the watch and return you to th # HRM usage The HRM is switched on when the app is started. It stays switch on while the app is running, even when the watch screen goes to stand-by. + + +Screenshot BJS2 emul + +![](bangle2-workout-HRM-screenshot.png) + diff --git a/apps/wohrm/app.js b/apps/wohrm/app.js index ab579463c..4b7ab7fc6 100644 --- a/apps/wohrm/app.js +++ b/apps/wohrm/app.js @@ -18,7 +18,7 @@ let lowerLimitChanged = true; let limitSetter = Setter.NONE; -let currentHeartRate = 0; +let currentHeartRate = 0; //use for emuls let hrConfidence = -1; let hrChanged = true; let confidenceChanged = true; @@ -31,7 +31,7 @@ const upperLshape = isB1 ? { left: 210, bottom: 40, top: 210, - rectWidth: 30, + rectWidth: 30, cornerRoundness: 5, orientation: -1, color: '#f00' @@ -39,7 +39,7 @@ const upperLshape = isB1 ? { right: Bangle.appRect.x2-100, left: Bangle.appRect.x2, bottom: 24, - top: Bangle.appRect.y2, + top: Bangle.appRect.y2-24, //for bottom widget rectWidth: 26, cornerRoundness: 4, orientation: -1, // rotated 180° @@ -58,19 +58,20 @@ const lowerLshape = { }; const centerBar = { - minY: (upperLshape.bottom + upperLshape.top - upperLshape.rectWidth)/2, - maxY: (upperLshape.bottom + upperLshape.top + upperLshape.rectWidth)/2, + //1.5 =height*2 + minY: (upperLshape.bottom + upperLshape.top - (upperLshape.rectWidth*1.5))/2, + maxY: (upperLshape.bottom + upperLshape.top + (upperLshape.rectWidth*1.5))/2, confidenceWidth: isB1 ? 10 : 8, - minX: isB1 ? 55 : upperLshape.rectWidth + 14, + minX: isB1 ? 55 : upperLshape.rectWidth + 14, maxX: isB1 ? 165 : Bangle.appRect.x2 - upperLshape.rectWidth - 14 }; const fontSizes = isB1 ? { - limits: 13, - heartRate: 24 + limits: 14, + heartRate: 44 } : { - limits: 12, - heartRate: 20 + limits: 16, + heartRate: 34 }; function fillEllipse(x, y, x2, y2) { @@ -178,10 +179,11 @@ function renderCurrentHeartRate() { g.setColor(g.theme.bg); g.setFontVector(fontSizes.heartRate); - g.setFontAlign(1, 0, 0); + g.setFontAlign(0, 0, 0);//center g.drawString(currentHeartRate, - Math.max(upperLshape.right+upperLshape.cornerRoundness, - lowerLshape.right-lowerLshape.cornerRoundness), + // Math.max(upperLshape.right+upperLshape.cornerRoundness, lowerLshape.right-lowerLshape.cornerRoundness), + // Math.max(upperLshape.right+upperLshape.cornerRoundness, lowerLshape.right-lowerLshape.cornerRoundness)-(g.stringWidth(currentHeartRate)/2), + centerBar.minX+((centerBar.maxX-centerBar.minX)/2), (centerBar.minY+centerBar.maxY)/2); //Reset alignment to defaults diff --git a/apps/wohrm/bangle2-workout-HRM-screenshot.png b/apps/wohrm/bangle2-workout-HRM-screenshot.png new file mode 100644 index 0000000000000000000000000000000000000000..b75c1b12c842ea9cb3afd74d3243b62c5899d931 GIT binary patch literal 2437 zcmb_e`#aS67k__7GvhMkHcT$#mSSW_i!|#x5@B7!NVH586&gu38S>HYS|wZbErrU& zRKqe;GcJAC(-&y2LgLNc*{Tu8aO8VX?O@NqO?PA)uV zf~-sq9>_So6Nz(OAI&mz%8Bb~j_vCZoq^l&`&~#L>97Zi29Y|102L!e9@q(3Z|N_q zo$gU3ffwEtxrZ#F>DTWQ9^w^A^669S+``IKa}ul1A0$PG(1^-JJI1>Yr|W*~e=_>~==2ncTGyhZ+y# zalq@jF4Q>tS;iBlWffEn-xwy&XMMKDFWP$@!k(@PcN`mn2=M%)V~5+FMKRgcXMLDa zvA`hPyk_%un#?9N{x!G!&L?)|EV^W)ua{Zxdi3inL7&iT?pEA6~$9BaLq8cX7{1w6Z%A%zJd z+eB2F=<^VxlM9xD+7~JEKsfkndyjbAtZOh*z3|8k_#1M)UdiX=G$GT8u|vl>^~q2A{YJWBY50BSoQ}O`kw52zLeuk>>WDT|BNDM zRC~ZJyGj=Jkzait6pi_t*fE|9(@&j@S(?N+CVGxW1H==(!`h>~)z{n(o76dXfXlnW z8%8IQB0Epf&FVkCN$Z%uN2j6trACFV{}p>WjvP zM?ggL+fzQ)S^)od!U+AxM&wyj6djz!a*k3#@%|iALi2l<2=L9Z&7#Fj?wu_#ngfUB z^f;ddX;)_@9jS||YKWvHg<*Uy6NfC0r&qlC2ovC1_dmUCY^fN!5oP2A9@Nvm>r%nM zUG2-E8Vd5zNhdM^xR56z_TrET&U`%`EY%k?@H+wH#*6ujkZeA=ktX`zq%>_LVA7$k z#%Jb2vy-N)2^#q_c3zSVZYkH>y#_c0ye>gzjD)=k4oAA014%acK`869FQ89=hnguI z$;!g}$qM4rMl)#85-}f)-n8`^Yh@}Y>URflR*{dc(?yxXtd$e3l}%V61u{)hD9q8n z?|Lzj2n}vQ+J4&FPmplRlLDd=Z{_N%A}^quD-umTy+2#o_N}%+L2l54=|mwa;I~9{ zv}X{$u7ALIt#BB{KMiwm_tH>vJs4OQyYx;=5$L=KO) zx9x!f-*#(aJ46RH8lxS0@P?uJHDkaANU~4Gsv_V6&RdcU2ymikx4?x+k6Wfw47GPp zt!oWX$%l3a1Ne^lPh*4HfL;_C=J@|C=`nDWk85#TXL70)pMto()+aF5)WA}H@re(r zjl^k+qKue4GaJ)TWB{Lw>oFJ!S6ARunz!S^u+hLJv$dQsu(9%%;PtEi56vsWE#ZmGH&W1aAHB;k@t|4=$l zn(-3IT#8laG+okt0`B)!hrH|`T2&J}h=9|k1{eP*>n&g4Y(bt3}Roge7|ncu&E@1A^uAj zFw~ONM0Md0R-Sj6neKjXMLXh`@d_1BqJcC5!X?_QF}Q|}!tOTOpcE0$Zwx3y``UM> z{4(@IXI^*q#91xQpyAC5VS?N3P^e(}Q)s4rqCYdHY}bR4l_cfvF>QB+qFAj0-*BZR z=J%vmda(U2Zf->42hN%CaCXyaNNxw8!JDt{>qj`;slo#dLoves(1)wEZ}Ge9*~_;c z#sxcd>f-CTsDO4YEpu(T>c=ma9CtE8WS62BZ!5#cO;)a@T-OB{S|ug}j$ zFe~89w%C~akw(%mU6qcY1tqw(4B}bXxI=)*Cb>Mc1W0dL?0pSoAXlW#QT!lqcbmOd zZXkfY9!-fR<|iawzkG_=U(v9uqn(jJuCyW+Ji*cvb##OR)bZ*89~2VK;j^qtxQCkj z*GhQ{oafBk8*tYT1^wHXRR{dhQuS1&Yp!G+z}%y(gR`tU6l5+Knn1c}32hm(ss5>{ zGBjJb;~>ft6^M$|BX95urf-m&Kmz-)f<)>TZr+VzWm;A`oVi0BEWGja2Xo`H%dhlE zpq9j3TIvSAYn;xqO?Bg#QWOLCbki-&wS1@i3?L;`X|TPEN|?4ss(EPXifK!90Gdec z@pGwk3!j0O9*Dl3X;co(T$E6PYfYhPZ%L9XWm7O0khL|I-i5gpgQQmm^ bk6*C{U2bnDW1dMi{wm Date: Sun, 7 May 2023 14:52:00 -0500 Subject: [PATCH 26/78] Update settings.js Switch from const to let --- apps/shadowclk/settings.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/shadowclk/settings.js b/apps/shadowclk/settings.js index 0315cb10d..b280bf9b0 100644 --- a/apps/shadowclk/settings.js +++ b/apps/shadowclk/settings.js @@ -1,8 +1,8 @@ (function (back) { - const LOC = "shadowclk.json"; - const SYS = "setting.json"; - const teletextColors = ["#000", "#f00", "#0f0", "#ff0", "#00f", "#f0f", "#0ff", "#fff"]; - const teletextColorNames = ["Black", "Red", "Green", "Yellow", "Blue", "Magenta", "Cyan", "White"]; + let LOC = "shadowclk.json"; + let SYS = "setting.json"; + let teletextColors = ["#000", "#f00", "#0f0", "#ff0", "#00f", "#f0f", "#0ff", "#fff"]; + let teletextColorNames = ["Black", "Red", "Green", "Yellow", "Blue", "Magenta", "Cyan", "White"]; // Load and set default settings let appSettings = Object.assign({ @@ -81,4 +81,4 @@ } // Initially show the menu showMenu(); -}); \ No newline at end of file +}); From 9b323dcdce12a00a303e26a864ac562cc71e7377 Mon Sep 17 00:00:00 2001 From: dapgo Date: Sun, 7 May 2023 22:45:40 +0200 Subject: [PATCH 27/78] thermometer improved several improvements --- apps/tempmonitor/ChangeLog | 1 + apps/tempmonitor/README.md | 2 +- apps/tempmonitor/metadata.json | 4 +- apps/tempmonitor/old_ss_emul_bjs1.png | Bin 0 -> 3602 bytes apps/tempmonitor/old_ss_emul_bjs2.png | Bin 0 -> 2510 bytes apps/tempmonitor/ss_emul_bjs1.png | Bin 3602 -> 3939 bytes apps/tempmonitor/ss_emul_bjs1_help.png | Bin 0 -> 4869 bytes apps/tempmonitor/ss_emul_bjs2.png | Bin 2510 -> 2813 bytes apps/tempmonitor/tempmonitor.app.js | 472 +++++++++++++------------ apps/tempmonitor/tempmonitor.info | 2 +- apps/wohrm/app.js | 6 +- 11 files changed, 256 insertions(+), 231 deletions(-) create mode 100644 apps/tempmonitor/old_ss_emul_bjs1.png create mode 100644 apps/tempmonitor/old_ss_emul_bjs2.png create mode 100644 apps/tempmonitor/ss_emul_bjs1_help.png diff --git a/apps/tempmonitor/ChangeLog b/apps/tempmonitor/ChangeLog index af69e6e0a..c14b9b1bb 100644 --- a/apps/tempmonitor/ChangeLog +++ b/apps/tempmonitor/ChangeLog @@ -1,3 +1,4 @@ 0.01: 1st version: saves values to csv 0.02: added HTML interface 0.03: Added Stop/start recording, change BG color, filesize info +0.04: Support for negative degree, Min/Max, random for emulator, clean of code diff --git a/apps/tempmonitor/README.md b/apps/tempmonitor/README.md index e50ac07cb..59a0af58e 100644 --- a/apps/tempmonitor/README.md +++ b/apps/tempmonitor/README.md @@ -1,5 +1,5 @@ # Temperature Monitor (with logging) -Temperature monitor that shows temperature on real time but also allows to store in a file for a later process. +Temperature / Thermometer monitor that not only shows degrees on real time but also allows to store this info in a file for a later process. Compatible with BangleJS1,BangleJS2,and EMSCRIPTENx emulators diff --git a/apps/tempmonitor/metadata.json b/apps/tempmonitor/metadata.json index 45d4d2c35..2ab4e414c 100644 --- a/apps/tempmonitor/metadata.json +++ b/apps/tempmonitor/metadata.json @@ -1,8 +1,8 @@ { "id": "tempmonitor", "name": "Temperature monitor", - "version": "0.03", - "description": "Displays the current temperature and stores in a CSV file", + "version": "0.04", + "description": "Another thermometer, besides displaying current temperature, stores it in a CSV file", "icon": "app.png", "tags": "tool", "interface": "interface.html", diff --git a/apps/tempmonitor/old_ss_emul_bjs1.png b/apps/tempmonitor/old_ss_emul_bjs1.png new file mode 100644 index 0000000000000000000000000000000000000000..da7a53bd1a40e1548e1babffcb52dfdc209f896d GIT binary patch literal 3602 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 literal 0 HcmV?d00001 diff --git a/apps/tempmonitor/old_ss_emul_bjs2.png b/apps/tempmonitor/old_ss_emul_bjs2.png new file mode 100644 index 0000000000000000000000000000000000000000..1cc2140f9e4280fdb778b4e25d0af082963742c4 GIT binary patch literal 2510 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 literal 3602 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 diff --git a/apps/tempmonitor/ss_emul_bjs1_help.png b/apps/tempmonitor/ss_emul_bjs1_help.png new file mode 100644 index 0000000000000000000000000000000000000000..4d85847b99f71db8e61992d694f64762adfb50a8 GIT binary patch literal 4869 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 literal 0 HcmV?d00001 diff --git a/apps/tempmonitor/ss_emul_bjs2.png b/apps/tempmonitor/ss_emul_bjs2.png index 1cc2140f9e4280fdb778b4e25d0af082963742c4..2cdc192f8b77685811a5d1e7c45ad2a3e8251926 100644 GIT binary patch literal 2813 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 K^GY*H{J#Lc6h`L& literal 2510 zcmd^>`#;l*AIE2gi8{?CDaU0Zw@u}eZ?2U~bmBz0Oooz6<7lQcms~!Th~bpWa?e4O zW?Pw&%RZ!{Y0IU#vyN%xw%k%HzWVX}4d;jV`}KIf-;c-h*Z2F*@2*ZeckJ5%fk1XT zpR#w~PTJ3cOK*27Q-IwL34*)R2}m7BZ59HNO>?$Cel7;PP_hs=swwYSBxcRb;}wZ$ zDQ(*7F>tsn!YrRZvv(@nG+Vgx_50J!SSu`Q|DW{R4}XQl!L3}SCQ>L4jx+nT8e|Y% za^cEH7nG1Pd3R_!&?KqFJR&!_b4d4q$d_NcjHJ_|D@WkpRfbMu54PK^fbCN#Pj-7>}S2$r#I@%)nHi4KRKD?LH&br-OYT00Q9#n)4z4UvE95n0#i?FAq58wvwLt4P%Izbv&DG-x{q$Jqs>Z%d(YGJ6*j#2lntWt*h#+WtCFd+ z-G%I%plsefIInDJfitqC&)rp1_}A<@Mr^5*(US>AKCkM>4{(|F)X7h4o0Kn0iSzD* zx9s^Uv?`cu$c<>}o(N`7%j^DFH}M$hLJ?zk%yA(5*{F@=;@`RG<+xit6iPNeYHrZ; z4k9KHV7Xa$J6xFUcx>8S`lIE*)#u?BXsz`mUt^>G@3RsXjDFpFF*fYFp=KCzO^s~HMK!Iw^hRfk(BMF!zsa#f5^lrLh1x}JY zsd(R!KbA1oTlWs^kEyGz~*rx4V?(R{f%6WIQXta_DUX z1go2ZMJb_rv3IG$NA;2WJ$oyAk3fCZk%BAvHi@oe9bRLV#cY4mlp>>VN?2OVJ9zzO zjJW^pWht9)ws)uJ*Ia?7oV*=-J#I7PXBYws+Vi7?kmx0Q;0) z%pvr7yDo)%?enmO3b{MkZ^0_Y0-Cg@l(-%|I{bWPUZ=SD-K;`|d9#Mtb|mUSHH!_u zt~7uQ3zPnB5X^533v|H^6>l^(@KkPNu=1bo3KiE2-1%_Y*gxqH;;eO{`&E%NL~f%h zGy}-tkRed<@`1wpkpBjON>Fl}Bu6n1nHrL$eaZSBpW79bH}pcTSP{4Xnega2gQ&3? zJC9H2CK80r2h=_J_s-ecl?~oCh%y}}5T@?65M8V)K{L8laDYQrQ9`&YOSa{VoOseV zxnf|jn)DH!uv3TT@VM55hIEQASe%^FTc96>hd()!;oZ7DOT{;84E7*JM~QfDY5~AS zSGFwf){9D;o6AQZy!yu(5-25L7>uwV0>w98+*KBt2kXL0wjRCH^VN|rdUjy41 zU~R3G0!+3!tj$v<lHF1BA9XP=(HT`;587R2n6?@{QGV4Xla?2=Im z)Y@$!zc5JNrYt*q@=29Ja4e;`q}^dlgQ!)-w8U53UHryk_O`wM8pe$t>97J#jWMP;t=O@m*Q@do(R*I^EF-gOO)#0GQrfRNKs7I zFWRD*&{_Ho2-Hw7N1FtJrk3l_{+k4@mt1>k>^;V+iQM}3s88if)o47+YhxZ)cO{{F zjn32vtakuTtKrs8Hw)JsGI^WctdH|UR9%26@$lv`-SGw=%c9!L8DN;dk<8h;Eo60N z7zX!lr0v=v-Ub#mPoGqy*J4RUL1%E?DJ~Bp$*Hl%Mu88bmA5rt z$u!n_0@VniucrNv16tqnmi~(!t2BBftF&!gD+tHg$9g1X({apKw-PF>L^*pJrd@uE zxzdkm!T1M{VK3!oHSyXST9qQVV&9su3$2=^(NY`={`9jyvO7`G>R4_-DGCTyVwgU} zeuyLQb_Xcc6UFjohZqZDJJfPKmIq~FL zWrH<_?=#rKDBu|c)rznRzO5E3Qz5dw1|n(&pPmvse$lc>3y1WP&c*c;JVgc_2Vc@f zwQoaFQ;()`;}avB@kd&xj=!Q;G$jc&7njM>KE9Y@zsd%sg`80yEVT7hZ6+h1dMzF& zjs(gWVRZ8y4N3AqpZkOQ+|Y>0ct}0^EM`Po^m>Nas!ci3(BQ0) var saveFreq=6000; //ms for testin 6sec else var saveFreq=60000; //ms 1min -var v_saveToFile= new Boolean(true); //true save //false +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 @@ -23,6 +23,8 @@ var v_model=process.env.BOARD; var v_color_erase=g.getBgColor(); //original BG color overwritten on SetVariables var v_color=g.getColor();//original FG color var id_rec_intv; //var for the recording interval +var v_t_max=-50; //preset with an opposite and impossible record measure +var v_t_min=70; if (readFreq>saveFreq) console.log("Read refresh freq should be higher than saving"); if (v_mode_debug>0) console.log("original BG/FG color="+v_color_erase+" / "+v_color); @@ -32,281 +34,303 @@ if (v_mode_debug>0) console.log("original BG/FG color="+v_color_erase+" / "+v_co function SetVariables(){ //EMSCRIPTEN,EMSCRIPTEN2 if (v_model=='BANGLEJS'||v_model=='EMSCRIPTEN') { - v_font_size1=16; - v_font_size2=50; - }else{ - //Banglejs2 or others - v_font_size1=11; //too small? - v_font_size2=40; - } - //overwriting default BG, is better detect? - if (g.theme.dark==1) v_color_erase=0x0000; //dynamic; //bg black - else if (g.theme.dark==0) v_color_erase=0xFFFF; //dynamic; //bg white +v_font_size1=16; +v_font_size2=50; +}else{ +//Banglejs2 or others +v_font_size1=11; //too small? +v_font_size2=40; +} +//overwriting default BG, is better detect? +if (g.theme.dark==1) v_color_erase=0x0000; //dynamic; //bg black +else if (g.theme.dark==0) v_color_erase=0xFFFF; //dynamic; //bg white } //print result function printTemperature(v_temp) { - if (v_mode_debug>1) console.log("v_temp in "+v_temp+" entries "+v_saved_entries); - ClearBox(); - //g.setFont("6x8",2).setFontAlign(0,0); - g.setFontVector(v_font_size1).setFontAlign(0,0); - var x = (rect.x+(rect.x2-60))/2;//-60 space for graph and layout buttons - var y = (rect.y+rect.y2)/2 + 20; +if (v_mode_debug>1) console.log("v_temp in "+v_temp+" entries "+v_saved_entries); - if (v_saveToFile==true) { - // if (v_mode_debug>0) console.log("prev color="+v_color); - printInfo("Recording : "+v_saved_entries, '#CC3333',x,rect.y+30); - //g.setColor('#CC3333'); //red - // g.drawString("Recording : "+v_saved_entries, x, rect.y+35); - //g.setColor(v_color);//restore default color - } - else printInfo("Rec paused : "+v_saved_entries, v_color,x,rect.y+30); - //else g.drawString("Rec paused : "+v_saved_entries, x, rect.y+35); - //space for printing info - g.drawString("Temperature:", x, rect.y+45+(v_font_size1*2)); - //dynamic font (g.getWidth() > 200 ? 60 : 40) - g.setFontVector(v_font_size2).setFontAlign(0,0); - // Avg of temperature readings - while (history.length>4) history.shift(); - history.push(v_temp); - var avrTemp = E.sum(history) / history.length; - //var t = require('locale').temp(avrTemp); - //.replace("'","°"); - lastMeasure=avrTemp.toString(); - if (lastMeasure.length>4) lastMeasure=lastMeasure.substr(0,4); - //DRAW temperature in the center - //remove g.drawString(" ", x-20, y); - g.drawString(v_temp+v_t_symbol, x, y); - g.flip(); +// Avg of temperature readings +while (history.length>4) history.shift(); +history.push(v_temp); +var avrTemp = E.sum(history) / history.length; +//var t = require('locale').temp(avrTemp); +//.replace("'","°"); +lastMeasure=avrTemp.toString(); +if (lastMeasure.length>4) lastMeasure=lastMeasure.substr(0,4); + + +ClearBox(); +//g.setFont("6x8",2).setFontAlign(0,0); +g.setFontVector(v_font_size1).setFontAlign(0,0); +var x = (rect.x+(rect.x2-60))/2;//-60 space for graph and layout buttons +var y = (rect.y+rect.y2)/2 + 20; + +if (v_saveToFile==true) { +// if (v_mode_debug>0) console.log("prev color="+v_color); +printInfo("Recording : "+v_saved_entries, '#CC3333',x,rect.y+30); +//g.setColor('#CC3333'); //red +// g.drawString("Recording : "+v_saved_entries, x, rect.y+35); +//g.setColor(v_color);//restore default color +} +else printInfo("Rec paused : "+v_saved_entries, v_color,x,rect.y+30); +//else g.drawString("Rec paused : "+v_saved_entries, x, rect.y+35); +//space for printing info +g.drawString("Temperature:", x, rect.y+45+(v_font_size1*2)); + +if (v_temp>v_t_max) { +g.setColor(v_color_erase); +g.drawString(v_t_max.toString().substr(0,5), rect.x2-40,(rect.y2/2)-30); +v_t_max=v_temp; +g.setColor(v_color); +} +g.drawString(v_t_max.toString().substr(0,5), rect.x2-40,(rect.y2/2)-30); +if (v_temp 200 ? 60 : 40) +g.setFontVector(v_font_size2).setFontAlign(0,0); + +//DRAW temperature in the center +//5 char required for negative degrees +g.drawString((v_temp.toString().substr(0,5))+v_t_symbol, x, y); +g.flip(); } // from: BJS2 pressure sensor, BJS1 inbuilt thermistor function getTemperature() { - if(v_model.substr(0,10)!='EMSCRIPTEN'){ - if (Bangle.getPressure) { - Bangle.getPressure().then(p =>{if (p) printTemperature(p);}); - } else printTemperature(E.getTemperature()); - } - else printTemperature(11.25);//fake temperature medition for emulators +if(v_model.substr(0,10)!='EMSCRIPTEN'){ +if (Bangle.getPressure) { +Bangle.getPressure().then(p =>{if (p) printTemperature(p);}); +} else printTemperature(E.getTemperature()); +} +else printTemperature(-11.2+Math.random());//fake temperature medition for emulators } /* Note that it changes BG and also FG to an opposite*/ -function changeBGcolor(){ - //pend to refactor - if (v_mode_debug>1) console.log("before BG/FG "+v_color_erase+" /"+v_color); - v_color_erase=0xFFFF-v_color_erase; - v_color=0xFFFF-v_color; - if (v_mode_debug>1) console.log("after result BG/FG "+v_color_erase+" /"+v_color); - //g.setColor(color_result); - g.setBgColor(v_color_erase);// 0 white, 1 black - g.setColor(v_color); - //move to event? - ClearScreen(); - ClearBox(); - drawGraph(); - getTemperature(); - //setDrawLayout(); //uncomment if layout can work with setUI - //g.clear();//impact on widgets +function changeBGcolor(){ +//pend to refactor +if (v_mode_debug>1) console.log("before BG/FG "+v_color_erase+" /"+v_color); +v_color_erase=0xFFFF-v_color_erase; +v_color=0xFFFF-v_color; +if (v_mode_debug>1) console.log("after result BG/FG "+v_color_erase+" /"+v_color); +//g.setColor(color_result); +g.setBgColor(v_color_erase);// 0 white, 1 black +g.setColor(v_color); +//move to event? +ClearScreen(); +ClearBox();//? +getTemperature(); +drawGraph(); +//setDrawLayout(); //uncomment if layout can work with setUI +//g.clear();//impact on widgets } function saveToFile(){ - //input global vars: lastMeasure - var a=new Date(); - 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+";"+a.getHours()+":"+a.getMinutes()+";"+lastMeasure); - if (v_saveToFile==true){ - //write(strlastSaveTime+";"+ - //var f = require("Storage").open(v_filename,"r"); - // f=require("Storage").read(v_filename+"\1");//suffix required load completely!! - //note that .read uses Storage Class .open uses StorageFile Class , difference in file chunks - // if (v_mode_debug>0) console.log("f "+f); - var f = require("Storage").open(v_filename,"r"); - if ((v_mode_debug>0) && (v_saved_entries==0)) console.log("file info:"+f); - if (f.len>0) { - if (!f) { - require("Storage").open(v_filename,"w").write("Month;Day;Time;Temp"+"\n"); - if (v_mode_debug>0) console.log("not exist but created "+f); - } - else{ - require("Storage").open(v_filename,"a").write((a.getMonth()+1)+";"+a.getDate()+";"+a.getHours()+":"+a.getMinutes()+";"+lastMeasure+"\n"); - //(getTime()+","); - v_saved_entries=v_saved_entries+1; - if (v_mode_debug>1) console.log("append to already exist "+f.name+" , "+v_saved_entries); - } - } - } - else if (v_mode_debug>0) console.log("recording mode stopped"); +//input global vars: lastMeasure +var a=new Date(); +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+";"+a.getHours()+":"+a.getMinutes()+";"+lastMeasure); +if (v_saveToFile==true){ +//write(strlastSaveTime+";"+ +//var f = require("Storage").open(v_filename,"r"); +// f=require("Storage").read(v_filename+"\1");//suffix required load completely!! +//note that .read uses Storage Class .open uses StorageFile Class , difference in file chunks +// if (v_mode_debug>0) console.log("f "+f); +var f = require("Storage").open(v_filename,"r"); +if ((v_mode_debug>0) && (v_saved_entries==0)) console.log("file info:"+f); +if (f.len>0) { +if (!f) { +require("Storage").open(v_filename,"w").write("Month;Day;Time;Temp"+"\n"); +if (v_mode_debug>0) console.log("not exist but created "+f); +} +else{ +require("Storage").open(v_filename,"a").write((a.getMonth()+1)+";"+a.getDate()+";"+a.getHours()+":"+a.getMinutes()+";"+lastMeasure+"\n"); +//(getTime()+","); +v_saved_entries=v_saved_entries+1; +if (v_mode_debug>1) console.log("append to already exist "+f.name+" , "+v_saved_entries); +} +} +} +else if (v_mode_debug>0) console.log("recording mode stopped"); } function drawGraph(){ - var img_obj_thermo = { - width : 36, height : 36, bpp : 3, - transparent : 0, - buffer : require("heatshrink").decompress(atob("AEFt2AMKm3bsAMJjdt23ABhEB+/7tgaJ///DRUP//7tuADRP923YDRXbDRfymwaJhu/koaK7eyiwaK3cLDRlWDRY1NKBY1Ztu5kjmJg3cyVI7YMHgdu5Mkyu2fxHkyVJjdgDRFJkmRDRPsDQNbDQ5QBGoONKBJrBoxQIQwO2eRcbtu24AMIFIQLJAH4AMA==")) - }; - g.drawImage(img_obj_thermo,rect.x2-60,rect.y2/2); - g.flip(); +if (v_mode_debug>1) console.log("drawGraph"); +var img_obj_thermo = { +width : 36, height : 36, bpp : 3, +transparent : 0, +buffer : require("heatshrink").decompress(atob("AEFt2AMKm3bsAMJjdt23ABhEB+/7tgaJ///DRUP//7tuADRP923YDRXbDRfymwaJhu/koaK7eyiwaK3cLDRlWDRY1NKBY1Ztu5kjmJg3cyVI7YMHgdu5Mkyu2fxHkyVJjdgDRFJkmRDRPsDQNbDQ5QBGoONKBJrBoxQIQwO2eRcbtu24AMIFIQLJAH4AMA==")) +}; +g.drawImage(img_obj_thermo,rect.x2-60,rect.y2/2); +g.flip(); } function ClearScreen(){ - //avoid widget areas - g.setBgColor(v_color_erase); - g.clearRect(rect.x, rect.y+24, rect.x2, rect.y2-24); - g.flip(); +//avoid widget areas +g.setBgColor(v_color_erase); +g.clearRect(rect.x, rect.y+24, rect.x2, rect.y2-24); +g.flip(); } function ClearBox(){ - //custom boxarea , left space for static graph at right - g.setBgColor(v_color_erase); - g.clearRect(rect.x, rect.y+24, rect.x2-60, rect.y2-24); - g.flip(); +//custom boxarea , left space for static graph at right +g.setBgColor(v_color_erase); +g.clearRect(rect.x, rect.y+24, rect.x2-60, rect.y2-24); +g.flip(); } function introPage(){ - //g.setFont("6x8",2).setFontAlign(0,0); - g.setFontVector(v_font_size1).setFontAlign(-1,0); - //x alignment. -1=left (default), 0=center, 1=right - var x=3; - //dynamic positions as height for BJS1 is double than BJS2 - var y = (rect.y+rect.y2)/2 + 10; - g.drawString(" Default values ", x, y - ((v_font_size1*3)+2)); - g.drawString("--------------------", x, y - ((v_font_size1*2)+2)); - g.drawString("Mode debug: "+v_mode_debug, x, y - ((v_font_size1*1)+2)); - g.drawString("Read freq(ms): "+readFreq, x, y ); - g.drawString("Save to file: "+v_saveToFile, x, y+ ((v_font_size1*1)+2) ); - g.drawString("Save freq(ms):"+saveFreq, x, y+((v_font_size1*2)+2) ); - fr=require("Storage").read(v_filename+"\1");//suffix required - if (fr) g.drawString("Filesize:"+fr.length.toString()+"kb", x, y+((v_font_size1*3)+2) ); - else g.drawString("File not exist", x, y+((v_font_size1*3)+2)); +//g.setFont("6x8",2).setFontAlign(0,0); +g.setFontVector(v_font_size1).setFontAlign(-1,0); +//x alignment. -1=left (default), 0=center, 1=right +var x=3; +//dynamic positions as height for BJS1 is double than BJS2 +var y = (rect.y+rect.y2)/2 + 10; +g.drawString(" Default values ", x, y - ((v_font_size1*3)+2)); +g.drawString("--------------------", x, y - ((v_font_size1*2)+2)); +g.drawString("Mode debug: "+v_mode_debug, x, y - ((v_font_size1*1)+2)); +g.drawString("Read frq(ms): "+readFreq, x, y ); +g.drawString("Save file: "+v_saveToFile, x, y+ ((v_font_size1*1)+2) ); +g.drawString("Save frq(ms):"+saveFreq, x, y+((v_font_size1*2)+2) ); +fr=require("Storage").read(v_filename+"\1");//suffix required +if (fr) g.drawString("Filesize:"+fr.length.toString()+"kb", x, y+((v_font_size1*3)+2) ); +else g.drawString("File not exist", x, y+((v_font_size1*3)+2)); } function printInfo(pmsg, pcolor,px,py){ - g.setColor(pcolor); - g.setFontVector(v_font_size1).setFontAlign(0,0); - g.drawString(pmsg, px,py+v_font_size1); - g.setColor(v_color);//restore default color +g.setColor(pcolor); +g.setFontVector(v_font_size1).setFontAlign(0,0); +g.drawString(pmsg, px,py+v_font_size1); +g.setColor(v_color);//restore default color } function toggleRecMode(duration, exectime){ - //bydefault float, standard epoch requires *1000 - if (v_mode_debug>0) console.log("duration"+duration); - if (duration>2) { //delete file - var x = (rect.x+(rect.x2-60))/2; - printInfo("Deleting file",'#CC3333',x, rect.y+32+v_font_size1); - // g.setColor('#CC3333'); //red +//bydefault float, standard epoch requires *1000 +if (v_mode_debug>0) console.log("duration"+duration); +if (duration>2) { //delete file +var x = (rect.x+(rect.x2-60))/2; +printInfo("Deleting file",'#CC3333',x, rect.y+32+v_font_size1); +// g.setColor('#CC3333'); //red - //too long "Deleting file: "+v_filename, - // for StorageFiles created with require("Storage").open(filename, ...) - //require("Storage").erase(v_filename); - //TODO refactor in a new function - //var mifile = require("Storage").open(v_filename,"w"); - var mifile = require("Storage").open("temphistory.csv","w"); - var v_output=mifile.erase(); - //mifile.StorageFile.erase(); - if (v_mode_debug>0) console.log("output"+v_output); - setTimeout(function() { if (v_mode_debug>0) console.log("pause for 1 sec");},1000); - return; //leave this function - } - if (v_saveToFile) v_saveToFile=false; - else v_saveToFile=true; - if (v_mode_debug>0) console.log("recording? "+v_saveToFile); - setRecordingFreq(); +//too long "Deleting file: "+v_filename, +// for StorageFiles created with require("Storage").open(filename, ...) +//require("Storage").erase(v_filename); +//TODO refactor in a new function +//var mifile = require("Storage").open(v_filename,"w"); +var mifile = require("Storage").open("temphistory.csv","w"); +var v_output=mifile.erase(); +//mifile.StorageFile.erase(); +if (v_mode_debug>0) console.log("output"+v_output); +setTimeout(function() { if (v_mode_debug>0) console.log("pause for 1 sec");},1000); +return; //leave this function +} +if (v_saveToFile) v_saveToFile=false; +else v_saveToFile=true; +if (v_mode_debug>0) console.log("recording? "+v_saveToFile); +setRecordingFreq(); } function setRecordingFreq(){ - if (v_saveToFile==true) { //TODO now start on false btn will no enable - id_rec_intv=setInterval(function() { - saveToFile(); - }, saveFreq); //ms - if (v_mode_debug>0) console.log("interval id / frq"+id_rec_intv+" / "+saveFreq); - } - else if (id_rec_intv){ - clearInterval(id_rec_intv); - if (v_mode_debug>0) console.log("rec interval removed, id "+id_rec_intv); - id_rec_intv=0; // to reset var - } +if (v_saveToFile==true) { //TODO now start on false btn will no enable +id_rec_intv=setInterval(function() { +saveToFile(); +}, saveFreq); //ms +if (v_mode_debug>0) console.log("interval id / frq"+id_rec_intv+" / "+saveFreq); +} +else if (id_rec_intv){ +clearInterval(id_rec_intv); +if (v_mode_debug>0) console.log("rec interval removed, id "+id_rec_intv); +id_rec_intv=0; // to reset var +} } -function UserInput(){ - //theoretically incompatible with Layout - Bangle.setUI({ - mode : "custom", - //adds a back icon on top widget area - back : function() {load();}, - //touch : function(n,e) {}, // optional - handler for 'touch' events - // righ/Left 1/-1 , updown - swipe : function(dir_rl,dir_ud) { - if(dir_rl == 1) { - if (v_mode_debug>0) console.log("swipe right: "); - getFileInfo(v_filename); - } - else if (dir_rl == -1){ - if (v_mode_debug>0) console.log("swipe left: "); - changeBGcolor(); - } - }, - touch : function(tzone,tobj){ - if ((process.env.HWVERSION == 2)&&(v_mode_debug>0)){ - console.log("tobj x,y,type : "+tobj.x+" "+tobj.y+" "+tobj.type); - } - switch(tzone){ - //case 1: //left , back managed by setUI - case 2: // right disable/enable recording - toggleRecMode(0); //toggleRecMode(duration, exectime) - break; - // case 3: console.log("Touch 3 aka 1+2 not for BJS1 emul");//center 1+2 - // break; - } - }, - //inferior to - btn : function(btn) { - if(btn == 1) { - if (v_model=='BANGLEJS'||v_model=='EMSCRIPTEN') toggleRecMode(1); //console.log("btn1 BJS1"); - else mainBtnShortcut(); //console.log("btn1 BJS2"); - } - else if (btn == 2) mainBtnShortcut(); //console.log("btn2 BJS1"); - else if (btn == 3) changeBGcolor(); //console.log("btn3 BJS1"); - } - }); //endof setUI +function UserInput(){ +//theoretically incompatible with Layout +Bangle.setUI({ +mode : "custom", +//adds a back icon on top widget area +back : function() {load();}, +//touch : function(n,e) {}, // optional - handler for 'touch' events +// righ/Left 1/-1 , updown +swipe : function(dir_rl,dir_ud) { +if(dir_rl == 1) { +if (v_mode_debug>0) console.log("swipe right: "); +getFileInfo(v_filename); +} +else if (dir_rl == -1){ +if (v_mode_debug>0) console.log("swipe left: "); +changeBGcolor(); +} +}, +touch : function(tzone,tobj){ +if ((process.env.HWVERSION == 2)&&(v_mode_debug>0)){ +console.log("tobj x,y,type : "+tobj.x+" "+tobj.y+" "+tobj.type); +} +switch(tzone){ +//case 1: //left , back managed by setUI +case 2: // right disable/enable recording +toggleRecMode(0); //toggleRecMode(duration, exectime) +break; +// case 3: console.log("Touch 3 aka 1+2 not for BJS1 emul");//center 1+2 +// break; +} +}, +//inferior to +btn : function(btn) { +if(btn == 1) { +if (v_model=='BANGLEJS'||v_model=='EMSCRIPTEN') toggleRecMode(1); //console.log("btn1 BJS1"); +else mainBtnShortcut(); //console.log("btn1 BJS2"); +} +else if (btn == 2) mainBtnShortcut(); //console.log("btn2 BJS1"); +else if (btn == 3) changeBGcolor(); //console.log("btn3 BJS1"); +} +}); //endof setUI } -function mainBtnShortcut() { - //if messages app installed shortcut otherwise default access to launcher - if (require("Storage").read("messagegui.app.js")===undefined) - { - if (require("Storage").read("messagelist.app.js")===undefined) Bangle.showLauncher(); // implies btn2(js1) btn(js2)- launcher - else if (v_model=='BANGLEJS'||v_model=='EMSCRIPTEN') load("messagelist.app.js"); - else load("messagelist.app.js"); - } - else if (v_model=='BANGLEJS'||v_model=='EMSCRIPTEN') load("messagegui.app.js"); - else load("messagegui.app.js"); - } +function mainBtnShortcut() { +//if messages app installed shortcut otherwise default access to launcher +if (require("Storage").read("messagegui.app.js")===undefined) +{ +if (require("Storage").read("messagelist.app.js")===undefined) Bangle.showLauncher(); // implies btn2(js1) btn(js2)- launcher +else if (v_model=='BANGLEJS'||v_model=='EMSCRIPTEN') load("messagelist.app.js"); +else load("messagelist.app.js"); +} +else if (v_model=='BANGLEJS'||v_model=='EMSCRIPTEN') load("messagegui.app.js"); +else load("messagegui.app.js"); +} // Show file size -function getFileInfo(v_filename) { - var f = require("Storage").open(v_filename,"r"); - //todo refactor and reuse common code - g.setFontVector(v_font_size1).setFontAlign(0,0); - var x = (rect.x+(rect.x2-60))/2; - printInfo("file size:"+f.len,v_color,x, rect.y+32+v_font_size1); - // g.drawString("file size:"+f.len, x, rect.y+37+v_font_size1); - if (v_mode_debug>0) console.log("file "+v_filename+" size: "+f.len); +function getFileInfo(v_filename) { +var f = require("Storage").open(v_filename,"r"); +//todo refactor and reuse common code +g.setFontVector(v_font_size1).setFontAlign(0,0); +var x = (rect.x+(rect.x2-60))/2; +printInfo("file size:"+f.len,v_color,x, rect.y+32+v_font_size1); +// g.drawString("file size:"+f.len, x, rect.y+37+v_font_size1); +if (v_mode_debug>0) console.log("file "+v_filename+" size: "+f.len); }// not used //MAIN SetVariables(); Bangle.loadWidgets(); - ClearScreen(); introPage(); - //setDrawLayout(); //uncomment if layout can work with setUI UserInput(); //inc SetUI and back icon setInterval(function() { - getTemperature(); +getTemperature(); }, readFreq); //ms - +//??need +drawGraph(); setRecordingFreq(); } \ No newline at end of file diff --git a/apps/tempmonitor/tempmonitor.info b/apps/tempmonitor/tempmonitor.info index f31704b57..4d20912ac 100644 --- a/apps/tempmonitor/tempmonitor.info +++ b/apps/tempmonitor/tempmonitor.info @@ -1 +1 @@ -{"id":"tempmonitor","name":"tempmonitor","src":"tempmonitor.app.js","icon":"tempmonitor.img","version":"0.03","files":"tempmonitor.info,tempmonitor.app.js,tempmonitor.img"} \ No newline at end of file +{"id":"tempmonitor","name":"tempmonitor","src":"tempmonitor.app.js","icon":"tempmonitor.img","version":"0.04","files":"tempmonitor.info,tempmonitor.app.js,tempmonitor.img"} \ No newline at end of file diff --git a/apps/wohrm/app.js b/apps/wohrm/app.js index 4b7ab7fc6..e32ab36ba 100644 --- a/apps/wohrm/app.js +++ b/apps/wohrm/app.js @@ -58,7 +58,7 @@ const lowerLshape = { }; const centerBar = { - //1.5 =height*2 + //1.5 =height*2 minY: (upperLshape.bottom + upperLshape.top - (upperLshape.rectWidth*1.5))/2, maxY: (upperLshape.bottom + upperLshape.top + (upperLshape.rectWidth*1.5))/2, confidenceWidth: isB1 ? 10 : 8, @@ -182,8 +182,8 @@ function renderCurrentHeartRate() { g.setFontAlign(0, 0, 0);//center g.drawString(currentHeartRate, // Math.max(upperLshape.right+upperLshape.cornerRoundness, lowerLshape.right-lowerLshape.cornerRoundness), - // Math.max(upperLshape.right+upperLshape.cornerRoundness, lowerLshape.right-lowerLshape.cornerRoundness)-(g.stringWidth(currentHeartRate)/2), - centerBar.minX+((centerBar.maxX-centerBar.minX)/2), + // Math.max(upperLshape.right+upperLshape.cornerRoundness, lowerLshape.right-lowerLshape.cornerRoundness)-(g.stringWidth(currentHeartRate)/2), + centerBar.minX+((centerBar.maxX-centerBar.minX)/2), (centerBar.minY+centerBar.maxY)/2); //Reset alignment to defaults From 3e9db2704446f6b95fa1c517a4668d6d5be32f93 Mon Sep 17 00:00:00 2001 From: stweedo <108593831+stweedo@users.noreply.github.com> Date: Sun, 7 May 2023 15:53:57 -0500 Subject: [PATCH 28/78] Update settings.js Fix typo in comment --- apps/shadowclk/settings.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/shadowclk/settings.js b/apps/shadowclk/settings.js index b280bf9b0..078b6dc1e 100644 --- a/apps/shadowclk/settings.js +++ b/apps/shadowclk/settings.js @@ -15,7 +15,7 @@ require('Storage').writeJSON(LOC, appSettings); } - // Colors from 'Ligh BW' and 'Dark BW' themes + // Colors from 'Light BW' and 'Dark BW' themes function createThemeColors(mode) { const cl = x => g.setColor(x).getColor(); return mode ? { From cf4daf58fe988461d9926bfea14e40de2d77c25d Mon Sep 17 00:00:00 2001 From: Rob Pilling Date: Sun, 7 May 2023 22:47:14 +0100 Subject: [PATCH 29/78] bikespeedo: add option for locale-units (e.g. mph) --- apps/bikespeedo/app.js | 8 +++++++- apps/bikespeedo/settings.js | 10 +++++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/apps/bikespeedo/app.js b/apps/bikespeedo/app.js index a62a429e5..6374c0d6f 100644 --- a/apps/bikespeedo/app.js +++ b/apps/bikespeedo/app.js @@ -416,6 +416,12 @@ function onGPS(fix) { // Age of last fix (secs) age = Math.max(0,Math.round(getTime())-(lf.time.getTime()/1000)); + } else { + // populate spd_unit + if (cfg.spd == 0) { + m = require("locale").speed(0).match(/[0-9,\.]+(.*)/); + cfg.spd_unit = m[1]; + } } if ( cfg.modeA == 1 ) { @@ -465,7 +471,7 @@ function updateClock() { // Read settings. let cfg = require('Storage').readJSON('bikespeedo.json',1)||{}; -cfg.spd = 1; // Multiplier for speed unit conversions. 0 = use the locale values for speed +cfg.spd = !cfg.localeUnits; // Multiplier for speed unit conversions. 0 = use the locale values for speed cfg.spd_unit = 'km/h'; // Displayed speed unit cfg.alt = 1; // Multiplier for altitude unit conversions. (feet:'0.3048') cfg.alt_unit = 'm'; // Displayed altitude units ('feet') diff --git a/apps/bikespeedo/settings.js b/apps/bikespeedo/settings.js index f41524263..1245fce4c 100644 --- a/apps/bikespeedo/settings.js +++ b/apps/bikespeedo/settings.js @@ -11,7 +11,15 @@ '< Back': back, '< Load Bike Speedometer': ()=>{load('bikespeedo.app.js');}, 'Barometer Altitude adjustment' : function() { E.showMenu(altdiffMenu); }, - 'Kalman Filters' : function() { E.showMenu(kalMenu); } + 'Kalman Filters' : function() { E.showMenu(kalMenu); }, + 'Speed units': { + value: !!settings.localeUnits, + format: b => b ? "Locale" : "km/h", + onchange: b => { + settings.localeUnits = b; + writeSettings(); + } + }, }; const altdiffMenu = { From afe37b55fa1de9ba3413215546527afb5b22ae18 Mon Sep 17 00:00:00 2001 From: Rob Pilling Date: Sun, 7 May 2023 23:08:04 +0100 Subject: [PATCH 30/78] bikespeedo: guard against showing NaN speed --- apps/bikespeedo/app.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/bikespeedo/app.js b/apps/bikespeedo/app.js index 6374c0d6f..023e7795c 100644 --- a/apps/bikespeedo/app.js +++ b/apps/bikespeedo/app.js @@ -403,6 +403,8 @@ function onGPS(fix) { if ( sp < 10 ) sp = sp.toFixed(1); else sp = Math.round(sp); + if (isNaN(sp)) sp = '---'; + if (parseFloat(sp) > parseFloat(max.spd) && max.n > 15 ) max.spd = parseFloat(sp); // Altitude From 9e93d1588d81d3be16fd27a12316c5aa0c313444 Mon Sep 17 00:00:00 2001 From: Rob Pilling Date: Sun, 7 May 2023 23:26:46 +0100 Subject: [PATCH 31/78] bikespeedo: add option to record ride --- apps/bikespeedo/app.js | 37 ++++++++++++++++++++++++------------- apps/bikespeedo/settings.js | 9 +++++++++ 2 files changed, 33 insertions(+), 13 deletions(-) diff --git a/apps/bikespeedo/app.js b/apps/bikespeedo/app.js index 023e7795c..297fd33d2 100644 --- a/apps/bikespeedo/app.js +++ b/apps/bikespeedo/app.js @@ -507,14 +507,6 @@ function onPressure(dat) { altiBaro = Number(dat.altitude.toFixed(0)) + Number(cfg.altDiff); } -Bangle.setBarometerPower(1); // needs some time... -g.clearRect(0,screenYstart,screenW,screenH); -onGPS(lf); -Bangle.setGPSPower(1); -Bangle.on('GPS', onGPS); -Bangle.on('pressure', onPressure); - -Bangle.setCompassPower(1); var CALIBDATA = require("Storage").readJSON("magnav.json",1)||null; if (!CALIBDATA) calibrateCompass = true; function Compass_tiltfixread(O,S){ @@ -552,11 +544,30 @@ function Compass_reading() { Compass_heading = Compass_newHeading(d,Compass_heading); hdngCompass = Compass_heading.toFixed(0); } -if (!calibrateCompass) setInterval(Compass_reading,200); -setButtons(); -if (emulator) setInterval(updateClock, 2000); -else setInterval(updateClock, 10000); +function start() { + Bangle.setBarometerPower(1); // needs some time... + g.clearRect(0,screenYstart,screenW,screenH); + onGPS(lf); + Bangle.setGPSPower(1); + Bangle.on('GPS', onGPS); + Bangle.on('pressure', onPressure); + + Bangle.setCompassPower(1); + if (!calibrateCompass) setInterval(Compass_reading,200); + + setButtons(); + if (emulator) setInterval(updateClock, 2000); + else setInterval(updateClock, 10000); + + Bangle.drawWidgets(); +} Bangle.loadWidgets(); -Bangle.drawWidgets(); +if (cfg.record && WIDGETS["recorder"]) { + WIDGETS["recorder"] + .setRecording(true) + .then(start); +} else { + start(); +} diff --git a/apps/bikespeedo/settings.js b/apps/bikespeedo/settings.js index 1245fce4c..781183305 100644 --- a/apps/bikespeedo/settings.js +++ b/apps/bikespeedo/settings.js @@ -22,6 +22,15 @@ }, }; + if (global.WIDGETS && WIDGETS["recorder"]) + appMenu[/*LANG*/"Record rides"] = { + value : !!settings.record, + onchange : v => { + settings.record = v; + writeSettings(); + } + }; + const altdiffMenu = { '': { 'title': 'Altitude adjustment' }, '< Back': function() { E.showMenu(appMenu); }, From 425df4a3dbc82185d9d1583908adb4a4026d2fde Mon Sep 17 00:00:00 2001 From: Rob Pilling Date: Sun, 7 May 2023 23:27:14 +0100 Subject: [PATCH 32/78] bikespeedo: changelog & metadata --- apps/bikespeedo/ChangeLog | 1 + apps/bikespeedo/metadata.json | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/bikespeedo/ChangeLog b/apps/bikespeedo/ChangeLog index 10752ee2b..b47f8cdc3 100644 --- a/apps/bikespeedo/ChangeLog +++ b/apps/bikespeedo/ChangeLog @@ -1,3 +1,4 @@ 0.01: New App! 0.02: Barometer altitude adjustment setting 0.03: Use default Bangle formatter for booleans +0.04: Add options for units in locale and recording GPS diff --git a/apps/bikespeedo/metadata.json b/apps/bikespeedo/metadata.json index 80b91427c..ea74db9a1 100644 --- a/apps/bikespeedo/metadata.json +++ b/apps/bikespeedo/metadata.json @@ -2,7 +2,7 @@ "id": "bikespeedo", "name": "Bike Speedometer (beta)", "shortName": "Bike Speedometer", - "version": "0.03", + "version": "0.04", "description": "Shows GPS speed, GPS heading, Compass heading, GPS altitude and Barometer altitude from internal sources", "icon": "app.png", "screenshots": [{"url":"Screenshot.png"}], From e3fed6ceb7afa701084559aff2b7bf2a1bc6d92d Mon Sep 17 00:00:00 2001 From: Rob Pilling Date: Sun, 7 May 2023 23:51:38 +0100 Subject: [PATCH 33/78] popcon: trim old entries from the cache --- apps/popconlaunch/boot.js | 21 +++++++++++++++++---- apps/popconlaunch/boot.ts | 26 ++++++++++++++++++++------ 2 files changed, 37 insertions(+), 10 deletions(-) diff --git a/apps/popconlaunch/boot.js b/apps/popconlaunch/boot.js index eb3f18e1b..9124344b2 100644 --- a/apps/popconlaunch/boot.js +++ b/apps/popconlaunch/boot.js @@ -1,6 +1,7 @@ { var oldRead_1 = require("Storage").readJSON; - var monthAgo_1 = Date.now() - 1000 * 86400 * 28; + var oneMonth_1 = 1000 * 86400 * 28; + var monthAgo_1 = Date.now() - oneMonth_1; var cache_1; var ensureCache_1 = function () { if (!cache_1) { @@ -10,8 +11,20 @@ } return cache_1; }; - var saveCache_1 = function (orderChanged) { - require("Storage").writeJSON("popcon.cache.json", cache_1); + var trimCache_1 = function (cache) { + var threeMonthsBack = Date.now() - oneMonth_1 * 3; + var del = []; + for (var k in cache) + if (cache[k].last < threeMonthsBack) + del.push(k); + for (var _i = 0, del_1 = del; _i < del_1.length; _i++) { + var k = del_1[_i]; + delete cache[k]; + } + }; + var saveCache_1 = function (cache, orderChanged) { + trimCache_1(cache); + require("Storage").writeJSON("popcon.cache.json", cache); if (orderChanged) { var info = oldRead_1("popcon.info", true); info.cacheBuster = !info.cacheBuster; @@ -74,7 +87,7 @@ ent.pop++; ent.last = Date.now(); var orderChanged = sortCache_1(); - saveCache_1(orderChanged); + saveCache_1(cache_3, orderChanged); } return oldLoad_1(src); }; diff --git a/apps/popconlaunch/boot.ts b/apps/popconlaunch/boot.ts index a7ac73518..306d4844a 100644 --- a/apps/popconlaunch/boot.ts +++ b/apps/popconlaunch/boot.ts @@ -1,9 +1,6 @@ { type Timestamp = number; - -const oldRead = require("Storage").readJSON; -const monthAgo = Date.now() - 1000 * 86400 * 28; -let cache: undefined | { +type Cache = { [key: string]: { sortorder: number, pop: number, // amount of launches @@ -11,6 +8,11 @@ let cache: undefined | { } }; +const oldRead = require("Storage").readJSON; +const oneMonth = 1000 * 86400 * 28; +const monthAgo = Date.now() - oneMonth; +let cache: undefined | Cache; + const ensureCache = (): NonNull => { if(!cache){ cache = oldRead("popcon.cache.json", true); @@ -20,7 +22,19 @@ const ensureCache = (): NonNull => { return cache; }; -const saveCache = (orderChanged: boolean) => { +const trimCache = (cache: Cache) => { + const threeMonthsBack = Date.now() - oneMonth * 3; + const del = []; + for(const k in cache) + if(cache[k]!.last < threeMonthsBack) + del.push(k); + + for(const k of del) + delete cache[k]; +}; + +const saveCache = (cache: Cache, orderChanged: boolean) => { + trimCache(cache); require("Storage").writeJSON("popcon.cache.json", cache); if(orderChanged){ // ensure launchers reload their caches: @@ -94,7 +108,7 @@ global.load = (src: string) => { ent.pop++; ent.last = Date.now(); const orderChanged = sortCache(); - saveCache(orderChanged); + saveCache(cache, orderChanged); } return oldLoad(src); From 2389371aa405d58fd47cbaf5b2229e2a40e40424 Mon Sep 17 00:00:00 2001 From: stweedo <108593831+stweedo@users.noreply.github.com> Date: Sun, 7 May 2023 20:56:42 -0500 Subject: [PATCH 34/78] Update settings.js Remove file name variables --- apps/shadowclk/settings.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/apps/shadowclk/settings.js b/apps/shadowclk/settings.js index 078b6dc1e..63d730d6e 100644 --- a/apps/shadowclk/settings.js +++ b/apps/shadowclk/settings.js @@ -1,6 +1,6 @@ (function (back) { - let LOC = "shadowclk.json"; - let SYS = "setting.json"; + + let teletextColors = ["#000", "#f00", "#0f0", "#ff0", "#00f", "#f0f", "#0ff", "#fff"]; let teletextColorNames = ["Black", "Red", "Green", "Yellow", "Blue", "Magenta", "Cyan", "White"]; @@ -8,11 +8,11 @@ let appSettings = Object.assign({ color: teletextColors[6], theme: 'light', - }, require('Storage').readJSON(LOC, true) || {}); + }, require('Storage').readJSON(shadowclk.json, true) || {}); // Save settings to storage function writeSettings() { - require('Storage').writeJSON(LOC, appSettings); + require('Storage').writeJSON(shadowclk.json, appSettings); } // Colors from 'Light BW' and 'Dark BW' themes @@ -28,9 +28,9 @@ // Switch theme and save to storage function switchTheme(mode) { if (mode === g.theme.dark) return; - let s = require("Storage").readJSON(SYS, 1) || {}; + let s = require("Storage").readJSON(setting.json, 1) || {}; s.theme = createThemeColors(mode); - require("Storage").writeJSON(SYS, s); + require("Storage").writeJSON(setting.json, s); updateTheme(mode); } @@ -51,7 +51,7 @@ // Read the current system theme function getCurrentTheme() { - let s = require("Storage").readJSON(SYS, 1) || {}; + let s = require("Storage").readJSON(setting.json, 1) || {}; return s.theme.dark ? 'dark' : 'light'; } From f8f540579578063a3bcd313d49a0a20258f3085c Mon Sep 17 00:00:00 2001 From: stweedo <108593831+stweedo@users.noreply.github.com> Date: Sun, 7 May 2023 21:14:18 -0500 Subject: [PATCH 35/78] Update settings.js Reverting back to https://github.com/stweedo/BangleApps/commit/10905e98ccb07797e5d353bc530124d9b0a30b88 --- apps/shadowclk/settings.js | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/apps/shadowclk/settings.js b/apps/shadowclk/settings.js index 63d730d6e..40a01713d 100644 --- a/apps/shadowclk/settings.js +++ b/apps/shadowclk/settings.js @@ -1,21 +1,21 @@ (function (back) { - - - let teletextColors = ["#000", "#f00", "#0f0", "#ff0", "#00f", "#f0f", "#0ff", "#fff"]; - let teletextColorNames = ["Black", "Red", "Green", "Yellow", "Blue", "Magenta", "Cyan", "White"]; + const LOC = "shadowclk.json"; + const SYS = "setting.json"; + const teletextColors = ["#000", "#f00", "#0f0", "#ff0", "#00f", "#f0f", "#0ff", "#fff"]; + const teletextColorNames = ["Black", "Red", "Green", "Yellow", "Blue", "Magenta", "Cyan", "White"]; // Load and set default settings let appSettings = Object.assign({ color: teletextColors[6], theme: 'light', - }, require('Storage').readJSON(shadowclk.json, true) || {}); + }, require('Storage').readJSON(LOC, true) || {}); // Save settings to storage function writeSettings() { - require('Storage').writeJSON(shadowclk.json, appSettings); + require('Storage').writeJSON(LOC, appSettings); } - // Colors from 'Light BW' and 'Dark BW' themes + // Colors from 'Ligh BW' and 'Dark BW' themes function createThemeColors(mode) { const cl = x => g.setColor(x).getColor(); return mode ? { @@ -28,9 +28,9 @@ // Switch theme and save to storage function switchTheme(mode) { if (mode === g.theme.dark) return; - let s = require("Storage").readJSON(setting.json, 1) || {}; + let s = require("Storage").readJSON(SYS, 1) || {}; s.theme = createThemeColors(mode); - require("Storage").writeJSON(setting.json, s); + require("Storage").writeJSON(SYS, s); updateTheme(mode); } @@ -51,7 +51,7 @@ // Read the current system theme function getCurrentTheme() { - let s = require("Storage").readJSON(setting.json, 1) || {}; + let s = require("Storage").readJSON(SYS, 1) || {}; return s.theme.dark ? 'dark' : 'light'; } From d6184765c1d8674d03b80a65d66e91f6a565efd0 Mon Sep 17 00:00:00 2001 From: stweedo <108593831+stweedo@users.noreply.github.com> Date: Sun, 7 May 2023 21:24:00 -0500 Subject: [PATCH 36/78] Update settings.js --- apps/shadowclk/settings.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/shadowclk/settings.js b/apps/shadowclk/settings.js index 40a01713d..b553522f9 100644 --- a/apps/shadowclk/settings.js +++ b/apps/shadowclk/settings.js @@ -15,7 +15,7 @@ require('Storage').writeJSON(LOC, appSettings); } - // Colors from 'Ligh BW' and 'Dark BW' themes + // Colors from 'Light BW' and 'Dark BW' themes function createThemeColors(mode) { const cl = x => g.setColor(x).getColor(); return mode ? { From bfeaa5219f095a917b8d484e06e48cfc094487f7 Mon Sep 17 00:00:00 2001 From: stweedo <108593831+stweedo@users.noreply.github.com> Date: Sun, 7 May 2023 21:28:56 -0500 Subject: [PATCH 37/78] Update settings.js --- apps/shadowclk/settings.js | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/apps/shadowclk/settings.js b/apps/shadowclk/settings.js index b553522f9..a3f9c55dc 100644 --- a/apps/shadowclk/settings.js +++ b/apps/shadowclk/settings.js @@ -1,18 +1,16 @@ (function (back) { - const LOC = "shadowclk.json"; - const SYS = "setting.json"; - const teletextColors = ["#000", "#f00", "#0f0", "#ff0", "#00f", "#f0f", "#0ff", "#fff"]; - const teletextColorNames = ["Black", "Red", "Green", "Yellow", "Blue", "Magenta", "Cyan", "White"]; + let teletextColors = ["#000", "#f00", "#0f0", "#ff0", "#00f", "#f0f", "#0ff", "#fff"]; + let teletextColorNames = ["Black", "Red", "Green", "Yellow", "Blue", "Magenta", "Cyan", "White"]; // Load and set default settings let appSettings = Object.assign({ color: teletextColors[6], theme: 'light', - }, require('Storage').readJSON(LOC, true) || {}); + }, require('Storage').readJSON(shadowclk.json, true) || {}); // Save settings to storage function writeSettings() { - require('Storage').writeJSON(LOC, appSettings); + require('Storage').writeJSON(shadowclk.json, appSettings); } // Colors from 'Light BW' and 'Dark BW' themes @@ -28,9 +26,9 @@ // Switch theme and save to storage function switchTheme(mode) { if (mode === g.theme.dark) return; - let s = require("Storage").readJSON(SYS, 1) || {}; + let s = require("Storage").readJSON(setting.json, 1) || {}; s.theme = createThemeColors(mode); - require("Storage").writeJSON(SYS, s); + require("Storage").writeJSON(setting.json, s); updateTheme(mode); } @@ -51,7 +49,7 @@ // Read the current system theme function getCurrentTheme() { - let s = require("Storage").readJSON(SYS, 1) || {}; + let s = require("Storage").readJSON(setting.json, 1) || {}; return s.theme.dark ? 'dark' : 'light'; } From 9a2873fb63492738eecdab2692905385995890bf Mon Sep 17 00:00:00 2001 From: stweedo <108593831+stweedo@users.noreply.github.com> Date: Sun, 7 May 2023 22:11:41 -0500 Subject: [PATCH 38/78] Update settings.js added missing quotations --- apps/shadowclk/settings.js | 45 +++++++++++++++++++++++++++----------- 1 file changed, 32 insertions(+), 13 deletions(-) diff --git a/apps/shadowclk/settings.js b/apps/shadowclk/settings.js index a3f9c55dc..a7b10db6d 100644 --- a/apps/shadowclk/settings.js +++ b/apps/shadowclk/settings.js @@ -1,4 +1,4 @@ -(function (back) { +(function(back) { let teletextColors = ["#000", "#f00", "#0f0", "#ff0", "#00f", "#f0f", "#0ff", "#fff"]; let teletextColorNames = ["Black", "Red", "Green", "Yellow", "Blue", "Magenta", "Cyan", "White"]; @@ -6,32 +6,44 @@ let appSettings = Object.assign({ color: teletextColors[6], theme: 'light', - }, require('Storage').readJSON(shadowclk.json, true) || {}); + }, require('Storage').readJSON("shadowclk.json", true) || {}); // Save settings to storage function writeSettings() { - require('Storage').writeJSON(shadowclk.json, appSettings); + require('Storage').writeJSON("shadowclk.json", appSettings); } - + // Colors from 'Light BW' and 'Dark BW' themes function createThemeColors(mode) { const cl = x => g.setColor(x).getColor(); return mode ? { - fg: cl("#fff"), bg: cl("#000"), fg2: cl("#fff"), bg2: cl("#004"), fgH: cl("#fff"), bgH: cl("#00f"), dark: true + fg: cl("#fff"), + bg: cl("#000"), + fg2: cl("#fff"), + bg2: cl("#004"), + fgH: cl("#fff"), + bgH: cl("#00f"), + dark: true } : { - fg: cl("#000"), bg: cl("#fff"), fg2: cl("#000"), bg2: cl("#cff"), fgH: cl("#000"), bgH: cl("#0ff"), dark: false + fg: cl("#000"), + bg: cl("#fff"), + fg2: cl("#000"), + bg2: cl("#cff"), + fgH: cl("#000"), + bgH: cl("#0ff"), + dark: false }; } // Switch theme and save to storage function switchTheme(mode) { if (mode === g.theme.dark) return; - let s = require("Storage").readJSON(setting.json, 1) || {}; + let s = require('Storage').readJSON("setting.json", 1) || {}; s.theme = createThemeColors(mode); - require("Storage").writeJSON(setting.json, s); + require('Storage').writeJSON("setting.json", s); updateTheme(mode); } - + // Update the current menu with the new theme function updateTheme(mode) { let newTheme = createThemeColors(mode); @@ -40,8 +52,13 @@ writeSettings(); delete g.reset; g._reset = g.reset; - g.reset = function (n) { return g._reset().setColor(newTheme.fg).setBgColor(newTheme.bg); }; - g.clear = function (n) { if (n) g.reset(); return g.clearRect(0, 0, g.getWidth(), g.getHeight()); }; + g.reset = function(n) { + return g._reset().setColor(newTheme.fg).setBgColor(newTheme.bg); + }; + g.clear = function(n) { + if (n) g.reset(); + return g.clearRect(0, 0, g.getWidth(), g.getHeight()); + }; g.clear(1); Bangle.drawWidgets(); showMenu(); @@ -49,14 +66,16 @@ // Read the current system theme function getCurrentTheme() { - let s = require("Storage").readJSON(setting.json, 1) || {}; + let s = require('Storage').readJSON("setting.json", 1) || {}; return s.theme.dark ? 'dark' : 'light'; } function showMenu() { appSettings.theme = getCurrentTheme(); E.showMenu({ - "": { "title": "Shadow Clock" }, + "": { + "title": "Shadow Clock" + }, "< Back": () => back(), 'Theme:': { value: (appSettings.theme === 'dark'), From e81259e2c4fe125dcee8ad7dc7f51d661e996ea6 Mon Sep 17 00:00:00 2001 From: stweedo <108593831+stweedo@users.noreply.github.com> Date: Sun, 7 May 2023 22:14:17 -0500 Subject: [PATCH 39/78] Update settings.js --- apps/shadowclk/settings.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/shadowclk/settings.js b/apps/shadowclk/settings.js index a7b10db6d..eaaa8a74e 100644 --- a/apps/shadowclk/settings.js +++ b/apps/shadowclk/settings.js @@ -15,7 +15,7 @@ // Colors from 'Light BW' and 'Dark BW' themes function createThemeColors(mode) { - const cl = x => g.setColor(x).getColor(); + let cl = x => g.setColor(x).getColor(); return mode ? { fg: cl("#fff"), bg: cl("#000"), From 4cac53596014199f3e23902290553b8c3b683bb4 Mon Sep 17 00:00:00 2001 From: stweedo <108593831+stweedo@users.noreply.github.com> Date: Sun, 7 May 2023 23:49:12 -0500 Subject: [PATCH 40/78] Update settings.js Added fallback to application theme setting if it can't read system theme setting --- apps/shadowclk/settings.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/shadowclk/settings.js b/apps/shadowclk/settings.js index eaaa8a74e..fd16d92e2 100644 --- a/apps/shadowclk/settings.js +++ b/apps/shadowclk/settings.js @@ -67,6 +67,9 @@ // Read the current system theme function getCurrentTheme() { let s = require('Storage').readJSON("setting.json", 1) || {}; + if (!s.theme) { + return appSettings.theme; // fallback to appSettings.theme (light or dark) + } return s.theme.dark ? 'dark' : 'light'; } From 4256f63dce5906fdcd7788da580064977717f5a2 Mon Sep 17 00:00:00 2001 From: stweedo <108593831+stweedo@users.noreply.github.com> Date: Mon, 8 May 2023 00:19:06 -0500 Subject: [PATCH 41/78] Update app.js Switch const to var --- apps/shadowclk/app.js | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/apps/shadowclk/app.js b/apps/shadowclk/app.js index bc0c07256..45d64e35d 100644 --- a/apps/shadowclk/app.js +++ b/apps/shadowclk/app.js @@ -42,22 +42,22 @@ Graphics.prototype.setFontLondrinaSolid = function() { let drawTimeout; function draw() { - const x = g.getWidth() / 2; - const y = g.getHeight() / 2; + var x = g.getWidth() / 2; + var y = g.getHeight() / 2; g.reset().clearRect(Bangle.appRect); - const date = new Date(); + var date = new Date(); var hour = String(date.getHours()).padStart(2, '0'); if (hour[0] === '0') hour = hour[1]; var minutes = String(date.getMinutes()).padStart(2, '0'); - const timeStr = hour + ':' + minutes; + var timeStr = hour + ':' + minutes; var color = settings.color; g.setFontAlign(0, 0).setFont("LondrinaSolid").setColor(color).drawString(timeStr, x - 1, y); g.reset().setFontAlign(0, 0).setFont("LondrinaShadow").drawString(timeStr, x - 1, y); - const locale = require("locale"); - const dayOfMonth = date.getDate(); - const month = locale.month(date, 1).slice(0, 1).toUpperCase() + locale.month(date, 1).slice(1).toLowerCase(); - const year = date.getFullYear(); + var locale = require("locale"); + var dayOfMonth = date.getDate(); + var month = locale.month(date, 1).slice(0, 1).toUpperCase() + locale.month(date, 1).slice(1).toLowerCase(); + var year = date.getFullYear(); var dayOfMonthStr = dayOfMonth.toString(); if (dayOfMonth === 1 || dayOfMonth === 21 || dayOfMonth === 31) { dayOfMonthStr += "st"; @@ -68,8 +68,8 @@ Graphics.prototype.setFontLondrinaSolid = function() { } else { dayOfMonthStr += "th"; } - const dayOfWeek = locale.dow(date, 0).slice(0, 1).toUpperCase() + locale.dow(date, 0).slice(1).toLowerCase(); - const dateStr = month + " " + dayOfMonthStr + ", " + year + "\n" + dayOfWeek; + var dayOfWeek = locale.dow(date, 0).slice(0, 1).toUpperCase() + locale.dow(date, 0).slice(1).toLowerCase(); + var dateStr = month + " " + dayOfMonthStr + ", " + year + "\n" + dayOfWeek; g.setFontAlign(0, 0).setFont("DotGothic16").drawString(dateStr, x, y + 48); if (drawTimeout) clearTimeout(drawTimeout); From b8b8bc41f3f2fa094616bccb234b9690380c002d Mon Sep 17 00:00:00 2001 From: gellnerm <47713613+gellnerm@users.noreply.github.com> Date: Mon, 8 May 2023 11:20:39 +0200 Subject: [PATCH 42/78] Update ChangeLog --- apps/widtemp/ChangeLog | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/widtemp/ChangeLog b/apps/widtemp/ChangeLog index af7f83942..8fd2f7ca1 100644 --- a/apps/widtemp/ChangeLog +++ b/apps/widtemp/ChangeLog @@ -1 +1,2 @@ 0.01: Initial release +0.02: Disallow emulator From 52fd577a939d1063bbedea538a68c56ba072fd89 Mon Sep 17 00:00:00 2001 From: gellnerm <47713613+gellnerm@users.noreply.github.com> Date: Mon, 8 May 2023 11:21:00 +0200 Subject: [PATCH 43/78] Update metadata.json Disallow emulator --- apps/widtemp/metadata.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/widtemp/metadata.json b/apps/widtemp/metadata.json index 7b28acd38..5ec0f2f0e 100644 --- a/apps/widtemp/metadata.json +++ b/apps/widtemp/metadata.json @@ -1,7 +1,7 @@ { "id": "widtemp", "name": "Temperature widget", - "version": "0.01", + "version": "0.02", "description": "A temperature widget, showing the current internal temperature", "readme": "README.md", "icon": "widtemp.png", @@ -10,7 +10,7 @@ "tags": "widget,health", "supports": ["BANGLEJS","BANGLEJS2"], "dependencies" : {}, - "allow_emulator":true, + "allow_emulator":false, "storage": [ {"name":"widtemp.wid.js","url":"widtemp.wid.js"} ] From ca03a82535716aa5986991d558112a96defcc803 Mon Sep 17 00:00:00 2001 From: Rob Pilling Date: Mon, 8 May 2023 10:49:33 +0100 Subject: [PATCH 44/78] bikespeedo: option to stop recording on app exit --- apps/bikespeedo/app.js | 3 +++ apps/bikespeedo/settings.js | 10 +++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/apps/bikespeedo/app.js b/apps/bikespeedo/app.js index 297fd33d2..6f462a820 100644 --- a/apps/bikespeedo/app.js +++ b/apps/bikespeedo/app.js @@ -568,6 +568,9 @@ if (cfg.record && WIDGETS["recorder"]) { WIDGETS["recorder"] .setRecording(true) .then(start); + + if (cfg.recordStopOnExit) + E.on('kill', () => WIDGETS["recorder"].setRecording(false)); } else { start(); } diff --git a/apps/bikespeedo/settings.js b/apps/bikespeedo/settings.js index 781183305..bb943c081 100644 --- a/apps/bikespeedo/settings.js +++ b/apps/bikespeedo/settings.js @@ -22,7 +22,7 @@ }, }; - if (global.WIDGETS && WIDGETS["recorder"]) + if (global.WIDGETS && WIDGETS["recorder"]) { appMenu[/*LANG*/"Record rides"] = { value : !!settings.record, onchange : v => { @@ -30,6 +30,14 @@ writeSettings(); } }; + appMenu[/*LANG*/"Stop record on exit"] = { + value : !!settings.recordStopOnExit, + onchange : v => { + settings.recordStopOnExit = v; + writeSettings(); + } + }; + } const altdiffMenu = { '': { 'title': 'Altitude adjustment' }, From b67a07962ff53899654006721f9535bd997e4c63 Mon Sep 17 00:00:00 2001 From: Rob Pilling Date: Mon, 8 May 2023 11:13:43 +0100 Subject: [PATCH 45/78] popcon: bump version --- apps/popconlaunch/ChangeLog | 1 + apps/popconlaunch/metadata.json | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/popconlaunch/ChangeLog b/apps/popconlaunch/ChangeLog index 5560f00bc..8a2124e33 100644 --- a/apps/popconlaunch/ChangeLog +++ b/apps/popconlaunch/ChangeLog @@ -1 +1,2 @@ 0.01: New App! +0.02: Trim old entries from the popcon app cache diff --git a/apps/popconlaunch/metadata.json b/apps/popconlaunch/metadata.json index 0ccc54d9e..1acab2b6c 100644 --- a/apps/popconlaunch/metadata.json +++ b/apps/popconlaunch/metadata.json @@ -2,7 +2,7 @@ "id": "popconlaunch", "name": "Popcon Launcher", "shortName": "Popcon", - "version": "0.01", + "version": "0.02", "description": "Launcher modification - your launchers will display your favourite (popular) apps first. Overrides `readJSON`, may slow down your watch", "readme": "README.md", "icon": "app.png", From 68ba2f29d6bc9145f1a029e09e730005b302a095 Mon Sep 17 00:00:00 2001 From: Rob Pilling Date: Mon, 8 May 2023 11:32:52 +0100 Subject: [PATCH 46/78] popcon: use emoji in README --- apps/popconlaunch/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/popconlaunch/README.md b/apps/popconlaunch/README.md index 2814082a7..18a5354a4 100644 --- a/apps/popconlaunch/README.md +++ b/apps/popconlaunch/README.md @@ -3,6 +3,6 @@ Popcon Display apps sorted by regular use. No config - install the app and all your launchers will sort apps by most popular, based off launch counts within the last month, and then sort them by the most recently launched app. -:warning: Warning: this app overrides [`Storage.readJSON`], so may slow down your watch when using apps that perform I/O. +⚠️ Warning: this app overrides [`Storage.readJSON`], so may slow down your watch when using apps that perform I/O. [`Storage.readJSON`]: https://www.espruino.com/ReferenceBANGLEJS2#l_Storage_readJSON From 17e99cb10c0a768ef892010c66f3b284aa57ff0c Mon Sep 17 00:00:00 2001 From: stweedo <108593831+stweedo@users.noreply.github.com> Date: Mon, 8 May 2023 13:27:03 -0500 Subject: [PATCH 47/78] Delete custom.html Switching to interface.html --- apps/shadowclk/custom.html | 231 ------------------------------------- 1 file changed, 231 deletions(-) delete mode 100644 apps/shadowclk/custom.html diff --git a/apps/shadowclk/custom.html b/apps/shadowclk/custom.html deleted file mode 100644 index 0b3faa974..000000000 --- a/apps/shadowclk/custom.html +++ /dev/null @@ -1,231 +0,0 @@ - - - - - - - - 3-Bit Color Picker - - - - -
-

3-Bit Color Picker

-
- -
- -
- -
- - -
- - - From 1964039eccf80500c2da8c2ce4b5404f7aec8569 Mon Sep 17 00:00:00 2001 From: stweedo <108593831+stweedo@users.noreply.github.com> Date: Mon, 8 May 2023 13:28:27 -0500 Subject: [PATCH 48/78] Interface to set color and theme from app loader --- apps/shadowclk/interface.html | 283 ++++++++++++++++++++++++++++++++++ apps/shadowclk/metadata.json | 3 +- 2 files changed, 285 insertions(+), 1 deletion(-) create mode 100644 apps/shadowclk/interface.html diff --git a/apps/shadowclk/interface.html b/apps/shadowclk/interface.html new file mode 100644 index 000000000..7c4692aed --- /dev/null +++ b/apps/shadowclk/interface.html @@ -0,0 +1,283 @@ + + + + + + + + + 3-Bit Color Picker + + + + + +
+

3-Bit Color Picker

+
+ +
+ +
+ +
+ + +
+ + + + \ No newline at end of file diff --git a/apps/shadowclk/metadata.json b/apps/shadowclk/metadata.json index b07e663ad..e1debfb6d 100644 --- a/apps/shadowclk/metadata.json +++ b/apps/shadowclk/metadata.json @@ -13,6 +13,7 @@ "tags": "clock", "supports": ["BANGLEJS", "BANGLEJS2"], "readme": "README.md", + "interface": "interface.html", "allow_emulator": true, "storage": [{ "name": "shadowclk.app.js", @@ -31,4 +32,4 @@ "data": [{ "name": "shadowclk.json" }] -} +} \ No newline at end of file From 9cdf97164c195ea9833f5be6ddcb26a0c73b6d6c Mon Sep 17 00:00:00 2001 From: Rob Pilling Date: Mon, 8 May 2023 13:04:30 +0100 Subject: [PATCH 49/78] widhid: new widget --- apps/widhid/icon-active.png | Bin 0 -> 966 bytes apps/widhid/icon.js | 1 + apps/widhid/icon.png | Bin 0 -> 4598 bytes apps/widhid/metadata.json | 14 ++++ apps/widhid/wid.js | 100 ++++++++++++++++++++++++++++ apps/widhid/wid.ts | 117 +++++++++++++++++++++++++++++++++ typescript/types/settings.d.ts | 51 ++++++++++++++ 7 files changed, 283 insertions(+) create mode 100644 apps/widhid/icon-active.png create mode 100644 apps/widhid/icon.js create mode 100644 apps/widhid/icon.png create mode 100644 apps/widhid/metadata.json create mode 100644 apps/widhid/wid.js create mode 100644 apps/widhid/wid.ts create mode 100644 typescript/types/settings.d.ts diff --git a/apps/widhid/icon-active.png b/apps/widhid/icon-active.png new file mode 100644 index 0000000000000000000000000000000000000000..9764fe5118834dcc4439c48a616d96821b19cbb1 GIT binary patch literal 966 zcmV;%13CPOP)EX>4Tx04R}tkv&MmKpe$iQ;S6_B6bjQ2w0u$q9Ts93Pq?8YK2xEOfLO`CJjl7 zi=*ILaPVWX>fqw6tAnc`2!4RLx;QDiNQwVT3N2ziIPS;0dyl(!fKV?p&FYE)nr@q^ zL|n{dSHC`-Nm{=^dvC_t@XllgM#1U1~DPPEV zta9Gstd*;*c~AbrP)=W2<~q$0B(R7jND!f*iW17O5v5fp#X^eq;~o6Nu3sXTLaq`R zITlcX2HEw4|H1EWt^CxamlTQvffvX57z4U@fkw@7zKjJ_!g4Bi4gYhG{7eVjf3Y3eF@0~{Oz z;|0oI@9^$mdvE`qY4-O6SqgHTaxWz*00006VoOIv0RI600RN!9r;`8x010qNS#tmY z3ljhU3ljkVnw%H_00GuXL_t(&-tCt$PZUuUg}?h|gP}6U5==}?W}_9I6tW<)*2Vi&9q~{fq*^kctJh z^dE0CxSEy;pj`(*3)Dhj38Sx_Zm1N@led9Mkjc}pt@8q#vQHro@E-!0d!RGG25^-1 zY5(5Dr;}wFSmyi7fRp|qkO}n91V|0&D>lG+-Cc3Or?X>$-NsE^Fb?i1NWGXj5H5)~ zu?O$~9^m=_WXpl1QAa9Ms2c$W0Z`dPGzPOy7};X}Qtr%!sJ;ej7hb2jg~(_xbD;Y- zkj&T6^bK&U^YXMcpSuTk=0dn+^Tjl=X%?yZ?f{ZT9d(aOJVt{TCC`EMQQ3oRz$Y>M z%oAWgdu#^#`2k1}XRfC1eSQF{YuN#GJ>R`hGXECR@hdjJMYTDWuZh)713#`%=MV{| z^PfW1<~K0Ufy1tv$2=p9z7%7OhEa?J!(iTB!uXqD9uh_|JyN#4`RCauh?zoU1a)`L on%+Y-M%^0KW(zMbFRyE@zqb{M=HZJPTL1t607*qoM6N<$g6u1`;Q#;t literal 0 HcmV?d00001 diff --git a/apps/widhid/icon.js b/apps/widhid/icon.js new file mode 100644 index 000000000..47486854c --- /dev/null +++ b/apps/widhid/icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwxH+AH4A/AH4A/AG9lsovvAAYvvGVIvIGcwvMGMQv/F/4vTGpQvmNJAvqBggvtAEQv/F/4v/F/4nbFIYvlFooAHF1wvgFxwvfFx4v/Fz4v/F/4v/F/4wfFzwvwGBwugGBouiGBYukGJAtnAH4A/AH4A/ACIA==")) diff --git a/apps/widhid/icon.png b/apps/widhid/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..9a4dc025f596fa12a9d66927bdd9724899ed241b GIT binary patch literal 4598 zcmeH~dsGuw9>*t91fs5JrLIbK3|gRdGBbISfgq8fq&A8W1=L-fOeQcjFOrc2Xbxp% ztqQ)t7M5DsLS5L3R_j}81x2x(Be<)(K8l*UKI&^}R|~$1dnX{mY0uf?Iotn8&SYkO z_jf<{_xs-8y(f2d;@sII1rr1i1dY@tXp+Dkq0zNlksrtcQ+IkIKc zA(>tO_dTg1rGISEt2+{=k2u?kXWslxR$$j(=hifYe_eCti>}E(x+fG@3+Idrt*_tN zI&*&4el)c6>x&xXN_*{rjo$}VO+5R<_6*c!&Y?(@8d4|B)eOuKxuJ7o0MrQ(LLps;dlYSYA~Gar4}no}9s(o!<> z-MP`$(|)Tb9~9L;J#p~b&dQ8gYt5!Dk#9}kbSU-ThJ|wd)rhO*Rqt%-XggSEzkIcB z;hj3qyzZlR_2RS}#HrDr?p!r(RS;agPVm{zpqd4t$2BWEODA=c&1lJ-*Hiq8Lx$I? z|9I_T<1?>ozbVUcR3`{4@D^F}i}{D^W4DptTxs5SiQw_u8b0{v59cZx?uOl3yYAH} z{;+)oMR(S{-oY!2YB*gg8ebCXm-)CT-uqMWR}rH|T;_Y0S#9?`n`5A~+i!S=goN;^ zX)V9+a=U8l_vg3mdGdt!-VR6Ims`KR4yrDf0o9eNdz+wa77=N*8EBE)Vh3dhLD4hZ zc9L2~v#^2AV5}-(NBt2Y%otU|6qydw+2iO;CLz~BC+E)9Q@P71rBOH|MiA{L0Kh`C zBY>o^RS1Oe#CPu|#1b86M94kw@5vwzlL-a5-w3Bi$c9yYO zVU9@}Y|B}dPzc)L=kZzWI$a;$>g-hk=z+RPJBo`i)M7#V_i(cD*#OcT&@c9I>cJvK zlW3=Hxr3tPvuP_E+8;4nt4r)7a4BUl7P~JgAl`t%j8vbWeYwNz^D$B=ZKf>%>ICuO z1N>RW^g^rwv2iWFbovJZhU?=G@P3}V&lz~>bcDu6E$0T+YE(ilUczXj7$f0(qz$B; zB=JZ@A;xh;YLY4tB_1h3q?o}VHA+nwC6V_-X{}C{v{E#O0&o!nI7VD57K;^1M26F1 zL`qROLMmwqqL5QE+Cbr$SYhagnCDB2wCjA(0p; z5y~JJ8N~j|#cwX|07CmF3lUb5e4VOns zWKyXdQ_2)#nYbrCA8;YmnVrIs@nkv;y_%(+UpnnZk&H?ygLln;)PUg2|AdD~9%FjB>li^OU2}pNSIf zbLh9tfPOtTuzi8u5bfIzdqv|mo?r3PI~l*?2mn1e$V=%vDA%A|FQvdsIS*FXpj
SB7gIwUalv~mD8aQeVGt8N-fu3>SKOe3s1(ra2LYfnThQGpH zJg8#xZ-LRD)#~E?Z~6rc55h04`er>iPgiO+YJKMAdu1wg==`xOE1k`6tey}&|4w*n z<+hJUHcmd@lwR`CFSAY)N_nR5o#Cwx`gpyDI(Anjm})NAd#&|)%%!OkXRD;NYxDSk zp?qH1$eH|##WA_PafVgjW}LsW&~>V)sSOtIB%7IB>(JzJyxPi&rK zO7@$lPkxwPa(n9e@f-MAXFJMb1G0hw`09qJi;E_1WO!A6JF8*EiRuJ$QH2cdI&z>Y~hs1I`HhqaoKtzgv0WVy-gJD{k6`q$Jnh=v-WDcEyGr zx$rdRc>95W>6W0plqao6*0XFVL( zcFuS!-}}K@R)7zOtC!}bS9}F+uljMpnuCIZSor&z9KL>0;irc_I}C%_gS7E;H9KZ5 H{lk9&mAj$V literal 0 HcmV?d00001 diff --git a/apps/widhid/metadata.json b/apps/widhid/metadata.json new file mode 100644 index 000000000..5acafb2e4 --- /dev/null +++ b/apps/widhid/metadata.json @@ -0,0 +1,14 @@ +{ + "id": "widhid", + "name": "Bluetooth Music Swipe Control Widget", + "shortName": "BLE Swipe Widget", + "version": "0.01", + "description": "Based on Swipe Bluetooth Music Controls (based on Bluetooth Music Controls). Swipe down to enable, then swipe up/down for volume, left/right for previous and next and tap for play/pause. Enable HID in settings, pair with your phone/computer, then use this widget to control music from your watch!", + "icon": "icon.png", + "tags": "widget,bluetooth", + "supports": ["BANGLEJS2"], + "storage": [ + {"name":"widhid.wid.js","url":"wid.js"}, + {"name":"widhid.img","url":"icon.js","evaluate":true} + ] +} diff --git a/apps/widhid/wid.js b/apps/widhid/wid.js new file mode 100644 index 000000000..cdb370842 --- /dev/null +++ b/apps/widhid/wid.js @@ -0,0 +1,100 @@ +(function () { + var settings = require('Storage').readJSON('setting.json', true) || { HID: false }; + if (settings.HID !== "kbmedia") { + console.log("widhid: can't enable, HID setting isn't \"kbmedia\""); + return; + } + var start = { x: 0, y: 0 }, end = { x: 0, y: 0 }; + var dragging = false; + var activeTimeout; + Bangle.on("swipe", function (_lr, ud) { + if (ud > 0) { + listen(); + Bangle.buzz(); + } + }); + Bangle.on('drag', function (e) { + if (!activeTimeout) + return; + if (!dragging) { + dragging = true; + start.x = e.x; + start.y = e.y; + return; + } + var released = e.b === 0; + if (released) { + var dx = end.x - start.x; + var dy = end.y - start.y; + if (Math.abs(dy) < 10) { + if (dx > 40) + next(); + else if (dx < 40) + prev(); + } + else if (Math.abs(dx) < 10) { + if (dy > 40) + down(); + else if (dy < 40) + up(); + } + else if (dx === 0 && dy === 0) { + toggle(); + } + Bangle.buzz(); + listen(); + return; + } + end.x = e.x; + end.y = e.y; + }); + var listen = function () { + suspendOthers(); + var wasActive = !!activeTimeout; + clearTimeout(activeTimeout); + activeTimeout = setTimeout(function () { + activeTimeout = undefined; + resumeOthers(); + redraw(); + }, 5000); + if (!wasActive) + redraw(); + }; + WIDGETS["hid"] = { + area: "tr", + sortorder: -20, + draw: function () { + g.drawImage(activeTimeout + ? require("heatshrink").decompress(atob("mEwxH+AH4A/AH4A/AG8gkAvvAAYvvGVIvIGcwvMGMQv/F/4vTGpQvmNJAvqBggvtAEQv/F/4v/F/4nbFIYvlFooAHF1wvgFxwvfFx4v/Fz4v/F/4v/F/4wfFzwvwGBwugGBouiGBYukGJAtnAH4A/AH4A/ACIA==")) + : require("heatshrink").decompress(atob("mEwxH+AH4A/AH4A/AG9lsovvAAYvvGVIvIGcwvMGMQv/F/4vTGpQvmNJAvqBggvtAEQv/F/4v/F/4nbFIYvlFooAHF1wvgFxwvfFx4v/Fz4v/F/4v/F/4wfFzwvwGBwugGBouiGBYukGJAtnAH4A/AH4A/ACIA==")), this.x + 2, this.y + 2); + }, + width: 24, + }; + var redraw = function () { return setTimeout(Bangle.drawWidgets, 50); }; + NRF.on("connect", function () { + WIDGETS["hid"].width = 24; + redraw(); + }); + NRF.on("disconnect", function () { + WIDGETS["hid"].width = 0; + redraw(); + }); + var sendHid = function (code) { + NRF.sendHIDReport([1, code], function () { return NRF.sendHIDReport([1, 0]); }); + }; + var next = function () { return sendHid(0x01); }; + var prev = function () { return sendHid(0x02); }; + var toggle = function () { return sendHid(0x10); }; + var up = function () { return sendHid(0x40); }; + var down = function () { return sendHid(0x80); }; + var suspendOthers = function () { + var swipeHandler = Bangle.swipeHandler; + if (swipeHandler) + Bangle.removeListener("swipe", swipeHandler); + }; + var resumeOthers = function () { + var swipeHandler = Bangle.swipeHandler; + if (swipeHandler) + Bangle.on("swipe", swipeHandler); + }; +})(); diff --git a/apps/widhid/wid.ts b/apps/widhid/wid.ts new file mode 100644 index 000000000..cddf67aaf --- /dev/null +++ b/apps/widhid/wid.ts @@ -0,0 +1,117 @@ +(() => { + const settings: Settings = require('Storage').readJSON('setting.json', true) || { HID: false } as Settings; + if (settings.HID !== "kbmedia") { + console.log("widhid: can't enable, HID setting isn't \"kbmedia\""); + return; + } + + let start = {x:0,y:0}, end = {x:0,y:0}; + let dragging = false; + let activeTimeout: number | undefined; + + Bangle.on("swipe", (_lr, ud) => { + if(ud! > 0){ + listen(); + Bangle.buzz(); + } + }); + + Bangle.on('drag', e => { + if(!activeTimeout) return; + + if(!dragging){ + dragging = true; + start.x = e.x; + start.y = e.y; + return; + } + + const released = e.b === 0; + if(released){ + const dx = end.x - start.x; + const dy = end.y - start.y; + + if(Math.abs(dy) < 10){ + if(dx > 40) next(); + else if(dx < 40) prev(); + }else if(Math.abs(dx) < 10){ + if(dy > 40) down(); + else if(dy < 40) up(); + }else if(dx === 0 && dy === 0){ + toggle(); + } + Bangle.buzz(); // feedback event sent + + listen(); // had an event, keep listening for more + return; + } + + end.x = e.x; + end.y = e.y; + }); + + const listen = () => { + suspendOthers(); + + const wasActive = !!activeTimeout; + + clearTimeout(activeTimeout); + activeTimeout = setTimeout(() => { + activeTimeout = undefined; + resumeOthers(); + redraw(); + }, 5000); + + if(!wasActive) redraw(); + }; + + WIDGETS["hid"] = { + area: "tr", + sortorder: -20, + draw: function() { + g.drawImage( + activeTimeout + ? require("heatshrink").decompress(atob("mEwxH+AH4A/AH4A/AG8gkAvvAAYvvGVIvIGcwvMGMQv/F/4vTGpQvmNJAvqBggvtAEQv/F/4v/F/4nbFIYvlFooAHF1wvgFxwvfFx4v/Fz4v/F/4v/F/4wfFzwvwGBwugGBouiGBYukGJAtnAH4A/AH4A/ACIA==")) + : require("heatshrink").decompress(atob("mEwxH+AH4A/AH4A/AG9lsovvAAYvvGVIvIGcwvMGMQv/F/4vTGpQvmNJAvqBggvtAEQv/F/4v/F/4nbFIYvlFooAHF1wvgFxwvfFx4v/Fz4v/F/4v/F/4wfFzwvwGBwugGBouiGBYukGJAtnAH4A/AH4A/ACIA==")), + this.x! + 2, + this.y! + 2 + ); + }, + width: 24, + }; + + const redraw = () => setTimeout(Bangle.drawWidgets, 50); + + NRF.on("connect", () => { + WIDGETS["hid"]!.width = 24; + redraw(); + }); + NRF.on("disconnect", () => { + WIDGETS["hid"]!.width = 0; + redraw(); + }); + + const sendHid = (code: number) => { + NRF.sendHIDReport( + [1, code], + () => NRF.sendHIDReport([1, 0]), + ); + }; + + const next = () => sendHid(0x01); + const prev = () => sendHid(0x02); + const toggle = () => sendHid(0x10); + const up = () => sendHid(0x40); + const down = () => sendHid(0x80); + + const suspendOthers = () => { + const swipeHandler = (Bangle as {swipeHandler?: () => void}).swipeHandler; + if(swipeHandler) + Bangle.removeListener("swipe", swipeHandler); // swiperclocklaunch + }; + const resumeOthers = () => { + const swipeHandler = (Bangle as {swipeHandler?: () => void}).swipeHandler; + if(swipeHandler) + Bangle.on("swipe", swipeHandler); + }; +})() diff --git a/typescript/types/settings.d.ts b/typescript/types/settings.d.ts new file mode 100644 index 000000000..a46b6ace7 --- /dev/null +++ b/typescript/types/settings.d.ts @@ -0,0 +1,51 @@ +type Settings = { + beep: boolean, + vibrate: boolean, + quiet: number, + + ble: boolean, + blerepl: boolean, + HID?: false | "kbmedia" | "kb" | "com" | "joy", + + passkey?: string, + whitelist_disabled?: boolean, + whitelist: string[], + + theme: Theme, + + brightness: number, + timeout: number, + rotate: number, + + options: SettingsOptions, + + timezone: number, + log: number, + + clock: string, + clockHasWidgets: boolean, + launcher: string, +}; + +type SettingsTheme = { + fg: string, + bg: string, + fg2: string, + bg2: string, + fgH: string, + bgH: string, + dark: boolean, +}; + +type SettingsOptions = { + wakeOnBTN1: boolean, + wakeOnBTN2: boolean, + wakeOnBTN3: boolean, + wakeOnFaceUp: boolean, + wakeOnTouch: boolean, + + wakeOnTwist: boolean, + twistThreshold: number, + twistMaxY: number, + twistTimeout: number, +}; From 683b2dff217893ecea36f9f3ec04c4a25a4ccd6d Mon Sep 17 00:00:00 2001 From: Rob Pilling Date: Mon, 8 May 2023 14:57:33 +0100 Subject: [PATCH 50/78] widhid: icon size changes --- apps/widhid/icon-active.png | Bin 966 -> 739 bytes apps/widhid/icon.png | Bin 4598 -> 738 bytes apps/widhid/wid.ts | 4 ++-- 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/widhid/icon-active.png b/apps/widhid/icon-active.png index 9764fe5118834dcc4439c48a616d96821b19cbb1..74ce4b2a08176183cdcf93ffb604f179e7959440 100644 GIT binary patch delta 656 zcmV;B0&o4s2jc}LiBL{Q4GJ0x0000DNk~Le0000O0000O2nGNE0N{5$_y7O_gOMd4 z8>$Xw5OK&*o$R6_j10C6=2oTNSA-Bo1OpHiX4U3oIR)SGb&mjF?_xa5|JTzXnMuzRi^Ni~i`6b>B~vG!CXQ;lLHR<~ zV~z8F7H7RuXYG6P7e?~N$}-n!jv|RgEJ20@6?K$RfsGig1}PTOw4d+gyR`~alU`CJ0fb&0=VJ`$-33|=$N4^XoYn~td1dO&0V#g~^hrcPR7l6|)ICZ=Q4ogV=Y&+Q zL2O)tAOvowyHH5%+(GJex`cEFOyv^1*m$F*8}J9T)>aYYvG5{MxJkS}m43}|VCKBT zH)jqFEBv+~9wj$OkqY4~bk85_2E>`;JFdQfOhPYvp3QGnbfAR|^l_R;bpn>^psd!h zj}w196(zMxzm8sZiy?+_l(a>gnAQgP2J2>TxTxEr#%HjU3N4DGWJT1+4%TpwaV?vi zU!I~fXUL(vMW3B_nw-II(?eceP&cg#cvw((R~2wP|4WVIYJeCIiZ&CMLO84h2z!$k qA#7uSYrN)hfUTc@{=fdXJ^=6^J@$)J9oh^40000iyL*qjcYshYGtKIX0h(@` zsYG1NWLL%RR|F75FGevSGs~Ehq$E0yuY36TdKcwcozML_`qZ4o0G~)4V}@xHZxGLH z+6L!+;xH@9D)Bk-gh>}9e&o91@f+uY%L2~~o9Wa%ahO;vw6W60tY~V))5H-~(il%@HK9h$To6p`eNq%CHfoRVT$liuU6j{KKwaB9}t0 z5*RraP=N;7^@IPx?{2O9)TEabiUWZc$N3lox_5y_&2heu9j9>u_@99*z2&def!R;e zYb`Bu1oUqM7uPLK*#jMD5y z92^4U13UZusFC{6HumLH50oF-GK~!ko?Uyl66j2m~zx!r` zp)$r2OiWB>qZOSLvLLe7#susQ2@CuZ8oPlFCR8*);}3W);%I589YjqCoj|bB1m9c> zD99Ep%VeDyd?%S=l9{>pdo$;rH{j*v<&~$T=M|FKT`(3A%Sqbe!Qw&L0QB5h3Ty)w zjK$r5_{jZNzsdyAuHT>^kctJh^dE0CxSEy;pj`(*3)Dhj38Sx_Zm1N@led9Mkjc}p zt@8q#vQHro@E-!0d!RGG25^-1Y5(5Dr;}wFSmyi7fRp|qkO}n91V|0&D>lG+-Cc3O zr?X>$-NsE^Fb?i1NWGXj5H5)~u?O$~9^m?a0A$O7q)|sIQ>YsO1_4mnLo^1nP8iu@ z{!;GDg{Zy;Y8PIox`oJSFLR*#H;~NN(DV&(tMl@-HJ`f&cIHC3Wb?%|v1t~m`R)Lc zMjdsJOFTw{7bVYu^ikP^Y``Zm{LB+zKYMHj`}qM#5NEEY?tOj$s%zN+bUoj_P%{5- z7Si!6Horx+IhL=9)lCCGu2AO?38wR(Le=IsFwcR*uA0X@BaFTjV~mDTj0D4A-d)1@ zn_wOiMln57w!Qi1*(ZpZLSzJWcg~vLLp4U-8r5bCFE1~zYpuVx6^Z8IiyB)10000< KMNUMnLSTYsdYD82 diff --git a/apps/widhid/icon.png b/apps/widhid/icon.png index 9a4dc025f596fa12a9d66927bdd9724899ed241b..dfb108060e87ca478531026d185dd01c53e9e2c0 100644 GIT binary patch delta 711 zcmV;&0yzElBjN>riBL{Q4GJ0x0000DNk~Le0000O0000O2nGNE0N{5$_y7O_gK0xU zP)S2WAaHVTW@&6?001bFeUUv#!$2IxUsH=kst#rlamY}e?4lx$wF*V35Nd^19ZW9$ zf+j6Vii@M*T5#}VvFhOBtgC~oAP9bdxVktgx=4xtOA0N2VmvtR$GdxvyLW)ltT5f` zi37S}o9Sdi%H~$3-dBVWMg#*86=v1uWH|-j@pX>?U+-c(%m3V;qhHHg3J z;tk@NO}oZz6+X^tX^MJz#v1Qm6ZQGtyZtp+I;(zKuO@sGHE znOrKl%3$PJKovR^*AM;&zq_>xQ~6(rCX<}= zo#dSPhK>>DRvZ_17-1xZbA$NQwn3`gO5A)I3Kz2YQl-a+2}GdRdcTz%w!#>fZAa932Q#5QqLXq_N;$T%j0e(TJDdD5 ze1!E{WwqqFBTDj#!<%=IcDgQkX^O6BYVbHkci+$;986TD*M|l7M literal 4598 zcmeH~dsGuw9>*t91fs5JrLIbK3|gRdGBbISfgq8fq&A8W1=L-fOeQcjFOrc2Xbxp% ztqQ)t7M5DsLS5L3R_j}81x2x(Be<)(K8l*UKI&^}R|~$1dnX{mY0uf?Iotn8&SYkO z_jf<{_xs-8y(f2d;@sII1rr1i1dY@tXp+Dkq0zNlksrtcQ+IkIKc zA(>tO_dTg1rGISEt2+{=k2u?kXWslxR$$j(=hifYe_eCti>}E(x+fG@3+Idrt*_tN zI&*&4el)c6>x&xXN_*{rjo$}VO+5R<_6*c!&Y?(@8d4|B)eOuKxuJ7o0MrQ(LLps;dlYSYA~Gar4}no}9s(o!<> z-MP`$(|)Tb9~9L;J#p~b&dQ8gYt5!Dk#9}kbSU-ThJ|wd)rhO*Rqt%-XggSEzkIcB z;hj3qyzZlR_2RS}#HrDr?p!r(RS;agPVm{zpqd4t$2BWEODA=c&1lJ-*Hiq8Lx$I? z|9I_T<1?>ozbVUcR3`{4@D^F}i}{D^W4DptTxs5SiQw_u8b0{v59cZx?uOl3yYAH} z{;+)oMR(S{-oY!2YB*gg8ebCXm-)CT-uqMWR}rH|T;_Y0S#9?`n`5A~+i!S=goN;^ zX)V9+a=U8l_vg3mdGdt!-VR6Ims`KR4yrDf0o9eNdz+wa77=N*8EBE)Vh3dhLD4hZ zc9L2~v#^2AV5}-(NBt2Y%otU|6qydw+2iO;CLz~BC+E)9Q@P71rBOH|MiA{L0Kh`C zBY>o^RS1Oe#CPu|#1b86M94kw@5vwzlL-a5-w3Bi$c9yYO zVU9@}Y|B}dPzc)L=kZzWI$a;$>g-hk=z+RPJBo`i)M7#V_i(cD*#OcT&@c9I>cJvK zlW3=Hxr3tPvuP_E+8;4nt4r)7a4BUl7P~JgAl`t%j8vbWeYwNz^D$B=ZKf>%>ICuO z1N>RW^g^rwv2iWFbovJZhU?=G@P3}V&lz~>bcDu6E$0T+YE(ilUczXj7$f0(qz$B; zB=JZ@A;xh;YLY4tB_1h3q?o}VHA+nwC6V_-X{}C{v{E#O0&o!nI7VD57K;^1M26F1 zL`qROLMmwqqL5QE+Cbr$SYhagnCDB2wCjA(0p; z5y~JJ8N~j|#cwX|07CmF3lUb5e4VOns zWKyXdQ_2)#nYbrCA8;YmnVrIs@nkv;y_%(+UpnnZk&H?ygLln;)PUg2|AdD~9%FjB>li^OU2}pNSIf zbLh9tfPOtTuzi8u5bfIzdqv|mo?r3PI~l*?2mn1e$V=%vDA%A|FQvdsIS*FXpj
SB7gIwUalv~mD8aQeVGt8N-fu3>SKOe3s1(ra2LYfnThQGpH zJg8#xZ-LRD)#~E?Z~6rc55h04`er>iPgiO+YJKMAdu1wg==`xOE1k`6tey}&|4w*n z<+hJUHcmd@lwR`CFSAY)N_nR5o#Cwx`gpyDI(Anjm})NAd#&|)%%!OkXRD;NYxDSk zp?qH1$eH|##WA_PafVgjW}LsW&~>V)sSOtIB%7IB>(JzJyxPi&rK zO7@$lPkxwPa(n9e@f-MAXFJMb1G0hw`09qJi;E_1WO!A6JF8*EiRuJ$QH2cdI&z>Y~hs1I`HhqaoKtzgv0WVy-gJD{k6`q$Jnh=v-WDcEyGr zx$rdRc>95W>6W0plqao6*0XFVL( zcFuS!-}}K@R)7zOtC!}bS9}F+uljMpnuCIZSor&z9KL>0;irc_I}C%_gS7E;H9KZ5 H{lk9&mAj$V diff --git a/apps/widhid/wid.ts b/apps/widhid/wid.ts index cddf67aaf..46317ff6f 100644 --- a/apps/widhid/wid.ts +++ b/apps/widhid/wid.ts @@ -71,8 +71,8 @@ draw: function() { g.drawImage( activeTimeout - ? require("heatshrink").decompress(atob("mEwxH+AH4A/AH4A/AG8gkAvvAAYvvGVIvIGcwvMGMQv/F/4vTGpQvmNJAvqBggvtAEQv/F/4v/F/4nbFIYvlFooAHF1wvgFxwvfFx4v/Fz4v/F/4v/F/4wfFzwvwGBwugGBouiGBYukGJAtnAH4A/AH4A/ACIA==")) - : require("heatshrink").decompress(atob("mEwxH+AH4A/AH4A/AG9lsovvAAYvvGVIvIGcwvMGMQv/F/4vTGpQvmNJAvqBggvtAEQv/F/4v/F/4nbFIYvlFooAHF1wvgFxwvfFx4v/Fz4v/F/4v/F/4wfFzwvwGBwugGBouiGBYukGJAtnAH4A/AH4A/ACIA==")), + ? require("heatshrink").decompress(atob("jEYxH+AEfH44XXAAYXXDKIXZDYp3pC/6KHUMwWHC/4XvUy4YGdqoA/AFoA==")) + : require("heatshrink").decompress(atob("jEYxH+AEcdjoXXAAYXXDKIXZDYp3pC/6KHUMwWHC/4XvUy4YGdqoA/AFoA==")), this.x! + 2, this.y! + 2 ); From 4af055dac72089d2a6c45bb130117748ae99a9de Mon Sep 17 00:00:00 2001 From: Rob Pilling Date: Mon, 8 May 2023 14:58:08 +0100 Subject: [PATCH 51/78] widhid: formatting --- apps/widhid/wid.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/widhid/wid.ts b/apps/widhid/wid.ts index 46317ff6f..30f32f037 100644 --- a/apps/widhid/wid.ts +++ b/apps/widhid/wid.ts @@ -1,5 +1,5 @@ (() => { - const settings: Settings = require('Storage').readJSON('setting.json', true) || { HID: false } as Settings; + const settings: Settings = require("Storage").readJSON("setting.json", true) || { HID: false } as Settings; if (settings.HID !== "kbmedia") { console.log("widhid: can't enable, HID setting isn't \"kbmedia\""); return; @@ -16,7 +16,7 @@ } }); - Bangle.on('drag', e => { + Bangle.on("drag", e => { if(!activeTimeout) return; if(!dragging){ From d2a989170cc8932598370c46052d2341a98017bc Mon Sep 17 00:00:00 2001 From: Rob Pilling Date: Mon, 8 May 2023 14:59:14 +0100 Subject: [PATCH 52/78] widhid: gesture/dragging improvements --- apps/widhid/wid.ts | 101 ++++++++++++++++++++++++++++----------------- 1 file changed, 64 insertions(+), 37 deletions(-) diff --git a/apps/widhid/wid.ts b/apps/widhid/wid.ts index 30f32f037..df5dd4480 100644 --- a/apps/widhid/wid.ts +++ b/apps/widhid/wid.ts @@ -5,64 +5,91 @@ return; } - let start = {x:0,y:0}, end = {x:0,y:0}; + let anchor = {x:0,y:0}; + let start = {x:0,y:0}; let dragging = false; let activeTimeout: number | undefined; + let waitForRelease = true; Bangle.on("swipe", (_lr, ud) => { - if(ud! > 0){ + if(!activeTimeout && ud! > 0){ listen(); - Bangle.buzz(); + Bangle.buzz(20); } }); - Bangle.on("drag", e => { - if(!activeTimeout) return; + const onDrag = (e => { + if(e.b === 0){ + // released + const wasDragging = dragging; + dragging = false; - if(!dragging){ - dragging = true; - start.x = e.x; - start.y = e.y; - return; - } - - const released = e.b === 0; - if(released){ - const dx = end.x - start.x; - const dy = end.y - start.y; - - if(Math.abs(dy) < 10){ - if(dx > 40) next(); - else if(dx < 40) prev(); - }else if(Math.abs(dx) < 10){ - if(dy > 40) down(); - else if(dy < 40) up(); - }else if(dx === 0 && dy === 0){ - toggle(); + if(waitForRelease){ + waitForRelease = false; + return; } - Bangle.buzz(); // feedback event sent - listen(); // had an event, keep listening for more + if(!wasDragging // i.e. tap + || (Math.abs(e.x - anchor.x) < 2 && Math.abs(e.y - anchor.y) < 2)) + { + toggle(); + onEvent(); + return; + } + } + if(waitForRelease) return; + + if(e.b && !dragging){ + dragging = true; + setStart(e); + Object.assign(anchor, start); return; } - end.x = e.x; - end.y = e.y; - }); + const dx = e.x - start.x; + const dy = e.y - start.y; + + if(Math.abs(dy) > 25 && Math.abs(dx) > 25){ + // diagonal, ignore + setStart(e); + return; + } + + // had a drag in a single axis + /**/ if(dx > 40) { next(); onEvent(); waitForRelease = true; } + else if(dx < -40){ prev(); onEvent(); waitForRelease = true; } + else if(dy > 30) { down(); onEvent(); setStart(e); } + else if(dy < -30){ up(); onEvent(); setStart(e); } + }) satisfies DragCallback; + + const setStart = ({ x, y }: { x: number, y: number }) => { + start.x = x; + start.y = y; + }; + + const onEvent = () => { + Bangle.buzz(20); // feedback event sent + listen(); // had an event, keep listening for more + }; const listen = () => { - suspendOthers(); - const wasActive = !!activeTimeout; + if(!wasActive){ + suspendOthers(); + waitForRelease = true; // wait for first touch up before accepting gestures + Bangle.on("drag", onDrag); + redraw(); + } - clearTimeout(activeTimeout); + if(activeTimeout) clearTimeout(activeTimeout); activeTimeout = setTimeout(() => { activeTimeout = undefined; - resumeOthers(); - redraw(); - }, 5000); - if(!wasActive) redraw(); + Bangle.removeListener("drag", onDrag); + resumeOthers(); + + redraw(); + }, 3000); }; WIDGETS["hid"] = { From 2fc4fdedacebef4fc87913016c912a8e63bdccfc Mon Sep 17 00:00:00 2001 From: Rob Pilling Date: Mon, 8 May 2023 14:59:30 +0100 Subject: [PATCH 53/78] widhid: debug comments --- apps/widhid/wid.ts | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/apps/widhid/wid.ts b/apps/widhid/wid.ts index df5dd4480..5e641938e 100644 --- a/apps/widhid/wid.ts +++ b/apps/widhid/wid.ts @@ -118,18 +118,20 @@ redraw(); }); + //const DEBUG = true; const sendHid = (code: number) => { + //if(DEBUG) return; NRF.sendHIDReport( [1, code], () => NRF.sendHIDReport([1, 0]), ); }; - const next = () => sendHid(0x01); - const prev = () => sendHid(0x02); - const toggle = () => sendHid(0x10); - const up = () => sendHid(0x40); - const down = () => sendHid(0x80); + const next = () => /*DEBUG ? console.log("next") : */ sendHid(0x01); + const prev = () => /*DEBUG ? console.log("prev") : */ sendHid(0x02); + const toggle = () => /*DEBUG ? console.log("toggle") : */ sendHid(0x10); + const up = () => /*DEBUG ? console.log("up") : */ sendHid(0x40); + const down = () => /*DEBUG ? console.log("down") : */ sendHid(0x80); const suspendOthers = () => { const swipeHandler = (Bangle as {swipeHandler?: () => void}).swipeHandler; From 69bfcfeb992de8262b4e3b1d63c6a6ca89402c4a Mon Sep 17 00:00:00 2001 From: Rob Pilling Date: Mon, 8 May 2023 15:02:54 +0100 Subject: [PATCH 54/78] widhid: regenerate JS --- apps/widhid/wid.js | 111 ++++++++++++++++++++++++------------- typescript/types/main.d.ts | 11 +++- 2 files changed, 79 insertions(+), 43 deletions(-) diff --git a/apps/widhid/wid.js b/apps/widhid/wid.js index cdb370842..4ebe13b6e 100644 --- a/apps/widhid/wid.js +++ b/apps/widhid/wid.js @@ -1,72 +1,103 @@ (function () { - var settings = require('Storage').readJSON('setting.json', true) || { HID: false }; + var settings = require("Storage").readJSON("setting.json", true) || { HID: false }; if (settings.HID !== "kbmedia") { console.log("widhid: can't enable, HID setting isn't \"kbmedia\""); return; } - var start = { x: 0, y: 0 }, end = { x: 0, y: 0 }; + var anchor = { x: 0, y: 0 }; + var start = { x: 0, y: 0 }; var dragging = false; var activeTimeout; + var waitForRelease = true; Bangle.on("swipe", function (_lr, ud) { - if (ud > 0) { + if (!activeTimeout && ud > 0) { listen(); - Bangle.buzz(); + Bangle.buzz(20); } }); - Bangle.on('drag', function (e) { - if (!activeTimeout) - return; - if (!dragging) { - dragging = true; - start.x = e.x; - start.y = e.y; - return; - } - var released = e.b === 0; - if (released) { - var dx = end.x - start.x; - var dy = end.y - start.y; - if (Math.abs(dy) < 10) { - if (dx > 40) - next(); - else if (dx < 40) - prev(); + var onDrag = (function (e) { + if (e.b === 0) { + var wasDragging = dragging; + dragging = false; + if (waitForRelease) { + waitForRelease = false; + return; } - else if (Math.abs(dx) < 10) { - if (dy > 40) - down(); - else if (dy < 40) - up(); - } - else if (dx === 0 && dy === 0) { + if (!wasDragging + || (Math.abs(e.x - anchor.x) < 2 && Math.abs(e.y - anchor.y) < 2)) { toggle(); + onEvent(); + return; } - Bangle.buzz(); - listen(); + } + if (waitForRelease) + return; + if (e.b && !dragging) { + dragging = true; + setStart(e); + Object.assign(anchor, start); return; } - end.x = e.x; - end.y = e.y; + var dx = e.x - start.x; + var dy = e.y - start.y; + if (Math.abs(dy) > 25 && Math.abs(dx) > 25) { + setStart(e); + return; + } + if (dx > 40) { + next(); + onEvent(); + waitForRelease = true; + } + else if (dx < -40) { + prev(); + onEvent(); + waitForRelease = true; + } + else if (dy > 30) { + down(); + onEvent(); + setStart(e); + } + else if (dy < -30) { + up(); + onEvent(); + setStart(e); + } }); + var setStart = function (_a) { + var x = _a.x, y = _a.y; + start.x = x; + start.y = y; + }; + var onEvent = function () { + Bangle.buzz(20); + listen(); + }; var listen = function () { - suspendOthers(); var wasActive = !!activeTimeout; - clearTimeout(activeTimeout); + if (!wasActive) { + suspendOthers(); + waitForRelease = true; + Bangle.on("drag", onDrag); + redraw(); + } + if (activeTimeout) + clearTimeout(activeTimeout); activeTimeout = setTimeout(function () { activeTimeout = undefined; + Bangle.removeListener("drag", onDrag); resumeOthers(); redraw(); - }, 5000); - if (!wasActive) - redraw(); + }, 3000); }; WIDGETS["hid"] = { area: "tr", sortorder: -20, draw: function () { g.drawImage(activeTimeout - ? require("heatshrink").decompress(atob("mEwxH+AH4A/AH4A/AG8gkAvvAAYvvGVIvIGcwvMGMQv/F/4vTGpQvmNJAvqBggvtAEQv/F/4v/F/4nbFIYvlFooAHF1wvgFxwvfFx4v/Fz4v/F/4v/F/4wfFzwvwGBwugGBouiGBYukGJAtnAH4A/AH4A/ACIA==")) - : require("heatshrink").decompress(atob("mEwxH+AH4A/AH4A/AG9lsovvAAYvvGVIvIGcwvMGMQv/F/4vTGpQvmNJAvqBggvtAEQv/F/4v/F/4nbFIYvlFooAHF1wvgFxwvfFx4v/Fz4v/F/4v/F/4wfFzwvwGBwugGBouiGBYukGJAtnAH4A/AH4A/ACIA==")), this.x + 2, this.y + 2); + ? require("heatshrink").decompress(atob("jEYxH+AEfH44XXAAYXXDKIXZDYp3pC/6KHUMwWHC/4XvUy4YGdqoA/AFoA==")) + : require("heatshrink").decompress(atob("jEYxH+AEcdjoXXAAYXXDKIXZDYp3pC/6KHUMwWHC/4XvUy4YGdqoA/AFoA==")), this.x + 2, this.y + 2); }, width: 24, }; diff --git a/typescript/types/main.d.ts b/typescript/types/main.d.ts index 29118b7c6..4e4dd224e 100644 --- a/typescript/types/main.d.ts +++ b/typescript/types/main.d.ts @@ -1584,7 +1584,7 @@ declare class NRF { * @param {any} callback - A callback function to be called when the data is sent * @url http://www.espruino.com/Reference#l_NRF_sendHIDReport */ - static sendHIDReport(data: any, callback: any): void; + static sendHIDReport(data: number[], callback?: () => void): void /** * Check if Apple Notification Center Service (ANCS) is currently active on the BLE @@ -3188,8 +3188,10 @@ declare class Puck { * Check out [the Puck.js page on the * accelerometer](http://www.espruino.com/Puck.js#on-board-peripherals) for more * information. + * **Note:** Puck.js cannot currently read every sample from the + * accelerometer at sample rates above 208Hz. * - * @param {number} samplerate - The sample rate in Hz, or undefined + * @param {number} samplerate - The sample rate in Hz, or `undefined` (default is 12.5 Hz) * @url http://www.espruino.com/Reference#l_Puck_accelOn */ static accelOn(samplerate: number): void; @@ -3819,6 +3821,9 @@ declare class Bangle { * and polling rate may not be exact. The algorithm's filtering is tuned for * 20-40ms poll intervals, so higher/lower intervals may effect the reliability * of the BPM reading. + * * `hrmSportMode` - on the newest Bangle.js 2 builds with with the proprietary + * heart rate algorithm, this is the sport mode passed to the algorithm. See `libs/misc/vc31_binary/algo.h` + * for more info. 0 = normal (default), 1 = running, 2 = ... * * `seaLevelPressure` (Bangle.js 2) Normally 1013.25 millibars - this is used for * calculating altitude with the pressure sensor * Where accelerations are used they are in internal units, where `8192 = 1g` @@ -13222,7 +13227,7 @@ declare module "Storage" { * @returns {any} An object containing parsed JSON from the file, or undefined * @url http://www.espruino.com/Reference#l_Storage_readJSON */ - function readJSON(name: string, noExceptions: boolean): any; + function readJSON(name: string, noExceptions: ShortBoolean): any; /** * Read a file from the flash storage area that has been written with From 0192b150e7e552df69a1fe957f14b945e2260034 Mon Sep 17 00:00:00 2001 From: Rob Pilling Date: Mon, 8 May 2023 15:07:42 +0100 Subject: [PATCH 55/78] widhid: only draw if width > 0 (i.e. when connected) --- apps/widhid/wid.js | 2 ++ apps/widhid/wid.ts | 1 + 2 files changed, 3 insertions(+) diff --git a/apps/widhid/wid.js b/apps/widhid/wid.js index 4ebe13b6e..0b6b4b33a 100644 --- a/apps/widhid/wid.js +++ b/apps/widhid/wid.js @@ -95,6 +95,8 @@ area: "tr", sortorder: -20, draw: function () { + if (this.width === 0) + return; g.drawImage(activeTimeout ? require("heatshrink").decompress(atob("jEYxH+AEfH44XXAAYXXDKIXZDYp3pC/6KHUMwWHC/4XvUy4YGdqoA/AFoA==")) : require("heatshrink").decompress(atob("jEYxH+AEcdjoXXAAYXXDKIXZDYp3pC/6KHUMwWHC/4XvUy4YGdqoA/AFoA==")), this.x + 2, this.y + 2); diff --git a/apps/widhid/wid.ts b/apps/widhid/wid.ts index 5e641938e..5e95c746d 100644 --- a/apps/widhid/wid.ts +++ b/apps/widhid/wid.ts @@ -96,6 +96,7 @@ area: "tr", sortorder: -20, draw: function() { + if(this.width === 0) return; g.drawImage( activeTimeout ? require("heatshrink").decompress(atob("jEYxH+AEfH44XXAAYXXDKIXZDYp3pC/6KHUMwWHC/4XvUy4YGdqoA/AFoA==")) From 02b41cf4ec8271e81cd9e8e2da039988d9b3c723 Mon Sep 17 00:00:00 2001 From: Rob Pilling Date: Mon, 8 May 2023 15:15:47 +0100 Subject: [PATCH 56/78] widhid: rename widget icons & add app icon --- apps/widhid/icon.js | 2 +- apps/widhid/icon.png | Bin 738 -> 959 bytes .../{icon-active.png => widget-active.png} | Bin apps/widhid/widget.png | Bin 0 -> 738 bytes 4 files changed, 1 insertion(+), 1 deletion(-) rename apps/widhid/{icon-active.png => widget-active.png} (100%) create mode 100644 apps/widhid/widget.png diff --git a/apps/widhid/icon.js b/apps/widhid/icon.js index 47486854c..9bd94bacf 100644 --- a/apps/widhid/icon.js +++ b/apps/widhid/icon.js @@ -1 +1 @@ -require("heatshrink").decompress(atob("mEwxH+AH4A/AH4A/AG9lsovvAAYvvGVIvIGcwvMGMQv/F/4vTGpQvmNJAvqBggvtAEQv/F/4v/F/4nbFIYvlFooAHF1wvgFxwvfFx4v/Fz4v/F/4v/F/4wfFzwvwGBwugGBouiGBYukGJAtnAH4A/AH4A/ACIA==")) +require("heatshrink").decompress(atob("mUywkBiIA/AFEQOIRuTRgwvSFoQ0DGCBFEDIRNGA44RBB4wIGEIQgNA4IJFCwMQCIpaHBwIyFDA5JHBwYYNFAQ6HDAhjHU4YJFFQ4nGF4YYNbxBeEDFRHDDCxjPeI6WDDBauHCAQIGDAxRPfKAYpMZKdIFIyVHZ5JCODBJCOMRwYSJLIYUUgIBBJN0BGCxJXGARJWAAJJWC6owCJCowwPP6RiC6oYBC6wA/AEQA=")) diff --git a/apps/widhid/icon.png b/apps/widhid/icon.png index dfb108060e87ca478531026d185dd01c53e9e2c0..d52c359d4edde2d1ea5be357ee3b8134298fb6ef 100644 GIT binary patch literal 959 zcmV;w13>(VP)5I8tAUe1E$|6w2R;JLk{t)u1CvNl1ImFPQrz!T2do0p zNC2h+FQix-a0w^|rU4^ms1b&rmeNmwc?!5(;F;um zeatgnea#q;Y-_WOIZrG@aytAiS90TSkr-?Ryq(sK>^X7Zv}K5wHRzB%%$^X5H1+*! z$@)pwLL69Z8DiYZCQtH4AM*^cHb##O$&CBPoL;~+%fEBAGI>^v?C~+r1obtp>M>Tb zm+>l5Myc2fm$hzalZ(V`^*2g*%(60KTuKzfK<&cK+DDqS5`K)ZYp!ZbwnZ{if5p5+ zi5As*d5I-EBUxcQN|b2PsFxcTLrS%1hc;&a)K1#ft21V*=B2F zbY?XQr1TqQn~Byn(lQ(&6L=-1H!4HDf$f2nOQDx9Ihx&tfK$UGKB1bua`=xD?V z-BUTiXdP;71I(#!B@U5i6@lJS)2za993dUp-yt(S4s+|6@YGlam^-a?s%D+zx>led hQT|7sBuNsw#eW4wQ*FXm()$1a002ovPDHLkV1l6ByoLY( delta 729 zcmV;~0w(>x2jT^PiBL{Q4GJ0x0000DNk~Le0000O0000O2nGNE0N{5$_y7O_gK0xU zP)S2WAaHVTW@&6?001bFeUUv#!$2IxUsH=kst#rlamY}e?4lx$wF*V35Nd^19ZW9$ zf+j6Vii@M*T5#}VvFhOBtgC~oAP9bdxVktgx=4xtOA0N2VmvtR$GdxvyLW)ltT5f` zi37S}o9Sdi%H~$3-dBVWMg#*86=v1uWH|-j@pX>?U+-c(%m3V;qhHHg3J z;tk@NO}oZz6+X^tX^MJz#v1Qm6ZQGtyZtp+I;(zKuO@sGHE znOrKl%3$PJKovR^*AM;&zq_>xQ_|&#Rs@zK4d>INCviMS^ z$A$?+tRlx5DgTYoDVi9pV3%-&=k`0ue|q2A)6_RE*HFlM*HwDIl^nLh7?*8F)OiOp zp+2IMa#2b-wy}%{(qTKB{4sol^;%`M$R4 zRHfNpQ%%XmUfpKmN{IW-3EX>4Tx04R}tkv&MmKpe$iQ;S8a4rUN>$WWc^q9Ts93Pq?8YK2xEOfLO`CM`*d zi=*ILaPVWX>fqw6tAnc`2!4RLx;QDiNQwVT3N2zhIPS;0dyl(!fY7Wk-Rg-0x?!8? zWJ1d3R;Auogb+pq0}vHv)#hY51>f;?j{slqVm!4L_2fw?u3R9C_QX~O{UL5CR4CvhjS`EkfK6aee2@re+u8fYq+5~1lNpEzt z=n*iu4P0DzG<6TS+yRE4YKp12Qjn%lC;;zg^i4Tn=oaW(^LlIV5!HeLLQR zN=2e_qeE0)fJmrmiQL^$5H@1(pX_eMX(p4L^PS|J`G$@W=2jdRcNk$Lg>!@W)V4vY z+)CVh844G&_)?|Eh6zNhBF7mi|BcWoni#BLmvDsV_B+UW-`dmEH!jyu$a>dRdcTz% zw!#>fZAa932Q#5QqLXq_N;$T%j0e(TJDdD5e1!E{WwqqFBTDj#!<%=IcDgQkX^O6B zYVbHkci+$;986TD* Date: Mon, 8 May 2023 20:44:21 +0100 Subject: [PATCH 57/78] widhid: disable if clkinfo is focused --- apps/widhid/wid.js | 4 ++++ apps/widhid/wid.ts | 4 ++++ typescript/types/clock_info.d.ts | 4 ++++ 3 files changed, 12 insertions(+) diff --git a/apps/widhid/wid.js b/apps/widhid/wid.js index 0b6b4b33a..00778500d 100644 --- a/apps/widhid/wid.js +++ b/apps/widhid/wid.js @@ -10,12 +10,16 @@ var activeTimeout; var waitForRelease = true; Bangle.on("swipe", function (_lr, ud) { + if (Bangle.CLKINFO_FOCUS) + return; if (!activeTimeout && ud > 0) { listen(); Bangle.buzz(20); } }); var onDrag = (function (e) { + if (Bangle.CLKINFO_FOCUS) + return; if (e.b === 0) { var wasDragging = dragging; dragging = false; diff --git a/apps/widhid/wid.ts b/apps/widhid/wid.ts index 5e95c746d..fe225339e 100644 --- a/apps/widhid/wid.ts +++ b/apps/widhid/wid.ts @@ -12,6 +12,8 @@ let waitForRelease = true; Bangle.on("swipe", (_lr, ud) => { + if((Bangle as BangleExt).CLKINFO_FOCUS) return; + if(!activeTimeout && ud! > 0){ listen(); Bangle.buzz(20); @@ -19,6 +21,8 @@ }); const onDrag = (e => { + if((Bangle as BangleExt).CLKINFO_FOCUS) return; + if(e.b === 0){ // released const wasDragging = dragging; diff --git a/typescript/types/clock_info.d.ts b/typescript/types/clock_info.d.ts index 06a2d400b..b12732683 100644 --- a/typescript/types/clock_info.d.ts +++ b/typescript/types/clock_info.d.ts @@ -57,3 +57,7 @@ declare module ClockInfo { focus: boolean, }; } + +interface BangleExt { + CLKINFO_FOCUS?: true; +} From a2e9c8db1edf50356a47c12e9dcc8ac9113f104b Mon Sep 17 00:00:00 2001 From: Rob Pilling Date: Mon, 8 May 2023 21:46:16 +0100 Subject: [PATCH 58/78] widhid: disable all touch events when active --- apps/widhid/wid.js | 39 +++++++++++++++++++++++++++++++++------ apps/widhid/wid.ts | 46 ++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 73 insertions(+), 12 deletions(-) diff --git a/apps/widhid/wid.js b/apps/widhid/wid.js index 00778500d..7ce273eee 100644 --- a/apps/widhid/wid.js +++ b/apps/widhid/wid.js @@ -124,14 +124,41 @@ var toggle = function () { return sendHid(0x10); }; var up = function () { return sendHid(0x40); }; var down = function () { return sendHid(0x80); }; + var touchEvents = { + tap: null, + gesture: null, + aiGesture: null, + swipe: null, + touch: null, + drag: null, + stroke: null, + }; var suspendOthers = function () { - var swipeHandler = Bangle.swipeHandler; - if (swipeHandler) - Bangle.removeListener("swipe", swipeHandler); + for (var event in touchEvents) { + var handlers = Bangle["#on".concat(event)]; + if (!handlers) + continue; + var newEvents = void 0; + if (handlers instanceof Array) + newEvents = handlers.slice(); + else + newEvents = [handlers]; + for (var _i = 0, newEvents_1 = newEvents; _i < newEvents_1.length; _i++) { + var handler = newEvents_1[_i]; + Bangle.removeListener(event, handler); + } + touchEvents[event] = newEvents; + } }; var resumeOthers = function () { - var swipeHandler = Bangle.swipeHandler; - if (swipeHandler) - Bangle.on("swipe", swipeHandler); + for (var event in touchEvents) { + var handlers = touchEvents[event]; + touchEvents[event] = null; + if (handlers) + for (var _i = 0, handlers_1 = handlers; _i < handlers_1.length; _i++) { + var handler = handlers_1[_i]; + Bangle.on(event, handler); + } + } }; })(); diff --git a/apps/widhid/wid.ts b/apps/widhid/wid.ts index fe225339e..34f41600f 100644 --- a/apps/widhid/wid.ts +++ b/apps/widhid/wid.ts @@ -138,14 +138,48 @@ const up = () => /*DEBUG ? console.log("up") : */ sendHid(0x40); const down = () => /*DEBUG ? console.log("down") : */ sendHid(0x80); + // similarly to the lightswitch app, we tangle with the listener arrays to + // disable event handlers + type Handler = () => void; + const touchEvents: { + [key: string]: null | Handler[] + } = { + tap: null, + gesture: null, + aiGesture: null, + swipe: null, + touch: null, + drag: null, + stroke: null, + }; + const suspendOthers = () => { - const swipeHandler = (Bangle as {swipeHandler?: () => void}).swipeHandler; - if(swipeHandler) - Bangle.removeListener("swipe", swipeHandler); // swiperclocklaunch + for(const event in touchEvents){ + const handlers: Handler[] | Handler | undefined + = (Bangle as any)[`#on${event}`]; + + if(!handlers) continue; + + let newEvents; + if(handlers instanceof Array) + newEvents = handlers.slice(); + else + newEvents = [handlers /* single fn */]; + + for(const handler of newEvents) + Bangle.removeListener(event, handler); + + touchEvents[event] = newEvents; + } }; const resumeOthers = () => { - const swipeHandler = (Bangle as {swipeHandler?: () => void}).swipeHandler; - if(swipeHandler) - Bangle.on("swipe", swipeHandler); + for(const event in touchEvents){ + const handlers = touchEvents[event]; + touchEvents[event] = null; + + if(handlers) + for(const handler of handlers) + Bangle.on(event as any, handler); + } }; })() From 610f4d61a739fc2d15897d3f81bb8d99a9b28c15 Mon Sep 17 00:00:00 2001 From: Rob Pilling Date: Mon, 8 May 2023 21:53:20 +0100 Subject: [PATCH 59/78] widhid: initial display based on NRF.connected --- apps/widhid/wid.js | 2 +- apps/widhid/wid.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/widhid/wid.js b/apps/widhid/wid.js index 7ce273eee..1e2097686 100644 --- a/apps/widhid/wid.js +++ b/apps/widhid/wid.js @@ -105,7 +105,7 @@ ? require("heatshrink").decompress(atob("jEYxH+AEfH44XXAAYXXDKIXZDYp3pC/6KHUMwWHC/4XvUy4YGdqoA/AFoA==")) : require("heatshrink").decompress(atob("jEYxH+AEcdjoXXAAYXXDKIXZDYp3pC/6KHUMwWHC/4XvUy4YGdqoA/AFoA==")), this.x + 2, this.y + 2); }, - width: 24, + width: NRF.getSecurityStatus().connected ? 24 : 0, }; var redraw = function () { return setTimeout(Bangle.drawWidgets, 50); }; NRF.on("connect", function () { diff --git a/apps/widhid/wid.ts b/apps/widhid/wid.ts index 34f41600f..38f45c357 100644 --- a/apps/widhid/wid.ts +++ b/apps/widhid/wid.ts @@ -109,7 +109,7 @@ this.y! + 2 ); }, - width: 24, + width: NRF.getSecurityStatus().connected ? 24 : 0, }; const redraw = () => setTimeout(Bangle.drawWidgets, 50); From 4352cd0f29362831ab804a4244e86076635b8fac Mon Sep 17 00:00:00 2001 From: Rob Pilling Date: Mon, 8 May 2023 22:05:41 +0100 Subject: [PATCH 60/78] widhid: formatting --- apps/widhid/wid.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/widhid/wid.ts b/apps/widhid/wid.ts index 38f45c357..fa81021e1 100644 --- a/apps/widhid/wid.ts +++ b/apps/widhid/wid.ts @@ -60,9 +60,9 @@ } // had a drag in a single axis - /**/ if(dx > 40) { next(); onEvent(); waitForRelease = true; } + if(dx > 40){ next(); onEvent(); waitForRelease = true; } else if(dx < -40){ prev(); onEvent(); waitForRelease = true; } - else if(dy > 30) { down(); onEvent(); setStart(e); } + else if(dy > 30){ down(); onEvent(); setStart(e); } else if(dy < -30){ up(); onEvent(); setStart(e); } }) satisfies DragCallback; From c1f8b1e4aa178959f76cdb442fd03d41e5e011cc Mon Sep 17 00:00:00 2001 From: Rob Pilling Date: Mon, 8 May 2023 22:06:01 +0100 Subject: [PATCH 61/78] widhid: guard against errors restoring handlers --- apps/widhid/wid.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/apps/widhid/wid.ts b/apps/widhid/wid.ts index fa81021e1..ed6c7b02e 100644 --- a/apps/widhid/wid.ts +++ b/apps/widhid/wid.ts @@ -179,7 +179,11 @@ if(handlers) for(const handler of handlers) - Bangle.on(event as any, handler); + try{ + Bangle.on(event as any, handler); + }catch(e){ + console.log(`couldn't restore "${event}" handler:`, e); + } } }; })() From c62056a0cf9c3c11dca9b2281c4818cdb2335d81 Mon Sep 17 00:00:00 2001 From: Rob Pilling Date: Mon, 8 May 2023 22:06:10 +0100 Subject: [PATCH 62/78] widhid: regenerate JS --- apps/widhid/wid.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/apps/widhid/wid.js b/apps/widhid/wid.js index 1e2097686..13ccddd5f 100644 --- a/apps/widhid/wid.js +++ b/apps/widhid/wid.js @@ -157,7 +157,12 @@ if (handlers) for (var _i = 0, handlers_1 = handlers; _i < handlers_1.length; _i++) { var handler = handlers_1[_i]; - Bangle.on(event, handler); + try { + Bangle.on(event, handler); + } + catch (e) { + console.log("couldn't restore \"".concat(event, "\" handler:"), e); + } } } }; From e1c99b167740d8d0015b78f08a3830a3c2fe2dfd Mon Sep 17 00:00:00 2001 From: Rob Pilling Date: Mon, 8 May 2023 22:18:05 +0100 Subject: [PATCH 63/78] widhid: add README --- apps/widhid/README.md | 21 +++++++++++++++++++++ apps/widhid/metadata.json | 1 + 2 files changed, 22 insertions(+) create mode 100644 apps/widhid/README.md diff --git a/apps/widhid/README.md b/apps/widhid/README.md new file mode 100644 index 000000000..7651d74eb --- /dev/null +++ b/apps/widhid/README.md @@ -0,0 +1,21 @@ +# Description + +A music control widget based on [Swipe Bluetooth Music Controls] (based on [Bluetooth Music Controls]). +By operating as a widget, you can control music without leaving your current app (e.g. on a run, bike ride or just watching the clock). + + +[Swipe Bluetooth Music Controls]: https://github.com/espruino/BangleApps/tree/master/apps/hidmsicswipe +[Bluetooth Music Controls]: https://github.com/espruino/BangleApps/tree/master/apps/hidmsic + +# Usage + +Swipe down to enable - note the icon changes from blue to orange, indicating it's listening for your instruction. Then drag up/down for volume, left/right for previous and next and tap for play/pause. + +All other watch interaction is disabled for 3 seconds, to prevent clashing taps/drags - this period is extended as you continue to alter the volume, play/pause and jump between tracks. + + +# Setup / Technical details + +Note that HID must be enabled in settings. Then provided you're paired with your phone/computer, the widget icon will appear and you can control music from your clock face! + +The app disables all other drag and tap handlers while this widget is "active" (in a similar manner to [`backswipe`](https://github.com/espruino/BangleApps/pull/2524#issuecomment-1406230564) and [`lightswitch`](https://github.com/espruino/Espruino/issues/2151#issuecomment-1042423211)). diff --git a/apps/widhid/metadata.json b/apps/widhid/metadata.json index 5acafb2e4..4ad6e17d1 100644 --- a/apps/widhid/metadata.json +++ b/apps/widhid/metadata.json @@ -5,6 +5,7 @@ "version": "0.01", "description": "Based on Swipe Bluetooth Music Controls (based on Bluetooth Music Controls). Swipe down to enable, then swipe up/down for volume, left/right for previous and next and tap for play/pause. Enable HID in settings, pair with your phone/computer, then use this widget to control music from your watch!", "icon": "icon.png", + "readme": "README.md", "tags": "widget,bluetooth", "supports": ["BANGLEJS2"], "storage": [ From cd2ea095092cbed5dbde48df53a192d4df246d06 Mon Sep 17 00:00:00 2001 From: Rob Pilling Date: Mon, 8 May 2023 22:29:45 +0100 Subject: [PATCH 64/78] widhid: resize app image --- apps/widhid/icon.js | 2 +- apps/widhid/icon.png | Bin 959 -> 2189 bytes 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/widhid/icon.js b/apps/widhid/icon.js index 9bd94bacf..a8f9cbdb4 100644 --- a/apps/widhid/icon.js +++ b/apps/widhid/icon.js @@ -1 +1 @@ -require("heatshrink").decompress(atob("mUywkBiIA/AFEQOIRuTRgwvSFoQ0DGCBFEDIRNGA44RBB4wIGEIQgNA4IJFCwMQCIpaHBwIyFDA5JHBwYYNFAQ6HDAhjHU4YJFFQ4nGF4YYNbxBeEDFRHDDCxjPeI6WDDBauHCAQIGDAxRPfKAYpMZKdIFIyVHZ5JCODBJCOMRwYSJLIYUUgIBBJN0BGCxJXGARJWAAJJWC6owCJCowwPP6RiC6oYBC6wA/AEQA=")) +require("heatshrink").decompress(atob("mEwwkBiIA/AEhtDNSSHGCyIbFGJ0QFAowIA48QE4oGBBAomBHAxXHA4IJED5IXJCAcQIAxGGC4YKEI44HCBAxAGO4wXBB4JYGNRBfHC/6HFB4wXHUA6YIC4oOCGA6YGU4quHJ5LXGdJIXNF65fIC5AQFQorHJXxwXJK5xGJC65GsgJG/Iw4uUfgIuUC4QWTIwIusLq4WBFy50tC1YXBCyoA/ADw=")) diff --git a/apps/widhid/icon.png b/apps/widhid/icon.png index d52c359d4edde2d1ea5be357ee3b8134298fb6ef..2ccc888832bc20e4084359e6dbe74c890747f75f 100644 GIT binary patch literal 2189 zcmY*ac|4SB8-B+yhAbu7JB?9xGe%4rdnC#-m^9_fKDIL(GscpAh)PG2bJRzJs1aGS zq%aBfsZ6P4DO+^NzGussDPMix^ZxGlzMlKNuIqm8=b!fi*5R1AsDdZ}0OGbbR?fVv z%MU1o_dX@Cn#@Zen)9(EKxv24IB%0kz}x!S+XI?B3tjWr`Gf>g>46k7jPL8^ zO$nu&z~THxKi7|Q(gXc|bt2QY$Knl$zlw1T2_*13^ZiXx#^0I$ zSKIDmjN~`}pTqo^^m~;zs;Q_k^5?agipskW2?GGc#Ma6J7a;U5D=@|Nq} zLaSO27+lm7Fkt2ql{KrH%k$I~Q)Kdmo&-o5Xs%&B;1efo18i-g*;rB0Ds`Gl-}B=x zPlzZ|u-3f+%5;P~*KQ@+U;3p{?AMR94jPLWUF#kC2BE=I)fsb#?yhhhY990z8;I7I z&^E*FJDfHWC*_Qrv!YzjVW%ZNdNwVRwZ_ri06=w>~-j9B-BE2x!0C0EQ~S+1Z$q>q9)h@q5fn3xx?la*p^SQwl9?d3->e>99F;NE zccK2%T*b6Xu0&!|E(yjybJibG;G|aDn&lf6ub(iBjl4DHf@Ws9l{rnAiE9nvWX;mh@NO2EIZHynRMw-cFE1l|MY3Dvh)14-d7E}AXB>c&L^++IWEd-DEi0)X&CR zcS{bEn&Ka~H6G|&%#a+B#}Y#C-I|<%&B|1oQ7X3BL|oILfl)-8l-pqiL&F9dW8y!s z?6cq(o5oq~gI_ctg){pGb$k^G72f1xwy{7J=-i;HKjOVw-}{1K_7_r~%3Q@K3T&j2 zK`q;FxvnE^vG%xr*TxllW|guu%KCx*ji%JJ^z~@e3t|5j;F0S|I{w;4|NE%K{N!-2 z<$0<3F4hg=Dv*D(_~3!naV^E6kg;p|$~nmM5j(}Bt^3`S1-Q|uT212GgNt0*&t2zY z^dkD|wR*fSok`swj4Z86cO)osZ2u*CxnplxtyaRT;rImwBZveOJG~qIM(%^ph`4Wp z^@vy0j;<#{x${%9#ldQfi3dqXXwL!^v&ELy9Lg>gq`TY-Ljh){3`}J}X{eO8QN~A$ zrbjvW_=)m~6{*Fe4TLfnc|gm-(; zFZVf)i5GU?|9OTP)v7)n**ckaC(tM-y?)jc0T!lvRb~q9URwXOplv7;V@Kkm-%7lU zaVlKkLW6dlRN}C4?-W}q`;NEXl`dT4epDc?lYN%07n(Qg1(dF=f86j3fb3~JS_J22 zy*rfhw1?62Zh!g4Z6WDm+%?Vl)WN4xX{>LoJYg{~bLC4aa%HPtXROvz{)%CWkSFK8 zIday=w@1qTx>NV<@{|ST%TnD+p#3hc9HUfax0S_Lnh&6lz)ms4P)KV@5|`0$0dv z$^kZ+t)Lh7gzDV3@1 l@|W176U5BQp6QU9SWqI_9^JhKf6f0V+a7hWDm~(v@DK1JrvLx| delta 952 zcmV;p14sOg5x)l^iBL{Q4GJ0x0000DNk~Le0000o0000o2nGNE03JVxv5~$Pe*ep$A77nmMyf=3Oy7A1rd>91%WBmZF`6cq7)*f3^F3JMXCoMq6a~% zrywh;r+O&pp@^bIDlLmZB9&I!Y0nl)je-9MgIu}ar}tj(!2Q98&T(eGbG|v}%$X6A zBuNrY`U9(hlRz!-31|mC0?m>ge+SkBlSohl%7GtJ-0xEdtOC+V0Hy*jq*xnp2`C1p z0V8GPWMBhuuM>kF0a-n1#2nzOl&JxxN9dmdYy(;~=AvBA{QetQ5%B$s#BB99N_fn&GGbgx6vII6!p+)8nzRyrjIe92YD>07GE;xWyhMo>)p~h}B|9To zVLVEdXwj&b8y7=LwP=SnX*lL3O0*7S=EWa?RLRy#cGJiBP&7)EXi%<~AG2ijk`?)! zBh=jzrMvXDj>q21f9I?HHbAoIan@L6Op12+hgKGHf)wC^l-?@YW@}?~W;F_=^c!WH ziPkmJG8`cjcqOGbDpqc(eF}%Dl+q0{;*eFco08rMa+K#=b$BY05x;<$IKnV}^>(ew zQk_9eJ0C|#1ujeJ`>I-hsckMQoT0+H11r_Z(XUGKB1bua`=xD?V-BUTiXdP;7 z1I(#!B@U5i6@lJS)2za993dUp-yt(S4s+|6@YGlam^-a?s%D+zx>ledQT|7sBuNsw a#eW4wQ*FXm4$}Jo0000 Date: Mon, 8 May 2023 22:31:13 +0100 Subject: [PATCH 65/78] widhid: fix type, add music tag --- apps/widhid/metadata.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/widhid/metadata.json b/apps/widhid/metadata.json index 4ad6e17d1..10e75fadc 100644 --- a/apps/widhid/metadata.json +++ b/apps/widhid/metadata.json @@ -6,7 +6,8 @@ "description": "Based on Swipe Bluetooth Music Controls (based on Bluetooth Music Controls). Swipe down to enable, then swipe up/down for volume, left/right for previous and next and tap for play/pause. Enable HID in settings, pair with your phone/computer, then use this widget to control music from your watch!", "icon": "icon.png", "readme": "README.md", - "tags": "widget,bluetooth", + "type": "widget", + "tags": "widget,bluetooth,music", "supports": ["BANGLEJS2"], "storage": [ {"name":"widhid.wid.js","url":"wid.js"}, From 6cca01db0b78ff4e56c6143bf9adf581f0fb01ef Mon Sep 17 00:00:00 2001 From: Rob Pilling Date: Tue, 9 May 2023 07:38:56 +0100 Subject: [PATCH 66/78] widhid: only register swipe/activation handler when connected --- apps/widhid/wid.js | 11 ++++++++--- apps/widhid/wid.ts | 14 ++++++++++---- 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/apps/widhid/wid.js b/apps/widhid/wid.js index 13ccddd5f..68da78906 100644 --- a/apps/widhid/wid.js +++ b/apps/widhid/wid.js @@ -9,7 +9,7 @@ var dragging = false; var activeTimeout; var waitForRelease = true; - Bangle.on("swipe", function (_lr, ud) { + var onSwipe = (function (_lr, ud) { if (Bangle.CLKINFO_FOCUS) return; if (!activeTimeout && ud > 0) { @@ -95,6 +95,8 @@ redraw(); }, 3000); }; + var redraw = function () { return setTimeout(Bangle.drawWidgets, 50); }; + var connected = NRF.getSecurityStatus().connected; WIDGETS["hid"] = { area: "tr", sortorder: -20, @@ -105,15 +107,18 @@ ? require("heatshrink").decompress(atob("jEYxH+AEfH44XXAAYXXDKIXZDYp3pC/6KHUMwWHC/4XvUy4YGdqoA/AFoA==")) : require("heatshrink").decompress(atob("jEYxH+AEcdjoXXAAYXXDKIXZDYp3pC/6KHUMwWHC/4XvUy4YGdqoA/AFoA==")), this.x + 2, this.y + 2); }, - width: NRF.getSecurityStatus().connected ? 24 : 0, + width: connected ? 24 : 0, }; - var redraw = function () { return setTimeout(Bangle.drawWidgets, 50); }; + if (connected) + Bangle.on("swipe", onSwipe); NRF.on("connect", function () { WIDGETS["hid"].width = 24; + Bangle.on("swipe", onSwipe); redraw(); }); NRF.on("disconnect", function () { WIDGETS["hid"].width = 0; + Bangle.removeListener("swipe", onSwipe); redraw(); }); var sendHid = function (code) { diff --git a/apps/widhid/wid.ts b/apps/widhid/wid.ts index ed6c7b02e..3235f48b5 100644 --- a/apps/widhid/wid.ts +++ b/apps/widhid/wid.ts @@ -11,14 +11,14 @@ let activeTimeout: number | undefined; let waitForRelease = true; - Bangle.on("swipe", (_lr, ud) => { + const onSwipe = ((_lr, ud) => { if((Bangle as BangleExt).CLKINFO_FOCUS) return; if(!activeTimeout && ud! > 0){ listen(); Bangle.buzz(20); } - }); + }) satisfies SwipeCallback; const onDrag = (e => { if((Bangle as BangleExt).CLKINFO_FOCUS) return; @@ -96,6 +96,9 @@ }, 3000); }; + const redraw = () => setTimeout(Bangle.drawWidgets, 50); + + const connected = NRF.getSecurityStatus().connected; WIDGETS["hid"] = { area: "tr", sortorder: -20, @@ -109,17 +112,20 @@ this.y! + 2 ); }, - width: NRF.getSecurityStatus().connected ? 24 : 0, + width: connected ? 24 : 0, }; - const redraw = () => setTimeout(Bangle.drawWidgets, 50); + if(connected) + Bangle.on("swipe", onSwipe); NRF.on("connect", () => { WIDGETS["hid"]!.width = 24; + Bangle.on("swipe", onSwipe); redraw(); }); NRF.on("disconnect", () => { WIDGETS["hid"]!.width = 0; + Bangle.removeListener("swipe", onSwipe); redraw(); }); From 1ce38450c9d6973852147bc46846d452b8195064 Mon Sep 17 00:00:00 2001 From: stweedo <108593831+stweedo@users.noreply.github.com> Date: Tue, 9 May 2023 04:47:32 -0500 Subject: [PATCH 67/78] update interface.html Removed `document.write` usage Added better font handling Added confirmation message --- apps/shadowclk/interface.html | 100 ++++++++++++++++++++++++++++------ 1 file changed, 83 insertions(+), 17 deletions(-) diff --git a/apps/shadowclk/interface.html b/apps/shadowclk/interface.html index 7c4692aed..036e7d624 100644 --- a/apps/shadowclk/interface.html +++ b/apps/shadowclk/interface.html @@ -78,31 +78,34 @@ #upload { margin-top: 20px; } + + #message { + text-align: center; + } - +

3-Bit Color Picker

-
- -
+
- +
From 51a5defac9f4520e6c21d40b7380a36204966661 Mon Sep 17 00:00:00 2001 From: stweedo <108593831+stweedo@users.noreply.github.com> Date: Tue, 9 May 2023 05:23:55 -0500 Subject: [PATCH 68/78] Add files via upload Meant to use this one instead --- apps/shadowclk/interface.html | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/apps/shadowclk/interface.html b/apps/shadowclk/interface.html index 036e7d624..b914e0163 100644 --- a/apps/shadowclk/interface.html +++ b/apps/shadowclk/interface.html @@ -281,7 +281,21 @@ // Update UI with loaded settings let previewBox = document.getElementById("preview-box"); previewBox.style.backgroundColor = isDarkBg ? "black" : "white"; - drawText(selectedColor); + + (function () { + // Load fonts before drawing for the first time + function loadFont(font) { + return document.fonts.load(font); + } + + Promise.all([ + loadFont('81px Londrina Solid'), + loadFont('81px Londrina Shadow'), + loadFont('19px DotGothic16') + ]).then(() => { + drawText(selectedColor); + }); + })(); // Start updating the time every second after loading the settings updateTime(); @@ -326,7 +340,11 @@ }, 5000); }); - (function() { + // Call loadSettings when the page loads + loadSettings(); + + // Fallback to defaults if we can't load settings + (function () { // Load fonts before drawing for the first time function loadFont(font) { return document.fonts.load(font); @@ -340,9 +358,6 @@ drawText(selectedColor); }); })(); - - // Call loadSettings when the page loads - loadSettings(); From f186d36b405c0110bcb7be3a8d51ff581eaac8a8 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Tue, 9 May 2023 13:05:08 +0100 Subject: [PATCH 69/78] Added patriot clock - show your country's flag! --- apps/patriotclk/ChangeLog | 1 + apps/patriotclk/app-icon.js | 1 + apps/patriotclk/app-preview-btm.png | Bin 0 -> 15791 bytes apps/patriotclk/app-preview.png | Bin 0 -> 10479 bytes apps/patriotclk/app.js | 71 ++++++++++ apps/patriotclk/app.png | Bin 0 -> 446 bytes apps/patriotclk/custom.html | 133 ++++++++++++++++++ apps/patriotclk/img/README.md | 9 ++ apps/patriotclk/img/icons8-australia-480.png | Bin 0 -> 13007 bytes apps/patriotclk/img/icons8-belgium-480.png | Bin 0 -> 4507 bytes apps/patriotclk/img/icons8-england-480.png | Bin 0 -> 5152 bytes .../img/icons8-flag-of-europe-480.png | Bin 0 -> 12117 bytes apps/patriotclk/img/icons8-france-480.png | Bin 0 -> 5094 bytes apps/patriotclk/img/icons8-germany-480.png | Bin 0 -> 4180 bytes .../img/icons8-great-britain-480.png | Bin 0 -> 9670 bytes apps/patriotclk/img/icons8-greece-480.png | Bin 0 -> 5003 bytes apps/patriotclk/img/icons8-hungary-480.png | Bin 0 -> 4194 bytes apps/patriotclk/img/icons8-italy-480.png | Bin 0 -> 5095 bytes apps/patriotclk/img/icons8-lgbt-flag-480.png | Bin 0 -> 4227 bytes apps/patriotclk/img/icons8-scotland-480.png | Bin 0 -> 8674 bytes .../patriotclk/img/icons8-switzerland-480.png | Bin 0 -> 4598 bytes apps/patriotclk/img/icons8-ukraine-480.png | Bin 0 -> 4180 bytes apps/patriotclk/img/icons8-usa-480.png | Bin 0 -> 8005 bytes apps/patriotclk/img/icons8-wales-480.png | Bin 0 -> 50546 bytes apps/patriotclk/metadata.json | 18 +++ apps/patriotclk/screenshot.png | Bin 0 -> 3283 bytes 26 files changed, 233 insertions(+) create mode 100644 apps/patriotclk/ChangeLog create mode 100644 apps/patriotclk/app-icon.js create mode 100644 apps/patriotclk/app-preview-btm.png create mode 100644 apps/patriotclk/app-preview.png create mode 100644 apps/patriotclk/app.js create mode 100644 apps/patriotclk/app.png create mode 100644 apps/patriotclk/custom.html create mode 100644 apps/patriotclk/img/README.md create mode 100644 apps/patriotclk/img/icons8-australia-480.png create mode 100644 apps/patriotclk/img/icons8-belgium-480.png create mode 100644 apps/patriotclk/img/icons8-england-480.png create mode 100644 apps/patriotclk/img/icons8-flag-of-europe-480.png create mode 100644 apps/patriotclk/img/icons8-france-480.png create mode 100644 apps/patriotclk/img/icons8-germany-480.png create mode 100644 apps/patriotclk/img/icons8-great-britain-480.png create mode 100644 apps/patriotclk/img/icons8-greece-480.png create mode 100644 apps/patriotclk/img/icons8-hungary-480.png create mode 100644 apps/patriotclk/img/icons8-italy-480.png create mode 100644 apps/patriotclk/img/icons8-lgbt-flag-480.png create mode 100644 apps/patriotclk/img/icons8-scotland-480.png create mode 100644 apps/patriotclk/img/icons8-switzerland-480.png create mode 100644 apps/patriotclk/img/icons8-ukraine-480.png create mode 100644 apps/patriotclk/img/icons8-usa-480.png create mode 100644 apps/patriotclk/img/icons8-wales-480.png create mode 100644 apps/patriotclk/metadata.json create mode 100644 apps/patriotclk/screenshot.png diff --git a/apps/patriotclk/ChangeLog b/apps/patriotclk/ChangeLog new file mode 100644 index 000000000..5560f00bc --- /dev/null +++ b/apps/patriotclk/ChangeLog @@ -0,0 +1 @@ +0.01: New App! diff --git a/apps/patriotclk/app-icon.js b/apps/patriotclk/app-icon.js new file mode 100644 index 000000000..49232b838 --- /dev/null +++ b/apps/patriotclk/app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwwJC/AH4A/AH4AgA==")) diff --git a/apps/patriotclk/app-preview-btm.png b/apps/patriotclk/app-preview-btm.png new file mode 100644 index 0000000000000000000000000000000000000000..98008996b88505c290d432d7a3cd110d83eb9a8c GIT binary patch literal 15791 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

`zQN`_`4S`CWHAO+&{o?+&757%Ve+NwFTv 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 + + + + + +

Please choose your country's flag:

+
+

Is your flag not here? Please add it here!

+
Preview:
+
+ + +
+ + +

Click

+ + + + + + + + + + + \ No newline at end of file diff --git a/apps/patriotclk/img/README.md b/apps/patriotclk/img/README.md new file mode 100644 index 000000000..53c26165c --- /dev/null +++ b/apps/patriotclk/img/README.md @@ -0,0 +1,9 @@ +Flags +------ + +These flags come from https://icons8.com/icon/set/flags/color and are 480x480px + +If you want to add your own flag ensure it's in the same style and then also list the image file in custom.html in the root directory. + +If your flag is listed in https://icons8.com/icon/set/flags/color and you can't download it in the right size, please file an issue and we'll download it with our account. + diff --git a/apps/patriotclk/img/icons8-australia-480.png b/apps/patriotclk/img/icons8-australia-480.png new file mode 100644 index 0000000000000000000000000000000000000000..edf34cdeed1354549b122bc64f7f53f4a5839855 GIT binary patch literal 13007 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 OJrw2CWQ!h~1pE(>EvG{O literal 0 HcmV?d00001 diff --git a/apps/patriotclk/img/icons8-belgium-480.png b/apps/patriotclk/img/icons8-belgium-480.png new file mode 100644 index 0000000000000000000000000000000000000000..395fef8d1add699536821e925e1c0a04731301d6 GIT binary patch literal 4507 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 KyX2;I=>Gu;0$B|J literal 0 HcmV?d00001 diff --git a/apps/patriotclk/img/icons8-france-480.png b/apps/patriotclk/img/icons8-france-480.png new file mode 100644 index 0000000000000000000000000000000000000000..e3cb56348adf42ca1a0ecfe67a157d3d2309fcb5 GIT binary patch literal 5094 zcmeAS@N?(olHy`uVBq!ia0y~yV0-|=9Be?5+AI5}0x8Y{kH}&M25w;xW@MN(M}mPt zc!sBoV@SoEx7RPOjd2%nc2rZdU}ImshDD+;L9}U!{6yRJTnS9QM{PHA0!HdnBdQ=psh31jcvmM_G2rt`?tO3ev075H82?mVejNE4-Wh8dxJ5 zekU3-<{f`^G<7b}oebO$rm{PXT0I)zqseSEbBz`$qXp?`^)Xs$jy4rW8%U$gLR{_e z+iRs$z-{O6hm(L!`K#Th!Od>51KRuz-`MXKy<&qj+y8Eu!LU8~>mx|BoAtvf<^_Kp zx6j!H=^_-^>!=-g8?ko>xW%8qxaSi?M*Rid<#`jp&GtL|-JAv1VfuRD7Jmf8dK-pY z@+GHNj#@p)0{rd1f0IBRsnNs$?6{6*0Z@N^G~)vYDTaM<_jVuCP#D2tV3?r)OnrI1 Vdc^y}2R}hB_H^}gS?83{1OTkMxxoMc literal 0 HcmV?d00001 diff --git a/apps/patriotclk/img/icons8-germany-480.png b/apps/patriotclk/img/icons8-germany-480.png new file mode 100644 index 0000000000000000000000000000000000000000..0f86aa568896fee8c1b15a252db2f4e5604f2588 GIT binary patch literal 4180 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 literal 0 HcmV?d00001 diff --git a/apps/patriotclk/img/icons8-greece-480.png b/apps/patriotclk/img/icons8-greece-480.png new file mode 100644 index 0000000000000000000000000000000000000000..319cf93cb883e6e99ed3f8275342fcd379b13327 GIT binary patch literal 5003 zcmeHLYfO_@82;MNUS`u40KDDSOvLgr59kU zMiJe-B&LG`A?W4>CUX;{d_V*y4yxin1zH6Jq(CdTa%*=E!h|gSu`DJ!Y4W8xJ#W7E zoacR>=e(x}LxKXRidPPOFw8 zhyy>+&u4qGs_&l9PXiw>sd+G5pE!iil^hT`?zS&F<{IU|;&RemyF={)IU@CX&(wss zLhLKgHL6`JH+5|Fd$XvfJmT6F-L;4Yw3m9$T2nUJa~2PBy#yb5%@?huWrtZJZ~P6IcT07NRj1&x`4)0r&TbK>FaL3xdUw*^lAt2PzqJ zAx-bJ38`T($^50xGCX{~K+21ij$PM1tPl(vcugMJ`{Nt08gH>5N<2VmmVrH9)QpUp zzq@gcHQB+CUCEM}_)pn&3b4yrKk0LNgKo;gGg%#D0jymBX-{k{jq??ls@iD~ZbI+; zfT{#rZdc>#1>34=D>(}RuNV$|(~VD?2HiCtu@SPtcC*`fMW)qJSJj@yo-$PRc9oC! z4p(JMg@8TG-}>W7KmfXs&_R7?=0lSCk)_J);xg(r)lzCIa{>}O3}u;SfT~00sFGl? z$@ORUArLC7b8ccI1OtUTWoKTohW=rR&koWm=nmxvfXe48x!|y%GVWj7A8-0L+W59 z_a2OHE0J0)1;7v0irx!JpkVBdMzahX(_!E+;uQ9aNq1TsWe9Mcucw(5Ml)U|FN}bu zUNR(Zw3WxjOHziNE&{pBi5E)Sd=f@423sT_s2VI&ox@`c>!JEp*-{tiAOYDayZg#A zV9VPSKAc^ifX!vD@CcIw-mrxB$z&KJ z(oZ`}>TLU*DEHU9!4S1#JrgLEvJUo6;0^b2ug@l_7cC^2xoy~lYX#l-$CUCEyjwu@ z&nq6s{^OFe3>F#y-H9B+e4nBm4cdf!#!h%9fVq?C8a(}JDOERtT}2$7c^~M-$X<)4 zODWzA%yFL&bO=x=_kku&w=@Z);;%xD)?pc!g ze0z>bB<)GotFuag7fH!L-Hen}f6m3f*(UxxTln|cD)MDpMSi7|@J&d$wIXjW{J-|M zM$FJ$Up#$XpDoo3MWX+Y9RAZzPAAK8FTtNjV2NigO|p-jxZeMyxb`SqaiD*Y--S)W G)V~0vSn^B& literal 0 HcmV?d00001 diff --git a/apps/patriotclk/img/icons8-hungary-480.png b/apps/patriotclk/img/icons8-hungary-480.png new file mode 100644 index 0000000000000000000000000000000000000000..ab838afeaec618ba2693724f4943701ec6c4365c GIT binary patch literal 4194 zcmeAS@N?(olHy`uVBq!ia0y~yV0-|=9Be?5+AI5}0x8Y{kH}&M25w;xW@MN(M}mPt zK*ZCjW54sg55iYKM|GP9*LxTz!~Z@?nQ1a4RH zG2guR#Q|Ex9cSlhYzMci794iiW^OxSGq@#o;3K2+14VGV>V?6m@d=}W18R|vrW{~S v8O>I}ikhfGVUGWw2Gx<;-Bs~?`AWWF%df5W^O)^`g9Z$qu6{1-oD!M<#-3<* literal 0 HcmV?d00001 diff --git a/apps/patriotclk/img/icons8-italy-480.png b/apps/patriotclk/img/icons8-italy-480.png new file mode 100644 index 0000000000000000000000000000000000000000..f917cd85abdcbb7de4017fa2bbe5cd0d3f1c51c6 GIT binary patch literal 5095 zcmeAS@N?(olHy`uVBq!ia0y~yV0-|=9Be?5+AI5}0x8Y{kH}&M25w;xW@MN(M}mPt zc&4X|V@SoEx7QD@jR_ZUc5GYP`?)a8E1=;ahnu3ut&TUpS2L(xkl0hK&ImMO2!MwD zukOFUZ}*IC|8MCZAMgKv#sQNY~VTXNy$d_vp9!e#Va<88ZK|9XZbY-Gg#%1~1RvCK_%z%$G+_LuaN-N^CchI$ z?${?7?)@|)qyB>K^1KP9Ogaac?(lbW7FdVr>%C@)Xkd+CSZ~8{OTOgvO6ioj4BQ(S zz8_9vy3=>H`!vL^1KRuz-`MXKy#l)E08sni4Ko`09!22jU!Gz$Pb+@l#EG)OVri@ODP!-v2C7RZU8 aj{ade_ReolvMp;ji0|p@=d#Wzp$P!iF3I`; literal 0 HcmV?d00001 diff --git a/apps/patriotclk/img/icons8-lgbt-flag-480.png b/apps/patriotclk/img/icons8-lgbt-flag-480.png new file mode 100644 index 0000000000000000000000000000000000000000..10f869a0a2bc04d6f7c0aee570cd940fe518534f GIT binary patch literal 4227 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 literal 0 HcmV?d00001 diff --git a/apps/patriotclk/img/icons8-switzerland-480.png b/apps/patriotclk/img/icons8-switzerland-480.png new file mode 100644 index 0000000000000000000000000000000000000000..801ba47765d752b206edee5b67e67dd872067755 GIT binary patch literal 4598 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 TiY0XcmmE20`9uDGhfDtj$0=y` literal 0 HcmV?d00001 diff --git a/apps/patriotclk/img/icons8-wales-480.png b/apps/patriotclk/img/icons8-wales-480.png new file mode 100644 index 0000000000000000000000000000000000000000..6c29413422a60f484ff0ff0bc0fe9fa3b4cb7142 GIT binary patch literal 50546 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 Dsox%LgoYbNG(2q07u4Owj8+|&xJnU%uM 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 z zVuUR>?}L*ilSaATu118MYZoHyW-PHvaq4xS;Afngk_7tW2q-n-z^v zJM@5IaD%{=y6&1c{KzMDsr0`S^B3IftG%XJ()`~LTz3?3+I!6%Ic9Fl@KBMX0mO!_9WLPi!0OFju1{FB||Ak6Zfh{5EJ1d7!8n8u1h!H3Gxa;4+M z$r$@8&R&BG?47$xOU;WHE8>uRUFV@bK6Mwr@Pi~}rK`DGCh@Tuj43Y zEr(mO+|Ssa1Iey7bqJzMIzm;bmwOu}xHoKvM#5?kl*X%JGlnMX*IkW}u+7cF7!r(x zMK}kkjN@rx-L9LfSSasDMPf89rJQe+)WOI!XR`hu4#^bavIMoWSD04{jh|rqjvIbG zU+N^<*kTtGWgrKzDD6%khud8b86F4}E6?ze*rjDmS;Kx^0yqt9+Ji`H{S*TIrp=aMRw!|n&dftqiW zB{6rIqIpnLeS{_)dVa+@_jk5g7Whjj6A1;r{e5nF)vqWUZ30b-ezuWgJ{ZC>19FkY zmczL_bX6bwBL8AdBEi`4rdEyN^JaAg?j#KwG*yr_P%Jn6JMwNy$VHT$9^LasQ$OHt z=_T7gndknp4w!R`VkB#P661qu6@q;v-}b7mLpI40rc#b&heH-i(mRHobEar_ zX*g|eT^HPEV5sMh*5L@f9~#+lyGB5$+ZU@~b zqA!htYwii|xry%+e@yr$TO>-3`l2J^a<6$l!zjjG=O9(9_pFlf*#)(=QzN6r3c1Ki zD1MIPedRNB$D(2N&KGJ_4%j?%+~jtrLVJf4;kDTqf)~Op#5Ic6x?+}nMfK8EXWCkF zsuuHY%4%wFfLb9p-xPz}l*bo<$?1>PUNYiBeSMCj#PDdY7D^&VgJ+5-tsktY&%XWe zLn3T5b)Q1?^LdEPQplB0EJl9daIWsf_^vq)Pkxb(7o5}JJxb^YX>-IQ%aY*|>hgC8 zkkyNOnFPLd17Eu>`M(lUaqzQQjO_6qhq%Je0%H;_KUC@$d8>r?5!USd8N&{Eg%yUK zy1aqhdaJVabL^*1c!W3OW+%eEjIklownCXvcrsu1Ul1=0-%-=aENy<a3w#8E*9 zmuGEeChQf0fFUC5!5%is^Fp|TEq<*;q206qwBhovWK`5Z9$RJ_^UrHSMY$lWyyDxG(7Ta|6_(^bhUEiRCZZF%@WxV1Fb8rMhGFSL? z4L+s%&&2D2S^97rmW*|uQkZzTvUGKhz3ZRfw2IK1P*SUYKp_Hqs;sGbGnJkE9S;kY zGDSdsD4Z+ZHWyBZuA{=In!%vPOa-FGs3sQ?ay)xnoqOjI+V!>jgLZ$rX2{Fy#XM)M z@DY#X`ufeyGQvu(s|G)Ykmy#xD5zmI1>n1vW&(1TA^dT#6>t|&Hq4Ns?ejl%XamuocJTw7hQqr;<%gv7EZ(KMQ; zr~MKq$8Ptw@@NR4?QF!uh7+B5ZYqBmq;dtn+ z0w@dL|4!Ek<2-e zp!t@+#_H+r=L==D!T4u4#B%JlJ*m}C`rEMZSm8RsEYhr?6Ad2xK$X6&n|F@IZfDsH zU#+Ds)2M)$H{jZCi}6#loX*}Y6KViq6AKP4uCWjJ-z-UO&9L*B;{B8%)ZSoM?rrgp zoJ&TaA{-Ta(@rYc$BMP?R5;=0mQ5Q_yOCjIS27C!pX7TL*+Ge&aI_Y5WGWeY3%lYtMJg(2<;lX--g9&EbWqg37eStKHwx?KU%DYWB zZoYYDvFjpau0Klx%w@vi2xSVN|7P?_JsJ9Iqj%9?pzPE@Mope}GlD7qM5P^DFU>=w3mqWc}1;b9l?zlg~&B)pw4*v3eOS)%ZfA|&lT00u4oX_y}M3| z-(RA=lY9RPNpd5?!MT|66qN+m{~<@tBFS-nrUFpV;kV?`dWT{WB@ zm6#+et_fPS?Z-a3=Jo8+w|YG(p^yEwa#%#4(Vsm=JBRQw-Ggyo_On^V$BndB*E)%@ zZ-q?5@z3nIvq`V0Rj#jOK9|0XiQ}XQ#YG0uT18G|I>cY6ROF=#Ov_D1*vraYEypN@ zCD)DrNo3gK$22BBMJBPCCruX~jP6BI)UbGMf?5FJ+yw%|l>%v;a8c_=<2b5TCS% z31%KGk{EJ*z;byg`&zyc5_IL`+b96gxwo9428;+zklhh*j1vdLkDypDX}EK*TORRt zKCKaQFUOWV<3#mYobhVlu-~R)6=MyOW=t#Cm*C@k?a*gy_wm@|#ANB~JXx)~&P#1$+M5wm-R|sw z2;$Ea!M6g7^A3)AGrC+&$8wHUt0}Zw_YTsq#pop&*3=qqi3_&*?KR| zkl>1Sv5)>W)nzt1M9p>ao}|Qff+j3qsTr(#E!T}D@X~oI3FkvL8aLp>eS_;`90Un> z$#Y0k?SA_z{@+eiNj6E~uTs@k_H_d@jA?&{V~MIcB11Y|2XpXR3e<9c1$ZM28N!p_ zodg{a;S@Y#C+ZLjDg#y5DoZ;&uI>p+sUSFC7vVSJqi7iW#?rV#4R5<_fMZM5-^evnh>vQ^&bf^6Sp)HjGzbw^MW>tNq@L;|%EFt? zUY#Y`=2nDU&3h+Dv)r6QVcOo0VM9d`2<$*<5oJLG2!E zNp+BY{qBT-XCm`)v*%6AZ+Y_$7Q zY{g;}x}4m1;ot|9;I=*C3|=3MZ@_*sx9b1f5Ou=WXThcd0S~1fyJx-Mb^qn7#eO)R zE(>(uu&bL|_?*Y`q%=moCu5}zQk&*V-k*T9$l&pqe+r&{ce97dR1-X*e8o97Cl}_A zXH3a=(}r{+kE`s=)yXw?YK;=x;PiyTK62qy<4?|zD=~)LF3;0v;_^!?`K+1^V%obr z+w7fj34nD{zdb_wF37pA&F=NDu{tJWc%5FrkmW^Qa~+vdkH9EIeNAnu=ss0T-@upHaB9 z=)Nu$>|eVyDV!m8-Dk{TzB6jXEU0aS+pEq73aB!*3has|JH2+Jnpz>l!K7}T5z zfe`2Jf4`joyG8F2?>8+?Qy;)mijN4;ZgP0lbgC?#P~&+3LaT8Zb)=|Cfv$&V&J&fu zo6B{m2`M&e17{;Qi^sl&YqBx#pxmVWWuiR}{tTnnEYL;e!$e;|)T0N>nD!^h5%0{Y zLUR?-Gq~QgXmqI-wjDO58{vyb#!GD17Qx#Xrzs)a$uwrpu2(d<~v4rCB25*UhO z&KJ~O+w8jldgWF=X@qx7&FsKG2mHA7^1qf`aymIU*%cH4!r8u4Ldcl1*P^ox_r4#M zWW%STeVS$159d}5>+D?|M(7~P?*R8(;~LXfrqbsDFsq3!-m_`0gKsotb1GwTgVd~3 zwaqf=p!hXKR35rTcrRA^eCip)($Mj5<#-^ea9_g-MG zRTc~D{=A%&xaPmOY;*~JQS*D45^e+S7EEmU;1Wl}vc7k*>5+zO*6BCIQf=v)wfatA z>vVH~?HftJ0+PJkX<4m6- z)?yw+S`hrcZ$&M*3GbZWS#_5$k!8$ZTdttw+pOQeXG@l#3D3QShZDGe zPs<>Je-uBC$p7<|{~z2J&Hr=!f94L{8iSn_v9PfGIIV9q=GvY-#C-mLeF#$S+ez8S T%2?3+^HaHx%2Fi~CjS2y`}F`l literal 0 HcmV?d00001 diff --git a/apps/patriotclk/metadata.json b/apps/patriotclk/metadata.json new file mode 100644 index 000000000..7c8752000 --- /dev/null +++ b/apps/patriotclk/metadata.json @@ -0,0 +1,18 @@ +{ "id": "patriotclk", + "name": "Patriotic Clock", + "shortName":"Patriot", + "version":"0.01", + "description": "Show your Patriotism with your Country's flag as a clock face (configurable)", + "icon": "app.png", + "screenshots": [{"url":"screenshot.png"}], + "type": "clock", + "tags": "clock,flag", + "supports" : ["BANGLEJS2"], + "custom": "custom.html", + "storage": [ + {"name":"patriotclk.app.js","url":"app.js"}, + {"name":"patriotclk.bg.img"}, + {"name":"patriotclk.opts"}, + {"name":"patriotclk.img","url":"app-icon.js","evaluate":true} + ] +} diff --git a/apps/patriotclk/screenshot.png b/apps/patriotclk/screenshot.png new file mode 100644 index 0000000000000000000000000000000000000000..1f8b1f5f53b9bd8da1f529b801b394220e6c52c2 GIT binary patch literal 3283 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 Date: Tue, 9 May 2023 13:22:17 +0100 Subject: [PATCH 70/78] more flags --- apps/patriotclk/app-icon.js | 2 +- apps/patriotclk/custom.html | 42 +++++++++++------- apps/patriotclk/img/icons8-austria-480.png | Bin 0 -> 4176 bytes apps/patriotclk/img/icons8-brazil-480.png | Bin 0 -> 9734 bytes apps/patriotclk/img/icons8-canada-480.png | Bin 0 -> 7807 bytes apps/patriotclk/img/icons8-china-480.png | Bin 0 -> 7914 bytes apps/patriotclk/img/icons8-denmark-480.png | Bin 0 -> 5517 bytes .../patriotclk/img/icons8-netherlands-480.png | Bin 0 -> 4193 bytes .../patriotclk/img/icons8-new-zealand-480.png | Bin 0 -> 15877 bytes apps/patriotclk/img/icons8-norway-480.png | Bin 0 -> 4808 bytes apps/patriotclk/img/icons8-spain-480.png | Bin 0 -> 4180 bytes apps/patriotclk/img/icons8-sweden-480.png | Bin 0 -> 5520 bytes 12 files changed, 27 insertions(+), 17 deletions(-) create mode 100644 apps/patriotclk/img/icons8-austria-480.png create mode 100644 apps/patriotclk/img/icons8-brazil-480.png create mode 100644 apps/patriotclk/img/icons8-canada-480.png create mode 100644 apps/patriotclk/img/icons8-china-480.png create mode 100644 apps/patriotclk/img/icons8-denmark-480.png create mode 100644 apps/patriotclk/img/icons8-netherlands-480.png create mode 100644 apps/patriotclk/img/icons8-new-zealand-480.png create mode 100644 apps/patriotclk/img/icons8-norway-480.png create mode 100644 apps/patriotclk/img/icons8-spain-480.png create mode 100644 apps/patriotclk/img/icons8-sweden-480.png diff --git a/apps/patriotclk/app-icon.js b/apps/patriotclk/app-icon.js index 49232b838..1dfde113e 100644 --- a/apps/patriotclk/app-icon.js +++ b/apps/patriotclk/app-icon.js @@ -1 +1 @@ -require("heatshrink").decompress(atob("mEwwJC/AH4A/AH4AgA==")) +require("heatshrink").decompress(atob("mEw4UA///8H55lCsHZHmEKgEVqoLIBQNVqgLGh4KBAANQBAUQBY1VoApBB4QLFDYoL/Bf4L/BbLrBBZAKBgEBBY0KAQIABgoLCCYQLEgEVBQYLGAAoL/Bf4LPAFw")) \ No newline at end of file diff --git a/apps/patriotclk/custom.html b/apps/patriotclk/custom.html index a8d0ba4a6..a6fc36abc 100644 --- a/apps/patriotclk/custom.html +++ b/apps/patriotclk/custom.html @@ -40,22 +40,32 @@

@@ -95,9 +100,12 @@
-
+
+
+
- \ No newline at end of file + From abc57030adc023a66fbc9bcceac592e9acdc6b96 Mon Sep 17 00:00:00 2001 From: Rob Pilling Date: Wed, 10 May 2023 08:05:29 +0100 Subject: [PATCH 72/78] widhid: delete unused variables --- apps/widhid/wid.js | 2 ++ apps/widhid/wid.ts | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/apps/widhid/wid.js b/apps/widhid/wid.js index 68da78906..ed1e78e76 100644 --- a/apps/widhid/wid.js +++ b/apps/widhid/wid.js @@ -4,6 +4,7 @@ console.log("widhid: can't enable, HID setting isn't \"kbmedia\""); return; } + delete settings; var anchor = { x: 0, y: 0 }; var start = { x: 0, y: 0 }; var dragging = false; @@ -111,6 +112,7 @@ }; if (connected) Bangle.on("swipe", onSwipe); + delete connected; NRF.on("connect", function () { WIDGETS["hid"].width = 24; Bangle.on("swipe", onSwipe); diff --git a/apps/widhid/wid.ts b/apps/widhid/wid.ts index 3235f48b5..6b5e38855 100644 --- a/apps/widhid/wid.ts +++ b/apps/widhid/wid.ts @@ -4,6 +4,8 @@ console.log("widhid: can't enable, HID setting isn't \"kbmedia\""); return; } + // @ts-ignore + delete settings; let anchor = {x:0,y:0}; let start = {x:0,y:0}; @@ -117,6 +119,8 @@ if(connected) Bangle.on("swipe", onSwipe); + // @ts-ignore + delete connected; NRF.on("connect", () => { WIDGETS["hid"]!.width = 24; From 9541d3a0764748d247a046e608ea3d448dd8d9c0 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Wed, 10 May 2023 10:28:15 +0100 Subject: [PATCH 73/78] remove beta tag --- apps/health/README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/apps/health/README.md b/apps/health/README.md index 960e5565b..b5f6191cc 100644 --- a/apps/health/README.md +++ b/apps/health/README.md @@ -2,8 +2,6 @@ Logs health data to a file in a defined interval, and provides an app to view it -**BETA - requires firmware 2v11 or later** - ## Usage Once installed, health data is logged automatically. From cccce9318e1191b880ffb0b04332159d0b48819f Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Wed, 10 May 2023 10:29:00 +0100 Subject: [PATCH 74/78] Show the current date as a widget in tha Patriot clock --- apps/patriotclk/ChangeLog | 1 + apps/patriotclk/app.js | 30 ++++++++++++++++++++++++------ apps/patriotclk/metadata.json | 4 ++-- 3 files changed, 27 insertions(+), 8 deletions(-) diff --git a/apps/patriotclk/ChangeLog b/apps/patriotclk/ChangeLog index 5560f00bc..c9f08fcc2 100644 --- a/apps/patriotclk/ChangeLog +++ b/apps/patriotclk/ChangeLog @@ -1 +1,2 @@ 0.01: New App! +0.02: Show the date inside the widget bar \ No newline at end of file diff --git a/apps/patriotclk/app.js b/apps/patriotclk/app.js index 4c3ed2d0f..e618b0106 100644 --- a/apps/patriotclk/app.js +++ b/apps/patriotclk/app.js @@ -14,7 +14,7 @@ Graphics.prototype.setFontAudiowide = function() { let options = require("Storage").readJSON("patriotclk.opts",1)||{}; // timeout used to update every minute - let drawTimeout; + let drawTimeout, widgetTimeout; // draw everything let draw = function() { @@ -55,17 +55,35 @@ Graphics.prototype.setFontAudiowide = function() { }, 60000 - (Date.now() % 60000)); }; - // Clear the screen once, at startup - g.clear(); - // draw immediately at first, queue update - draw(); // Show launcher when middle button pressed Bangle.setUI({mode:"clock", remove:function() { //f ree memory if (drawTimeout) clearTimeout(drawTimeout); + if (widgetTimeout) clearTimeout(widgetTimeout); + require("widget_utils").show(); + var e = WIDGETS["patriot"]; + g.reset().clearRect(e.x,e.y,e.x+63,e.y+23); + delete WIDGETS["patriot"]; delete Graphics.prototype.setFontAudiowide; - require("widget_utils").cleanup(); }}); // Load widgets (make them swipeable) Bangle.loadWidgets(); + WIDGETS["patriot"] = { + area:"tl", + width: 64, // how wide is the widget? You can change this and call Bangle.drawWidgets() to re-layout + draw : function(e) { + g.reset().clearRect(e.x,e.y,e.x+63,e.y+23); + var d = new Date(); + g.setFont("6x8").setFontAlign(-1,0).drawString(require("locale").dow(d,0), e.x+2, e.y+8); + g.setFont("6x8").setFontAlign(-1,0).drawString(require("locale").date(d).trim(), e.x+2, e.y+16); + widgetTimeout = setTimeout(function() { // redraw every hour (it's just easier that working out timezones) + widgetTimeout = undefined; + WIDGETS["patriot"].draw(WIDGETS["patriot"]); + }, 3600000 - (Date.now() % 3600000)); + } + }; require("widget_utils").swipeOn(); + // Clear the screen once, at startup + g.clear(); + // draw immediately at first, queue update + draw(); } \ No newline at end of file diff --git a/apps/patriotclk/metadata.json b/apps/patriotclk/metadata.json index 7c8752000..689f1422d 100644 --- a/apps/patriotclk/metadata.json +++ b/apps/patriotclk/metadata.json @@ -1,8 +1,8 @@ { "id": "patriotclk", "name": "Patriotic Clock", "shortName":"Patriot", - "version":"0.01", - "description": "Show your Patriotism with your Country's flag as a clock face (configurable)", + "version":"0.02", + "description": "Show your Patriotism with your Country's flag as a clock face (configurable). Swipe down to show widgets and date.", "icon": "app.png", "screenshots": [{"url":"screenshot.png"}], "type": "clock", From 6084c2b9ad22d484086feceb1d148df8163bd074 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Wed, 10 May 2023 12:05:30 +0100 Subject: [PATCH 75/78] Fix issue with widget utils - just a single hidden widget would cancel checking others --- modules/widget_utils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/widget_utils.js b/modules/widget_utils.js index 2a6a407be..e83555729 100644 --- a/modules/widget_utils.js +++ b/modules/widget_utils.js @@ -88,7 +88,7 @@ exports.swipeOn = function(autohide) { } for (var w of global.WIDGETS) { - if (w._draw) return; // already hidden + if (w._draw) continue; // already hidden w._draw = w.draw; w.draw = function() { g=og; From 5d08afdba08d1850e10108356bb56d6f8f674e3c Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Wed, 10 May 2023 12:06:54 +0100 Subject: [PATCH 76/78] New widget - allows you to use clock info from your widget bar --- apps/widclkinfo/ChangeLog | 1 + apps/widclkinfo/metadata.json | 13 +++++++++ apps/widclkinfo/screenshot.png | Bin 0 -> 3011 bytes apps/widclkinfo/widget.js | 49 +++++++++++++++++++++++++++++++++ apps/widclkinfo/widget.png | Bin 0 -> 7064 bytes 5 files changed, 63 insertions(+) create mode 100644 apps/widclkinfo/ChangeLog create mode 100644 apps/widclkinfo/metadata.json create mode 100644 apps/widclkinfo/screenshot.png create mode 100644 apps/widclkinfo/widget.js create mode 100644 apps/widclkinfo/widget.png diff --git a/apps/widclkinfo/ChangeLog b/apps/widclkinfo/ChangeLog new file mode 100644 index 000000000..4c21f3ace --- /dev/null +++ b/apps/widclkinfo/ChangeLog @@ -0,0 +1 @@ +0.01: New Widget! diff --git a/apps/widclkinfo/metadata.json b/apps/widclkinfo/metadata.json new file mode 100644 index 000000000..3848563c6 --- /dev/null +++ b/apps/widclkinfo/metadata.json @@ -0,0 +1,13 @@ +{ "id": "widclkinfo", + "name": "Clock Info Widget", + "version":"0.01", + "description": "Use 'Clock Info' in the Widget bar. Tap on the widget to select, then drag up/down/left/right to choose what information is displayed.", + "icon": "widget.png", + "screenshots" : [ { "url":"screenshot.png" }], + "type": "widget", + "tags": "widget,clkinfo", + "supports" : ["BANGLEJS2"], + "storage": [ + {"name":"widclkinfo.wid.js","url":"widget.js"} + ] +} diff --git a/apps/widclkinfo/screenshot.png b/apps/widclkinfo/screenshot.png new file mode 100644 index 0000000000000000000000000000000000000000..d36f6bf05273212e8a54e20a0937ac7e5450c12b GIT binary patch literal 3011 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 literal 0 HcmV?d00001 diff --git a/apps/widclkinfo/widget.js b/apps/widclkinfo/widget.js new file mode 100644 index 000000000..403f289e7 --- /dev/null +++ b/apps/widclkinfo/widget.js @@ -0,0 +1,49 @@ +if (!require("clock_info").loadCount) { // don't load if a clock_info was already loaded + // Load the clock infos + let clockInfoItems = require("clock_info").load(); + // Add the + let clockInfoMenu = require("clock_info").addInteractive(clockInfoItems, { + // Add the dimensions we're rendering to here - these are used to detect taps on the clock info area + x : 0, y: 0, w: 72, h:24, + // You can add other information here you want to be passed into 'options' in 'draw' + // This function draws the info + draw : (itm, info, options) => { + // itm: the item containing name/hasRange/etc + // info: data returned from itm.get() containing text/img/etc + // options: options passed into addInteractive + clockInfoInfo = info; + if (WIDGETS["clkinfo"]) + WIDGETS["clkinfo"].draw(WIDGETS["clkinfo"]); + } + }); + let clockInfoInfo; // when clockInfoMenu.draw is called we set this up + + // The actual widget we're displaying + WIDGETS["clkinfo"] = { + area:"tl", + width: clockInfoMenu.w, + draw:function(e) { + clockInfoMenu.x = e.x; + clockInfoMenu.y = e.y; + var o = clockInfoMenu; + // Clear the background + g.reset(); + // indicate focus - make background reddish + //if (clockInfoMenu.focus) g.setBgColor(g.blendColor(g.theme.bg, "#f00", 0.25)); + if (clockInfoMenu.focus) g.setColor("#f00"); + g.clearRect(o.x, o.y, o.x+o.w-1, o.y+o.h); + if (clockInfoInfo) { + var x = o.x; + if (clockInfoInfo.img) { + g.drawImage(clockInfoInfo.img, x,o.y); // draw the image + x+=24; + } + var availableWidth = o.x+clockInfoMenu.w - (x+2); + g.setFont("6x8:2").setFontAlign(-1,0); + if (g.stringWidth(clockInfoInfo.text) > availableWidth) + g.setFont("6x8"); + g.drawString(clockInfoInfo.text, x+2,o.y+12); // draw the text + } + } + }; +} \ No newline at end of file diff --git a/apps/widclkinfo/widget.png b/apps/widclkinfo/widget.png new file mode 100644 index 0000000000000000000000000000000000000000..16ecea9f8d6a2bd9e205b5061406bd3aa5df4715 GIT binary patch literal 7064 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 literal 0 HcmV?d00001 From 8a65bc9c7b498e4bf9a918dae9e100a57130ba5d Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Wed, 10 May 2023 13:48:09 +0100 Subject: [PATCH 77/78] docs --- apps/cscsensor/metadata.json | 2 +- apps/recorder/README.md | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/apps/cscsensor/metadata.json b/apps/cscsensor/metadata.json index ba250c914..87eb5d12f 100644 --- a/apps/cscsensor/metadata.json +++ b/apps/cscsensor/metadata.json @@ -5,7 +5,7 @@ "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", + "tags": "outdoors,exercise,ble,bluetooth,bike,cycle,bicycle", "supports": ["BANGLEJS", "BANGLEJS2"], "readme": "README.md", "storage": [ diff --git a/apps/recorder/README.md b/apps/recorder/README.md index 34955b986..0dd208af5 100644 --- a/apps/recorder/README.md +++ b/apps/recorder/README.md @@ -15,10 +15,11 @@ You can record * **Time** The current time * **GPS** GPS Latitude, Longitude and Altitude -* **Steps** Steps counted by the step counter * **HR** Heart rate and confidence * **BAT** Battery percentage and voltage -* **Core** CoreTemp body temperature +* **Steps** Steps counted by the step counter +* **Baro** (Bangle.js 2) Using the built-in barometer to record Temperature, Pressure and Altitude +* **Core** CoreTemp body temperature *if* you have a CoreTemp device and the https://banglejs.com/apps/?id=coretemp app installed You can then start/stop recording from the Recorder app itself (and as long as widgets are enabled in the app you're using, you can move to another app and continue recording). From e8036a3780c49fb4f2694ad0cd3eaeef4f2bc917 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Thu, 11 May 2023 13:32:58 +0100 Subject: [PATCH 78/78] changed other timeout bits to interval --- apps/messages/lib.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/messages/lib.js b/apps/messages/lib.js index 95a8d6ad8..7a515a1f8 100644 --- a/apps/messages/lib.js +++ b/apps/messages/lib.js @@ -217,7 +217,7 @@ exports.buzz = function(msgSrc) { if (repeat===undefined) repeat = 4; // repeat may be zero if (repeat) { - exports.buzzTimeout = setInterval(() => require("buzz").pattern(pattern), repeat*1000); + exports.buzzInterval = setInterval(() => require("buzz").pattern(pattern), repeat*1000); let vibrateTimeout = msgSettings.vibrateTimeout; if (vibrateTimeout===undefined) vibrateTimeout = 60; if (vibrateTimeout && !exports.stopTimeout) exports.stopTimeout = setTimeout(exports.stopBuzz, vibrateTimeout*1000); @@ -228,8 +228,8 @@ exports.buzz = function(msgSrc) { * Stop buzzing */ exports.stopBuzz = function() { - if (exports.buzzTimeout) clearTimeout(exports.buzzTimeout); - delete exports.buzzTimeout; + if (exports.buzzInterval) clearInterval(exports.buzzInterval); + delete exports.buzzInterval; if (exports.stopTimeout) clearTimeout(exports.stopTimeout); delete exports.stopTimeout; };
Date HolidayTypeRepeat