diff --git a/apps/activityreminder/ChangeLog b/apps/activityreminder/ChangeLog index da897b899..37820dce6 100644 --- a/apps/activityreminder/ChangeLog +++ b/apps/activityreminder/ChangeLog @@ -4,4 +4,5 @@ 0.04: Obey system quiet mode 0.05: Battery optimisation, add the pause option, bug fixes 0.06: Add a temperature threshold to detect (and not alert) if the BJS isn't worn. Better support for the peoples using the app at night -0.07: Fix bug on the cutting edge firmware \ No newline at end of file +0.07: Fix bug on the cutting edge firmware +0.08: Use default Bangle formatter for booleans diff --git a/apps/activityreminder/metadata.json b/apps/activityreminder/metadata.json index fb9423e7c..75ebf80b2 100644 --- a/apps/activityreminder/metadata.json +++ b/apps/activityreminder/metadata.json @@ -3,7 +3,7 @@ "name": "Activity Reminder", "shortName":"Activity Reminder", "description": "A reminder to take short walks for the ones with a sedentary lifestyle", - "version":"0.07", + "version":"0.08", "icon": "app.png", "type": "app", "tags": "tool,activity", diff --git a/apps/activityreminder/settings.js b/apps/activityreminder/settings.js index ce7cdc913..de490b796 100644 --- a/apps/activityreminder/settings.js +++ b/apps/activityreminder/settings.js @@ -9,7 +9,6 @@ "< Back": () => back(), 'Enable': { value: settings.enabled, - format: v => v ? "Yes" : "No", onchange: v => { settings.enabled = v; activityreminder.writeSettings(settings); @@ -38,9 +37,7 @@ settings.maxInnactivityMin = v; activityreminder.writeSettings(settings); }, - format: x => { - return x + " min"; - } + format: x => x + "m" }, 'Dismiss delay': { value: settings.dismissDelayMin, @@ -49,9 +46,7 @@ settings.dismissDelayMin = v; activityreminder.writeSettings(settings); }, - format: x => { - return x + " min"; - } + format: x => x + "m" }, 'Pause delay': { value: settings.pauseDelayMin, @@ -61,7 +56,7 @@ activityreminder.writeSettings(settings); }, format: x => { - return x + " min"; + return x + "m"; } }, 'Min steps': { diff --git a/apps/advcasio/ChangeLog b/apps/advcasio/ChangeLog new file mode 100644 index 000000000..7de176672 --- /dev/null +++ b/apps/advcasio/ChangeLog @@ -0,0 +1 @@ +0.01: AdvCasio first version diff --git a/apps/advcasio/README.md b/apps/advcasio/README.md new file mode 100644 index 000000000..3ce771497 --- /dev/null +++ b/apps/advcasio/README.md @@ -0,0 +1,62 @@ +# Adv Casio Clock + + + +An over-engineered clock inspired by Casio watches.
+It has a dedicated timer, a scratchpad and can display the weather condition 4 days ahead.
+It uses a custom web app to update its content.
+Forked from the awesome Cassio Watch.
+ +## Todo + +- Improving quality of the background images, right now it is quite blurry. +- Improving screenshots quality. +- Improving web app look. +- Improving bangle app performances (using functions for images and specialized array). + +## Functionalities + +- Current time +- Current day and month +- Footsteps +- Battery +- Simple Timer embedded +- Weather forecast (7 days) +- Scratchpad + +## Screenshots +Clock:
+ + + + +Web interface to update weather & scratchpad
+https://dotgreg.github.io/advCasioBangleClock + + + +## Usage +### How to update the tasks list / weather +- you will need a free openweathermap.org api key. +- go to https://dotgreg.github.io/advCasioBangleClock/ + - Alternatively you can install it on your own server/heroku/service/github pages, the web-app code is here +- fill the location and the api key (it will be saved on your browser, no need to do it each time) +- edit the scratchpad with what you want +- click on sync +- reload your clock! + +### How to start/stop the timer +- swipe up : add time (+5min) +- swipe down : remove time (-5min) +- swipe right : start timer +- swipe left : stop timer + +## Links +### Issues, suggestions and bugtracker +https://github.com/dotgreg/advCasioBangleClock/issues + +### Code repository (bangle app and web app) +https://github.com/dotgreg/advCasioBangleClock + +### Creator +https://github.com/dotgreg diff --git a/apps/advcasio/app-icon.js b/apps/advcasio/app-icon.js new file mode 100644 index 000000000..2471ceac7 --- /dev/null +++ b/apps/advcasio/app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwghC/AH4A/AGsCmUQC6kf/8wC6k///wgEv//zD4PxAQIJBABP//4QBC4IcBh/yEQIXKgP/l4rBl/yGAMP/4iBKJUC/5gBIAQVBBAMR/8gC5IQBAAMQC4IVBFoMjAYIXNmAXBgYXCPgQAJl/xHwPwj/yn5kC/55BUxSlC+JiBVgQ5BUxiDBUIIXBIQQXBcCoA/AH4ADXAUgUAUQBAkPeoTDFgIHBAALQEA4XwC4IOEAAQRBbAQBBCAIgBEYMQC4TnEC4XyeQgBDAAMwC4pIDC4kDAgJLD//xC5QIBNQISCFYIZCC4aEBAQRCDAAPyl4hBOIh3Cn53GNgMRiKxGBAR5BAoYA/AH4A/AH4A5A")) diff --git a/apps/advcasio/app.js b/apps/advcasio/app.js new file mode 100644 index 000000000..8c27b7823 --- /dev/null +++ b/apps/advcasio/app.js @@ -0,0 +1,306 @@ +const storage = require('Storage'); + +require("Font6x12").add(Graphics); +require("Font6x8").add(Graphics); +require("Font8x12").add(Graphics); +require("Font7x11Numeric7Seg").add(Graphics); + +function bigThenSmall(big, small, x, y) { + g.setFont("7x11Numeric7Seg", 2); + g.drawString(big, x, y); + x += g.stringWidth(big); + g.setFont("8x12"); + g.drawString(small, x, y); +} + +function getClockBg() { + return require("heatshrink").decompress(atob("icVgf/ABv8v4DBx4CB+PH8F+nAGB48fwEHBwXjxwqBuPH//+nAGBBwIjCAwI2D/wGBgIyDI4QGDwAGBHYX/4AGBn4UFEYQpCEYYpCAAMfMhP4FIgABwJ8OEBIA==")); +} + + +// sun, cloud, rain, thunder +var iconsWeather = [ + require("heatshrink").decompress(atob("i8Ugf/ACcfA434BA/AAwsAv0/8F/BAcDwEHHIpECFI3wn4GC/gOC+PAGoXggEH/+ODQgXBGQv/wAbBBAnguEACIn4gfxI4JXFwJmG/kPBA3jSynw")), require("heatshrink").decompress(atob("i0Ugf/AEXggIGE/0A/kPBAmBCIN/A4Y8CgAICwEHBYoUE/ACCj4sDn4CBC4YyDwBrDCgYA3A")), require("heatshrink").decompress(atob("h8Rgf/AAuBAgf8h4FDCwM/AgPA/gFC/0HgEBBQPwnEfDoWAg4jC/gOCAoQmBAQXjFIV//8f//4IQP4j/+gAIB4EcHII4CAoI+DLQJXF/AA==")), require("heatshrink").decompress(atob("h0Pgf/AA8fAYX+g4EC8EBAgXADAeAgAECgAOC/wrCDQIOBBYfwgAaC/kAn4EB/EAv4aDHAeBIg38")) +]; + + +function getBackgroundImage() { + return require("heatshrink").decompress(atob("2GwghC/AH4A/AH4AMl////wAwURiQECgUzmcxBQQCBiYUBBARW+LAcCAgcPBYgFBkAIFG7kQiAKIiIKBgISOAAJBD//zKQfxK4vyAoMQCgn/ERBhBBYR5BAwR1DB4Y2DgYPCGIQRCCQcP+EfGJI0FEgRSCGAQCCX4JXCkAhDn4lI+HyK4YWBFIPzJYJXHAIMSK4cwJ4I3CAYMzA4cfcRMBdwytBK4i6FK4IUCMgYAEGIITBK4cCaAPwgJXB+fzK4sAgYtCK5EfA4pXR+AmBaIZYCK6KcCAwSjDEYXx/8vK5QRCK4kPK6cDkJREBIMBfgIrDK5svUAIQBAwIaCK4w+DK4YGBK7IaBboIuCK4gFCJwYBBiBCCCgQhHHYgGDgArBK5IGDAYMgJ4Xwn53BGgLVDmBXKAAinDLpJXCAAYhHR4YODn/wJIPyTYZXDE4RXD+ECNILIDAIPwj4xIAAYNCR4fyVIYLFA4KEBBAglKAGUCmcykEAiMQBIURBYM/BgIUEgcz+bTKAH4A/AH4A/AHP/AGY1d+BWCh5X/LCpW1K74fgG/5X/AH5X/K9Bg/K63wK/5XWgBX/K6pWBK/5XU+BWBh5J/K6auCK/5XTVwRfFAH5XOKwRX/K6auDh5I/K6SuDWP5XSVwYADWX6vXK/5XQWQpW/K6auDJP5XWV35XT+Cu/K7Ku/K65H/K6hW/K7EPI35XWIv5XWAH5X/K/4A/K/5X/K/4A/K9cAAH4A/AFzz/AHRX/K/5X/AH5X/K/5X/AH5X/K/4A/K/5X/K/4A/K/5X/K/4A/K/5X/AH5X/K/5X/AH5X/K/5X/AH5X/K/4A/K/5X/K/4A/K/5X/K/4A/K/5X/AH5X/K/5X/AH5X/K/5X/AH5X/K/4A/K/5X/K/4A/K/5X/K/4A/K/5X/AH5X/K/5X/AH5X/K/5X/AH5X/K/4A/K/5X/K/4A/K/5X/K/4A/K/5X/AH5X/K/5X/AH5X/K/40VAH4A/AFzLb+EPDm4AdK/5X/K+PwgEAHy5X9HgMAK/5XXH6xX/H65X/K/5X/K98AK7sAgBX3DjBWFO644DSTHwGzJXED4RXaDoLqcK7weWDIQcXK8I6YK77KXK4o8DPbY6ZK7qvDDy6vdR7JXDh60EDyw5BAIRXYSwjMbAgIhUDwJZCHwJX0GwjRWNwIAEHSwBCDSpXFH4pXzDS5XIEARXVSYbQEDaYzCK+6vcKaxXNDypX9HwQkbHS40COSpXKK2A6CHgRXcPIhX0SwpXYVuQ6EgBX/K644YODBXkSDJX/K/5X/DtRX6gA3YOkRWbLDZX4KwYA/AG8F5vdABncKH4AGhpRJAYXNAgPAKP4AF5vMJwoDBAQIKE6BR/AAvc5vO9wAB7oCB9veAoPcAoPcK+kwh8AgcA98An//gH/+sD//wCISgBJ4IABAYpaC9vdK4UP/9AAQNQr/zgHwEYNQFYQAh+EP+FegH+A4QBCMQIKBAAPNK4yxBA4RXCV4YZBE4IjChwCDmApCK8VdmHggHgFYf0SQJXE5nMK4anCAoYHC5pXCaQJXBop+BqAGEK7f/AAQeEKwQrBqCtDAILjBCQfNK4JTCAYZXF7qvD//gV4S2DgEFFIYAECgIACMC8PKoIBB8n1K4ivF5vc5xOCWYZbBAYavHU4RXCr4pEAEMDfoNQGoMEgEwYQPwAoIBBAAPM5ipC7oDCVIIAE7hXCD4SdBiEP+gGBgihCFYIAz5pXBAAnN7oIB7nc5gOBK4QA/K4pNCWgSpCBInNK/4AGhncKIStC7gCBA4QAC4BR/AAysCABZW/AHwA=")); +} + + + +// schedule a draw for the next minute +let rocketInterval; +var drawTimeout; +function queueDraw() { + if (drawTimeout) clearTimeout(drawTimeout); + drawTimeout = setTimeout(function() { + drawTimeout = undefined; + draw(); + }, 60000 - (Date.now() % 60000)); +} + + +function clearIntervals() { + if (rocketInterval) clearInterval(rocketInterval); + rocketInterval = undefined; + if (drawTimeout) clearTimeout(drawTimeout); + drawTimeout = undefined; +} + +//////////////////////////////////////////// +// TIMER FUNC +// +var timer_time = 0; +var alreadyListenTouch = false; +function initTouchTimer () { + if (alreadyListenTouch) return; + alreadyListenTouch = true; + + Bangle.on('swipe', function(dirX,dirY) { + if (canTouch === false) return; + var njson = getDataJson(); + if (!njson) return; + + if (dirX === -1) { + timer_time = 0; + delete njson.timer; + setDataJson(njson); + } + else if (dirX === 1) { + var now = new Date().getTime(); + njson.timer = now + (timer_time * 1000 * 60); + Bangle.setLocked(true); + setDataJson(njson); + Bangle.buzz(200, 0); + timer_time = 0; + } + else if (dirY === -1) { + if (canTouch === false || njson.timer) return; + timer_time = timer_time + 5; + } + else if (dirY === 1) { + if (canTouch === false || njson.timer) return; + timer_time = timer_time - 5; + } + draw(); + }); +} +setTimeout(() => { + initTouchTimer (); +}); + +function getTimerTime() { + // if timer_time !== -1, take it + if (timer_time !== 0) { + return timer_time + "m"; + } else { + // else, show diff between njsontime and now + var njson = getDataJson(); + if (!njson) return false; + var now = new Date().getTime(); + var diff = Math.round((njson.timer - now) / (1000 * 60)); + //console.log(123, njson, diff, now, njson.timer - now); + if (diff > 0) return diff + "m"; + else if (njson.timer) { + Bangle.buzz(1000, 1); + console.log("END OF TIMER"); + delete njson.timer; + setDataJson(njson); + return false; + } else { + return false; + } + // if diff is <0, delete timer from json + } +} +function drawTimer() { + //g.drawString(getTimerTime(), 100, 100); + g.setFont("8x12", 2); + var t = 97; + var l = 105; + var time = getTimerTime(); + if (time || timer_time !== 0) g.drawString(time, l+5, t+0); + if (time && timer_time === 0) g.drawImage(getClockBg(), l-20, t+2, { scale: 1 }); +} + + +//////////////////////////////////////////// +// DATA READING +// +function getDataJson(){ + var res = {"tasks":"", "weather":[]}; + try { + res = storage.readJSON('advcasio.data.json'); + } catch(ex) { + return res; + } + return res; +} +function setDataJson(resJson){ + try { + res = storage.writeJSON('advcasio.data.json', resJson); + } catch(ex) { + return res; + } + return res; +} +var dataJson = getDataJson(); + +//////////////////////////////////////////// +// WEATHER! +// +function drawWeather(arr) { + g.setFont("6x8", 1); + var p = {l: 8, tText: 40, tIcon:20, decal:25}; + var today = new Date().getTime(); + var yesterday = today - (1000 * 60 * 60 * 24); + var testday = today + (1000 * 60 * 60 * 24 * 2); + //12h auj > 12h hier qui est sup a 0h auj + //23h59 hier est sup a 0h auj + var j = 0; + for(var i = 0; i yesterday && j < 4) { + g.drawString(arr[i][0], p.l + p.decal*j + 4, p.tText); + g.drawImage(iconsWeather[arr[i][1]], p.l + p.decal*j, p.tIcon, { scale: 1 }); + j++ + } + } +} + + +//////////////////////////////////////////// +// DRAWING FUNCS +// +function drawTasks(str) { + g.setFont("6x8", 1); + var t = 57; + var l = 0; + g.drawString(str, l+5, t+0); +} + +function drawSteps() { + g.setFont("8x12", 2); + var t = 132; + var l = 150; + g.drawString(getSteps(), l+5, t+0); +} + + +function drawClock() { + g.setFont("7x11Numeric7Seg", 3); + g.clearRect(80, 57, 170, 96); + g.setColor(255, 255, 255); + var l = 77; + var t = 57; + var w = 170; + var h = 116; + g.drawRect(l, t, w, h); + g.fillRect(l, t, w, h); + g.setColor(0, 0, 0); + g.drawString(require("locale").time(new Date(), 1), 76, 60); + + // day + //g.setFont("8x12", 1); + //g.setFont("9x18", 1); + //g.drawString(require("locale").dow(new Date(), 2).toUpperCase(), 25, 136); + g.setFont("8x12", 2); + g.drawString(require("locale").dow(new Date(), 2), 18, 130); + + // month + g.setFont("8x12"); + g.drawString(require("locale").month(new Date(), 2).toUpperCase(), 80, 127); + + // day nb + g.setFont("8x12", 2); + const time = new Date().getDate(); + g.drawString(time < 10 ? "0" + time : time, 78, 137); +} + +function drawBattery() { + bigThenSmall(E.getBattery(), "%", 140, 23); +} + + +function getSteps() { + var steps = 0; + try{ + if (WIDGETS.wpedom !== undefined) { + steps = WIDGETS.wpedom.getSteps(); + } else if (WIDGETS.activepedom !== undefined) { + steps = WIDGETS.activepedom.getSteps(); + } else { + steps = Bangle.getHealthStatus("day").steps; + } + } catch(ex) { + // In case we failed, we can only show 0 steps. + return "? k"; + } + + steps = Math.round(steps/1000); + return steps + "k"; +} + + + +function draw() { + + queueDraw(); + + g.reset(); + g.clear(); + g.setColor(255, 255, 255); + g.fillRect(0, 0, g.getWidth(), g.getHeight()); + let background = getBackgroundImage(); + g.drawImage(background, 0, 0, { scale: 1 }); + + + g.setColor(0, 0, 0); + g.setFont("6x12"); + if(dataJson && dataJson.weather) drawWeather(dataJson.weather); + if(dataJson && dataJson.tasks) drawTasks(dataJson.tasks); + + + g.setFontAlign(0,-1); + g.setFont("8x12", 2); + + drawSteps(); + g.setFontAlign(-1,-1); + drawClock(); + drawBattery(); + drawTimer(); + // Hide widgets + for (let wd of WIDGETS) {wd.draw=()=>{};wd.area="";} +} + +// save batt power, does not seem to work although... +var canTouch = true; +Bangle.on("lcdPower", (on) => { + if (on) { + draw(); + } else { + canTouch = false; + clearIntervals(); + } +}); + + +Bangle.on("lock", (locked) => { + clearIntervals(); + draw(); + if (!locked) { + canTouch = true; + } else { + canTouch = false; + } +}); + + +// Load widgets, but don't show them +Bangle.loadWidgets(); +Bangle.setUI("clock"); + +g.reset(); +g.clear(); +draw(); diff --git a/apps/advcasio/app.png b/apps/advcasio/app.png new file mode 100644 index 000000000..a7c1b2736 Binary files /dev/null and b/apps/advcasio/app.png differ diff --git a/apps/advcasio/data.json b/apps/advcasio/data.json new file mode 100644 index 000000000..d986fa09c --- /dev/null +++ b/apps/advcasio/data.json @@ -0,0 +1 @@ +{"tasks":"", "weather":[]}; diff --git a/apps/advcasio/metadata.json b/apps/advcasio/metadata.json new file mode 100644 index 000000000..0f0c75c07 --- /dev/null +++ b/apps/advcasio/metadata.json @@ -0,0 +1,25 @@ +{ "id": "advcasio", + "name": "Advanced Casio Clock", + "shortName":"advcasio", + "version":"0.01", + "description": "An over-engineered clock inspired by Casio watches. It has a 4 days weather, a timer using swipe and a scratchpad. Can be updated using a dedicated webapp.", + "icon": "app.png", + "tags": "clock", + "type": "clock", + "screenshots": [ + { "url": "screenshot-clock-1.jpg" }, + { "url": "screenshot-clock-2.jpg" }, + { "url": "screenshot-clock-3.jpg" }, + { "url": "screenshot-webapp.jpg" } + ], + "supports" : ["BANGLEJS", "BANGLEJS2"], + "readme": "README.md", + "allow_emulator":true, + "storage": [ + {"name":"advcasio.app.js","url":"app.js"}, + {"name":"advcasio.img","url":"app-icon.js","evaluate":true} + ], + "data": [ + { "name": "advcasio.data.json", "url": "data.json", "storageFile": true } + ] +} diff --git a/apps/advcasio/screenshot-clock-1.jpg b/apps/advcasio/screenshot-clock-1.jpg new file mode 100644 index 000000000..7f6f042c9 Binary files /dev/null and b/apps/advcasio/screenshot-clock-1.jpg differ diff --git a/apps/advcasio/screenshot-clock-2.jpg b/apps/advcasio/screenshot-clock-2.jpg new file mode 100644 index 000000000..b5f1e38af Binary files /dev/null and b/apps/advcasio/screenshot-clock-2.jpg differ diff --git a/apps/advcasio/screenshot-clock-3.jpg b/apps/advcasio/screenshot-clock-3.jpg new file mode 100644 index 000000000..59389eb31 Binary files /dev/null and b/apps/advcasio/screenshot-clock-3.jpg differ diff --git a/apps/advcasio/screenshot-webapp.jpg b/apps/advcasio/screenshot-webapp.jpg new file mode 100644 index 000000000..d67bdba91 Binary files /dev/null and b/apps/advcasio/screenshot-webapp.jpg differ diff --git a/apps/agenda/ChangeLog b/apps/agenda/ChangeLog index 56dfffa0d..ae650deeb 100644 --- a/apps/agenda/ChangeLog +++ b/apps/agenda/ChangeLog @@ -1 +1,2 @@ 0.01: Basic agenda with events from GB +0.02: Added settings page to force calendar sync diff --git a/apps/agpsdata/ChangeLog b/apps/agpsdata/ChangeLog new file mode 100644 index 000000000..c17eac852 --- /dev/null +++ b/apps/agpsdata/ChangeLog @@ -0,0 +1 @@ +0.01: First, proof of concept diff --git a/apps/agpsdata/README.md b/apps/agpsdata/README.md new file mode 100644 index 000000000..93cc94259 --- /dev/null +++ b/apps/agpsdata/README.md @@ -0,0 +1,18 @@ +# A-GPS Data + +Load assisted GPS data directly to the watch using the new http requests on Android GadgetBridge. + +Make sure: +* your GadgetBridge version supports http requests +* turn on internet access in GadgetBridge settings + +Currently proof of concept on Bangle2 only. Will eventually add a widget for automatic download. + +![](screenshot.png) +![](screenshot2.png) +![](screenshot3.png) +![](screenshot4.png) +![](screenshot5.png) + +## Creator +[@pidajo](https://github.com/pidajo) diff --git a/apps/agpsdata/agpsdata-icon.js b/apps/agpsdata/agpsdata-icon.js new file mode 100644 index 000000000..1677a2177 --- /dev/null +++ b/apps/agpsdata/agpsdata-icon.js @@ -0,0 +1 @@ +atob("MDCEAAAAAAAAAAAAAAAAiIgAAAAAAAAAAAAAAAAAAAAAAAAAAAAIiIiAAAAAAAAAAAAAAAAAAAAAAAAAAAAIiIiAAAAAAAAAAAAAAAAAAAAAAAAAAACIiIiIAAAAAAAAAAAAAAAAAAAAAAAAAACIiIiIAAAAAAAAAAAAAAAAAAAAAAAAAACIiIiIAAAAAAAAAAAAAAAAAAAAAAAAAAiIiIiIgAAAAAAAAAAAAAAAAAAAAAAAAAiIiIiIgAAAAAAAAAAAAAAAAAAAAAAAAIiIOIiIiAAAAAAAAAAAAAAAAAAAAAAAAIiDOIiIiAAAAAAAAAAAAAAAAAAAAAAAAIiDOIiIiIAAAAAAAAAAAAAAAAAAAAAACIiPOIiIiIAAAAAAAAAAAAAAAAAAAAAAiIj/OIiIiIgAAAAAAAAAAAAAAAAAAAAAiI//OIiIiIgAAAAAAAAAAAAAAAAAAAAAiI//OIiIiIiAAAAAAAAAAAAAAAAAAAAAiD//OIiIiIiAAAAAAAAAAAAAAAAAAAAIiP//OIiIiIiAAAAAAAAAAAAAAAAAAAAIg///OIiIiIiIAAAAAAAAAAAAAAAAAACIj///OIiIiIiIAAAAAAAAAAAAAAAAAACIP///OIiIiIiIgAAAAAAAAAAAAAAAAACI////OIiIiIiIgAAAAAAAAAAAAAAAAAiD////OIiIiIiIiAAAAAAAAAAAAAAAAAiP////OIiIiIiIiAAAAAAAAAAAAAAAAIiP////OIiIiIiIiIAAAAAAAAAAAAAAAIj/////OIiIiIiIiIAAAAAAAAAAAAAACIj/////OIiIiIiIiIgAAAAAAAAAAAAACI//////OIiIiIiIiIgAAAAAAAAAAAAAiI//////OIiIiIiIiIgAAAAAAAAAAAAAiIiIiIiIgzMzMzMziIiAAAAAAAAAAAAAiIiIiIiIj///////+IiAAAAAAAAAAAAIiIiIiIiIj////////4iIAAAAAAAAAAAIiIiIiIiIgzMzMzMzM4iIAAAAAAAAAACIP///////OIiIiIiIiIiIgAAAAAAAAACI////////OIiIiIiIiIiIgAAAAAAAAAiI////////OIiIiIiIiIiIiAAAAAAAAAiP////////OIiIiIiIiIiIiAAAAAAAAIiP////////OIiIiIiIiIiIiIAAAAAAAIj/////////OIiIiIiIiIiIiIAAAAAACIj////////ziIiIiIiIiIiIiIgAAAAACIP///////+IiIiIiIiIiIiIiIgAAAAACI//////84gYiIiIiIiIiIiIiIgAAAAAiD////84iIiAAAiIiIiIiIiIiIiAAAAAiP///ziIiIAAAAAIiIiIiIiIiIiAAAAIg/8ziIiIAAAAAAAAAIiIiIiIiIiIAAAIj/iIiIAAAAAAAAAAAAAIiIiIiIiIAACIiIiBgAAAAAAAAAAAAAAACIiIiIiIgACIiIgAAAAAAAAAAAAAAAAAAACIiIiIgACIgAAAAAAAAAAAAAAAAAAAAAAAiIiIgA==") diff --git a/apps/agpsdata/agpsdata.png b/apps/agpsdata/agpsdata.png new file mode 100644 index 000000000..a0f4de4cb Binary files /dev/null and b/apps/agpsdata/agpsdata.png differ diff --git a/apps/agpsdata/app.js b/apps/agpsdata/app.js new file mode 100644 index 000000000..825eda273 --- /dev/null +++ b/apps/agpsdata/app.js @@ -0,0 +1,125 @@ +var _GB = global.GB; +var counter = 0; + +function GB(msg) { + console.log(msg); + if (msg.t == "http") { + display("Received", "(" + msg.resp.length + ") Touch to apply", () => { + display("Apply data..", ""); + setTimeout(() => { + if (setAGPS(msg.resp)) { + display("Success", "Touch for restart", httpTest); + } + else { + display("Error", "Touch for restart", httpTest); + } + }, 1); + }); + } + if (_GB) { + _GB(msg); + } +} + +function setAGPS(data) { + var js = jsFromBase64(data); + console.log(js); + try { + eval(js); + return true; + } + catch(e) { + console.log("Error:", e); + } + return false; +} + +function jsFromBase64(b64) { + var bin = atob(b64); + var chunkSize = 128; + var js = "Bangle.setGPSPower(1);\n"; // turn GPS on + var gnss_select="1"; + js += `Serial1.println("${CASIC_CHECKSUM("$PCAS04,"+gnss_select)}")\n`; // set GNSS mode + // What about: + // NAV-TIMEUTC (0x01 0x10) + // NAV-PV (0x01 0x03) + // or AGPS.zip uses AID-INI (0x0B 0x01) + + for (var i=0;i { + display("Request...", "Touch for restart", httpTest); + if (Bluetooth.println) { + console.log("On device"); + Bluetooth.println(JSON.stringify({t:"info", msg:"HTTP Request"})); + Bluetooth.println(JSON.stringify({t:"http", url:"https://www.espruino.com/agps/casic.base64"})); + } + else { + console.log("Testing on Emulator"); + setTimeout(() => { + GB({t:"http", resp:testData}); + }, 1); + } + }); +} + +var nextStep = null; + +Bangle.on("touch", () => { + if (nextStep) { + nextStep(); + } +}); + +httpTest(); + +// Show launcher when middle button pressed +// Load widgets +Bangle.loadWidgets(); +Bangle.drawWidgets(); + + +/* +require("Storage").write("httptest.info",{ + "id":"httptest", + "name":"Http Test", + "src":"httptest.js", + "icon":"wristlight.img" +}); +*/ + +var testData = "QUdOU1MgZGF0YSBmcm9tIENBU0lDLgpEYXRhTGVuZ3RoOiAyNTk4LgpMaW1pdGF0aW9uOiAzLzEwMDAuCrrOSAAIB7YdxSr+Sg2h8NYlBux1jiUgQbrXgJk/KJvFZVv8pP//uy3i/PH6rv9EMQH6SwBfAOxepgDsXgAAlCULALv/AAtCAAAAAQMAALQ7kly6zkgACAdBzVam9HANoXGycgoqGmnG5X9h3mKrWicvBKhXAp7//+00U/9j/jP/SDHM/Vn/JADrXqYA614AAF6d6v8DAADaEAAAAAIDAADKmrVTus5IAAgHTUirJrjvDKHJDjACcmXJJ+8Lv6rw5LQnl4OChUCt//9XKG3/+u6ZE84ZQuwDAMf/7F6mAOxeAADa0Pb/mP8ABDUAAAADAwAA4pBeVLrOSAAIB5291DTIzAyhJGfzAJ7pCIcIUQMgcfEoJ2TIjrHkqv//YjDTCKj/wRPdGIz/8/9NAOxepgDsXgAAl9/6/yQAAPbhAAAABAMAAIJ7sXC6zkgACAeKKDOgmwEOocKrFwP8Jmgqq4lOQ1VtLSfEi8yDVqn//5MskP6E7WQRPxzv6vv/0//sXqYA7F4AAM4w/f/0/wDoJwAAAAUDAABcUW5Hus5IAAgHu+Va48nxDaFaw0UBkVc73Y3FB+HFmDgoUWIPW+Ck//+iLcf9X/t5/ikzgPrT/wgA7F6mAOxeAAADVgsAiQAACB0AAAAGAwAAvsu9zbrOSAAIB0OVp/7+JQ2hFANPCF+F6KOOMwe9/nC5JsX0CtthqP//WzhzADr/dgqbIRj/nwDj/+xepgDsXgAAP4oKAPv/AOg4AAAABwMAAM4qVwS6zkgACAey9J9b+zwOofLIzwObDg0HLdEmMOA3PydWaUQvr6b//0wxwf/7EJ8K/yLREhkANADsXqYA7F4AALug/f/y/wALLAAAAAgDAACs6Ue+us5IAAgHm7NJLLhaDKEumRQBAFtVTExfuke3AeEmNg9cr2Cq//92MTIJm/63FCkXPv4gABgA616mAOteAACQQfX/HgAAAzUAAAAJAwAAfmebX7rOSAAIB9fgVnnchw2hNlTrAyWnJ5rnBMWFV9GyJzPfZYV8rf//Oyh2AA3xmhLdGtXu/f/Z/+xepgDsXgAA8gXx/37/AAU/AAAACgMAAPbBtfm6zkgACAc+F7Ct97wMoVEVPQCJJG1yeakXMm80PSet+BBd+aH//5AzPf2J+uX97jG7+fj/DgDsXqYA7F4AAGqE//8WAADufQIAAAsDAADELmhius5IAAgHW3g6rwRJDqFpPmYEPf8lNRy9lKO/IX8nJPRjCLOt//90Lir7QQcEGFYUTAguAA4A7F6mAOxeAADrZfj/zP8A5SsAAAAMAwAA/vB8ZbrOSAAIB1mVSsfiXw2hUX8RA60JSyUgLkEgC910JykTq7Usqv//8S9rBw//HhIpGyT/+v8fAOxepgDsXgAAitgKAD4AAOcpAAAADQMAAPoqnZW6zkgACAcCLzz8Q1ANocBvBQFuUWqAxVSgoRjR0SaS5AkH3qr//7cx3vlcB2AYPROjCOr/vf/sXqYA7F4AAA5Y/P/7/wDvGwMAAA4DAABMXoD/us5IAAgH+RiyseCLDKGnOjkHATiXLOud6AnbGuclr2roqg2l///FNxcHi/0hFLoW4fyj/10A7F6mAOxeAAANRf7/GgAA6TQAAAAPAwAAOjJsarrOSAAIB1/+xFM3Xg2hVDKBBg6Tsx25u5hYROV9J/QyJQmLrf//zC1e+7QGxRfmFOAHhf+s/+xepgDsXgAAaE/v/+j/AOonAAAAEAMAAAb9ka66zkgACAc74z4AUZEMofLN6wbbUEjD/w54MWPC3SfOFa4yQ6f//4wtrwH5EOwKOCRTFLz/UP/sXqYA7F4AAOaAFAApAADoOQAAABEDAAC+xoUHus5IAAgH1yXSbYfZDaFOrzwBIM5keona3uYD8JYnC6ekWw+l//8JMC/9ivsaAGEwM/ssAN//7F6mAOxeAAAymwQAof8A7l8AAAASAwAA9kus4rrOSAAIB/9znedCsA2h5VDBBLdHG1Uw8P6P93bRJw5UgTR9qf//LS1BAj0TAwkqJioWBABHAOxepgDsXgAAD54FACwAAN6xAAAAEwMAAEboQta6zkgACAdVJvSzetsMoRclcgKU4/OAvUl5A73wdCYbpBB/P6X//08yQ/4N7voNgx5160gAFwDsXqYA7F4AADa+EADk/wDuLwAAABQDAADyTPBuus5IAAgHhpZXHJnuDaGfsmkMbSLS2QeTnDZBLR8ntwGPV8mj//+SM6n8rftj/EUyZfw7AaX/7F6mAOxeAAAvSQUAAAAA6j4AAAAVAwAAVC23P7rOSAAIB8FSSGuHmw2hXoTeBoU+tLS9TdsrYGopJ+h3h7O9p///mjEIB3X/GhN5GXP/c//V/+xepgDsXgAASREJADgAAO4rAAAAFgMAAMqlmN26zkgACAeGsPJwF8ENoU2cJwHhxiN62PG7uVyKfydPWVyEG6z//8spSgCQ8NkRnxsl7sr/EQDsXqYA7F4AAI0S///u/wDudQEAABcDAABUYe3ous5IAAgHtHJyvWVdDaFr1mwGwPVWIZcaxOQXwAwmeHqW1+Sh//+PPnAAQgAOCxwhof8sAGwA7F6mAOxeAAAhMQcAtf8ABjsAAAAYAwAAsOXsgbrOSAAIB4nxObhoSQ2hOjBcBf2n5ijflOaX/Iz8JpPiNAUTrP//ajEL++oEchfzE9AFSgDT/+tepgDrXgAAohMLACkAAAweAAAAGQMAAFrje3e6zkgACAexAdJ/MyYOoeXvjwPazb0PcXcXfIVaNCZ2mjMDkqn//z02W/qPBMcW7BM7BcX/6//sXqYA7F4AABv4BgAVAAAPIgAAABoDAACqA6wGus5IAAgHxYz/b8dNDaH6/WQF3AILHLKDgTJ+VponRocZMKSm//8bLycAMRANDG8i/RHR/2wA7F6mAOxeAAArEwcAHAAABEgAAQAbAwAA0hkH57rOSAAIB5HXkJcOjA2h8B4kAebzvl2gmkU1K1TzJ86wODP6qP//0CzCAM4OmQrkI1UR7f/n/+xepgDsXgAAcs/u/9//AOplAAAAHQMAAGqvKTa6zkgACAekogIGh+8NoYBTBQMDtQeTiKQ4u0KYHiYkF4HbzaT//7A80v9N/gQLmSC4/icA6v/sXqYA7F4AAB2V7v/2/wAIGQAAAB4DAACQRQ0Tus5IAAgHUsOCUJ71DaHkPFgFdJcpEDguP6ldR+UmgbrM2+6m//9vOPT/S/7vC1sh6/49AJH/7F6mAOxeAAAQCfr/8/8A4wwAAAAfAwAA7IYNqLrOSAAIByZDZIfa4AyhxlEVA9QtFKN+R+1NPIIIJ8xm1q8Qqv//djDzB9H+pBNQGGj+rv++/+xepgDsXgAA3f/6/67/AAFUAAAAIAMAAJSG0BW6zhQACAWVGZOmAAAAAPr///8SEpCmiQcDAD4zLlK6zhAACAZIDf33DwP+/jYK//gDAAAAoBoC9g=="; diff --git a/apps/agpsdata/metadata.json b/apps/agpsdata/metadata.json new file mode 100644 index 000000000..af51f3a10 --- /dev/null +++ b/apps/agpsdata/metadata.json @@ -0,0 +1,16 @@ +{ "id": "agpsdata", + "name": "A-GPS Data", + "shortName":"AGPS Data", + "icon": "agpsdata.png", + "version":"0.01", + "description": "Download assisted GPS data directly to watch", + "tags": "assisted,gps,agps,http", + "allow_emulator":true, + "supports": ["BANGLEJS2"], + "readme":"README.md", + "screenshots" : [ { "url":"screenshot.png" }, { "url":"screenshot2.png" }, { "url":"screenshot3.png" }, { "url":"screenshot4.png" }, { "url":"screenshot5.png" } ], + "storage": [ + {"name":"agpsdata.app.js","url":"app.js"}, + {"name":"agpsdata.img","url":"agpsdata-icon.js","evaluate":true} + ] +} diff --git a/apps/agpsdata/screenshot.png b/apps/agpsdata/screenshot.png new file mode 100644 index 000000000..fae53ba85 Binary files /dev/null and b/apps/agpsdata/screenshot.png differ diff --git a/apps/agpsdata/screenshot2.png b/apps/agpsdata/screenshot2.png new file mode 100644 index 000000000..7cdba1487 Binary files /dev/null and b/apps/agpsdata/screenshot2.png differ diff --git a/apps/agpsdata/screenshot3.png b/apps/agpsdata/screenshot3.png new file mode 100644 index 000000000..be152ba28 Binary files /dev/null and b/apps/agpsdata/screenshot3.png differ diff --git a/apps/agpsdata/screenshot4.png b/apps/agpsdata/screenshot4.png new file mode 100644 index 000000000..305a166d0 Binary files /dev/null and b/apps/agpsdata/screenshot4.png differ diff --git a/apps/agpsdata/screenshot5.png b/apps/agpsdata/screenshot5.png new file mode 100644 index 000000000..6468a1872 Binary files /dev/null and b/apps/agpsdata/screenshot5.png differ diff --git a/apps/alarm/ChangeLog b/apps/alarm/ChangeLog index 1be0dcdd5..0ac863909 100644 --- a/apps/alarm/ChangeLog +++ b/apps/alarm/ChangeLog @@ -31,3 +31,6 @@ 0.29: Fix wrong 'dow' handling in new timer if first day of week is Monday 0.30: Fix "Enable All" 0.31: Add seconds to timers +0.32: Fix wrong hidden filter + Add option for auto-delete a timer after it expires + diff --git a/apps/alarm/app.js b/apps/alarm/app.js index 0a7bb8f24..bc0b2cf0e 100644 --- a/apps/alarm/app.js +++ b/apps/alarm/app.js @@ -280,6 +280,10 @@ function showEditTimerMenu(selectedTimer, timerIndex) { value: timer.on, onchange: v => timer.on = v }, + /*LANG*/"Delete After Expiration": { + value: timer.del, + onchange: v => timer.del = v + }, /*LANG*/"Vibrate": require("buzz_menu").pattern(timer.vibrate, v => timer.vibrate = v), /*LANG*/"Cancel": () => showMainMenu() }; diff --git a/apps/alarm/metadata.json b/apps/alarm/metadata.json index 54472a12c..b2d25b77c 100644 --- a/apps/alarm/metadata.json +++ b/apps/alarm/metadata.json @@ -2,7 +2,7 @@ "id": "alarm", "name": "Alarms & Timers", "shortName": "Alarms", - "version": "0.31", + "version": "0.32", "description": "Set alarms and timers on your Bangle", "icon": "app.png", "tags": "tool,alarm,widget", diff --git a/apps/alarm/widget.js b/apps/alarm/widget.js index 052ac9ebd..964176fc7 100644 --- a/apps/alarm/widget.js +++ b/apps/alarm/widget.js @@ -2,7 +2,7 @@ WIDGETS["alarm"]={area:"tl",width:0,draw:function() { if (this.width) g.reset().drawImage(atob("GBgBAAAAAAAAABgADhhwDDwwGP8YGf+YMf+MM//MM//MA//AA//AA//AA//AA//AA//AB//gD//wD//wAAAAADwAABgAAAAAAAAA"),this.x,this.y); },reload:function() { // don't include library here as we're trying to use as little RAM as possible - WIDGETS["alarm"].width = (require('Storage').readJSON('sched.json',1)||[]).some(alarm=>alarm.on&&(alarm.hidden!==false)) ? 24 : 0; + WIDGETS["alarm"].width = (require('Storage').readJSON('sched.json',1)||[]).some(alarm=>alarm.on&&(alarm.hidden!==true)) ? 24 : 0; } }; WIDGETS["alarm"].reload(); diff --git a/apps/android/ChangeLog b/apps/android/ChangeLog index f13ccd95c..acdeeaaa0 100644 --- a/apps/android/ChangeLog +++ b/apps/android/ChangeLog @@ -9,3 +9,4 @@ 0.08: Handling of alarms 0.09: Alarm vibration, repeat, and auto-snooze now handled by sched 0.10: Fix SMS bug +0.12: Use default Bangle formatter for booleans diff --git a/apps/android/metadata.json b/apps/android/metadata.json index 27b77cf2f..ec8b8b0fe 100644 --- a/apps/android/metadata.json +++ b/apps/android/metadata.json @@ -2,7 +2,7 @@ "id": "android", "name": "Android Integration", "shortName": "Android", - "version": "0.11", + "version": "0.12", "description": "Display notifications/music/etc sent from the Gadgetbridge app on Android. This replaces the old 'Gadgetbridge' Bangle.js widget.", "icon": "app.png", "tags": "tool,system,messages,notifications,gadgetbridge", diff --git a/apps/android/settings.js b/apps/android/settings.js index 695d483c6..c7c34a76f 100644 --- a/apps/android/settings.js +++ b/apps/android/settings.js @@ -18,7 +18,6 @@ }), /*LANG*/"Keep Msgs" : { value : !!settings.keep, - format : v=>v?/*LANG*/"Yes":/*LANG*/"No", onchange: v => { settings.keep = v; updateSettings(); diff --git a/apps/antonclk/ChangeLog b/apps/antonclk/ChangeLog index 73a63f7c7..f7e95b5fa 100644 --- a/apps/antonclk/ChangeLog +++ b/apps/antonclk/ChangeLog @@ -9,4 +9,5 @@ when weekday name and calendar weeknumber are on then display is # week is buffered until date or timezone changes 0.07: align default settings with app.js (otherwise the initial displayed settings will be confusing to users) -0.08: fixed calendar weeknumber not shortened to two digits \ No newline at end of file +0.08: fixed calendar weeknumber not shortened to two digits +0.09: Use default Bangle formatter for booleans \ No newline at end of file diff --git a/apps/antonclk/metadata.json b/apps/antonclk/metadata.json index c58ee2a1b..16bdf3aa8 100644 --- a/apps/antonclk/metadata.json +++ b/apps/antonclk/metadata.json @@ -1,7 +1,7 @@ { "id": "antonclk", "name": "Anton Clock", - "version": "0.08", + "version": "0.09", "description": "A clock using the bold Anton font, optionally showing seconds and date in ISO-8601 format.", "readme":"README.md", "icon": "app.png", diff --git a/apps/antonclk/settings.js b/apps/antonclk/settings.js index 6882cbd0f..4448c00ed 100644 --- a/apps/antonclk/settings.js +++ b/apps/antonclk/settings.js @@ -2,7 +2,6 @@ (function(back) { var FILE = "antonclk.json"; - // Load settings var settings = Object.assign({ secondsOnUnlock: false, }, require('Storage').readJSON(FILE, true) || {}); @@ -41,7 +40,6 @@ "Date": stringInSettings("dateOnMain", ["Long", "Short", "ISO8601"]), "Show Weekday": { value: (settings.weekDay !== undefined ? settings.weekDay : true), - format: v => v ? "On" : "Off", onchange: v => { settings.weekDay = v; writeSettings(); @@ -49,7 +47,6 @@ }, "Show CalWeek": { value: (settings.calWeek !== undefined ? settings.calWeek : false), - format: v => v ? "On" : "Off", onchange: v => { settings.calWeek = v; writeSettings(); @@ -57,7 +54,6 @@ }, "Uppercase": { value: (settings.upperCase !== undefined ? settings.upperCase : true), - format: v => v ? "On" : "Off", onchange: v => { settings.upperCase = v; writeSettings(); @@ -65,7 +61,6 @@ }, "Vector font": { value: (settings.vectorFont !== undefined ? settings.vectorFont : false), - format: v => v ? "On" : "Off", onchange: v => { settings.vectorFont = v; writeSettings(); @@ -82,7 +77,6 @@ "Show": stringInSettings("secondsMode", ["Never", "Unlocked", "Always"]), "With \":\"": { value: (settings.secondsWithColon !== undefined ? settings.secondsWithColon : true), - format: v => v ? "On" : "Off", onchange: v => { settings.secondsWithColon = v; writeSettings(); @@ -90,7 +84,6 @@ }, "Color": { value: (settings.secondsColoured !== undefined ? settings.secondsColoured : true), - format: v => v ? "On" : "Off", onchange: v => { settings.secondsColoured = v; writeSettings(); @@ -99,9 +92,6 @@ "Date": stringInSettings("dateOnSecs", ["Year", "Weekday", "No"]) }; - // Actually display the menu E.showMenu(mainmenu); }); - -// end of file diff --git a/apps/bikespeedo/ChangeLog b/apps/bikespeedo/ChangeLog index 2a3023750..10752ee2b 100644 --- a/apps/bikespeedo/ChangeLog +++ b/apps/bikespeedo/ChangeLog @@ -1,2 +1,3 @@ 0.01: New App! 0.02: Barometer altitude adjustment setting +0.03: Use default Bangle formatter for booleans diff --git a/apps/bikespeedo/metadata.json b/apps/bikespeedo/metadata.json index c3de0487c..80b91427c 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.02", + "version": "0.03", "description": "Shows GPS speed, GPS heading, Compass heading, GPS altitude and Barometer altitude from internal sources", "icon": "app.png", "screenshots": [{"url":"Screenshot.png"}], diff --git a/apps/bikespeedo/settings.js b/apps/bikespeedo/settings.js index a3921f4a3..f41524263 100644 --- a/apps/bikespeedo/settings.js +++ b/apps/bikespeedo/settings.js @@ -33,12 +33,10 @@ '< Back': function() { E.showMenu(appMenu); }, 'Speed' : { value : settings.spdFilt, - format : v => v?"On":"Off", onchange : () => { settings.spdFilt = !settings.spdFilt; writeSettings(); } }, 'Altitude' : { value : settings.altFilt, - format : v => v?"On":"Off", onchange : () => { settings.altFilt = !settings.altFilt; writeSettings(); } } }; diff --git a/apps/bthrm/ChangeLog b/apps/bthrm/ChangeLog index 7ca8319b6..00ed856d6 100644 --- a/apps/bthrm/ChangeLog +++ b/apps/bthrm/ChangeLog @@ -22,3 +22,4 @@ Restructure the settings menu 0.08: Allow scanning for devices in settings 0.09: Misc Fixes and improvements (https://github.com/espruino/BangleApps/pull/1655) +0.10: Use default Bangle formatter for booleans diff --git a/apps/bthrm/metadata.json b/apps/bthrm/metadata.json index 39c1ff8bb..9e40896f0 100644 --- a/apps/bthrm/metadata.json +++ b/apps/bthrm/metadata.json @@ -2,7 +2,7 @@ "id": "bthrm", "name": "Bluetooth Heart Rate Monitor", "shortName": "BT HRM", - "version": "0.09", + "version": "0.10", "description": "Overrides Bangle.js's build in heart rate monitor with an external Bluetooth one.", "icon": "app.png", "type": "app", diff --git a/apps/bthrm/settings.js b/apps/bthrm/settings.js index b376d6a2d..8887ee81e 100644 --- a/apps/bthrm/settings.js +++ b/apps/bthrm/settings.js @@ -85,14 +85,12 @@ '< Back': function() { E.showMenu(buildMainMenu()); }, 'Alert on disconnect': { value: !!settings.warnDisconnect, - format: v => settings.warnDisconnect ? "On" : "Off", onchange: v => { writeSettings("warnDisconnect",v); } }, 'Debug log': { value: !!settings.debuglog, - format: v => settings.debuglog ? "On" : "Off", onchange: v => { writeSettings("debuglog",v); } diff --git a/apps/bwclk/ChangeLog b/apps/bwclk/ChangeLog index ecd0c355f..ef4edcff0 100644 --- a/apps/bwclk/ChangeLog +++ b/apps/bwclk/ChangeLog @@ -6,4 +6,6 @@ 0.06: Design and usability improvements. 0.07: Improved positioning. 0.08: Select the color of widgets correctly. Additional settings to hide colon. -0.09: Larger font size if colon is hidden to improve readability further. \ No newline at end of file +0.09: Larger font size if colon is hidden to improve readability further. +0.10: HomeAssistant integration if HomeAssistant is installed. +0.11: Performance improvements. \ No newline at end of file diff --git a/apps/bwclk/README.md b/apps/bwclk/README.md index f6a1c6522..190488d6b 100644 --- a/apps/bwclk/README.md +++ b/apps/bwclk/README.md @@ -7,6 +7,7 @@ - Tab left/right of screen to show steps, temperature etc. - Enable / disable lock icon in the settings. - If the "sched" app is installed tab top / bottom of the screen to set the timer. +- If HomeAssistant is installed, triggers are shown. Simple select the trigger and touch the middle of the screen to send the trigger to HomeAssistant. - The design is adapted to the theme of your bangle. - The colon (e.g. 7:35 = 735) can be hidden now in the settings. diff --git a/apps/bwclk/app.js b/apps/bwclk/app.js index 5bfec4097..4c4359a4f 100644 --- a/apps/bwclk/app.js +++ b/apps/bwclk/app.js @@ -62,86 +62,131 @@ Graphics.prototype.setMediumFont = function(scale) { Graphics.prototype.setSmallFont = function(scale) { // Actual height 28 (27 - 0) - this.setFontCustom(atob("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//84D//zgP/+GAAAAAAAAAAAAAAAAAAAD4AAAPgAAA+AAAAAAAAAAAAA+AAAD4AAAPgAAAAAAAAAAAAAAAAAAAAAAAAAAAAOAAAg4AAHDgAAcOCABw54AHD/gAf/8AD/8AB//gAP8OAA9w4YCHD/gAcf+AB//gAf/gAP/uAA/w4ADnDgAAcOAABw4AAHAAAAcAAAAAAAAAAAAAAAIAA+A4AH8HwA/4PgHjgOAcHAcBwcBw/BwH78DgfvwOB8HA4HAOBw8A+HngB4P8ADgfgAAAYAAAAAAAAAAB4AAAf4AQB/gDgOHAeA4cDwDhweAOHDwA88eAB/nwAD88AAAHgAAA8AAAHn4AA8/wAHnvgA8cOAHhg4A8GDgHgcOA8B74BgD/AAAH4AAAAAAAAAAAAAAAAAMAAAH8AD8/4Af/3wB/8HgODwOA4HA4DgODgOAcOA4A44DwDzgHAH8AMAPwAQP+AAA/8AAAB4AAADAAAAAA+AAAD4AAAPgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH/8AD//+A/+/+H4AD98AAB3gAADIAAAAAAAAAAAAAIAAABwAAAXwAAHPwAB8P8D/gP//4AH/8AAAAAAAAAAAAAAAAAAAAAAAAGAAAA4gAAB/AAAH8AAD/AAAP8AAAH4AAAfwAADiAAAOAAAAAAAAAAAAAAGAAAAYAAABgAAAGAAAAYAAABgAAD/+AAP/4AABgAAAGAAAAYAAABgAAAGAAAAYAAAAAAAAAAAAAADkAAAPwAAA/AAAAAAAAAAAAAAAAAAAAAAAAABgAAAGAAAAYAAABgAAAGAAAAYAAABgAAAGAAAAYAAAAAAAAAAAAAAAAAAAAAAADgAAAOAAAA4AAAAAAAAAAAAAAAAAAAAAAAAAAA4AAA/gAA/+AA//AA//AAP/AAA/AAADAAAAAAAAAAAAAAAAAAA//gAP//gB///AHgA8A8AB4DgADgOAAOA4AA4DgADgPAAeAeADwB///AD//4AD/+AAAAAAAAAAAAAAAA4AAAHgAAAcAAADwAAAP//+A///4D///gAAAAAAAAAAAAAAAAAAAAAAYAeADgD4AeAfAD4DwAfgOAD+A4Ae4DgDzgOAeOA4Dw4DweDgH/wOAP+A4AfwDgAAAAAAAAAAAAIAOAA4A4ADwDggHAOHgOA48A4DnwDgO/AOA7uA4D84HgPh/8A8H/gDgH8AAACAAAAAAAAAAAAAHgAAB+AAA/4AAP7gAD+OAA/g4AP4DgA+AOADAA4AAB/+AAH/4AAf/gAADgAAAOAAAAAAAAAAAAAAAAD4cAP/h4A/+HwDw4HgOHAOA4cA4DhwDgOHAOA4cA4Dh4HAOD58A4H/gAAP8AAAGAAAAAAAAAAAAAAAAD/+AAf/8AD//4AePDwDw4HgOHAOA4cA4DhwDgOHAOA4cB4Bw8PAHD/8AIH/gAAH4AAAAAAAAAADgAAAOAAAA4AAYDgAHgOAD+A4B/wDgf4AOP+AA7/AAD/gAAP4AAA8AAAAAAAAAAAAAAAAAAeH8AD+/4Af//wDz8HgOHgOA4OA4Dg4DgODgOA4eA4Dz8HgH//8AP7/gAeH8AAAAAAAAAAAAAAAA+AAAH+AgB/8HAHh4cA8Dg4DgODgOAcOA4Bw4DgODgPA4eAeHDwB///AD//4AD/+AAAAAAAAAAAAAAAAAAAAAAAAAAODgAA4OAADg4AAAAAAAAAAAAAAAAAAAAAAAAAAAAABwA5AHAD8AcAPgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGAAAB8AAAP4AAB5wAAPDgAB4HAAHAOAAIAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGMAAAYwAABjAAAGMAAAYwAABjAAAGMAAAYwAABjAAAGMAAAYwAABjAAAGMAAAYwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAEAAcA4AB4HAADw4AADnAAAH4AAAPAAAAYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPAAAB8AAAHgAAA4AAADgDzgOA/OA4D84DgeAAPHwAAf+AAA/wAAB8AAAAAAAAAAAAAAAAAAD+AAB/+AAP/8AB4B4AOABwBwADgHB8OA4P4cDhxxwMGDDAwYMMDBgwwOHHHA4f4cDh/xwHAHCAcAMAA8AwAB8PAAD/4AAD/AAAAAAAAAAAAAACAAAB4AAB/gAA/8AAf+AAP/wAH/nAA/gcADwBwAPwHAA/4cAA/9wAAf/AAAP/AAAD/gAAB+AAAA4AAAAAAAAAAAAAAD///gP//+A///4DgcDgOBwOA4HA4DgcDgOBwOA4HA4Dg8DgPHwOAf/h4A///AB8f4AAAfAAAAAAAP+AAD/+AAf/8AD4D4AeADwBwAHAOAAOA4AA4DgADgOAAOA4AA4DgADgOAAOAcABwB4APAD4D4AHgPAAOA4AAAAAAAAAAAAAAAP//+A///4D///gOAAOA4AA4DgADgOAAOA4AA4DgADgOAAOA8AB4BwAHAHwB8AP//gAP/4AAP+AAAAAAAAAAAAAAAA///4D///gP//+A4HA4DgcDgOBwOA4HA4DgcDgOBwOA4HA4DgcDgOBgOA4AA4AAAAAAAAAAAAAAD///gP//+A///4DgcAAOBwAA4HAADgcAAOBwAA4HAADgcAAOAwAA4AAAAAAAAAf+AAD/+AA//+ADwB4AeADwDwAHgOAAOA4AA4DgADgOAAOA4AA4DgMDgPAweAcDBwB8MfADw/4AHD/AAAPwAAAAAAAAAAAAAAAP//+A///4D///gABwAAAHAAAAcAAABwAAAHAAAAcAAABwAAAHAAAAcAAABwAA///4D///gP//+AAAAAAAAAAAAAAAAAAAD///gP//+A///4AAAAAAAAAAAADgAAAPAAAA+AAAA4AAADgAAAOAAAA4AAAHgP//8A///wD//8AAAAAAAAAAAAAAAAAAAA///4D///gP//+AAHAAAA+AAAP8AAB54AAPDwAB4HgAPAPAB4AfAPAA+A4AA4DAABgAAACAAAAAAAAAAP//+A///4D///gAAAOAAAA4AAADgAAAOAAAA4AAADgAAAOAAAA4AAADgAAAAAAAAAAAAAAP//+A///4D///gD+AAAD+AAAB+AAAB/AAAB/AAAB/AAAB+AAAH4AAB+AAA/gAAP4AAD+AAA/AAAfwAAD///gP//+A///4AAAAAAAAAAAAAAAAAAAP//+A///4D///gHwAAAPwAAAPgAAAfgAAAfAAAAfAAAA/AAAA+AAAB+AAAB8A///4D///gP//+AAAAAAAAAAAP+AAD/+AAf/8AD4D4AeADwBwAHAOAAOA4AA4DgADgOAAOA4AA4DgADgOAAOAcABwB4APAD4D4AH//AAP/4AAP+AAAAAAAAAAAP//+A///4D///gOAcAA4BwADgHAAOAcAA4BwADgHAAOAcAA4DgAD4eAAH/wAAP+AAAPgAAAAAAAA/4AAP/4AB//wAPgPgB4APAHAAcA4AA4DgADgOAAOA4AA4DgADgOAAOA4AO4BwA/AHgB8APgPwAf//gA//uAA/4QAAAAAAAAAA///4D///gP//+A4BwADgHAAOAcAA4BwADgHAAOAcAA4B8ADgP8APh/8Af/H4A/4HgA+AGAAAAAAAAAAAABgAHwHAA/g+AH/A8A8cBwDg4DgODgOA4OA4DgcDgOBwOA4HA4DwODgHg4cAPh/wAcH+AAwPwAAAAADgAAAOAAAA4AAADgAAAOAAAA4AAAD///gP//+A///4DgAAAOAAAA4AAADgAAAOAAAA4AAADgAAAAAAAAAAAAAAAAAP//AA///AD//+AAAB8AAABwAAADgAAAOAAAA4AAADgAAAOAAAA4AAAHgAAA8A///gD//8AP//gAAAAAAAAAAIAAAA8AAAD+AAAH/AAAD/wAAB/4AAA/8AAAf4AAAPgAAB+AAA/4AAf+AAP/AAH/gAD/wAAP4AAA4AAAAAAAAPAAAA/gAAD/4AAA/+AAAf/AAAH/gAAB+AAAf4AAf/AAf/AAP/gAD/gAAPwAAA/4AAA/+AAAf/AAAH/wAAB/gAAB+AAB/4AA/+AA/+AA/+AAD/AAAPAAAAgAAAAAAAAMAAGA4AA4D4APgHwB8APwfAAPn4AAf+AAAfwAAB/AAAf+AAD4+AA/B8AHwB8A+AD4DgADgMAAGAwAAADwAAAPwAAAPwAAAfgAAAfgAAAf/4AAf/gAH/+AB+AAAPwAAD8AAA/AAADwAAAMAAAAgAAAAAAAAMAACA4AA4DgAPgOAD+A4Af4DgH7gOB+OA4Pw4Dj8DgO/AOA/4A4D+ADgPgAOA4AA4DAADgAAAAAAAAAAAAAAAAAAAAAAAAAAAAP/////////gAAAOAAAA4AAADAAAAAAAAAAAAAAAAAAAAAAA4AAAD+AAAP/gAAH/4AAB/+AAAf+AAAH4AAABgAAAAAAAAADAAAAOAAAA4AAADgAAAP////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAADgAAAcAAADgAAAcAAADgAAAcAAAB4AAADwAAADgAAAHAAAAOAAAAYAAAAAAAAAAAAAAAAAAAAMAAAAwAAADAAAAMAAAAwAAADAAAAMAAAAwAAADAAAAMAAAAwAAADAAAAMAAAAwAAADAAAAMAAAAwAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+AAHH8AA8/4AHzjgAcMOABxwYAHHBgAccOABxwwAHGHAAP/4AA//4AA//gAAAAAAAAAAAAAAAAAAA///4D///gP//+AA4BwAHADgAcAOABwA4AHADgAcAOAB4B4ADwPAAP/8AAf/AAAf4AAAAAAAAAAAAPwAAD/wAAf/gADwPAAeAeABwA4AHADgAcAOABwA4AHADgAeAeAA8DwABwOAADAwAAAAAAAAAAAA/AAAP/AAD//AAPA8AB4B4AHADgAcAOABwA4AHADgAcAOAA4BwD///gP//+A///4AAAAAAAAAAAAAAAAPwAAD/wAAf/gAD2PAAeYeABxg4AHGDgAcYOABxg4AHGDgAeYeAA/jwAB+OAAD4wAABgAAAAAAAAAAABgAAAGAAAB//+Af//4D///gPcAAA5gAADGAAAMYAAAAAAAAAPwAAD/wMA//w4DwPHgeAePBwA4cHADhwcAOHBwA4cHADhwOAcPB///4H///Af//wAAAAAAAAAAAAAAAAAAD///gP//+AA//4ADgAAAcAAABwAAAHAAAAcAAABwAAAHgAAAP/+AAf/4AA//gAAAAAAAAAAAAAAMf/+A5//4Dn//gAAAAAAAAAAAAAAAAAAHAAAAfn///+f//+5///wAAAAAAAAAAAAAAAAAAP//+A///4D///gAAcAAAD8AAAf4AADzwAAeHgAHwPAAeAeABgA4AEABgAAAAAAAAAD///gP//+A///4AAAAAAAAAAAAAAAAAAAAf/+AB//4AH//gAOAAABwAAAHAAAAcAAABwAAAHgAAAP/+AA//4AB//gAOAAABwAAAHAAAAcAAABwAAAHgAAAf/+AA//4AA//gAAAAAAAAAAAAAAAf/+AB//4AD//gAOAAABwAAAHAAAAcAAABwAAAHAAAAeAAAA//4AB//gAD/+AAAAAAAAAAAAAAAAD8AAA/8AAH/4AA8DwAHgHgAcAOABwA4AHADgAcAOABwA4AHgHgAPh8AAf/gAA/8AAA/AAAAAAAAAAAAAAAAB///8H///wf///A4BwAHADgAcAOABwA4AHADgAcAOAB4B4ADwPAAP/8AAf/AAAf4AAAAAAAAAAAAPwAAD/wAA//wADwPAAeAeABwA4AHADgAcAOABwA4AHADgAOAcAB///8H///wf///AAAAAAAAAAAAAAAAAAAH//gAf/+AB//4ADwAAAcAAABwAAAHAAAAcAAAAAAAAAAMAAHw4AA/jwAH+HgAcYOABxw4AHHDgAcMOABw44AHjjgAPH+AA8fwAAw+AAAAAABgAAAGAAAAcAAAf//wB///AH//+ABgA4AGADgAYAOABgA4AAAAAAAAAAAAAAAH/AAAf/wAB//wAAB/AAAAeAAAA4AAADgAAAOAAAA4AAADgAAAcAB//4AH//gAf/+AAAAAAAAAAAAAAABwAAAH4AAAf8AAAP8AAAH+AAAD+AAAD4AAA/gAAf8AAP+AAH/AAAfgAABwAAAAAAAAAAAABwAAAH8AAAf+AAAP/gAAD/gAAB+AAAf4AAP8AAP+AAB/AAAH4AAAf8AAAP+AAAD/gAAB+AAAf4AAf/AAP/AAB/gAAHgAAAQAAABAAIAHADgAeAeAA8HwAB8+AAD/gAAD8AAAPwAAD/gAAfPgADwfAAeAeABwA4AEAAgAAAAABAAAAHgAAAfwAAA/wAAAf4BwAP4/AAP/8AAP+AAD/AAB/wAA/4AAP8AAB+AAAHAAAAQAAAAAAIAHADgAcAeABwD4AHA/gAcHuABx84AHPDgAf4OAB/A4AHwDgAeAOABgA4AEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYAAAH4Af//////n//AAAA4AAADgAAAAAAAAAAAAAAAAAP//+A///4D///gAAAAAAAAAAAAAAAAAAA4AAADgAAAOAAAA//5/9////wAH4AAAGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAeAAAD4AAAOAAAA4AAADgAAAHAAAAcAAAA4AAADgAAAOAAAD4AAAPAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"), 32, atob("BgkMGhEZEgYMDAwQCAwICxILEBAREBEOEREJCREVEQ8ZEhEUExAOFBQHDREPGBMUERQSEhEUERsREBIMCwwTEg4QERAREQoREQcHDgcYEREREQoPDBEPFg8PDwwIDBMc"), 28+(scale<<8)+(1<<16)); + this.setFontCustom( + atob('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAf/+cB//5wH//nAAAAAAAAAAAAAAAAAAAB8AAAHwAAAfAAAAAAAAAAAAAfAAAB8AAAHwAAAAAAAAAAAAAAAAAAAAAAAAAAAAHAAAQcAADhwAAOHBAA4c8ADh/wAP/+AB/+AA//wAH+HAAe4cMBDh/wAOP/AA//wAP/wAH/3AAf4cABzhwAAOHAAA4cAADgAAAOAAAAAAAAAAAAAAAAAAAAwAH8HwA/4PgD/geAePA8BwcBw/BwH78DgfvwOB+HA4HAeBwcA8HDgB4f+ADg/wAGB+AAAAAAAAAAAAAAAH4AAA/wBwHngPAcOB4Bw4PAHDh4AcOPAA/x4AD/PAADx4AAAPAAAB5wAAPPwAB5/gAPOPAB4wcAPDBwB4MHAPA4cA4B/gBAH8AAAHAAAAAAAAAAAAAPAAHD/AB/f+AP/x4B4+DwHB4HAcDwcBwHhwHAPHAcAccB4A5wDgB+AGA/4AAH/AAAf+AAAA8AAABgAAAAAfAAAB8AAAHwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH/8AD//+A/+/+H4AD98AAB3gAADIAAAAAAAAAAAAAIAAABwAAAXwAAHPwAB8P8D/gP//4AH/8AAAAAAAAAAAAAAAAAAAAAAAAHAAAAcwAAA/gAAb8AAB/gAAH+AAAD+AAAOwAABxAAADAAAAAAAAAAAAAADAAAAMAAAAwAAADAAAAMAAAAwAAB//AAH/8AAAwAAADAAAAMAAAAwAAADAAAAMAAAAAAAAAAAAAABwAAAHIAAAfgAAB8AAAAAAAAAAAAAAAAAAAAAwAAADAAAAMAAAAwAAADAAAAMAAAAwAAADAAAAMAAAAAAAAAAAAAAAAAAAAAAABwAAAHAAAAcAAAAAAAAAAAAAAAAAAAAAAAAAAA8AAA/wAA//AA//AA//AAH/AAAfAAABAAAAAAAAAAAAAAAAAAAf/wAH//wA///gDgAOAcAAcBwABwHAAHAcAAcBwABwHgAPAPAB4Af//AA//4AA/+AAAAAAAAAAAAAAAAMAAABwAAAOAAAB4AAAH///Af//8B///wAAAAAAAAAAAAAAAAAAAAwAcAPADwB8AfAPAB8B4APwHAB/AcAPcBwB5wHAPHAcB4cA8PBwD/4HAH/AcAHwBwAAAAAAAAAAAAGAHAAcAcAB4BwYDwHDwHAceAcBz4BwHfgHAf3AcB+eDwHw/+AeB/wBwD+AAAAAAAAAAAAAAAAABwAAAfAAAP8AAD/wAA/nAAP4cAD+BwAfgHAB4AcAEA//AAD/8AAP/wAABwAAAHAAAAMAAAAAAAAAAAAAEAH/w4Af/D4B/8HgHDgPAcOAcBw4BwHDgHAcOAcBw8DwHB4eAcH/wBgP+AAAPwAAAAAAAAAAAAAAAB//AAf//AD//+AOHB4Bw4BwHDgHAcOAcBw4BwHDgHAcPA8A4eHgDh/8AEB/gAAD4AAAAAAAAAABwAAAHAAAAcAAMBwADwHAB/AcA/4BwP8AHH/AAd/gAB/wAAH8AAAeAAAAAAAAAAAAAAAEAAPD+AB/f8AP//4B4+DwHDwHAcHAcBwcBwHBwHAcPAcB/+DgD//+AH5/wACB8AAAAAAAAAAAAAAAAEAAAD+AAAf+DAD74OAODw8BwHBwHAOHAcA4cBwDBwHAcHAeBw8A+ePgB//8AD//gAB/wAAAAAAAAAAAAAAAAAAAAAHBwAAcHAABwcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA4AcgDgB+AOAHwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAeAAAD8AAAf4AADzwAAeHgADwPAAGAYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADGAAAMYAAAxgAADGAAAMYAAAxgAADGAAAMYAAAxgAADGAAAMYAAAxgAADGAAAMYAAAxgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABACAAOAcAA8DgAB4cAABzgAAD8AAAHgAAAMAAAAAAAAAAAAAAAAAAAAAAAAAAYAAAHgAAA+AAAHgAAAcAAABwD5wHAfnAcD8cBweAAHzwAAP+AAAfwAAAcAAAAAAAAAAAAAAAAAAB/AAA//AAH/+AA8A8AHAA4A4ABwDg+HAcH8OBw444GDBhgYMGGBgwYYHDjjgcP8OBw/44DgDhAOAGAAeAYAA+HgAB/8AAB/gAAAAAAAAAAAAABAAAA8AAAfwAAP/AAH/gAD/4AB/zgAf4OAB8A4AHwDgAf4OAA/84AAP/gAAH/AAAD/gAAB/AAAA8AAAAQAAAAAAAAAB///wH///Af//8BwOBwHA4HAcDgcBwOBwHA4HAcDgcBweBwHj4HAP/58Afz/gAcH8AAAPAAAAAAAH/AAB//AAf//AB4A8APAB4B4ADwHAAHAcAAcBwABwHAAHAcAAcBwABwHAAHAOAA4A8AHgB8B8ADwHgADAYAAAAAAAAAAAAAAAH///Af//8B///wHAAHAcAAcBwABwHAAHAcAAcBwABwHAAHAeAA8A8AHgB8B+AD//gAH/8AAD/AAAAAAAAAAAAAAAAf//8B///wH///AcDgcBwOBwHA4HAcDgcBwOBwHA4HAcDgcBwOBwHAAHAcAAcAAAAAAAAAAAAAAB///wH///Af//8BwOAAHA4AAcDgABwOAAHA4AAcDgABwOAAHAAAAcAAAAAAAAAP/AAB//AAf//AB4A8APAB4B4ADwHAAHAcAAcBwABwHAAHAcAAcBwGBwHgYPAOBg4A+GPgB4f8ADh/gAAH4AAAAAAAAAAAAAAAH///Af//8B///wAA4AAADgAAAOAAAA4AAADgAAAOAAAA4AAADgAAAOAAAA4AAf//8B///wH///AAAAAAAAAAAAAAAAAAAB///wH///Af//8AAAAAAAAAAAABgAAAHgAAAeAAAA8AAABwAAAHAAAAcAAABwH///Af//4B///AAAAAAAAAAAAAAAAAAAAf//8B///wH///AAHgAAA/AAAH+AAA88AAHh8AA8D4AHgDwA8AHgHgAPAYAAcBAAAwAAABAAAAAAAAAAH///Af//8B///wAAAHAAAAcAAABwAAAHAAAAcAAABwAAAHAAAAcAAABwAAAAAAAAAAAAAAH///Af//8B///wB/AAAB/AAAA/AAAA/gAAA/gAAA/gAAA/AAAD8AAA/AAAfwAAH8AAB/AAAfgAAP4AAB///wH///Af//8AAAAAAAAAAAAAAAAAAAH///Af//8B///wD8AAAD4AAAH4AAAHwAAAPwAAAPgAAAPgAAAfAAAAfAAAA/Af//8B///wH///AAAAAAAAAAAH/AAB//AAf//AB4A8APAB4B4ADwHAAHAcAAcBwABwHAAHAcAAcBwABwHAAHAOAA4A8AHgB+D8AD//gAH/8AAD+AAAAAAAAAAAH///Af//8B///wHAOAAcA4ABwDgAHAOAAcA4ABwDgAHAeAAeBwAA+fAAD/4AAD/AAADgAAAAAAAAf8AAH/8AB//8AHgDwA8AHgHgAPAcAAcBwABwHAAHAcAAcBwABwHAAnAcAHcA4AfgDwA+AH4P4AP//wAf/3AAP4AAAAAAAAAAAf//8B///wH///AcA4ABwDgAHAOAAcA4ABwDgAHAOAAcB+AB4H+AD59/AP/h8AP8BwAOABAAAAAAAAAAAAAwAD4HwA/4fAD/geAePA8BwcBwHBwHAcDgcBwOBwHA4HAcDgcA4HDwD4eeAHw/4AOD/AAIDwAAAAABwAAAHAAAAcAAABwAAAHAAAAcAAABwAAAH///Af//8B///wHAAAAcAAABwAAAHAAAAcAAABwAAAGAAAAAAAAAAAAAH//wAf//gB///AAAAeAAAA8AAABwAAAHAAAAcAAABwAAAHAAAAcAAADgAAAeAf//wB//+AH//gAAAAAAAAAAGAAAAfAAAB/gAAB/wAAA/4AAAf8AAAP/AAAH8AAADwAAA/AAAf8AAP+AAP/AAH/gAB/wAAH4AAAcAAABAAAAHwAAAf4AAA/+AAAP/gAAH/wAAB/wAAA/AAAf8AAf/AAP/gAP/gAB/gAAH4AAAf+AAAf/AAAH/wAAB/8AAAfwAAB/AAB/8AA/+AA/+AAf+AAB/AAAHAAAAAAAAAAAAQGAADAeAA8B8AHwD8B+AD4PgAH74AAH/AAAPwAAA/gAAP/gAD8fAAfA/AH4A+AeAA8BwABwEAABAQAAABwAAAHwAAAPwAAAfwAAAfgAAAfgAAAf/wAB//AAf/8AH8AAA/AAAPwAAB8AAAHAAAAQAAAAAAAAAAABAcAAcBwADwHAA/AcAP8BwD/wHAfnAcH4cBx+BwHPwHAf8AcB/ABwH4AHAeAAcBgABwAAAAAAAAAAAAAAAAAAAAAAAAAAAAP/////////gAAAOAAAA4AAADAAAAAAAAAAAAAAAAAAAAAAAeAAAB/gAAH/4AAB/+AAAf/gAAH/AAAB8AAAAQAAAAAAAAAAAAAAOAAAA4AAADgAAAP/////////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAADgAAAcAAADgAAAcAAADgAAAcAAAB4AAADwAAADgAAAHAAAAOAAAAYAAAAAAAAAAAAAAAAAAAAGAAAAYAAABgAAAGAAAAYAAABgAAAGAAAAYAAABgAAAGAAAAYAAABgAAAGAAAAYAAABgAAAGAAAAYAAABgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAfAADj+AAef8AD5xwAOGHAA44MADjgwAOOHAA44YADjDgAH/8AAf/8AAf/wAAAAAAAAAAAAAAAAAAAf//8B///wH//+AAcA4ADgBwAOAHAA4AcADgBwAOAHAA8A8AB8PgAD/8AAH/gAAH4AAAAAAAAAAAAH4AAB/4AAP/wAB4HgAPAPAA4AcADgBwAOAHAA4AcADgBwAPAPAAeB4AA4HAABgYAAAAAAAAAAAAfgAAH/gAB//gAHgeAA8A8ADgBwAOAHAA4AcADgBwAOAHAAcA4B///wH///Af//8AAAAAAAAAAAAAAAAH4AAB/4AAP/wAB7HgAPMPAA4wcADjBwAOMHAA4wcADjBwAPMPAAfx4AA/HAAB8YAAAwAAAAAAAAAAAAwAAADAAAB///AP//8B///wHMAAAYwAABjAAAGMAAAAAAAAAPwAAD/wMA//w4DwPHgeAePBwA4cHADhwcAOHBwA4cHADhwOAcPB///4H///Af//wAAAAAAAAAAAAAAAAAAB///wH///AAf/8ABwAAAOAAAA4AAADgAAAOAAAA4AAADwAAAH//AAP/8AAf/wAAAAAAAAAAAAAAAAAAAc//8Bz//wHP//AAAAAAAAAAAAAAHAAAAcAAAH+f///5///7H//8AAAAAAAAAAAAAAH///Af//8B///wAAPAAAB+AAAP8AAB54AAfDwAD4HgAOAPAAwAcACAAwAAAAAAAAAB///wH///Af//8AAAAAAAAAAAAAAAAAAAAP//AA//8AB//wAHAAAA4AAADgAAAOAAAA4AAAD4AAAH//AAP/8AB//wAHAAAA4AAADgAAAOAAAA4AAADwAAAH//AAP/8AAf/wAAAAAAAAAAAAAAAP//AA//8AB//wAHAAAA4AAADgAAAOAAAA4AAADgAAAPAAAAf/8AA//wAB//AAAAAAAAAAAAAAAAB+AAAf+AAD/8AAeB4ADwDwAOAHAA4AcADgBwAOAHAA4AcADwDwAHw+AAP/wAAf+AAAfgAAAAAAAAAAAAAAAB///8H///wP///A4BwAHADgAcAOABwA4AHADgAcAOAB4B4AD4fAAH/4AAP/AAAPwAAAAAAAAAAAAPwAAD/wAA//wADwPAAeAeABwA4AHADgAcAOABwA4AHADgAOAcAB///8H///wf///AAAAAAAAAAAAAAAAAAAD//wAP//AAf/8ABwAAAOAAAA4AAADgAAAOAAAAAAAAAYGAAD4cAAfx4AD3DwAOOHAA44cADjhwAOGHAA4ccADxzwAHj+AAOP4AAYOAAAAAAAwAAADAAAAMAAAP//wA///gD///AAwAcADABwAMAHAAwAcADAAwAAAAAAAAAAD/gAAP/4AA//4AAA/gAAAPAAAAcAAABwAAAHAAAAcAAABwAAAOAA//8AD//wAP//AAAAAAAAAAAIAAAA4AAAD8AAAH+AAAH/AAAD/gAAB/AAAB8AAA/wAAf8AAP+AAD/AAAPgAAAwAAAAAAAAIAAAA8AAAD/AAAH/gAAD/wAAA/wAAA/AAAf8AAP+AAP+AAA/AAAD+AAAH/AAAD/gAAA/wAAA/AAAf8AAP/AAP/AAA/gAADgAAAAAAAAAAEADAAwAOAHAA+B8AB8PgAB74AAD/AAAH4AAA/wAAHvgAB8PgAPgfAA4AcADAAwAAABABAAAAHAAAAfgAAA/wAAA/wAwAf4fAAP/8AAP/AAB/gAA/wAAf4AAP+AAB/AAAHgAAAQAAAAAAEADAAwAOAPAA4B8ADgPwAOD/AA4ecADnxwAO8HAA/gcAD8BwAPAHAA4AcACAAwAAAAAAAAAAAAAAAAAAAAAAAAAA8AB////f//////n/+AAAA4AAADgAAAAAAAAAAAAAAAAAH///Af//8B///wAAAAAAAAAAAAAAAAAAA4AAADgAAAOAAAA//5/9////z////AAPAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPAAAB8AAAHwAAAcAAABwAAAHgAAAOAAAA8AAABwAAAHAAAB8AAAHwAAAeAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGAAAAYAAABgAAAGAAAAYAAABgAAAGAAAAYAAABgAAAGAAAAGAAABwAAAOAAABwAAAHAAAAcAAAA4AAABwAAABgAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAOAB4B4ADwPAAHh4AAPPAAAf4AAA/AAAB4AAAPwAAB/gAAPPAAB4eAAPA8AB4B4AHADgAIAEAAAAAAADAAAAMAAAAwAAADAAAAMAAAAwAAHDDgA8MPADww8AGDBgAAMAAAAwAAADAAAAMAAAAwAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADn//gOf/+A5//4AAAAAAAAAAAAAAAAAAAD/AAA//AAH/+AA+B8ADgBwAOAHAHwAPgfAA+B8AD4A4AcADwDwAHgeAAOBwAAQCAAAAAAAAAAAADgcAAOBwAA4HAD//8A///wD///AeDgcBwOBwHA4HAcDgcB4GBwD4AHAHgAcAOAAAAAAAAAAAAAMAGAB7+8AD//gAHx8AAcBwADgDgAOAOAA4A4ADgDgAOAOAA4A4ABwHAAHg8AA//4AH//wAMOGAAAAAAQAAABwAAAHwMYAPwxgAfjGAAfsYAAf7gAAf/wAB//AAf/8AH7GAA/MYAPwxgB8DGAHAAAAQAAAAAAAAAAAAAf/D/5/8P/n/w/+AAAAAAAAAAAAAAAAAAAABwAAffhwD//Hgf+cfBzwwcGHDhwYcOHBxw4cHDhxwfOPvA8//4Bx//AADwwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/wAAP/wAB//gAPAPAB4AOAPDw8A4/xwHH/jgc4HOBzgc4HMAzgcwDOBzgc4HPDjgOcOeA4whwBwAOAHwD4APw/AAf/4AAf+AAAPAAAAAAAATgAAD/AAANsAAA2wAADTAAAP8AAAfwAAAAAAAAAAAAAAAAAAgAAAPAAAB+AAAOeAADw8AAOIwAADxAAAfgAADngAA8PAADgMAAEAQAAAAAAAAAAABgAAAGAAAAYAAABgAAAGAAAAYAAABgAAAGAAAAYAAABgAAAGAAAAYAAAB+AAAH4AAAAAAAAAAAAAAAAAAAAD8AAA/8AAHh4AAYDgAD/3AAN/MAA0QwADRjAAN/MAA7hwABwOAADhwAAH+AAAPwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAfgAAD/AAAeeAABw4AAGDgAAYOAABw4AAH/AAAP8AAAfAAAAAAAAAAAAAAAAAAAwYAADBgAAMGAAAwYAADBgAAMGAAP+YAA/5gAD/mAAAwYAADBgAAMGAAAwYAADBgAAAAAAAAAAAAAAAMDAABwcAAPDwAAwPAADB8AAMOwAA5zAAB+MAADwwAAAAAAAAAAAIBAAAwGAADMcAANwwAA/DAAD8MAAO/wAAx+AAABgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAf///B///8H//AAAAeAAAA4AAADgAAAOAAAA4AAADgAAAcAB//gAH//gAf/+AAAAAAAAAAAAAAAAAAAAP4AAB/4AAP/gAB//AAH/8AAf/wAB//AAH///8f///x////AAAAAAAAAB////H///8f///wAAAAAAAAAAAAAAABAAAAOAAAB4AAADgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAAAzAAAPMAAA/wAAAeAAAAAAAAAAAAAAAAAAAIAAABgAAAMAAAA//AAD/8AAAAAAAAAAAAAAAAAAAAAA8AAAP4AAAwwAADDAAAMMAAA5wAAB+AAADwAAAAAAAAAAAAAAAAAMAwAA8HAAB44AAD/AAAD4AADGMAAOBwAAeOAAA/wAAA+AAABgAAAAAAAAAAAAAAABAAAAMAAABwAAAH/8CAf/wcAAAHgAAA8AAAHgAAB4AAAPAAAB4AAAeAAADwAAA+AAAHgCAA8A8APAfwB4H7AHB+MAAHAwAAQ/wAAD/AAAAwAAADAAAAAAAAAAAAAAAAAAAAEAAAAwAAAHAAAAf/wIB//BwAAAeAAADwAAAeAAAHgAAA8AAAHgAAB4AAAPAAAD4AAAeAAADwAAA8GAwHg4HAcHA8AAYHwABg7AAGHMAAf4wAA/DAAA4MAAAAAAAAAAYBgABgHAAGMOAAZwYABvBgAH8OCAe/wcBx+HgABg8AAAHgAAB4AAAPAAAB4AAAeAAADwAAA+AAAHgHAA8B8APAfwB4HzADB8MAAHAwAAQ/wAAD/AAAAwAAAAAAAAAAAAAAAAAA4AAAP4AAB/wAAPHgABwOA4/A4Dn4DgOfAOAAAA4AAAHgAAB8AAAHgAAAYAAAAAAAAEAAADwAAB/AAA/8AAf+AAP/gAH/OAB/g4AHwDgAfAOAB/g4AD/zgAA/+AAAf8AAAP+AAAH8AAADwAAABAAAAEAAADwAAB/AAA/8AAf+AAP/gAH/OAB/g4AHwDgAfAOAB/g4AD/zgAA/+AAAf8AAAP+AAAH8AAADwAAABAAAAEAAADwAAB/AAA/8AAf+AAP/gAH/OAB/g4AHwDgAfAOAB/g4AD/zgAA/+AAAf8AAAP+AAAH8AAADwAAABAAAAEAAADwAAB/AAA/8AAf+AAP/gAH/OAB/g4AHwDgAfAOAB/g4AD/zgAA/+AAAf8AAAP+AAAH8AAADwAAABAAAAEAAADwAAB/AAA/8AAf+AAP/gAH/OAB/g4AHwDgAfAOAB/g4AD/zgAA/+AAAf8AAAP+AAAH8AAADwAAABAAAAAAAAABwAAA/AAAf8AAP/AAH/wfD/nD+/wcMb4BwxvgHD+/wcHx/5wEAf/AAAP+AAAH/AAAD8AAABwAAAAAAAEAAADwAAB/AAA/8AAf+AAP/gAH/OAB/g4AHwDgAcAOABwA4AHADgAf//8B///wHA4HAcDgcBwOBwHA4HAcDgcBwOBwHA4HAcDgcBwOBwHAAHAYAAMAAAAAAAAAAA/4AAP/4AD//4APAHgB4APAPAAeA4AA4DgADg+AAPz4AA//gAD/+AAOe4AA4BwAHAHgA8APgPgAeA8AAYDAAAAAAAAAAAAAAAAf//8B///wH///AcDgcBwOBwHA4HAcDgcBwOBwHA4HAcDgcBwOBwHAAHAcAAcAAAAAAAAAAAAAAB///wH///Af//8BwOBwHA4HAcDgcBwOBwHA4HAcDgcBwOBwHA4HAcAAcBwABwAAAAAAAAAAAAAAH///Af//8B///wHA4HAcDgcBwOBwHA4HAcDgcBwOBwHA4HAcDgcBwABwHAAHAAAAAAAAAAAAAAAf//8B///wH///AcDgcBwOBwHA4HAcDgcBwOBwHA4HAcDgcBwOBwHAAHAcAAcAAAAAAAAAAAAAAB///wH///Af//8AAAAAAAAAAAAAAAAAAAH///Af//8B///wAAAAAAAAAAAAAAAAAAAf//8B///wH///AAAAAAAAAAAAAAAAAAAB///wH///Af//8AAAAAAAAAAABgAAAGAAH///Af//8B///wHAYHAcBgcBwGBwHAYHAcBgcBwABwHAAHAeAA8A8AHgB+D8AD//gAH/8AAD+AAAAAAAAAAAAAAAAf//8B///wH///APwAAAPgAAAfgAAAfAAAA/AAAA+AAAA+AAAB8AAAB8AAAD8B///wH///Af//8AAAAAAAAAAAf8AAH/8AB//8AHgDwA8AHgHgAPAcAAcBwABwHAAHAcAAcBwABwHAAHAcAAcA4ADgDwAeAH4PwAP/+AAf/wAAP4AAAAAAAH/AAB//AAf//AB4A8APAB4B4ADwHAAHAcAAcBwABwHAAHAcAAcBwABwHAAHAOAA4A8AHgB+D8AD//gAH/8AAD+AAAAAAAB/wAAf/wAH//wAeAPADwAeAeAA8BwABwHAAHAcAAcBwABwHAAHAcAAcBwABwDgAOAPAB4Afg/AA//4AB//AAA/gAAAAAAAf8AAH/8AB//8AHgDwA8AHgHgAPAcAAcBwABwHAAHAcAAcBwABwHAAHAcAAcA4ADgDwAeAH4PwAP/+AAf/wAAP4AAAAAAAH/AAB//AAf//AB4A8APAB4B4ADwHAAHAcAAcBwABwHAAHAcAAcBwABwHAAHAOAA4A8AHgB+D8AD//gAH/8AAD+AAAAAAAAAAAAGDgAA8eAAB7wAAD+AAAHwAAAfAAAD+AAAe8AADw4AAGBAAAAAAAAAAAAAAAAAf8MAH//4B///AHgD4A8AfgHgD/AcAecBwDxwHAeHAcDwcBw+BwHHgHAc8AcA/gDgD8AeAH4PwA//+AH//wAMP4AAAAAAAAAAAf//AB//+AH//8AAAB4AAADwAAAHAAAAcAAABwAAAHAAAAcAAABwAAAOAAAB4B///AH//4Af/+AAAAAAAAAAAAAAAAAAAAH//wAf//gB///AAAAeAAAA8AAABwAAAHAAAAcAAABwAAAHAAAAcAAADgAAAeAf//wB//+AH//gAAAAAAAAAAAAAAAAAAAB//8AH//4Af//wAAAHgAAAPAAAAcAAABwAAAHAAAAcAAABwAAAHAAAA4AAAHgH//8Af//gB//4AAAAAAAAAAAAAAAAAAAAf//AB//+AH//8AAAB4AAADwAAAHAAAAcAAABwAAAHAAAAcAAABwAAAOAAAB4B///AH//4Af/+AAAAAAAAAAAQAAABwAAAHwAAAPwAAAfwAAAfgAAAfgAAAf/wAB//AAf/8AH8AAA/AAAPwAAB8AAAHAAAAQAAAAAAAAAAAAAf//8B///wH///ABwHAAHAcAAcBwABwHAAHAcAAcBwABwHAAHg8AAP/gAAf8AAA/gAAAAAAAAAAAAAAAA///AP//8A///wHgAAAcAAcBwABwHBwHAcHAcB4+BwD/4PAH954APn/gAAP8AAAOAAAAAAAAAAAAAD4AAcfwADz/gAfOOCBww4PHHBg+ccGAZxw4AHHDAAcYcAA//gAD//gAD/+AAAAAAAAAAAAAAAAAPgABx/AAPP+AB844AHDDgAccGAZxwYPnHDg8ccMDBxhwAD/+AAP/+AAP/4AAAAAAAAAAAAAAAAA+AAHH8AA8/4BnzjgOcMOBxxwYOHHBg4ccOBxxwwDnGHAGP/4AA//4AA//gAAAAAAAAAAAAAAAAHwAA4/gAHn/A8+ccDzhhwMOODA444MBjjhwHOOGAM4w4Dx//AOH//AAH/8AAAAAAAAAAAAAAAAAfAADj+AAef8Bz5xwHOGHAc44MADjgwAOOHAY44YBzjDgHH/8AAf/8AAf/wAAAAAAAAAAAAAAAAAfAADj+AAef8AD5xweOGHD844MMzjgwzOOHD844YHjjDgAH/8AAf/8AAf/wAAAAAAAAAAAAAAAAHwAAx/gAHn/AAc4cADjhwAOMDAA4wcADjBwAOMHAA4w4AB//AAH/4AAP/wAB/fgAPMPAA4wcADjBwAOMHAA4wcADjBwAPMPAAfx4AA/HAAB8YAAAAAAAAAAAA/AAAP/AAB/+AAPA8AB4B4AHADgwcAPzBwA/8HADngcAOMB4B4ADwPAAHA4AAMDAAAAAAAAAAAAA/AAAP/AAB/+AAPY8AB5h4OHGDg+cYOB5xg4AnGDgAcYOAB5h4AD+PAAH44AAPjAAAGAAAAAAAAAAAAAPwAAD/wAAf/gAD2PAAeYeABxg4AHGDgOcYOD5xg4OHGDggeYeAA/jwAB+OAAD4wAABgAAAAAAAAAAAAD8AAA/8AAH/4AY9jwDnmHgecYODhxg4OHGDg8cYOB5xg4BnmHgCP48AAfjgAA+MAAAYAAAAAAAAAAAAB+AAAf+AAD/8Acex4BzzDwHOMHAA4wcADjBwAOMHAc4wcBzzDwGH8eAAPxwAAfGAAAMAAAAAAAAAAAOAAAA+f/+A5//4An//gAAAAAAAAAAAAAAAAAAAJ//4Dn//g+f/+DgAAAAAAAAMAAABwAAAOP//Aw//8Dj//wHAAAAMAAABwAAAHAAAAA//8AD//wAP//AcAAABwAAAAAAAAAA/gAAP/AAB//AAPA8AA4A4DDgDgPMAOA/wA4D7ADgPOAOB+8B4C/+/AA//4AB//AAAHAAAAAAAAAAAAP//AA//8Bx//wPHAAAw4AADjgAAGOAAAc4AAAzgAAPPAAA4f/8AA//wAB//AAAAAAAAAAAAAAAAA/AAAP/AAB/+AAPA8CB4B4OHADg+cAOA5wA4AHADgAcAOAB4B4AD4fAAH/4AAP/AAAPwAAAAAAAAAAAAPwAAD/wAAf/gADwPAAeAeABwA4AnADgecAOD5wA4OHADgAeAeAA+HwAB/+AAD/wAAD8AAAAAAAAAAAAD8AAA/8AAH/4AY8DwDngHgecAODhwA4OHADg8cAOB5wA4BngHgCPh8AAf/gAA/8AAA/AAAAAAAAAAAAB+AAAf+AAD/8AceB4DzwDwMOAHA44AcBjgBwHOAHAM4AcDzwDwOHw+AAP/wAAf+AAAfgAAAAAAAAAAAAfgAAH/gAA//AHHgeAc8A8BzgBwAOAHAA4AcADgBwHOAHAc8A8Bh8PgAD/8AAH/gAAH4AAAAAAAAAAAAMAAAAwAAADAAAAMAAAAwAAADAAADtwAAO3AAA7cAAAMAAAAwAAADAAAAMAAAAAAAAAAAAAH5gAB//AAP/4AB4PgAPB/AA4PcADh5wAOPHAA54cADvBwAP4PAAfD4AB//AAP/4AAZ+AAAAAAAAAAAAf8AAB//AAH//AAAH8AAAB4OAADg+AAOB4AA4AgADgAAAOAAABwAH//gAf/+AB//4AAAAAAAAAAAAAAAH/AAAf/wAB//wAAB/AAAAeAAAA4BgADgeAAOD4AA4MAADgAAAcAB//4AH//gAf/+AAAAAAAAAAAAAAAB/wAAH/8AAf/8AYAfwDgAHgcAAODgAA4OAADg8AAOB4AA4BgAHACf/+AB//4AH//gAAAAAAAAAAAAAAA/4AAD/+AAP/+AcAP4BwADwHAAHAAAAcAAABwAAAHAcAAcBwADgGP//AA//8AD//wAAAAAAAAAABAAAAHAAAAfgAAA/wAAA/wAAAf4cAAP/zgAP/+AB/jgA/wAAf4AAP+AAB/AAAHgAAAQAAAAAAAAAAAA//////////////A4BwAHADgAcAOABwA4AHADgAcAOAB4B4AD4fAAH/4AAP/AAAPwAAAAAABAAAAHAAAAfgAAw/wADg/wA+Af4fAAP/8AAP/AAB/g4A/wDgf4AOP+AAB/AAAHgAAAQAAA=='), + 32, + atob("BgkMGhEZEgYMDAwQCAwICxILEBAREBEOEREJCREVEQ8ZEhEUExAOFBQHDREPGBMUERQSEhEUERsREBIMCwwTEg4QERAREQoREQcHDgcYEREREQoPDBEPFg8PDwwIDBMcCgoAAAAAAAAAAAAAACERESEAAAAAAAAAAAAAAAAhIQAGCRAQEhAIDw8XCQ8RABIODRELCw4REwcLCQoPHBscDxISEhISEhoUEBAQEAcHBwcTExQUFBQUDhQUFBQUEBEREBAQEBAQGhARERERBwcHBxAREREREREPEREREREPEQ8="), + 28+(scale<<8)+(1<<16) + ); return this; }; -var imgLock = { - width : 16, height : 16, bpp : 1, - transparent : 0, - buffer : E.toArrayBuffer(atob("A8AH4A5wDDAYGBgYP/w//D/8Pnw+fD58Pnw//D/8P/w=")) -}; +function imgLock(){ + return { + width : 16, height : 16, bpp : 1, + transparent : 0, + buffer : E.toArrayBuffer(atob("A8AH4A5wDDAYGBgYP/w//D/8Pnw+fD58Pnw//D/8P/w=")) + } +} -var imgSteps = { - width : 24, height : 24, bpp : 1, - transparent : 1, - buffer : require("heatshrink").decompress(atob("/H///wv4CBn4CD8ACCj4IBj8f+Eeh/wjgCBngCCg/4nEH//4h/+jEP/gRBAQX+jkf/wgB//8GwP4FoICDHgICCBwIA==")) -}; +function imgSteps(){ + return { + width : 24, height : 24, bpp : 1, + transparent : 1, + buffer : require("heatshrink").decompress(atob("/H///wv4CBn4CD8ACCj4IBj8f+Eeh/wjgCBngCCg/4nEH//4h/+jEP/gRBAQX+jkf/wgB//8GwP4FoICDHgICCBwIA==")) + } +} -var imgBattery = { - width : 24, height : 24, bpp : 1, - transparent : 1, - buffer : require("heatshrink").decompress(atob("/4AN4EAg4TBgd///9oEAAQv8ARQRDDQQgCEwQ4OA")) -}; +function imgBattery(){ + return { + width : 24, height : 24, bpp : 1, + transparent : 1, + buffer : require("heatshrink").decompress(atob("/4AN4EAg4TBgd///9oEAAQv8ARQRDDQQgCEwQ4OA")) + } +} -var imgBpm = { - width : 24, height : 24, bpp : 1, - transparent : 1, - buffer : require("heatshrink").decompress(atob("/4AOn4CD/wCCjgCCv/8jF/wGYgOA5MB//BC4PDAQnjAQPnAQgANA")) -}; +function imgBpm() { + return { + width : 24, height : 24, bpp : 1, + transparent : 1, + buffer : require("heatshrink").decompress(atob("/4AOn4CD/wCCjgCCv/8jF/wGYgOA5MB//BC4PDAQnjAQPnAQgANA")) + } +} -var imgTemperature = { - width : 24, height : 24, bpp : 1, - transparent : 1, - buffer : require("heatshrink").decompress(atob("//D///wICBjACBngCNkgCP/0kv/+s1//nDn/8wICEBAIOC/08v//IYJECA==")) -}; +function imgTemperature() { + return { + width : 24, height : 24, bpp : 1, + transparent : 1, + buffer : require("heatshrink").decompress(atob("//D///wICBjACBngCNkgCP/0kv/+s1//nDn/8wICEBAIOC/08v//IYJECA==")) + } +} -var imgWind = { - width : 24, height : 24, bpp : 1, - transparent : 1, - buffer : require("heatshrink").decompress(atob("/0f//8h///Pn//zAQXzwf/88B//mvGAh18gEevn/DIICB/PwgEBAQMHBAIADFwM/wEAGAP/54CD84CE+eP//wIQU/A==")) -}; +function imgWind () { + return { + width : 24, height : 24, bpp : 1, + transparent : 1, + buffer : require("heatshrink").decompress(atob("/0f//8h///Pn//zAQXzwf/88B//mvGAh18gEevn/DIICB/PwgEBAQMHBAIADFwM/wEAGAP/54CD84CE+eP//wIQU/A==")) + } +} -var imgTimer = { - width : 24, height : 24, bpp : 1, - transparent : 1, - buffer : require("heatshrink").decompress(atob("/+B/4CD84CEBAPygFP+F+h/x/+P+fz5/n+HnAQNn5/wuYCBmYCC5kAAQfOgFz80As/ngHn+fD54mC/F+j/+gF/HAQA==")) -}; +function imgTimer() { + return { + width : 24, height : 24, bpp : 1, + transparent : 1, + buffer : require("heatshrink").decompress(atob("/+B/4CD84CEBAPygFP+F+h/x/+P+fz5/n+HnAQNn5/wuYCBmYCC5kAAQfOgFz80As/ngHn+fD54mC/F+j/+gF/HAQA==")) + } +} -var imgCharging = { - width : 24, height : 24, bpp : 1, - transparent : 1, - buffer : require("heatshrink").decompress(atob("//+v///k///4AQPwBANgBoMxBoMb/P+h/w/kH8H4gfB+EBwfggHH4EAt4CBn4CBj4CBh4FCCIO/8EB//Agf/wEH/8Gh//x////fAQIA=")) -}; +function imgCharging() { + return { + width : 24, height : 24, bpp : 1, + transparent : 1, + buffer : require("heatshrink").decompress(atob("//+v///k///4AQPwBANgBoMxBoMb/P+h/w/kH8H4gfB+EBwfggHH4EAt4CBn4CBj4CBh4FCCIO/8EB//Agf/wEH/8Gh//x////fAQIA=")) + } +} -var imgWatch = { - width : 24, height : 24, bpp : 1, - transparent : 1, - buffer : require("heatshrink").decompress(atob("/8B//+ARANB/l4//5/1/+f/n/n5+fAQnf9/P44CC8/n7/n+YOB/+fDQQgCEwQsCHBBEC")) -}; +function imgWatch() { + return { + width : 24, height : 24, bpp : 1, + transparent : 1, + buffer : require("heatshrink").decompress(atob("/8B//+ARANB/l4//5/1/+f/n/n5+fAQnf9/P44CC8/n7/n+YOB/+fDQQgCEwQsCHBBEC")) + } +} /* * INFO ENTRIES + * List of [Data, Icon, left/right, Function to execute] */ var infoArray = [ - function(){ return [ null, null, "left" ] }, - function(){ return [ "Bangle", imgWatch, "right" ] }, - function(){ return [ E.getBattery() + "%", imgBattery, "left" ] }, - function(){ return [ getSteps(), imgSteps, "left" ] }, - function(){ return [ Math.round(Bangle.getHealthStatus("last").bpm) + " bpm", imgBpm, "left"] }, - function(){ return [ getWeather().temp, imgTemperature, "left" ] }, - function(){ return [ getWeather().wind, imgWind, "left" ] }, + function(){ return [ null, null, "left", null ] }, + function(){ return [ "Bangle", imgWatch(), "right", null ] }, + function(){ return [ E.getBattery() + "%", imgBattery(), "left", null ] }, + function(){ return [ getSteps(), imgSteps(), "left", null ] }, + function(){ return [ Math.round(Bangle.getHealthStatus("last").bpm) + " bpm", imgBpm(), "left", null] }, + function(){ return [ getWeather().temp, imgTemperature(), "left", null ] }, + function(){ return [ getWeather().wind, imgWind(), "left", null ] }, ]; + +/* + * We append the HomeAssistant integrations if HomeAssistant is available + */ +try{ + var triggers = require("ha.lib.js").getTriggers(); + triggers.forEach(trigger => { + infoArray.push(function(){ + return [trigger.display, trigger.getIcon(), "left", function(){ + var ha = require("ha.lib.js"); + ha.sendTrigger("TRIGGER_BW"); + ha.sendTrigger(trigger.trigger); + }] + }); + }) +} catch(ex){ + // Nothing to do if HomeAssistant is not available... +} const NUM_INFO=infoArray.length; function getInfoEntry(){ if(isAlarmEnabled()){ - return [getAlarmMinutes() + " min.", imgTimer, "left"] + return [getAlarmMinutes() + " min.", imgTimer(), "left", null] } else if(Bangle.isCharging()){ - return [E.getBattery() + "%", imgCharging, "left"] + return [E.getBattery() + "%", imgCharging(), "left", null] } else{ + // In case the user removes HomeAssistant entries, showInfo + // could be larger than infoArray.length... + settings.showInfo = settings.showInfo % infoArray.length; return infoArray[settings.showInfo](); } } @@ -351,12 +396,14 @@ function drawTime(){ g.setSmallFont(); var imgWidth = 0; if(infoImg !== undefined){ - imgWidth = infoImg.width; + imgWidth = 26.0; var strWidth = g.stringWidth(infoStr); + var scale = imgWidth / infoImg.width; g.drawImage( infoImg, - W/2 + (printImgLeft ? -strWidth/2-2 : strWidth/2+2) - infoImg.width/2, - y - infoImg.height/2 + W/2 + (printImgLeft ? -strWidth/2-2 : strWidth/2+2) - parseInt(imgWidth/2), + y - parseInt(imgWidth/2), + { scale: scale } ); } g.drawString(infoStr, printImgLeft ? W/2 + imgWidth/2 + 2 : W/2 - imgWidth/2 - 2, y+3); @@ -366,7 +413,7 @@ function drawTime(){ function drawLock(){ if(settings.showLock && Bangle.isLocked()){ g.setColor(g.theme.fg); - g.drawImage(imgLock, W-16, 2); + g.drawImage(imgLock(), W-16, 2); } } @@ -420,15 +467,16 @@ Bangle.on('charging',function(charging) { }); Bangle.on('touch', function(btn, e){ - var left = parseInt(g.getWidth() * 0.2); + var left = parseInt(g.getWidth() * 0.3); var right = g.getWidth() - left; - var upper = parseInt(g.getHeight() * 0.2); + var upper = parseInt(g.getHeight() * 0.3); var lower = g.getHeight() - upper; var is_left = e.x < left; var is_right = e.x > right; var is_upper = e.y < upper; var is_lower = e.y > lower; + var is_center = !is_upper && !is_lower && !is_left && !is_right; if(is_upper){ Bangle.buzz(40, 0.6); @@ -454,11 +502,33 @@ Bangle.on('touch', function(btn, e){ settings.showInfo = settings.showInfo < 0 ? NUM_INFO-1 : settings.showInfo; drawTime(); } + + if(is_center){ + var infoEntry = getInfoEntry(); + var fun = infoEntry[3]; + if(fun != null){ + Bangle.buzz(80, 0.6).then(()=>{ + try{ + fun(); + setTimeout(()=>{ + Bangle.buzz(80, 0.6); + }, 250); + } catch(ex){ + // In case it fails, we simply ignore it. + } + } + ); + } + } }); E.on("kill", function(){ - storage.write(SETTINGS_FILE, settings); + try{ + storage.write(SETTINGS_FILE, settings); + } catch(ex){ + // If this fails, we still kill the app... + } }); diff --git a/apps/bwclk/metadata.json b/apps/bwclk/metadata.json index eba1449a6..834712743 100644 --- a/apps/bwclk/metadata.json +++ b/apps/bwclk/metadata.json @@ -1,11 +1,11 @@ { "id": "bwclk", "name": "BW Clock", - "version": "0.09", + "version": "0.11", "description": "BW Clock.", "readme": "README.md", "icon": "app.png", - "screenshots": [{"url":"screenshot.png"}, {"url":"screenshot_2.png"}, {"url":"screenshot_3.png"}], + "screenshots": [{"url":"screenshot.png"}, {"url":"screenshot_2.png"}, {"url":"screenshot_3.png"}, {"url":"screenshot_4.png"}], "type": "clock", "tags": "clock", "supports": ["BANGLEJS2"], diff --git a/apps/bwclk/screenshot_4.png b/apps/bwclk/screenshot_4.png new file mode 100644 index 000000000..3807d47ad Binary files /dev/null and b/apps/bwclk/screenshot_4.png differ diff --git a/apps/calendar/ChangeLog b/apps/calendar/ChangeLog index 873f90de6..0583ea45f 100644 --- a/apps/calendar/ChangeLog +++ b/apps/calendar/ChangeLog @@ -8,3 +8,4 @@ 0.08: Do not register as watch, manually start clock on button read start of week from system settings 0.09: Fix scope of let variables +0.10: Use default Bangle formatter for booleans diff --git a/apps/calendar/metadata.json b/apps/calendar/metadata.json index 65a54c097..48fd52d3e 100644 --- a/apps/calendar/metadata.json +++ b/apps/calendar/metadata.json @@ -1,7 +1,7 @@ { "id": "calendar", "name": "Calendar", - "version": "0.09", + "version": "0.10", "description": "Simple calendar", "icon": "calendar.png", "screenshots": [{"url":"screenshot_calendar.png"}], diff --git a/apps/calendar/settings.js b/apps/calendar/settings.js index 192d2ece0..54ed50a64 100644 --- a/apps/calendar/settings.js +++ b/apps/calendar/settings.js @@ -17,7 +17,6 @@ "< Back": () => back(), 'B2 Colors': { value: settings.ndColors, - format: v => v ? "Yes" : "No", onchange: v => { settings.ndColors = v; writeSettings(); diff --git a/apps/calibration/ChangeLog b/apps/calibration/ChangeLog index 0e22605af..64bff2b31 100644 --- a/apps/calibration/ChangeLog +++ b/apps/calibration/ChangeLog @@ -1,2 +1,3 @@ -1.00: New App! -1.01: Use fractional numbers and scale the points to keep working consistently on whole screen +0.01: New App! +0.02: Use fractional numbers and scale the points to keep working consistently on whole screen +0.03: Use default Bangle formatter for booleans diff --git a/apps/calibration/metadata.json b/apps/calibration/metadata.json index b7a719e1c..b60650300 100644 --- a/apps/calibration/metadata.json +++ b/apps/calibration/metadata.json @@ -2,7 +2,7 @@ "name": "Touchscreen Calibration", "shortName":"Calibration", "icon": "calibration.png", - "version":"1.01", + "version":"0.03", "description": "A simple calibration app for the touchscreen", "supports": ["BANGLEJS","BANGLEJS2"], "readme": "README.md", diff --git a/apps/calibration/settings.js b/apps/calibration/settings.js index 6db8dd3bb..08c728d96 100644 --- a/apps/calibration/settings.js +++ b/apps/calibration/settings.js @@ -13,7 +13,6 @@ "< Back" : () => back(), 'Active': { value: !!settings.active, - format: v => v? "On":"Off", onchange: v => { settings.active = v; writeSettings(); diff --git a/apps/chronowid/ChangeLog b/apps/chronowid/ChangeLog index ed230b737..08a9ac828 100644 --- a/apps/chronowid/ChangeLog +++ b/apps/chronowid/ChangeLog @@ -4,3 +4,4 @@ 0.04: Change to 7 segment font, move to top widget bar Better auto-update behaviour, less RAM used 0.05: Fix error running app on new firmwares (fix #1140) +0.06: Use default Bangle formatter for booleans diff --git a/apps/chronowid/app.js b/apps/chronowid/app.js index ab363ed17..b0ee7625a 100644 --- a/apps/chronowid/app.js +++ b/apps/chronowid/app.js @@ -79,7 +79,6 @@ function showMenu() { }, 'Timer on': { value: settingsChronowid.started, - format: v => v ? "On" : "Off", onchange: v => { settingsChronowid.started = v; updateSettings(); diff --git a/apps/chronowid/metadata.json b/apps/chronowid/metadata.json index 7cb32709f..69a5d3a2e 100644 --- a/apps/chronowid/metadata.json +++ b/apps/chronowid/metadata.json @@ -2,7 +2,7 @@ "id": "chronowid", "name": "Chrono Widget", "shortName": "Chrono Widget", - "version": "0.05", + "version": "0.06", "description": "Chronometer (timer) which runs as widget.", "icon": "app.png", "tags": "tool,widget", diff --git a/apps/circlesclock/ChangeLog b/apps/circlesclock/ChangeLog index c3e7918e7..c398a89b6 100644 --- a/apps/circlesclock/ChangeLog +++ b/apps/circlesclock/ChangeLog @@ -24,3 +24,5 @@ Improve performance, reduce memory usage Small optical adjustments 0.12: Allow configuration of update interval +0.13: Load step goal from Bangle health app as fallback + Memory optimizations diff --git a/apps/circlesclock/app.js b/apps/circlesclock/app.js index 48e3a1a1a..fc501a5d0 100644 --- a/apps/circlesclock/app.js +++ b/apps/circlesclock/app.js @@ -1,10 +1,5 @@ const locale = require("locale"); const storage = require("Storage"); -const SunCalc = require("https://raw.githubusercontent.com/mourner/suncalc/master/suncalc.js"); - -const shoesIcon = atob("EBCBAAAACAAcAB4AHgAeABwwADgGeAZ4AHgAMAAAAHAAIAAA"); -const temperatureIcon = atob("EBCBAAAAAYADwAJAAkADwAPAA8ADwAfgB+AH4AfgA8ABgAAA"); - Graphics.prototype.setFontRobotoRegular50NumericOnly = function(scale) { // Actual height 39 (40 - 2) this.setFontCustom(atob("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAAAAB8AAAAAAAfAAAAAAAPwAAAAAAB8AAAAAAAeAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAA4AAAAAAB+AAAAAAD/gAAAAAD/4AAAAAH/4AAAAAP/wAAAAAP/gAAAAAf/gAAAAAf/AAAAAA/+AAAAAB/+AAAAAB/8AAAAAD/4AAAAAH/4AAAAAD/wAAAAAA/wAAAAAAPgAAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA///wAAAB////gAAA////8AAA/////gAAP////8AAH8AAA/gAB8AAAD4AA+AAAAfAAPAAAADwADwAAAA8AA8AAAAPAAPAAAADwADwAAAA8AA8AAAAPAAPgAAAHwAB8AAAD4AAfwAAD+AAD/////AAA/////wAAH////4AAAf///4AAAB///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeAAAAAAAPgAAAAAADwAAAAAAB8AAAAAAAfAAAAAAAHgAAAAAAD4AAAAAAA+AAAAAAAPAAAAAAAH/////wAB/////8AA//////AAP/////wAD/////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOAAAAAAAfgAADwAAP4AAB8AAH+AAA/AAD/gAAfwAB/AAAf8AAfAAAP/AAPgAAH7wAD4AAD88AA8AAB+PAAPAAA/DwADwAAfg8AA8AAPwPAAPAAH4DwADwAH8A8AA+AD+APAAPwB/ADwAB/D/gA8AAf//gAPAAD//wADwAAf/wAA8AAD/4AAPAAAHwAADwAAAAAAA8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAADgAAAHwAA+AAAD8AAP4AAB/AAD/AAA/wAA/wAAf4AAD+AAHwAAAPgAD4APAB8AA+ADwAPAAPAA8ADwADwAPAA8AA8ADwAPAAPAA8ADwADwAfAA8AA8AH4APAAPgD+AHwAB8B/wD4AAf7/+B+AAD//v//AAA//x//wAAD/4P/4AAAf8B/4AAAAYAH4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPAAAAAAAHwAAAAAAH8AAAAAAD/AAAAAAD/wAAAAAD/8AAAAAB/vAAAAAB/jwAAAAA/g8AAAAA/wPAAAAAfwDwAAAAf4A8AAAAf4APAAAAP8ADwAAAP8AA8AAAH8AAPAAAD/////8AA//////AAP/////wAD/////8AA//////AAAAAAPAAAAAAADwAAAAAAA8AAAAAAAPAAAAAAADwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8AAAAB/APwAAH//wD+AAD//8A/wAA///AH+AAP//wAPgAD/B4AB8AA8A+AAfAAPAPAADwADwDwAA8AA8A8AAPAAPAPAADwADwD4AA8AA8A+AAPAAPAPwAHwADwD8AD4AA8AfwD+AAPAH///AADwA///wAA8AH//4AAPAAf/4AAAAAB/4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//AAAAAD//+AAAAD///4AAAD////AAAB////4AAA/78D/AAAfw8AH4AAPweAA+AAD4PgAHwAB8DwAA8AAfA8AAPAAHgPAADwAD4DwAA8AA+A8AAPAAPAPgAHwADwD4AB8AA8AfgA+AAPAH+B/gAAAA///wAAAAH//4AAAAA//8AAAAAH/8AAAAAAP4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwAAAAAAA8AAAAAAAPAAAAAAADwAAAAAAA8AAAABAAPAAAABwADwAAAB8AA8AAAB/AAPAAAB/wADwAAD/8AA8AAD/8AAPAAD/4AADwAD/4AAA8AD/4AAAPAH/wAAADwH/wAAAA8H/wAAAAPH/wAAAAD3/gAAAAA//gAAAAAP/gAAAAAD/gAAAAAA/AAAAAAAPAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwA/4AAAH/Af/AAAH/8P/4AAD//n//AAA//7//4AAfx/+A+AAHwD+AHwAD4AfgB8AA8AHwAPAAPAA8ADwADwAPAA8AA8ADwAPAAPAA8ADwADwAfAA8AA+AH4AfAAHwD+AHwAB/D/4D4AAP/+/n+AAD//n//AAAf/w//gAAB/wH/wAAAHwA/4AAAAAABgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB+AAAAAAD/8AAAAAD//wAAAAB//+AAAAA///wAAAAf4H+APAAH4AfgDwAD8AB8A8AA+AAfAPAAPAADwDwADwAA8B8AA8AAPAfAAPAADwHgADwAA8D4AA+AAeB+AAHwAHg/AAB+ADwfgAAP8D4/4AAD////8AAAf///8AAAB///+AAAAP//+AAAAAP/4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADgAAOAAAB8AAHwAAAfgAD8AAAH4AA/AAAB8AAHwAAAOAAA4AAAAAAAAAAAAAAAAAAAAAAAAAA"), 46, atob("DRUcHBwcHBwcHBwcDA=="), 50+(scale<<8)+(1<<16)); @@ -22,10 +17,16 @@ let settings = Object.assign( storage.readJSON("circlesclock.default.json", true) || {}, storage.readJSON(SETTINGS_FILE, true) || {} ); -// Load step goal from pedometer widget as fallback + +// Load step goal from health app and pedometer widget as fallback if (settings.stepGoal == undefined) { - const d = storage.readJSON("wpedom.json", true) || {}; - settings.stepGoal = d != undefined && d.settings != undefined ? d.settings.goal : 10000; + let d = storage.readJSON("health.json", true) || {}; + settings.stepGoal = d != undefined && d.settings != undefined ? d.settings.stepGoal : undefined; + + if (settings.stepGoal == undefined) { + d = storage.readJSON("wpedom.json", true) || {}; + settings.stepGoal = d != undefined && d.settings != undefined ? d.settings.goal : 10000; + } } /* @@ -125,20 +126,11 @@ function draw() { g.setFontAlign(0, 0); g.drawString(locale.date(new Date()), w / 2, h2); g.drawString(locale.dow(new Date()), w / 2, h2 + dowOffset); - - // draw the circles a little bit delayed so we decrease the blocking time - setTimeout(function() { - drawCircle(1); - }, 1); - setTimeout(function() { - drawCircle(2); - }, 1); - setTimeout(function() { - drawCircle(3); - }, 1); - setTimeout(function() { - if (circleCount >= 4) drawCircle(4); - }, 1); + + drawCircle(1); + drawCircle(2); + drawCircle(3); + if (circleCount >= 4) drawCircle(4); } function drawCircle(index) { @@ -294,7 +286,7 @@ function drawSteps(w) { writeCircleText(w, shortValue(steps)); - g.drawImage(getImage(shoesIcon, getCircleIconColor("steps", color, percent)), w - iconOffset, h3 + radiusOuter - iconOffset); + g.drawImage(getImage(atob("EBCBAAAACAAcAB4AHgAeABwwADgGeAZ4AHgAMAAAAHAAIAAA"), getCircleIconColor("steps", color, percent)), w - iconOffset, h3 + radiusOuter - iconOffset); } function drawStepsDistance(w) { @@ -319,7 +311,7 @@ function drawStepsDistance(w) { writeCircleText(w, shortValue(stepsDistance)); - g.drawImage(getImage(shoesIcon, getCircleIconColor("stepsDistance", color, percent)), w - iconOffset, h3 + radiusOuter - iconOffset); + g.drawImage(getImage(atob("EBCBAAAACAAcAB4AHgAeABwwADgGeAZ4AHgAMAAAAHAAIAAA"), getCircleIconColor("stepsDistance", color, percent)), w - iconOffset, h3 + radiusOuter - iconOffset); } function drawHeartRate(w) { @@ -490,8 +482,8 @@ function drawTemperature(w) { if (temperature) writeCircleText(w, locale.temp(temperature)); - - g.drawImage(getImage(temperatureIcon, getCircleIconColor("temperature", color, percent)), w - iconOffset, h3 + radiusOuter - iconOffset); + + g.drawImage(getImage(atob("EBCBAAAAAYADwAJAAkADwAPAA8ADwAfgB+AH4AfgA8ABgAAA"), getCircleIconColor("temperature", color, percent)), w - iconOffset, h3 + radiusOuter - iconOffset); }); } @@ -517,7 +509,7 @@ function drawPressure(w) { if (pressure) writeCircleText(w, Math.round(pressure)); - g.drawImage(getImage(temperatureIcon, getCircleIconColor("pressure", color, percent)), w - iconOffset, h3 + radiusOuter - iconOffset); + g.drawImage(getImage(atob("EBCBAAAAAYADwAJAAkADwAPAA8ADwAfgB+AH4AfgA8ABgAAA"), getCircleIconColor("pressure", color, percent)), w - iconOffset, h3 + radiusOuter - iconOffset); }); } @@ -543,7 +535,7 @@ function drawAltitude(w) { if (altitude) writeCircleText(w, locale.distance(Math.round(altitude))); - g.drawImage(getImage(temperatureIcon, getCircleIconColor("altitude", color, percent)), w - iconOffset, h3 + radiusOuter - iconOffset); + g.drawImage(getImage(atob("EBCBAAAAAYADwAJAAkADwAPAA8ADwAfgB+AH4AfgA8ABgAAA"), getCircleIconColor("altitude", color, percent)), w - iconOffset, h3 + radiusOuter - iconOffset); }); } @@ -614,8 +606,8 @@ function getWeatherIconByCode(code) { default: return weatherCloudy; } - default: - return undefined; + default: + return undefined; } } @@ -641,6 +633,7 @@ function formatSeconds(s) { function getSunData() { if (location != undefined && location.lat != undefined) { + const SunCalc = require("https://raw.githubusercontent.com/mourner/suncalc/master/suncalc.js"); // get today's sunlight times for lat/lon return SunCalc ? SunCalc.getTimes(new Date(), location.lat, location.lon) : undefined; } diff --git a/apps/circlesclock/metadata.json b/apps/circlesclock/metadata.json index c35d99334..837fcaa88 100644 --- a/apps/circlesclock/metadata.json +++ b/apps/circlesclock/metadata.json @@ -1,7 +1,7 @@ { "id": "circlesclock", "name": "Circles clock", "shortName":"Circles clock", - "version":"0.12", + "version":"0.13", "description": "A clock with three or four circles for different data at the bottom in a probably familiar style", "icon": "app.png", "screenshots": [{"url":"screenshot-dark.png"}, {"url":"screenshot-light.png"}, {"url":"screenshot-dark-4.png"}, {"url":"screenshot-light-4.png"}], diff --git a/apps/clockcal/ChangeLog b/apps/clockcal/ChangeLog index 8b40a87ac..20a46b5b7 100644 --- a/apps/clockcal/ChangeLog +++ b/apps/clockcal/ChangeLog @@ -1,3 +1,4 @@ 0.01: Initial upload 0.02: Added scrollable calendar and swipe gestures 0.03: Configurable drag gestures +0.04: Use default Bangle formatter for booleans diff --git a/apps/clockcal/metadata.json b/apps/clockcal/metadata.json index 3998215d7..6d547a7a3 100644 --- a/apps/clockcal/metadata.json +++ b/apps/clockcal/metadata.json @@ -1,7 +1,7 @@ { "id": "clockcal", "name": "Clock & Calendar", - "version": "0.03", + "version": "0.04", "description": "Clock with Calendar", "readme":"README.md", "icon": "app.png", diff --git a/apps/clockcal/settings.js b/apps/clockcal/settings.js index abedad99b..d4cc4df68 100644 --- a/apps/clockcal/settings.js +++ b/apps/clockcal/settings.js @@ -26,7 +26,6 @@ "< Back": () => back(), 'Buzz(dis)conn.?': { value: settings.BUZZ_ON_BT, - format: v => v ? "On" : "Off", onchange: v => { settings.BUZZ_ON_BT = v; writeSettings(); @@ -59,7 +58,6 @@ }, 'Red Saturday?': { value: settings.REDSAT, - format: v => v ? "On" : "Off", onchange: v => { settings.REDSAT = v; writeSettings(); @@ -67,7 +65,6 @@ }, 'Red Sunday?': { value: settings.REDSUN, - format: v => v ? "On" : "Off", onchange: v => { settings.REDSUN = v; writeSettings(); diff --git a/apps/coretemp/ChangeLog b/apps/coretemp/ChangeLog index ad6f0742d..7386bbc35 100644 --- a/apps/coretemp/ChangeLog +++ b/apps/coretemp/ChangeLog @@ -1,3 +1,4 @@ 0.01: New app 0.02: Cleanup interface and add settings, widget, add skin temp reporting. 0.03: Move code for recording to this app +0.04: Use default Bangle formatter for booleans diff --git a/apps/coretemp/metadata.json b/apps/coretemp/metadata.json index cb12624ae..87cb42722 100644 --- a/apps/coretemp/metadata.json +++ b/apps/coretemp/metadata.json @@ -1,7 +1,7 @@ { "id": "coretemp", "name": "CoreTemp", - "version": "0.03", + "version": "0.04", "description": "Display CoreTemp device sensor data", "icon": "coretemp.png", "type": "app", diff --git a/apps/coretemp/settings.js b/apps/coretemp/settings.js index 3fc2dfbf2..23ea09167 100644 --- a/apps/coretemp/settings.js +++ b/apps/coretemp/settings.js @@ -35,7 +35,6 @@ const menu = { '< Back' : back, 'Enabled' : { value : !!s.enabled, - format : v => v ? "Yes" : "No", onchange : v => { s.enabled = v; updateSettings(); diff --git a/apps/daisy/ChangeLog b/apps/daisy/ChangeLog index d5844c62b..829ff3d13 100644 --- a/apps/daisy/ChangeLog +++ b/apps/daisy/ChangeLog @@ -4,3 +4,4 @@ 0.04: added heart rate which is switched on when cycled to it through up/down touch on rhs 0.05: changed text to uppercase, just looks better, removed colons on text 0.06: better contrast for light theme, use fg color instead of dithered for ring +0.07: Use default Bangle formatter for booleans diff --git a/apps/daisy/metadata.json b/apps/daisy/metadata.json index 5073db603..802ba6834 100644 --- a/apps/daisy/metadata.json +++ b/apps/daisy/metadata.json @@ -1,6 +1,6 @@ { "id": "daisy", "name": "Daisy", - "version":"0.06", + "version":"0.07", "dependencies": {"mylocation":"app"}, "description": "A beautiful digital clock with large ring guage, idle timer and a cyclic information line that includes, day, date, steps, battery, sunrise and sunset times", "icon": "app.png", diff --git a/apps/daisy/settings.js b/apps/daisy/settings.js index 044eee0d1..6397a81f4 100644 --- a/apps/daisy/settings.js +++ b/apps/daisy/settings.js @@ -41,7 +41,6 @@ }, 'Idle Warning': { value: !!s.idle_check, - format: v => v ? /*LANG*/"Yes":/*LANG*/"No", onchange: v => { s.idle_check = v; save(); diff --git a/apps/dane_tcr/ChangeLog b/apps/dane_tcr/ChangeLog index 4f6fe2edc..69424b1f4 100644 --- a/apps/dane_tcr/ChangeLog +++ b/apps/dane_tcr/ChangeLog @@ -4,4 +4,5 @@ 0.04: Move code to Arwes Module 0.05: Add icon 0.06: remove app image as it is unused -0.07: Bump version number for change to apps.json causing 404 on upload \ No newline at end of file +0.07: Bump version number for change to apps.json causing 404 on upload +0.08: Use default Bangle formatter for booleans diff --git a/apps/dane_tcr/metadata.json b/apps/dane_tcr/metadata.json index 817d0c59b..5527c846d 100644 --- a/apps/dane_tcr/metadata.json +++ b/apps/dane_tcr/metadata.json @@ -2,7 +2,7 @@ "id": "dane_tcr", "name": "DANE Touch Launcher", "shortName": "DANE Toucher", - "version": "0.07", + "version": "0.08", "description": "Touch enable left to right launcher in the style of the DANE Watchface", "icon": "app.png", "type": "launch", diff --git a/apps/dane_tcr/settings.js b/apps/dane_tcr/settings.js index 9d28d1b30..46988ec26 100644 --- a/apps/dane_tcr/settings.js +++ b/apps/dane_tcr/settings.js @@ -41,7 +41,6 @@ }, "Animation" : { value : settings.animation, - format : v => v?"On":"Off", onchange : saveChange('animation') }, "Frame rate" : { @@ -51,7 +50,6 @@ }, "Debug" : { value : settings.debug, - format : v => v?"On":"Off", onchange : saveChange('debug') }, '< Back': back diff --git a/apps/dtlaunch/ChangeLog b/apps/dtlaunch/ChangeLog index a360e4875..16c550334 100644 --- a/apps/dtlaunch/ChangeLog +++ b/apps/dtlaunch/ChangeLog @@ -13,3 +13,4 @@ 0.13: Added swipeExit setting so that left-right to exit is an option 0.14: Don't move pages when doing exit swipe - Bangle 2. 0.15: 'Swipe to exit'-code is slightly altered to be more reliable - Bangle 2. +0.16: Use default Bangle formatter for booleans diff --git a/apps/dtlaunch/metadata.json b/apps/dtlaunch/metadata.json index 9711a6964..36728f342 100644 --- a/apps/dtlaunch/metadata.json +++ b/apps/dtlaunch/metadata.json @@ -1,7 +1,7 @@ { "id": "dtlaunch", "name": "Desktop Launcher", - "version": "0.15", + "version": "0.16", "description": "Desktop style App Launcher with six (four for Bangle 2) apps per page - fast access if you have lots of apps installed.", "screenshots": [{"url":"shot1.png"},{"url":"shot2.png"},{"url":"shot3.png"}], "icon": "icon.png", diff --git a/apps/dtlaunch/settings-b1.js b/apps/dtlaunch/settings-b1.js index f3101da16..fe5546edb 100644 --- a/apps/dtlaunch/settings-b1.js +++ b/apps/dtlaunch/settings-b1.js @@ -15,7 +15,6 @@ "< Back" : () => back(), 'Show clocks': { value: settings.showClocks, - format: v => v?"On":"Off", onchange: v => { settings.showClocks = v; writeSettings(); @@ -23,7 +22,6 @@ }, 'Show launchers': { value: settings.showLaunchers, - format: v => v?"On":"Off", onchange: v => { settings.showLaunchers = v; writeSettings(); diff --git a/apps/dtlaunch/settings-b2.js b/apps/dtlaunch/settings-b2.js index 7ead63be0..fac9c0fff 100644 --- a/apps/dtlaunch/settings-b2.js +++ b/apps/dtlaunch/settings-b2.js @@ -18,7 +18,6 @@ "< Back" : () => back(), 'Show clocks': { value: settings.showClocks, - format: v => v?"On":"Off", onchange: v => { settings.showClocks = v; writeSettings(); @@ -26,7 +25,6 @@ }, 'Show launchers': { value: settings.showLaunchers, - format: v => v?"On":"Off", onchange: v => { settings.showLaunchers = v; writeSettings(); @@ -34,7 +32,6 @@ }, 'Direct launch': { value: settings.direct, - format: v => v?"On":"Off", onchange: v => { settings.direct = v; writeSettings(); @@ -42,7 +39,6 @@ }, 'Swipe Exit': { value: settings.swipeExit, - format: v => v?"On":"Off", onchange: v => { settings.swipeExit = v; writeSettings(); @@ -50,7 +46,6 @@ }, 'One click exit': { value: settings.oneClickExit, - format: v => v?"On":"Off", onchange: v => { settings.oneClickExit = v; writeSettings(); diff --git a/apps/dvdbounce/ChangeLog b/apps/dvdbounce/ChangeLog new file mode 100644 index 000000000..6d1dc4ce4 --- /dev/null +++ b/apps/dvdbounce/ChangeLog @@ -0,0 +1 @@ +0.01: Created the app. The logo bounces and buzz when it hits the angles. diff --git a/apps/dvdbounce/README.md b/apps/dvdbounce/README.md new file mode 100644 index 000000000..50f3ef0e9 --- /dev/null +++ b/apps/dvdbounce/README.md @@ -0,0 +1,9 @@ +# Bouncing DVD logo + +Have you ever wanted to admire the bouncing DVD logo on your watch? Now you can! Let's hope it touches an angle. + +![Gif of the DVD logo bouncing around](screenshot.gif) + +## Creator + +I'm [TrinTragula](https://github.com/TrinTragula) on Github. Feel free to reach me. \ No newline at end of file diff --git a/apps/dvdbounce/dvdbounce-icon.js b/apps/dvdbounce/dvdbounce-icon.js new file mode 100644 index 000000000..0625c2394 --- /dev/null +++ b/apps/dvdbounce/dvdbounce-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwwhC/AH4A/AH4A/ACWIAA4MJwAXPhALKC5AlCBZYADE4gXELQ4SDC4gCBC4IDCAwYTEBAghCBYYCEC5YUFAooOIBBAKDMwwIFCwQIDNIZtGTRANEEIiyMVYrYHLIq0GQA4OGABIPPAA77GC8CDGABAfFBAbpCAIIfCAQqmJhAXDhB4CCIMIEgIYETAoaCC5zYHIIRQDDATAKPJasWAH4A/AH4A/AE4")) \ No newline at end of file diff --git a/apps/dvdbounce/dvdbounce.app.js b/apps/dvdbounce/dvdbounce.app.js new file mode 100644 index 000000000..39037df34 --- /dev/null +++ b/apps/dvdbounce/dvdbounce.app.js @@ -0,0 +1,108 @@ +// The DVD logo +var dvdLogo = require("heatshrink").decompress(atob("3dTwIFC/4AG/ALCgYJEwAcDj4XHBgYJF4AJCg4WH8AMCn4KFF4YWH/wLCh4KJIpA7CgIKG+BnHOg1/BYxGCCw4LDHQ/8IpQ6CQBBRBIpBpDBY4uCKA6jDUQy8FTIn3EQYIBGYSQDBYTVF/x0DKITMGFwh4D96jDKILuDDoSvDEAn9AQIeDB4glCwA5ELwW/FIRNB/x2BVQSvDHIgIB+ZvCNwWPOwZ7DAYKEFDwJoBAYPhHgYeC8ADCP4QEB85YCEQRFELoIqBBA5oFL4SMEwBFEBAWfDwQFB4K1EJoPwIooIB+InCHIQ8EOgYIHA4PAIQP8IogqCBYQIFw4TBAoRICIoQiB/AaDBAfwJAOAUwTrEFQZFHAQPwCYPwCIIxBWIZFIwICBSIIKBIo4IHFYXgSwRFKBARFCFYLlC8DDCRZTaDOIPPHgngaIhFFBoQfB/YhCIojRDBAg/B/gaCGYRFEHgaUED4IEBD4JBDIAIDBLgQEBIoYbC4AMCHAQcBG4IbCAgJFDCQRlBJIIzCIogJCBAgWCD4IICHARFDCwQIEIAY7DGYRmBEAIWCBAJOCNwYfBPAQSBEIWDMog8DAAQfBUYYzEAATkCBAq+CGgQzEYQgIGD4Q3CGYJnDKYhFGCwLtEVAjQDIow2BawY8HNQQIFCwR0CfYgWFBAoWDEAJ5CIogWCIooHCEAR5CJQQWFIoYPCOgg0BHgiJBIooHDUYaCCIoRLCABl/CB4AFg5MFACBNGAB8fQYYARgL/CACc/CysHLisAuAWVhgWVgL/BCyn/WyX/AAx4Mv4VHAARLJFZAAEbA5VBABwWFh4WPJAs/CZoODOA3A/8H/k//BNBK4N/AQQPB/wWF/kf4P/w4jBg4+BKIMAgYuC/BEF4P4n/w//gEIPwCYJYBCAYLBT4f4n0P/0f/k+g/+FoPwn4uDHQYACwZFB4ZHB8A2BKAQYBCAXwW4nwuF//BCBFgJ3CwZ/BCAR1BUIkEJYJHCFgINB+F/GgIAC4BLENgXhI4J5B8BfCI4KMEFwY0BKoK6BvwSDYoIoDCAIuE8APBXQMPwJaC/kPDALqEGgf8NAK6NAoLpDTYS6CCAKCCAoK+BCwhYBMYQiBXQOALQQ2BAQQWFXggAMGoIAECx6gBAArVEABJDDAAhQDABCTBABIYJ4AVKAAbCDChYA=")); + +// Screen width +const WIDTH = g.getWidth(); +// Screen height +const HEIGHT = g.getHeight(); +// dvd logo image width +const IMG_WIDTH = 94; +/// dvd logo image height +const IMG_HEIGHT = 42; + +// Assign a random X and Y initial speed between 1.5 and 1 +var speedX = 1.5 - Math.random() / 2; +var speedY = 1.5 - Math.random() / 2; +// The logo X and Y position +var posX = 0; +var posY = 0; + +// The current logo color +var currentColor = "#ff00ff"; + +// Get a random value between "ff" and "00" +function getHexColor() { + if (Math.round(Math.random())) { + return "ff"; + } else { + return "00"; + } +} + +// Get a new 8 bit color +function getNewColor() { + return "#" + getHexColor() + getHexColor() + getHexColor(); +} + +// Change the dvd logo color on impact +// Only allow colors different from the current one +// and different from the bg +function changeColor() { + var newColor = getNewColor(); + while (newColor == currentColor || newColor == "#000000") { + newColor = getNewColor(); + } + currentColor = newColor; + g.setColor(newColor); +} + +// Draw the logo +function draw() { + // Move it + posX += speedX; + posY += speedY; + + var collisions = 0; + // Collision detection + if (posX <= 0) { + speedX = -speedX; + posX = 0; + collisions++; + } + if (posY <= 0) { + speedY = -speedY; + posY = 0; + collisions++; + } + if (posX >= (WIDTH - IMG_WIDTH)) { + speedX = -speedX; + posX = WIDTH - IMG_WIDTH; + collisions++; + } + if (posY >= (HEIGHT - IMG_HEIGHT)) { + speedY = -speedY; + posY = HEIGHT - IMG_HEIGHT; + collisions++; + } + + // If we detected 2 collisions, we touched an angle, HURRAY! + if (collisions > 1) { + Bangle.buzz(); + } + + // Change logo color on collision + if (collisions > 0) { + changeColor(); + } + + // Actually draw the logo + g.clear(); + g.drawImage(dvdLogo, posX, posY, { + scale: 0.5 + }); + setTimeout(function () { + draw(); + }, 15); +} + +// Set the background to black +g.setBgColor(0, 0, 0); +// Start from purple +g.setColor(currentColor); +// Clear the screen +g.clear(); +// Start drawing +draw(); + +// Exit on button press +setWatch(Bangle.showLauncher, BTN, { repeat: false, edge: "falling" }); diff --git a/apps/dvdbounce/dvdbounce.png b/apps/dvdbounce/dvdbounce.png new file mode 100644 index 000000000..a44e7a4ba Binary files /dev/null and b/apps/dvdbounce/dvdbounce.png differ diff --git a/apps/dvdbounce/metadata.json b/apps/dvdbounce/metadata.json new file mode 100644 index 000000000..f1c3e8343 --- /dev/null +++ b/apps/dvdbounce/metadata.json @@ -0,0 +1,31 @@ +{ + "id": "dvdbounce", + "name": "Bouncing DVD logo", + "shortName": "Bouncing DVD", + "version": "0.01", + "description": "Have you ever wanted to admire the bouncing DVD logo on your watch? Now you can! Let's hope it touches an angle.", + "icon": "dvdbounce.png", + "tags": "game", + "supports": [ + "BANGLEJS", + "BANGLEJS2" + ], + "readme": "README.md", + "allow_emulator": true, + "storage": [ + { + "name": "dvdbounce.app.js", + "url": "dvdbounce.app.js" + }, + { + "name": "dvdbounce.img", + "url": "dvdbounce-icon.js", + "evaluate": true + } + ], + "screenshots": [ + { + "url": "screenshot.gif" + } + ] +} \ No newline at end of file diff --git a/apps/dvdbounce/screenshot.gif b/apps/dvdbounce/screenshot.gif new file mode 100644 index 000000000..6c82438bc Binary files /dev/null and b/apps/dvdbounce/screenshot.gif differ diff --git a/apps/files/files.js b/apps/files/files.js index e7b42c101..e81e9589f 100644 --- a/apps/files/files.js +++ b/apps/files/files.js @@ -1,7 +1,5 @@ const store = require('Storage'); -const boolFormat = (v) => v ? "On" : "Off"; - function showMainMenu() { const mainmenu = { '': { diff --git a/apps/football/metadata.json b/apps/football/metadata.json index 253026c39..43e7ac1bf 100644 --- a/apps/football/metadata.json +++ b/apps/football/metadata.json @@ -2,7 +2,7 @@ "id": "football", "name": "football", "shortName": "football", - "version": "1.00", + "version": "1.01", "type": "app", "description": "Classic football game of the CASIO chronometer", "icon": "app.png", diff --git a/apps/game1024/ChangeLog b/apps/game1024/ChangeLog index 800fa6b9d..df36b6456 100644 --- a/apps/game1024/ChangeLog +++ b/apps/game1024/ChangeLog @@ -8,3 +8,4 @@ 0.08: Bug fix at end of the game with victorious splash and glorious orchestra 0.09: Added settings menu, removed symbol selection button (*), added highscore reset 0.10: fixed clockmode in settings +0.11: Use default Bangle formatter for booleans diff --git a/apps/game1024/metadata.json b/apps/game1024/metadata.json index 728b5dc0e..f3b72aad3 100644 --- a/apps/game1024/metadata.json +++ b/apps/game1024/metadata.json @@ -1,7 +1,7 @@ { "id": "game1024", "name": "1024 Game", "shortName" : "1024 Game", - "version": "0.10", + "version": "0.11", "icon": "game1024.png", "screenshots": [ {"url":"screenshot.png" } ], "readme":"README.md", diff --git a/apps/game1024/settings.js b/apps/game1024/settings.js index 24a972600..b52e060b1 100644 --- a/apps/game1024/settings.js +++ b/apps/game1024/settings.js @@ -32,7 +32,7 @@ } }, "Exit press:": { - value: !settings.clockMode, // ! converts undefined to true + value: !settings.clockMode, format: v => v?"short":"long", onchange: v => { settings.clockMode = v; @@ -40,8 +40,7 @@ }, }, "Debug mode:": { - value: !!settings.debugMode, // !! converts undefined to false - format: v => v?"On":"Off", + value: !!settings.debugMode, onchange: v => { settings.debugMode = v; writeSettings(); diff --git a/apps/gbmusic/ChangeLog b/apps/gbmusic/ChangeLog index e2ee53ede..d8379b317 100644 --- a/apps/gbmusic/ChangeLog +++ b/apps/gbmusic/ChangeLog @@ -9,3 +9,4 @@ 0.09: Move event listener from widget to boot code, stops music from showing up in messages 0.10: Simplify touch events Remove date+time +0.11: Use default Bangle formatter for booleans diff --git a/apps/gbmusic/metadata.json b/apps/gbmusic/metadata.json index 0ded80452..bbe2a158d 100644 --- a/apps/gbmusic/metadata.json +++ b/apps/gbmusic/metadata.json @@ -2,7 +2,7 @@ "id": "gbmusic", "name": "Gadgetbridge Music Controls", "shortName": "Music Controls", - "version": "0.10", + "version": "0.11", "description": "Control the music on your Gadgetbridge-connected phone", "icon": "icon.png", "screenshots": [{"url":"screenshot_v1_d.png"},{"url":"screenshot_v1_l.png"}, diff --git a/apps/gbmusic/settings.js b/apps/gbmusic/settings.js index ae013fda5..6619eab1c 100644 --- a/apps/gbmusic/settings.js +++ b/apps/gbmusic/settings.js @@ -25,19 +25,16 @@ } } - const yesNo = (v) => translate(v ? "Yes" : "No"); let menu = { "": {"title": "Music Control"}, }; menu[translate("< Back")] = back; menu[translate("Auto start")] = { value: !!s.autoStart, - format: yesNo, onchange: save("autoStart"), }; menu[translate("Simple button")] = { value: !!s.simpleButton, - format: yesNo, onchange: save("simpleButton"), }; diff --git a/apps/gbridge/ChangeLog b/apps/gbridge/ChangeLog index 059767ece..f707ffb94 100644 --- a/apps/gbridge/ChangeLog +++ b/apps/gbridge/ChangeLog @@ -27,3 +27,4 @@ 0.25: workaround call notification Fix inflated step number 0.26: Include charging status in battery updates to phone +0.27: Use default Bangle formatter for booleans diff --git a/apps/gbridge/metadata.json b/apps/gbridge/metadata.json index db7119758..e6130b06b 100644 --- a/apps/gbridge/metadata.json +++ b/apps/gbridge/metadata.json @@ -1,7 +1,7 @@ { "id": "gbridge", "name": "Gadgetbridge", - "version": "0.26", + "version": "0.27", "description": "(NOT RECOMMENDED) Displays Gadgetbridge notifications from Android. Please use the 'Android Integration' Bangle.js app instead.", "icon": "app.png", "type": "widget", diff --git a/apps/gbridge/settings.js b/apps/gbridge/settings.js index f9c7cde90..cf6c84c73 100644 --- a/apps/gbridge/settings.js +++ b/apps/gbridge/settings.js @@ -27,13 +27,11 @@ "Connected" : { value : NRF.getSecurityStatus().connected?"Yes":"No" }, "Show Icon" : { value: settings().showIcon, - format: v => v?"Yes":"No", onchange: setIcon }, "Find Phone" : function() { E.showMenu(findPhone); }, "Record HRM" : { value: !!settings().hrm, - format: v => v?"Yes":"No", onchange: v => updateSetting('hrm', v) } }; diff --git a/apps/gpsautotime/ChangeLog b/apps/gpsautotime/ChangeLog index 97b80ecdf..de7af4fc7 100644 --- a/apps/gpsautotime/ChangeLog +++ b/apps/gpsautotime/ChangeLog @@ -1,3 +1,4 @@ 0.01: New App! 0.02: Set Bangle.js 2 compatible 0.03: Add setting to hide the widget +0.04: Use default Bangle formatter for booleans diff --git a/apps/gpsautotime/metadata.json b/apps/gpsautotime/metadata.json index 217a27931..c852c6a3e 100644 --- a/apps/gpsautotime/metadata.json +++ b/apps/gpsautotime/metadata.json @@ -2,7 +2,7 @@ "id": "gpsautotime", "name": "GPS auto time", "shortName": "GPS auto time", - "version": "0.03", + "version": "0.04", "description": "A widget that automatically updates the Bangle.js time to the GPS time whenever there is a valid GPS fix.", "icon": "widget.png", "type": "widget", diff --git a/apps/gpsautotime/settings.js b/apps/gpsautotime/settings.js index dbdd121d1..be6e3bbec 100644 --- a/apps/gpsautotime/settings.js +++ b/apps/gpsautotime/settings.js @@ -13,9 +13,8 @@ E.showMenu({ "" : { "title" : "GPS auto time" }, "< Back" : () => back(), - 'Show widget?': { - value: !!settings.show, // !! converts undefined to false - format: v => v?"Show":"Hide", + 'Show Widgets': { + value: !!settings.show, onchange: v => { settings.show = v; writeSettings(); diff --git a/apps/gpsrec/ChangeLog b/apps/gpsrec/ChangeLog index f923739f0..5867140fb 100644 --- a/apps/gpsrec/ChangeLog +++ b/apps/gpsrec/ChangeLog @@ -30,3 +30,4 @@ 0.26: Multiple bugfixes 0.27: Map drawing with light theme (fix #1023) 0.28: Show distance more accurately in conjunction with new locale app (fix #1523) +0.29: Use default Bangle formatter for booleans diff --git a/apps/gpsrec/app.js b/apps/gpsrec/app.js index 4595f616d..acd5433b2 100644 --- a/apps/gpsrec/app.js +++ b/apps/gpsrec/app.js @@ -22,7 +22,6 @@ function showMainMenu() { '': { 'title': 'GPS Record' }, 'RECORD': { value: !!settings.recording, - format: v=>v?"On":"Off", onchange: v => { settings.recording = v; updateSettings(); diff --git a/apps/gpsrec/metadata.json b/apps/gpsrec/metadata.json index c870157df..192b05edf 100644 --- a/apps/gpsrec/metadata.json +++ b/apps/gpsrec/metadata.json @@ -1,7 +1,7 @@ { "id": "gpsrec", "name": "GPS Recorder", - "version": "0.28", + "version": "0.29", "description": "(NOT RECOMMENDED) - please use the more flexible 'Recorder' app instead. Application that allows you to record a GPS track. Can run in background", "icon": "app.png", "tags": "tool,outdoors,gps,widget", diff --git a/apps/ha/ChangeLog b/apps/ha/ChangeLog new file mode 100644 index 000000000..e78b4ccd0 --- /dev/null +++ b/apps/ha/ChangeLog @@ -0,0 +1,2 @@ +0.01: Release +0.02: Includeas the ha.lib.js library that can be used by other apps or clocks. \ No newline at end of file diff --git a/apps/ha/README.md b/apps/ha/README.md new file mode 100644 index 000000000..654a262c8 --- /dev/null +++ b/apps/ha/README.md @@ -0,0 +1,90 @@ +# Home Assistant +This app integrates your BangleJs into the HomeAssistant. + + +# How to use +Click on the left and right side of the screen to select the triggers that you +configured. Click in the middle of the screen to send the trigger to HomeAssistant. + +![](screenshot.png) + + +# Initial Setup +1.) First of all, make sure that HomeAssistant and the HomeAssistant Android App works. + +2.) Open your BangleJs Gadgetbridge App, click on the Settings icon of your BangleJs and enable "Allow Intent Access" + +3.) Enable sensor in HomeAssistant Andoird App/Configuration/Companion App/Manage Sensors/LastUpdate Trigger + +4.) At the bottom of the same screen click on "Add New Intent" and enter "com.espruino.gadgetbridge.banglejs.HA" + +5.) The HomeAssistant Android app must be restarted in order to listen for those actions + -- a "Force Stop" is necessary (through Android App settings) or restart your phone! + +This setup must be done only once -- now you are ready to configure your BangleJS to +control some devices or entities in your HomeAssistant :) + + +# Setup Trigger +1.) Upload the app and all corresponding triggers through the AppStore UI. You must specify +the display name, the trigger as well as an icon. +The following icons are currently supported: +- ha (default) +- light +- door +- fire + + +2.) Create an "automation" in the HomeAssistant WebUI for each trigger that you created on your BangleJs in order to tell HomeAssistant what you want to control. A sample configuration is shown in the image below -- I use this trigger to open the door: + +![](ha_automation.png) + +3.) Don't forget to select the action that should be executed at the bottom of each automation. + + +# Default Trigger +This app also implements two default trigger that can always be used: +- APP_STARTED -- Will be sent whenever the app is started. So you could do some actions already when the app is sarted without the need of any user interaction. +- TRIGGER -- Will be sent whenever some trigger is executed. So you could generically listen to that. + + +# How to use the library (ha.lib.js) in my own app/clk +This app inlcludes a library that can be used by other apps or clocks +to read all configured intents or to send a trigger. Example code: + +```js +// First of all impport the library +var ha = require("ha.lib.js"); + +// You can read all triggers that a user configured simply via +var triggers = ha.getTriggers(); + +// Get display name and icon of trigger +var display = triggers[0].display; +var icon = triggers[0].getIcon(); + +// Trigger the first configured trigger +ha.sendTrigger(triggers[0].trigger); + +// Send a custom trigger that is not configured by a user +ha.sendTrigger("MY_CUSTOM_TRIGGER"); +``` + + +# FAQ + +## Sometimes the trigger is not executed +While playing and testing a bit I found that it is very important that you allow the android HomeAssistant app, as well as BangleJs Gadgetbridge app to (1) run in background and (2), disable energy optimizations for both apps. +Otherwise, Android could stop one of both apps and the trigger will never be sent to HomeAssistant... + +If you still have problems, you can try another trick: +Install "MacroDroid" from the Android AppStore and start the HomeAssistant App +each time the "com.espruino.gadgetbridge.banglejs.HA" intent is send together +with the extra trigger: APP_STARTED. Then whenever you open the app on your BangleJs +it is ensured that HomeAssistant is running... + +## Thanks to +Icons created by Flaticon + +## Creator +- [David Peer](https://github.com/peerdavid). diff --git a/apps/ha/custom.html b/apps/ha/custom.html new file mode 100644 index 000000000..49f5a2eb8 --- /dev/null +++ b/apps/ha/custom.html @@ -0,0 +1,51 @@ + + + + + +

Upload Tigger

+

+

+ + + + + + diff --git a/apps/ha/ha.app.js b/apps/ha/ha.app.js new file mode 100644 index 000000000..d9199fb0e --- /dev/null +++ b/apps/ha/ha.app.js @@ -0,0 +1,75 @@ +/** + * This app uses the ha library to send trigger to HomeAssistant. + */ +var ha = require("ha.lib.js"); +var W = g.getWidth(), H = g.getHeight(); +var position=0; +var triggers = ha.getTriggers(); + + +function draw() { + g.reset().clearRect(Bangle.appRect); + + var h = 22; + g.setFont("Vector", h); + var trigger = triggers[position]; + var w = g.stringWidth(trigger.display); + + g.setFontAlign(-1,-1); + var icon = trigger.getIcon(); + g.setColor(g.theme.fg).drawImage(icon, 12, H/5-2); + g.drawString("Home", icon.width + 20, H/5); + g.drawString("Assistant", icon.width + 18, H/5+24); + + g.setFontAlign(0,0); + var ypos = H/5*3+20; + g.drawRect(W/2-w/2-8, ypos-h/2-8, W/2+w/2+5, ypos+h/2+5); + g.fillRect(W/2-w/2-6, ypos-h/2-6, W/2+w/2+3, ypos+h/2+3); + g.setColor(g.theme.bg).drawString(trigger.display, W/2, ypos); +} + + +Bangle.on('touch', function(btn, e){ + var left = parseInt(g.getWidth() * 0.3); + var right = g.getWidth() - left; + var isLeft = e.x < left; + var isRight = e.x > right; + + if(isRight){ + Bangle.buzz(40, 0.6); + position += 1; + position = position >= triggers.length ? 0 : position; + draw(); + } + + if(isLeft){ + Bangle.buzz(40, 0.6); + position -= 1; + position = position < 0 ? triggers.length-1 : position; + draw(); + } + + if(!isRight && !isLeft){ + ha.sendTrigger("TRIGGER"); + + // Now send the selected trigger + Bangle.buzz(80, 0.6).then(()=>{ + ha.sendTrigger(triggers[position].trigger); + setTimeout(()=>{ + Bangle.buzz(80, 0.6); + }, 250); + }); + } +}); + + +// Send intent that the we started the app. +ha.sendTrigger("APP_STARTED"); + +// Next load the widgets and draw the app +Bangle.loadWidgets(); +Bangle.drawWidgets(); + +// Draw app +draw(); +setWatch(_=>load(), BTN1); diff --git a/apps/ha/ha.icon.js b/apps/ha/ha.icon.js new file mode 100644 index 000000000..9bf6af796 --- /dev/null +++ b/apps/ha/ha.icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwwIjggOAAocH8AFDh/wAocfAok//gFDv/+Aof+vwoD/Ef3gFBgfwh4YCg/xx4FCh/z54FCj4LEn4XEv4jBGAX//k//4uBAokDAofAg/wnk8h/gLoIFE8ccnHH+Ef8+cnPn/EAAoYvB8ARBg4FB+EMmEPAoP4gkgj5BCwA+BAoXAHwIFC8EHAoZfBAoZfBAoZZDAsgAiA==")) \ No newline at end of file diff --git a/apps/ha/ha.lib.js b/apps/ha/ha.lib.js new file mode 100644 index 000000000..b09cbeab2 --- /dev/null +++ b/apps/ha/ha.lib.js @@ -0,0 +1,80 @@ +/** + * This library can be used to read all triggers that a user + * configured and send a trigger to homeassistant. + */ +function _getIcon(trigger){ + icon = trigger.icon; + if(icon == "light"){ + return { + width : 48, height : 48, bpp : 1, + transparent : 0, + buffer : require("heatshrink").decompress(atob("AAMBwAFE4AFDgYFJjgFBnAFBjwXBvAFBh4jBuAFCAQPwAQMHAQPgEQQCBEgcf/AvDn/8Aof//5GDAoJOBh+BAoOB+EP8YFB4fwgfnAoPnGANHAoPjHYQFBHYQFd44pDg47C4/gh/DIIZNFLIplGgF//wFIgZ9BRIUHRII7Ch4FBUIUOAoKzCjwFEhgCBmDpIVooFFh4oCAA4LFC5b7BAob1BAYI=")) + }; + } else if(icon == "door"){ + return { + width : 48, height : 48, bpp : 1, + transparent : 0, + buffer : require("heatshrink").decompress(atob("AAM4Aok/4AED///Aov4Aon8DgQGBAv4FpnIFKJv4FweAQFFAgQFB8AFDnADC")) + }; + } else if (icon == "fire"){ + return { + width : 48, height : 48, bpp : 1, + transparent : 0, + buffer : require("heatshrink").decompress(atob("ABsDAokBwAFE4AFE8AFE+AFE/AFJgf8Aon+AocHAokP/8QAokYAoUfAok//88ApF//4kDAo//AgMQAgIFCjgFEjwFCOYIFFHQIFDn/+AoJ/BAoIqBAoN//xCBAoI5BDIPAgP//gFB8AFChYFBgf//EJAogOBAoSgBAoMHAQIFEFgXAAoJEBv4FCNoQFGVYd/wAFEYYIFIvwCBDoV8UwQCBcgUPwDwDfQMBaIYADA")) + }; + } + + // Default is always the HA icon + return { + width : 48, height : 48, bpp : 1, + transparent : 0, + buffer : require("heatshrink").decompress(atob("AD8BwAFDg/gAocP+AFDj4FEn/8Aod//wFD/1+FAf4j+8AoMD+EPDAUH+OPAoUP+fPAoUfBYk/C4l/EYIwC//8n//FwIFEgYFD4EH+E8nkP8BdBAonjjk44/wj/nzk58/4gAFDF4PgCIMHAoPwhkwh4FB/EEkEfIIWAHwIFC4A+BAoXgg4FDL4IFDL4IFDLIYFkAEQA==")) + }; +} + +exports.getTriggers = function(){ + var triggers = [ + {display: "Empty", trigger: "NOP", icon: "ha"}, + ]; + + try{ + triggers = require("Storage").read("ha.trigger.json"); + triggers = JSON.parse(triggers); + + // We lazy load all icons, otherwise, we have to keep + // all the icons n times in memory which can be + // problematic for embedded devices. Therefore, + // we lazy load icons only if needed using the getIcon + // method of each trigger... + triggers.forEach(trigger => { + trigger.getIcon = function(){ + return _getIcon(trigger); + } + }) + } catch(e) { + // In case there are no user triggers yet, we show the default... + } + + return triggers; +} + +exports.sendTrigger = function(triggerName){ + var retries=3; + + while(retries > 0){ + try{ + // Now lets send the trigger that we sould send. + Bluetooth.println(JSON.stringify({ + t:"intent", + action:"com.espruino.gadgetbridge.banglejs.HA", + extra:{ + trigger: triggerName + }}) + ); + retries = -1; + + } catch(e){ + retries--; + } + } +} \ No newline at end of file diff --git a/apps/ha/ha.png b/apps/ha/ha.png new file mode 100644 index 000000000..8fce958e4 Binary files /dev/null and b/apps/ha/ha.png differ diff --git a/apps/ha/ha_automation.png b/apps/ha/ha_automation.png new file mode 100644 index 000000000..9372cfa15 Binary files /dev/null and b/apps/ha/ha_automation.png differ diff --git a/apps/ha/metadata.json b/apps/ha/metadata.json new file mode 100644 index 000000000..63308b933 --- /dev/null +++ b/apps/ha/metadata.json @@ -0,0 +1,25 @@ +{ + "id": "ha", + "name": "HomeAssistant", + "version": "0.02", + "description": "Integrates your BangleJS into HomeAssistant.", + "icon": "ha.png", + "type": "app", + "tags": "tool", + "readme": "README.md", + "supports": ["BANGLEJS2"], + "custom": "custom.html", + "screenshots": [ + {"url":"screenshot.png"}, + {"url":"screenshot_2.png"}, + {"url":"screenshot_3.png"} + ], + "data": [ + {"name":"ha.trigger.json" } + ], + "storage": [ + {"name":"ha.app.js","url":"ha.app.js"}, + {"name":"ha.lib.js","url":"ha.lib.js"}, + {"name":"ha.img","url":"ha.icon.js","evaluate":true} + ] +} diff --git a/apps/ha/screenshot.png b/apps/ha/screenshot.png new file mode 100644 index 000000000..dc059e2de Binary files /dev/null and b/apps/ha/screenshot.png differ diff --git a/apps/ha/screenshot_2.png b/apps/ha/screenshot_2.png new file mode 100644 index 000000000..55019c3b1 Binary files /dev/null and b/apps/ha/screenshot_2.png differ diff --git a/apps/ha/screenshot_3.png b/apps/ha/screenshot_3.png new file mode 100644 index 000000000..b9eae0b74 Binary files /dev/null and b/apps/ha/screenshot_3.png differ diff --git a/apps/hardalarm/ChangeLog b/apps/hardalarm/ChangeLog index dac7d317e..fea8770fc 100644 --- a/apps/hardalarm/ChangeLog +++ b/apps/hardalarm/ChangeLog @@ -1,3 +1,4 @@ 0.01: Add a number to match to turn off alarm 0.02: Respect Quiet Mode 0.03: Fix hour/minute wrapping code for new menu system +0.04: Use default Bangle formatter for booleans diff --git a/apps/hardalarm/app.js b/apps/hardalarm/app.js index 0c72a2c8f..0aa33b21b 100644 --- a/apps/hardalarm/app.js +++ b/apps/hardalarm/app.js @@ -66,17 +66,14 @@ function editAlarm(alarmIndex) { }, /*LANG*/'Enabled': { value: en, - format: v=>v?"On":"Off", onchange: v=>en=v }, /*LANG*/'Repeat': { value: en, - format: v=>v?"Yes":"No", onchange: v=>repeat=v }, /*LANG*/'Auto snooze': { value: as, - format: v=>v?"Yes":"No", onchange: v=>as=v } }; diff --git a/apps/hardalarm/metadata.json b/apps/hardalarm/metadata.json index 1dab4501d..df287b426 100644 --- a/apps/hardalarm/metadata.json +++ b/apps/hardalarm/metadata.json @@ -2,7 +2,7 @@ "id": "hardalarm", "name": "Hard Alarm", "shortName": "HardAlarm", - "version": "0.03", + "version": "0.04", "description": "Make sure you wake up! Count to the right number to turn off the alarm", "icon": "app.png", "tags": "tool,alarm,widget", diff --git a/apps/heart/ChangeLog b/apps/heart/ChangeLog index f6fd9793e..fe03575c9 100644 --- a/apps/heart/ChangeLog +++ b/apps/heart/ChangeLog @@ -11,5 +11,6 @@ Reduce memory usage by ~30% Generate scale based on defined minimum and maximum measurement Added background line on 50% to ease estimation of drawn values -0.06: tag HRM power requests to allow this ot work alongside other widgets/apps (fix #799) -0.07: theme support +0.06: Tag HRM power requests to allow this ot work alongside other widgets/apps (fix #799) +0.07: Theme support +0.08: Use default Bangle formatter for booleans diff --git a/apps/heart/app.js b/apps/heart/app.js index 5428ea06b..c10185b5f 100644 --- a/apps/heart/app.js +++ b/apps/heart/app.js @@ -28,7 +28,6 @@ function showMainMenu() { '': { 'title': 'Heart Recorder' }, 'RECORD': { value: !!settings.isRecording, - format: v=>v?"On":"Off", onchange: v => { settings.isRecording = v; updateSettings(); diff --git a/apps/heart/metadata.json b/apps/heart/metadata.json index 6265dbfef..2071bdf08 100644 --- a/apps/heart/metadata.json +++ b/apps/heart/metadata.json @@ -2,7 +2,7 @@ "id": "heart", "name": "Heart Rate Recorder", "shortName": "HRM Record", - "version": "0.07", + "version": "0.08", "description": "Application that allows you to record your heart rate. Can run in background", "icon": "app.png", "tags": "tool,health,widget", diff --git a/apps/hebrew_calendar/customizer.html b/apps/hebrew_calendar/customizer.html index bea860e53..c6d529414 100644 --- a/apps/hebrew_calendar/customizer.html +++ b/apps/hebrew_calendar/customizer.html @@ -7,6 +7,333 @@ Hebrew Calendar Customizer + + @@ -20,11 +347,15 @@
- + - -
get your latitude and longitude from plus.codes or:
- + +
get your latitude and longitude from plus.codes or: +
+
- - diff --git a/apps/hebrew_calendar/customizer.mjs b/apps/hebrew_calendar/customizer.mjs deleted file mode 100644 index 06716a63b..000000000 --- a/apps/hebrew_calendar/customizer.mjs +++ /dev/null @@ -1,329 +0,0 @@ -import { - HebrewCalendar, - HDate, - Location, - Zmanim, -} from "https://cdn.skypack.dev/@hebcal/core@^3?min"; - -function onload(event) { - event.preventDefault(); - const latLon = getLatLonFromForm(); - const events = generateHebCal(latLon); - const calendar = serializeEvents(events); - console.debug(calendar); - globalThis["cal"] = calendar; - loadWatch(calendar); -} - -function loadWatch(json) { - sendCustomizedApp({ - id: "hebrew_calendar", - - storage: [ - { - name: "hebrew_calendar.app.js", - url: "app.js", - // content below is same as app.js except for the first line which customizes the hebrewCalendar object used - content: ` -let hebrewCalendar = ${json}; - -const dayInMS = 86400000; - -const DateProvider = { now: () => Date.now() }; - -const Layout = require("Layout"); -const Locale = require("locale"); - -let nextEndingEvent; - -function getCurrentEvents() { - const now = DateProvider.now(); - - const current = hebrewCalendar.filter( - (x) => x.startEvent <= now && x.endEvent >= now - ); - - nextEndingEvent = current.reduce((acc, ev) => { - return Math.min(acc, ev.endEvent); - }, Infinity); - - return current.map((event, i) => { - return { - type: "txt", - font: "12x20", - id: "currentEvents" + i, - label: event.desc, - pad: 2, - bgCol: g.theme.bg, - }; - }); -} - -function getUpcomingEvents() { - const now = DateProvider.now(); - - const futureEvents = hebrewCalendar.filter( - (x) => x.startEvent >= now && x.startEvent <= now + dayInMS - ); - - let warning; - let eventsLeft = hebrewCalendar.filter( - (x) => x.startEvent >= now && x.startEvent <= now + dayInMS * 14 - ).length; - - if (eventsLeft < 14) { - warning = { - startEvent: 0, - type: "txt", - font: "4x6", - id: "warning", - label: "only " + eventsLeft + " events left in calendar; update soon", - pad: 2, - bgCol: g.theme.bg, - }; - } - - return futureEvents - .slice(0, 2) - .map((event, i) => { - return { - startEvent: event.startEvent, - type: "txt", - font: "6x8", - id: "upcomingEvents" + 1, - label: event.desc + " at " + Locale.time(new Date(event.startEvent), 1), - pad: 2, - bgCol: g.theme.bg, - }; - }) - .concat(warning) - .sort(function (a, b) { - return a.startEvent - b.startEvent; - }); -} - -function dateTime() { - return ( - Locale.dow(new Date(), 1) + - " " + - Locale.date(new Date(), 1) + - " " + - Locale.time(new Date(), 1) - ); -} - -function makeLayout() { - return new Layout( - { - type: "v", - c: [ - { - type: "txt", - font: "6x8", - id: "title", - label: "-- Hebrew Calendar Events --", - pad: 2, - bgCol: g.theme.bg2, - }, - { - type: "txt", - font: "6x8", - id: "currently", - label: "Currently", - pad: 2, - bgCol: g.theme.bgH, - }, - ] - .concat(getCurrentEvents()) - .concat([ - { - type: "txt", - font: "6x8", - label: "Upcoming", - id: "upcoming", - pad: 2, - bgCol: g.theme.bgH, - }, - ]) - .concat(getUpcomingEvents()) - .concat([ - { - type: "txt", - font: "Vector14", - id: "time", - label: dateTime(), - pad: 2, - bgCol: undefined, - }, - ]), - }, - { lazy: true } - ); -} -let layout = makeLayout(); -// see also https://www.espruino.com/Bangle.js+Layout#updating-the-screen - -// timeout used to update every minute -let drawTimeout; - -function draw() { - layout.time.label = dateTime(); - layout.render(); - - // schedule a draw for the next minute - if (drawTimeout) clearTimeout(drawTimeout); - drawTimeout = setTimeout(function () { - drawTimeout = undefined; - draw(); - }, 60000 - (DateProvider.now() % 60000)); - console.log("updated time"); -} - -// update time and draw -g.clear(); -Bangle.loadWidgets(); -Bangle.drawWidgets(); -draw(); - -function findNextEvent() { - return hebrewCalendar.find((ev) => { - return ev.startEvent > DateProvider.now(); - }); -} - -function updateCalendar() { - layout.clear(); - layout = makeLayout(); - layout.forgetLazyState(); - layout.render(); - - let nextChange = Math.min( - findNextEvent().startEvent - DateProvider.now() + 5000, - nextEndingEvent - DateProvider.now() + 5000 - ); - setTimeout(updateCalendar, nextChange); - console.log("updated events"); -} - -updateCalendar(); - -Bangle.setUI("clock"); - `, - }, - ], - }); -} - -document - .querySelector("button[type=submit]") - .addEventListener("click", onload, false); - -document.querySelector("#geoloc")?.addEventListener("click", (event) => { - event.preventDefault(); - navigator.geolocation.getCurrentPosition( - (pos) => { - const { - coords: { latitude, longitude }, - } = pos; - locationElements[0].value = latitude; - locationElements[1].value = longitude; - console.debug(pos); - }, - (err) => { - if (err.PERMISSION_DENIED) { - alert("permission required to use geolocation api; enter manually"); - } - if (err.POSITION_UNAVAILABLE) { - alert("position unavailable; enter manually"); - } - }, - { enableHighAccuracy: false } - ); -}); - -document.querySelector( - "#hDate" -).innerText = `Today is ${new Date().toLocaleDateString()} & ${new HDate().toString()}`; - -const locationElements = [ - document.querySelector("#lat"), - document.querySelector("#lon"), -]; - -function getLatLonFromForm() { - const latLon = locationElements.map((el) => el.value); - if (locationElements.every((x) => x.checkValidity())) { - return latLon; - } else { - console.debug("lat lon invalid error"); - return [0, 0]; - } -} - -function groupBy(arr, fn) { - return arr - .map(typeof fn === "function" ? fn : (val) => val[fn]) - .reduce((acc, val, i) => { - acc[val] = (acc[val] || []).concat(arr[i]); - return acc; - }, {}); -} - -function generateHebCal(latLon) { - const location = new Location( - ...latLon, - document.querySelector("#inIL").checked - ); - - const now = new Date(); - - const options = { - year: now.getFullYear(), - isHebrewYear: false, - candlelighting: true, - location, - addHebrewDates: true, - addHebrewDatesForEvents: true, - sedrot: true, - start: now, - end: new Date(now.getFullYear(), now.getMonth() + 3), - }; - - const events = HebrewCalendar.calendar(options).map((ev) => { - const { desc, eventTime, startEvent, endEvent } = ev; - - const zman = new Zmanim(ev.date, ...latLon.map(Number)); - - let output = { - desc, - startEvent: startEvent?.eventTime?.getTime() || zman.gregEve().getTime(), - endEvent: endEvent?.eventTime?.getTime() || zman.shkiah().getTime(), - }; - - if (eventTime) { - delete output.startEvent; - delete output.endEvent; - output.startEvent = eventTime.getTime(); - output.endEvent = eventTime.getTime() + 60000 * 15; - } - - return output; - }); - - // console.table(events) - - return events.sort((a, b) => { - return a.startEvent - b.startEvent; - }); -} - -function enc(data) { - return btoa(heatshrink.compress(new TextEncoder().encode(data))); -} - -function serializeEvents(events) { - // const splitByGregorianMonth = groupBy(events, (evt) => { - // return new Date(evt.startEvent).getMonth(); - // }); - return JSON.stringify(events); -} diff --git a/apps/hralarm/ChangeLog b/apps/hralarm/ChangeLog index 4c21f3ace..11e79d703 100644 --- a/apps/hralarm/ChangeLog +++ b/apps/hralarm/ChangeLog @@ -1 +1,2 @@ 0.01: New Widget! +0.02: Use default Bangle formatter for booleans diff --git a/apps/hralarm/metadata.json b/apps/hralarm/metadata.json index 1fae68084..4c661b3fc 100644 --- a/apps/hralarm/metadata.json +++ b/apps/hralarm/metadata.json @@ -2,7 +2,7 @@ "id": "hralarm", "name": "Heart rate alarm", "shortName":"HR Alarm", - "version":"0.01", + "version":"0.02", "description": "This invisible widget vibrates whenever the heart rate gets close to the upper limit or goes over or under the configured limits", "icon": "widget.png", "type": "widget", diff --git a/apps/hralarm/settings.js b/apps/hralarm/settings.js index 3158ab8b7..02cdccdaf 100644 --- a/apps/hralarm/settings.js +++ b/apps/hralarm/settings.js @@ -17,7 +17,6 @@ '< Back': back, 'Enabled': { value: !!settings.enabled, - format: v => settings.enabled ? "On" : "Off", onchange: v => { settings.enabled = v; writeSettings(); diff --git a/apps/hrm/ChangeLog b/apps/hrm/ChangeLog index f05a9dc13..62956e8cd 100644 --- a/apps/hrm/ChangeLog +++ b/apps/hrm/ChangeLog @@ -7,3 +7,4 @@ 0.07: Update scaling for new firmware 0.08: Don't force backlight on/watch unlocked on Bangle 2 0.09: Grey out BPM until confidence is over 50% +0.10: Autoscale raw graph to maximum value seen diff --git a/apps/hrm/heartrate.js b/apps/hrm/heartrate.js index 703b60c01..386341e6d 100644 --- a/apps/hrm/heartrate.js +++ b/apps/hrm/heartrate.js @@ -4,7 +4,7 @@ if (process.env.HWVERSION == 1) { } Bangle.setHRMPower(1); -var hrmInfo, hrmOffset = 0; +var hrmInfo = {}, hrmOffset = 0; var hrmInterval; var btm = g.getHeight()-1; var lastHrmPt = []; // last xy coords we draw a line to @@ -29,19 +29,34 @@ function onHRM(h) { hrmInterval = setInterval(readHRM,41); }, 40); } + updateHrm(); +} +Bangle.on('HRM', onHRM); +function updateHrm(){ var px = g.getWidth()/2; - g.setFontAlign(0,0); + g.setFontAlign(0,-1); g.clearRect(0,24,g.getWidth(),80); - g.setFont("6x8").drawString("Confidence "+hrmInfo.confidence+"%", px, 75); - var str = hrmInfo.bpm; + g.setFont("6x8").drawString("Confidence "+(hrmInfo.confidence || "--")+"%", px, 70); + + updateScale(); + + g.setFontAlign(0,0); + var str = hrmInfo.bpm || "--"; g.setFontVector(40).setColor(hrmInfo.confidence > 50 ? g.theme.fg : "#888").drawString(str,px,45); px += g.stringWidth(str)/2; g.setFont("6x8").setColor(g.theme.fg); g.drawString("BPM",px+15,45); } -Bangle.on('HRM', onHRM); +function updateScale(){ + g.setFontAlign(-1,-1); + g.clearRect(2,70,40,78); + g.setFont("6x8").drawString(scale, 2, 70); +} + +var rawMax = 0; +var scale = 2000; var MID = (g.getHeight()+80)/2; /* On newer (2v10) firmwares we can subscribe to get HRM events as they happen */ @@ -49,19 +64,27 @@ Bangle.on('HRM-raw', function(v) { h=v; hrmOffset++; if (hrmOffset>g.getWidth()) { - hrmOffset=0; + let thousands = Math.round(rawMax / 1000) * 1000; + if (thousands > scale) scale = thousands; + g.clearRect(0,80,g.getWidth(),g.getHeight()); + updateScale(); + + hrmOffset=0; lastHrmPt = [-100,0]; } - - y = E.clip(btm-(8+v.filt/2000),btm-16,btm); + if (rawMax < v.raw) { + rawMax = v.raw; + } + y = E.clip(btm-(8+v.filt/3000),btm-24,btm); g.setColor(1,0,0).fillRect(hrmOffset,btm, hrmOffset, y); - y = E.clip(btm - (v.raw/45),84,btm); + y = E.clip(btm - (v.raw/scale*84),84,btm); g.setColor(g.theme.fg).drawLine(lastHrmPt[0],lastHrmPt[1],hrmOffset, y); lastHrmPt = [hrmOffset, y]; if (counter !==undefined) { counter = undefined; g.clearRect(0,24,g.getWidth(),g.getHeight()); + updateHrm(); } }); @@ -76,7 +99,8 @@ function countDown() { g.clear(); Bangle.loadWidgets(); Bangle.drawWidgets(); -g.reset().setFont("6x8",2).setFontAlign(0,0); +g.setColor(g.theme.fg); +g.reset().setFont("6x8",2).setFontAlign(0,-1); g.drawString("Please wait...",g.getWidth()/2,g.getHeight()/2 - 16); countDown(); diff --git a/apps/hrm/metadata.json b/apps/hrm/metadata.json index 10821d094..c5a5f4f4d 100644 --- a/apps/hrm/metadata.json +++ b/apps/hrm/metadata.json @@ -1,7 +1,7 @@ { "id": "hrm", "name": "Heart Rate Monitor", - "version": "0.09", + "version": "0.10", "description": "Measure your heart rate and see live sensor data", "icon": "heartrate.png", "tags": "health", diff --git a/apps/hrmaccevents/ChangeLog b/apps/hrmaccevents/ChangeLog index 5560f00bc..2748e5f62 100644 --- a/apps/hrmaccevents/ChangeLog +++ b/apps/hrmaccevents/ChangeLog @@ -1 +1,3 @@ 0.01: New App! +0.02: Show status info on display + Allow recording to Bangle diff --git a/apps/hrmaccevents/README.md b/apps/hrmaccevents/README.md new file mode 100644 index 000000000..9c131cfd8 --- /dev/null +++ b/apps/hrmaccevents/README.md @@ -0,0 +1,18 @@ +# Record HRM and accelerometer events + +Record events as they happen via bluetooth or to a file. +This app can use [BTHRM](https://banglejs.com/apps/#bthrm) as a reference. + +## Steps for usage + +* (Optional) Install [BTHRM](https://banglejs.com/apps/#bthrm) as reference (use ECG based sensor for best accuracy). + * Configure BTHRM to "Both"-Mode. This prevents data beeing lost because BTHRM can replace the HRM-events data with BTHRM data. +* Click "Start" in browser. +* Wait until the "Events" number starts to grow, that means there are events recorded. +* Record for some time, since BTHRM and HRM often need some seconds to start getting useful values. Consider 2000 events a useful minimum. +* (Recording to file) Stop the recording with a long press of the button and download log.csv with the Espruino IDE. +* (Recording to browser) Click "Stop" followed by "Save" and store the resulting file on your device. + +## Creator + +[halemmerich](https://github.com/halemmerich) diff --git a/apps/hrmaccevents/custom.html b/apps/hrmaccevents/custom.html index c0098eb12..02276eb64 100644 --- a/apps/hrmaccevents/custom.html +++ b/apps/hrmaccevents/custom.html @@ -4,130 +4,181 @@ - - - - +

Store on Bangle (file named log.csv, download with IDE)

+

+ + + + +