From 49136a1ca7c4a3290c3e75424f9cb3515a7fd514 Mon Sep 17 00:00:00 2001 From: Marco Heiming Date: Thu, 16 Dec 2021 08:06:53 +0100 Subject: [PATCH] Initial version of circles clock --- apps.json | 25 +++- apps/circlesclock/Changelog | 1 + apps/circlesclock/README.md | 19 +++ apps/circlesclock/app-icon.js | 1 + apps/circlesclock/app.js | 218 +++++++++++++++++++++++++++++++ apps/circlesclock/app.png | Bin 0 -> 3576 bytes apps/circlesclock/screenshot.png | Bin 0 -> 3576 bytes apps/circlesclock/settings.js | 33 +++++ 8 files changed, 295 insertions(+), 2 deletions(-) create mode 100644 apps/circlesclock/Changelog create mode 100644 apps/circlesclock/README.md create mode 100644 apps/circlesclock/app-icon.js create mode 100644 apps/circlesclock/app.js create mode 100644 apps/circlesclock/app.png create mode 100644 apps/circlesclock/screenshot.png create mode 100644 apps/circlesclock/settings.js diff --git a/apps.json b/apps.json index c379a1de4..e0bab5917 100644 --- a/apps.json +++ b/apps.json @@ -4981,7 +4981,7 @@ "description": "Displays the image file in showimage.user.img. Returns to watch face after 60s or button push. I use it to display my vaccination certificate.", "icon": "app.png", "tags": "tool", - "supports" : ["BANGLEJS2"], + "supports" : ["BANGLEJS2"], "storage": [ {"name":"showimg.app.js","url":"app.js"}, {"name":"showimg.img","url":"app-icon.js","evaluate":true} @@ -5003,5 +5003,26 @@ {"name":"lapcounter.app.js","url":"app.js"}, {"name":"lapcounter.img","url":"app-icon.js","evaluate":true} ] - } + }, + { "id": "circlesclock", + "name": "Circles clock", + "shortName":"Circles clock", + "version":"0.01", + "description": "A clock with circles for different data at the bottom in a probably familiar style", + "icon": "app.png", + "dependencies": {"widpedom":"app"}, + "type": "clock", + "tags": "clock", + "supports" : ["BANGLEJS2"], + "allow_emulator":true, + "readme": "README.md", + "storage": [ + {"name":"circlesclock.app.js","url":"app.js"}, + {"name":"circlesclock.img","url":"app-icon.js","evaluate":true}, + {"name":"circlesclock.settings.js","url":"settings.js"} + ], + "data": [ + {"name":"circlesclock.json"} + ] + } ] diff --git a/apps/circlesclock/Changelog b/apps/circlesclock/Changelog new file mode 100644 index 000000000..af119ab59 --- /dev/null +++ b/apps/circlesclock/Changelog @@ -0,0 +1 @@ +0.01: New clock diff --git a/apps/circlesclock/README.md b/apps/circlesclock/README.md new file mode 100644 index 000000000..87edd5981 --- /dev/null +++ b/apps/circlesclock/README.md @@ -0,0 +1,19 @@ +# Circles clock + +A clock with circles for different data at the bottom in a probably familiar style + +It shows besides time, date and day of week the following information: + * Steps (requires [pedometer widget](https://banglejs.com/apps/#pedometer)) + * Heart rate (when screen is on and unlocked) + * Battery + +## Screenshot + +![Screenshot](screenshot.png) + +## TODO +* Show weather information + + +## Creator +Marco ([myxor](https://github.com/myxor)) diff --git a/apps/circlesclock/app-icon.js b/apps/circlesclock/app-icon.js new file mode 100644 index 000000000..ad727251a --- /dev/null +++ b/apps/circlesclock/app-icon.js @@ -0,0 +1 @@ + require("heatshrink").decompress(atob("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")) diff --git a/apps/circlesclock/app.js b/apps/circlesclock/app.js new file mode 100644 index 000000000..8474b7f4e --- /dev/null +++ b/apps/circlesclock/app.js @@ -0,0 +1,218 @@ +const locale = require("locale"); +const heatshrink = require("heatshrink"); + +var shoesIcon = heatshrink.decompress(atob("h0OwYJGgmAAgUBkgECgVJB4cSoAUDyEBkARDpADBhMAyQRBgVAkgmDhIUDAAuQAgY1DAAYA=")); +var heartIcon = heatshrink.decompress(atob("h0OwYOLkmQhMkgACByVJgESpIFBpEEBAIFBCgIFCCgsABwcAgQOCAAMSpAwDyBNM")); +var powerIcon = heatshrink.decompress(atob("h0OwYQNsAED7AEDmwEDtu2AgUbtuABwXbBIUN23AAoYOCgEDFIgODABI")); + +const SETTINGS_FILE = "circlesclock.json"; +let settings; + +function loadSettings() { + settings = require("Storage").readJSON(SETTINGS_FILE, 1) || { + 'maxHR': 200, + 'stepGoal': 10000 + }; +} + +const colorFg = '#fff'; +const colorBg = '#000'; +const colorGrey = '#808080'; + +let hrtValue; + +const h = g.getHeight(); +const w = g.getWidth(); +const hOffset = 30; +const h1 = Math.round(1 * h / 5 - hOffset); +const h2 = Math.round(3 * h / 5 - hOffset); +const h3 = Math.round(8 * h / 8 - hOffset); +const w1 = Math.round(w / 6); +const w2 = Math.round(3 * w / 6); +const w3 = Math.round(5 * w / 6); +const radiusOuter = 22; +const radiusInner = 16; + +function draw() { + g.reset(); + g.setColor(colorBg); + g.fillRect(0, 0, w, h); + + // time + g.setFont("Vector:50"); + g.setFontAlign(-1, -1); + g.setColor(colorFg); + g.drawString(locale.time(new Date(), 1), w / 10, h1 + 8); + + // date & dow + g.setFont("Vector:20"); + g.setFontAlign(-1, 0); + g.drawString(locale.date(new Date()), w / 10, h2); + g.drawString(locale.dow(new Date()), w / 10, h2 + 22); + + // Steps circle + drawSteps(); + + // Heart circle + drawHeartRate(); + + // Battery circle + drawBattery(); +} + + + +function drawSteps() { + const steps = getSteps(); + const blue = '#0000ff'; + g.setColor(colorGrey); + g.fillCircle(w1, h3, radiusOuter); + + const stepGoal = settings.stepGoal; + if (stepGoal > 0) { + let percent = steps / stepGoal; + if (stepGoal < steps) percent = 1; + drawGauge(w1, h3, percent, blue); + } + + g.setColor(colorBg); + g.fillCircle(w1, h3, radiusInner); + + g.fillPoly([w1, h3, w1 - 15, h3 + radiusOuter + 5, w1 + 15, h3 + radiusOuter + 5]); + + g.setFont("Vector:12"); + g.setFontAlign(0, 0); + g.setColor(colorFg); + g.drawString(shortValue(steps), w1 + 2, h3); + + g.drawImage(shoesIcon, w1 - 6, h3 + radiusOuter - 6); +} + +function drawHeartRate() { + const red = '#ff0000'; + g.setColor(colorGrey); + g.fillCircle(w2, h3, radiusOuter); + + if (hrtValue != undefined) { + const percent = hrtValue / settings.maxHR; + drawGauge(w2, h3, percent, red); + } + + g.setColor(colorBg); + g.fillCircle(w2, h3, radiusInner); + + g.fillPoly([w2, h3, w2 - 15, h3 + radiusOuter + 5, w2 + 15, h3 + radiusOuter + 5]); + + g.setFont("Vector:12"); + g.setFontAlign(0, 0); + g.setColor(colorFg); + g.drawString(hrtValue != undefined ? hrtValue : 0, w2, h3); + + g.drawImage(heartIcon, w2 - 6, h3 + radiusOuter - 6); +} + +function drawBattery() { + const battery = E.getBattery(); + const yellow = '#ffff00'; + g.setColor(colorGrey); + g.fillCircle(w3, h3, radiusOuter); + + if (battery > 0) { + const percent = battery / 100; + drawGauge(w3, h3, percent, yellow); + } + + g.setColor(colorBg); + g.fillCircle(w3, h3, radiusInner); + + g.fillPoly([w3, h3, w3 - 15, h3 + radiusOuter + 5, w3 + 15, h3 + radiusOuter + 5]); + + g.setFont("Vector:12"); + g.setFontAlign(0, 0); + g.setColor(colorFg); + g.drawString(battery + '%', w3, h3); + + g.drawImage(powerIcon, w3 - 6, h3 + radiusOuter - 6); +} + +function radians(a) { + return a * Math.PI / 180; +} + + +function drawGauge(cx, cy, percent, color) { + let offset = 30; + let end = 300; + var i = 0; + var r = radiusInner + 3; + + if (percent > 1) percent = 1; + + var startrot = -offset; + var endrot = startrot - ((end - offset) * percent); + + g.setColor(color); + + // draw gauge + for (i = startrot; i > endrot; i -= 4) { + x = cx + r * Math.sin(radians(i)); + y = cy + r * Math.cos(radians(i)); + g.fillCircle(x, y, 4); + } +} + +function shortValue(v) { + if (isNaN(v)) return '-'; + if (v <= 999) return v; + if (v >= 1000 && v < 10000) { + v = Math.floor(v / 100) * 100; + return (v / 1000).toFixed(1).replace(/\.0$/, '') + 'k'; + } + if (v >= 10000) { + v = Math.floor(v / 1000) * 1000; + return (v / 1000).toFixed(1).replace(/\.0$/, '') + 'k'; + } +} + +function getSteps() { + if (WIDGETS.wpedom !== undefined) { + return WIDGETS.wpedom.getSteps(); + } + return 0; +} + +Bangle.on('lock', function(isLocked) { + if (!isLocked) { + Bangle.setHRMPower(1, "watch"); + } else { + Bangle.setHRMPower(0, "watch"); + } + drawHeartRate(); + drawSteps(); +}); + +Bangle.on('HRM', function(hrm) { + //if(hrm.confidence > 90){ + hrtValue = hrm.bpm; + if (Bangle.isLCDOn()) + drawHeartRate(); + //} else { + // hrtValue = undefined; + //} +}); + +g.clear(); +Bangle.loadWidgets(); +/* + * we are not drawing the widgets as we are taking over the whole screen + * so we will blank out the draw() functions of each widget and change the + * area to the top bar doesn't get cleared. + */ +for (let wd of WIDGETS) { + wd.draw = () => {}; + wd.area = ""; +} +loadSettings(); +setInterval(draw, 60000); +draw(); +Bangle.setUI("clock"); diff --git a/apps/circlesclock/app.png b/apps/circlesclock/app.png new file mode 100644 index 0000000000000000000000000000000000000000..94ff885faba99f8be0bed9a3dc9c3523e32de816 GIT binary patch literal 3576 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 literal 0 HcmV?d00001 diff --git a/apps/circlesclock/screenshot.png b/apps/circlesclock/screenshot.png new file mode 100644 index 0000000000000000000000000000000000000000..94ff885faba99f8be0bed9a3dc9c3523e32de816 GIT binary patch literal 3576 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 literal 0 HcmV?d00001 diff --git a/apps/circlesclock/settings.js b/apps/circlesclock/settings.js new file mode 100644 index 000000000..2de278b47 --- /dev/null +++ b/apps/circlesclock/settings.js @@ -0,0 +1,33 @@ +(function(back) { + const SETTINGS_FILE = "circlesclock.json"; + const storage = require('Storage'); + let settings = storage.readJSON(SETTINGS_FILE, 1) || {}; + function save(key, value) { + settings[key] = value; + storage.write(SETTINGS_FILE, settings); + } + E.showMenu({ + '': { 'title': 'circlesclock' }, + 'max heartrate': { + value: "maxHR" in settings ? settings.maxHR : 200, + min: 20, + max : 250, + step: 10, + format: x => { + return x; + }, + onchange: x => save('maxHR', x), + }, + 'step goal': { + value: "stepGoal" in settings ? settings.stepGoal : 10000, + min: 2000, + max : 50000, + step: 2000, + format: x => { + return x; + }, + onchange: x => save('stepGoal', x), + }, + '< Back': back, + }); +});