From 71504a7414dc35d136ae1cd45b991289fab1ec9a Mon Sep 17 00:00:00 2001 From: Marco Heiming Date: Wed, 5 Jan 2022 12:16:14 +0100 Subject: [PATCH 01/29] Setting to toggle visibility of widgets Setting to set minimal heart rate --- apps/circlesclock/app.js | 45 +++++++++++++++++++++-------------- apps/circlesclock/settings.js | 18 ++++++++++++++ 2 files changed, 45 insertions(+), 18 deletions(-) diff --git a/apps/circlesclock/app.js b/apps/circlesclock/app.js index 026b47cc6..f123e0c2a 100644 --- a/apps/circlesclock/app.js +++ b/apps/circlesclock/app.js @@ -8,12 +8,13 @@ const powerIconGreen = heatshrink.decompress(atob("h0OwYQNkAEDpAEDiQEDkmSAgUJkmA const powerIconRed = heatshrink.decompress(atob("h0OwYQNoAEDyAEDkgEDpIFDiVJBweSAgUJkmAAoYZDgQpEBwYAJA")); let settings; - function loadSettings() { settings = require("Storage").readJSON("circlesclock.json", 1) || { + 'minHR': 40, 'maxHR': 200, 'stepGoal': 10000, - 'batteryWarn': 30 + 'batteryWarn': 30, + 'showWidgets': false }; // Load step goal from pedometer widget as fallback if (settings.stepGoal == undefined) { @@ -21,18 +22,21 @@ function loadSettings() { settings.stepGoal = d != undefined && d.settings != undefined ? d.settings.goal : 10000; } } +loadSettings(); +const showWidgets = settings.showWidgets || false; +let hrtValue; + +// layout values: const colorFg = g.theme.dark ? '#fff' : '#000'; const colorBg = g.theme.dark ? '#000' : '#fff'; const colorGrey = '#808080'; const colorRed = '#ff0000'; const colorGreen = '#00ff00'; - -let hrtValue; - -const h = g.getHeight(); +const widgetOffset = showWidgets ? 12 : 0; +const h = g.getHeight() - widgetOffset; const w = g.getWidth(); -const hOffset = 30; +const hOffset = 30 - widgetOffset; const h1 = Math.round(1 * h / 5 - hOffset); const h2 = Math.round(3 * h / 5 - hOffset); const h3 = Math.round(8 * h / 8 - hOffset); @@ -102,7 +106,7 @@ function drawHeartRate() { g.fillCircle(w2, h3, radiusOuter); if (hrtValue != undefined && hrtValue > 0) { - const minHR = 40; + const minHR = settings.minHR || 40; const percent = (hrtValue - minHR) / (settings.maxHR - minHR); drawGauge(w2, h3, percent, colorRed); } @@ -233,19 +237,24 @@ Bangle.on('charging', function(charging) { }); 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. - */ -if (typeof WIDGETS === "object") { - for (let wd of WIDGETS) { - wd.draw = () => {}; - wd.area = ""; +if (!showWidgets) { + /* + * 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. + */ + if (WIDGETS && typeof WIDGETS === "object") { + for (let wd of WIDGETS) { + wd.draw = () => {}; + wd.area = ""; + } } } -loadSettings(); + + setInterval(draw, 60000); draw(); Bangle.setUI("clock"); diff --git a/apps/circlesclock/settings.js b/apps/circlesclock/settings.js index ffda51538..15596ff18 100644 --- a/apps/circlesclock/settings.js +++ b/apps/circlesclock/settings.js @@ -8,6 +8,16 @@ } E.showMenu({ '': { 'title': 'circlesclock' }, + 'min heartrate': { + value: "minHR" in settings ? settings.minHR : 40, + min: 0, + max : 250, + step: 10, + format: x => { + return x; + }, + onchange: x => save('minHR', x), + }, 'max heartrate': { value: "maxHR" in settings ? settings.maxHR : 200, min: 20, @@ -38,6 +48,14 @@ }, onchange: x => save('batteryWarn', x), }, + 'show widgets': { + value: "showWidgets" in settings ? settings.showWidgets : false, + format: () => (settings.showWidgets ? 'Yes' : 'No'), + onchange: () => { + settings.showWidgets = !settings.showWidgets; + save('showWidgets', settings.showWidgets); + }, + }, '< Back': back, }); }); From c41bae14c9e6c5a0dc8d33163415a03787baa632 Mon Sep 17 00:00:00 2001 From: Marco Heiming Date: Wed, 5 Jan 2022 12:16:38 +0100 Subject: [PATCH 02/29] Update README --- apps/circlesclock/README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/apps/circlesclock/README.md b/apps/circlesclock/README.md index 66d9afe08..df47c369b 100644 --- a/apps/circlesclock/README.md +++ b/apps/circlesclock/README.md @@ -8,13 +8,11 @@ It shows besides time, date and day of week the following information: * Battery (including charging and battery low) ## Screenshot - ![Screenshot](screenshot.png) ## TODO * Show weather information * Configure which information to show in each circle -* Configure visibility of widgets ## Creator Marco ([myxor](https://github.com/myxor)) From 766d3cc1892874b5a8be3f611c3e4335da236c80 Mon Sep 17 00:00:00 2001 From: Marco Heiming Date: Wed, 5 Jan 2022 13:27:50 +0100 Subject: [PATCH 03/29] Make the types of the circles configurable --- apps/circlesclock/app.js | 163 ++++++++++++++++++++++++---------- apps/circlesclock/settings.js | 29 ++++++ 2 files changed, 144 insertions(+), 48 deletions(-) diff --git a/apps/circlesclock/app.js b/apps/circlesclock/app.js index f123e0c2a..58055e96e 100644 --- a/apps/circlesclock/app.js +++ b/apps/circlesclock/app.js @@ -14,7 +14,10 @@ function loadSettings() { 'maxHR': 200, 'stepGoal': 10000, 'batteryWarn': 30, - 'showWidgets': false + 'showWidgets': false, + 'circle1': 'hr', + 'circle2': 'steps', + 'circle3': 'battery' }; // Load step goal from pedometer widget as fallback if (settings.stepGoal == undefined) { @@ -32,7 +35,9 @@ const colorFg = g.theme.dark ? '#fff' : '#000'; const colorBg = g.theme.dark ? '#000' : '#fff'; const colorGrey = '#808080'; const colorRed = '#ff0000'; -const colorGreen = '#00ff00'; +const colorGreen = '#008000'; +const colorBlue = '#0000ff'; +const colorYellow = '#ffff00'; const widgetOffset = showWidgets ? 12 : 0; const h = g.getHeight() - widgetOffset; const w = g.getWidth(); @@ -63,82 +68,137 @@ function draw() { 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(); + drawCircle(1, "steps"); + drawCircle(2, "hr"); + drawCircle(3, "battery"); } +function drawCircle(index, defaultType) { + const type = settings['circle' + index] || defaultType; + const w = index == 1 ? w1: index == 2 ? w2 : w3; -function drawSteps() { + switch (type) { + case "steps": + drawSteps(w); + break; + case "stepsDist": + drawStepsDistance(w); + break; + case "hr": + drawHeartRate(w); + break; + case "battery": + drawBattery(w); + break; + } +} +function getCirclePosition(type, defaultPos) { + for (let i = 1; i <= 3; i++) { + const setting = settings['circle' + i]; + if (setting == type) return i; + } + return defaultPos; +} + +function isCircleEnabled(type) { + return getCirclePosition(type) != undefined; +} + +function drawSteps(w) { + if (!w) w = getCirclePosition("steps", w1); const steps = getSteps(); - const blue = '#0000ff'; g.setColor(colorGrey); - g.fillCircle(w1, h3, radiusOuter); + g.fillCircle(w, h3, radiusOuter); const stepGoal = settings.stepGoal || 10000; if (stepGoal > 0) { let percent = steps / stepGoal; if (stepGoal < steps) percent = 1; - drawGauge(w1, h3, percent, blue); + drawGauge(w, h3, percent, colorBlue); } g.setColor(colorBg); - g.fillCircle(w1, h3, radiusInner); + g.fillCircle(w, h3, radiusInner); - g.fillPoly([w1, h3, w1 - 15, h3 + radiusOuter + 5, w1 + 15, h3 + radiusOuter + 5]); + g.fillPoly([w, h3, w - 15, h3 + radiusOuter + 5, w + 15, h3 + radiusOuter + 5]); g.setFont("Vector:12"); g.setFontAlign(0, 0); g.setColor(colorFg); - g.drawString(shortValue(steps), w1 + 2, h3); + g.drawString(shortValue(steps), w + 2, h3); - g.drawImage(shoesIcon, w1 - 6, h3 + radiusOuter - 6); + g.drawImage(shoesIcon, w - 6, h3 + radiusOuter - 6); } -function drawHeartRate() { +function drawStepsDistance(w) { + if (!w) w = getCirclePosition("steps", w1); + const steps = getSteps(); + const stepDistance = 0.8; // TODO make configurable + const stepsDistance = steps * stepDistance; + g.setColor(colorGrey); - g.fillCircle(w2, h3, radiusOuter); + g.fillCircle(w, h3, radiusOuter); + + const stepDistanceGoal = settings.stepDistanceGoal || 5; + if (stepDistanceGoal > 0) { + let percent = stepsDistance / stepDistanceGoal; + if (stepDistanceGoal < stepsDistance) percent = 1; + drawGauge(w, h3, percent, colorGreen); + } + + g.setColor(colorBg); + g.fillCircle(w, h3, radiusInner); + + g.fillPoly([w, h3, w - 15, h3 + radiusOuter + 5, w + 15, h3 + radiusOuter + 5]); + + g.setFont("Vector:12"); + g.setFontAlign(0, 0); + g.setColor(colorFg); + g.drawString(shortValue(stepsDistance), w + 2, h3); + + g.drawImage(shoesIcon, w - 6, h3 + radiusOuter - 6); +} + +function drawHeartRate(w) { + if (!w) w = getCirclePosition("hr", w2); + g.setColor(colorGrey); + g.fillCircle(w, h3, radiusOuter); if (hrtValue != undefined && hrtValue > 0) { const minHR = settings.minHR || 40; const percent = (hrtValue - minHR) / (settings.maxHR - minHR); - drawGauge(w2, h3, percent, colorRed); + drawGauge(w, h3, percent, colorRed); } g.setColor(colorBg); - g.fillCircle(w2, h3, radiusInner); + g.fillCircle(w, h3, radiusInner); - g.fillPoly([w2, h3, w2 - 15, h3 + radiusOuter + 5, w2 + 15, h3 + radiusOuter + 5]); + g.fillPoly([w, h3, w - 15, h3 + radiusOuter + 5, w + 15, h3 + radiusOuter + 5]); g.setFont("Vector:12"); g.setFontAlign(0, 0); g.setColor(colorFg); - g.drawString(hrtValue != undefined ? hrtValue : "-", w2, h3); + g.drawString(hrtValue != undefined ? hrtValue : "-", w, h3); - g.drawImage(heartIcon, w2 - 6, h3 + radiusOuter - 6); + g.drawImage(heartIcon, w - 6, h3 + radiusOuter - 6); } -function drawBattery() { +function drawBattery(w) { + if (!w) w = getCirclePosition("battery", w3); const battery = E.getBattery(); - const yellow = '#ffff00'; g.setColor(colorGrey); - g.fillCircle(w3, h3, radiusOuter); + g.fillCircle(w, h3, radiusOuter); if (battery > 0) { const percent = battery / 100; - drawGauge(w3, h3, percent, yellow); + drawGauge(w, h3, percent, colorYellow); } g.setColor(colorBg); - g.fillCircle(w3, h3, radiusInner); + g.fillCircle(w, h3, radiusInner); - g.fillPoly([w3, h3, w3 - 15, h3 + radiusOuter + 5, w3 + 15, h3 + radiusOuter + 5]); + g.fillPoly([w, h3, w - 15, h3 + radiusOuter + 5, w + 15, h3 + radiusOuter + 5]); g.setFont("Vector:12"); g.setFontAlign(0, 0); @@ -156,9 +216,9 @@ function drawBattery() { } } g.setColor(color); - g.drawString(battery + '%', w3, h3); + g.drawString(battery + '%', w, h3); - g.drawImage(icon, w3 - 6, h3 + radiusOuter - 6); + g.drawImage(icon, w - 6, h3 + radiusOuter - 6); } function radians(a) { @@ -210,30 +270,37 @@ function getSteps() { Bangle.on('lock', function(isLocked) { if (!isLocked) { - Bangle.setHRMPower(1, "watch"); - if (hrtValue == undefined) { - hrtValue = '...'; - drawHeartRate(); + if (isCircleEnabled("hr")) { + Bangle.setHRMPower(1, "watch"); + if (hrtValue == undefined) { + hrtValue = '...'; + drawHeartRate(); + } } } else { - Bangle.setHRMPower(0, "watch"); + if (isCircleEnabled("hr")) { + Bangle.setHRMPower(0, "watch"); + } } - drawHeartRate(); - drawSteps(); + if (isCircleEnabled("hr")) drawHeartRate(); + if (isCircleEnabled("steps")) drawSteps(); + if (isCircleEnabled("stepsDistance")) drawStepsDistance(); }); Bangle.on('HRM', function(hrm) { - //if(hrm.confidence > 90){ - hrtValue = hrm.bpm; - if (Bangle.isLCDOn()) - drawHeartRate(); - //} else { - // hrtValue = undefined; - //} + if (isCircleEnabled("hr")) { + //if(hrm.confidence > 90){ + hrtValue = hrm.bpm; + if (Bangle.isLCDOn()) + drawHeartRate(); + //} else { + // hrtValue = undefined; + //} + } }); Bangle.on('charging', function(charging) { - drawBattery(); + if (isCircleEnabled("battery")) drawBattery(); }); g.clear(); diff --git a/apps/circlesclock/settings.js b/apps/circlesclock/settings.js index 15596ff18..754fa0c69 100644 --- a/apps/circlesclock/settings.js +++ b/apps/circlesclock/settings.js @@ -6,6 +6,8 @@ settings[key] = value; storage.write(SETTINGS_FILE, settings); } + var valuesCircleTypes = ["steps", "stepsDist", "hr", "battery"]; + var namesCircleTypes = ["steps", "step distance", "heart", "battery"]; E.showMenu({ '': { 'title': 'circlesclock' }, 'min heartrate': { @@ -56,6 +58,33 @@ save('showWidgets', settings.showWidgets); }, }, + 'Left circle': { + value: Math.max(0,0 | valuesCircleTypes.indexOf(settings.circle1)), + min: 0, max: 3, + format: v => namesCircleTypes[v], + onchange: v => { + settings.circle1 = valuesCircleTypes[v]; + save('circle1', settings.circle1); + } + }, + 'Middle circle': { + value: Math.max(0,0 | valuesCircleTypes.indexOf(settings.circle2)), + min: 0, max: 3, + format: v => namesCircleTypes[v], + onchange: v => { + settings.circle2 = valuesCircleTypes[v]; + save('circle2', settings.circle2); + } + }, + 'Right circle': { + value: Math.max(0,0 | valuesCircleTypes.indexOf(settings.circle3)), + min: 0, max: 3, + format: v => namesCircleTypes[v], + onchange: v => { + settings.circle3 = valuesCircleTypes[v]; + save('circle3', settings.circle3); + } + }, '< Back': back, }); }); From ee252a3a97fc3880c7744ed79966e6f25bb6e8da Mon Sep 17 00:00:00 2001 From: Marco Heiming Date: Wed, 5 Jan 2022 14:04:04 +0100 Subject: [PATCH 04/29] Fix position, default settings and add green step distance icon --- apps/circlesclock/app.js | 5 +++-- apps/circlesclock/settings.js | 14 +++++++------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/apps/circlesclock/app.js b/apps/circlesclock/app.js index 58055e96e..686de735b 100644 --- a/apps/circlesclock/app.js +++ b/apps/circlesclock/app.js @@ -2,6 +2,7 @@ const locale = require("locale"); const heatshrink = require("heatshrink"); const shoesIcon = heatshrink.decompress(atob("h0OwYJGgmAAgUBkgECgVJB4cSoAUDyEBkARDpADBhMAyQRBgVAkgmDhIUDAAuQAgY1DAAYA=")); +const shoesIconGreen = heatshrink.decompress(atob("h0OwYJGhIEDgVIAgUEyQKDkmACgcggVACIeQAYMSgIRCgmApIbDiQUDAAkBkAFDGoYAD")); const heartIcon = heatshrink.decompress(atob("h0OwYOLkmQhMkgACByVJgESpIFBpEEBAIFBCgIFCCgsABwcAgQOCAAMSpAwDyBNM")); const powerIcon = heatshrink.decompress(atob("h0OwYQNsAED7AEDmwEDtu2AgUbtuABwXbBIUN23AAoYOCgEDFIgODABI")); const powerIconGreen = heatshrink.decompress(atob("h0OwYQNkAEDpAEDiQEDkmSAgUJkmABwVJBIUEyVAAoYOCgEBFIgODABI")); @@ -96,7 +97,7 @@ function drawCircle(index, defaultType) { function getCirclePosition(type, defaultPos) { for (let i = 1; i <= 3; i++) { const setting = settings['circle' + i]; - if (setting == type) return i; + if (setting == type) return i == 1 ? w1: i == 2 ? w2 : w3; } return defaultPos; } @@ -157,7 +158,7 @@ function drawStepsDistance(w) { g.setColor(colorFg); g.drawString(shortValue(stepsDistance), w + 2, h3); - g.drawImage(shoesIcon, w - 6, h3 + radiusOuter - 6); + g.drawImage(shoesIconGreen, w - 6, h3 + radiusOuter - 6); } function drawHeartRate(w) { diff --git a/apps/circlesclock/settings.js b/apps/circlesclock/settings.js index 754fa0c69..3ddacd29c 100644 --- a/apps/circlesclock/settings.js +++ b/apps/circlesclock/settings.js @@ -7,7 +7,7 @@ storage.write(SETTINGS_FILE, settings); } var valuesCircleTypes = ["steps", "stepsDist", "hr", "battery"]; - var namesCircleTypes = ["steps", "step distance", "heart", "battery"]; + var namesCircleTypes = ["steps", "distance", "heart", "battery"]; E.showMenu({ '': { 'title': 'circlesclock' }, 'min heartrate': { @@ -40,7 +40,7 @@ }, onchange: x => save('stepGoal', x), }, - 'battery warn lvl': { + 'battery warn': { value: "batteryWarn" in settings ? settings.batteryWarn : 30, min: 10, max : 100, @@ -58,7 +58,7 @@ save('showWidgets', settings.showWidgets); }, }, - 'Left circle': { + 'left': { value: Math.max(0,0 | valuesCircleTypes.indexOf(settings.circle1)), min: 0, max: 3, format: v => namesCircleTypes[v], @@ -67,8 +67,8 @@ save('circle1', settings.circle1); } }, - 'Middle circle': { - value: Math.max(0,0 | valuesCircleTypes.indexOf(settings.circle2)), + 'middle': { + value: Math.max(0,2 | valuesCircleTypes.indexOf(settings.circle2)), min: 0, max: 3, format: v => namesCircleTypes[v], onchange: v => { @@ -76,8 +76,8 @@ save('circle2', settings.circle2); } }, - 'Right circle': { - value: Math.max(0,0 | valuesCircleTypes.indexOf(settings.circle3)), + 'right': { + value: Math.max(0,3 | valuesCircleTypes.indexOf(settings.circle3)), min: 0, max: 3, format: v => namesCircleTypes[v], onchange: v => { From 3538c6024fe36715a82d0d2018862cab2992f944 Mon Sep 17 00:00:00 2001 From: Marco Heiming Date: Wed, 5 Jan 2022 14:14:47 +0100 Subject: [PATCH 05/29] Configuration of stepDistanceGoal and stepLength --- apps/circlesclock/app.js | 6 ++++-- apps/circlesclock/settings.js | 40 +++++++++++++++++++++-------------- 2 files changed, 28 insertions(+), 18 deletions(-) diff --git a/apps/circlesclock/app.js b/apps/circlesclock/app.js index 686de735b..3099b02ea 100644 --- a/apps/circlesclock/app.js +++ b/apps/circlesclock/app.js @@ -14,6 +14,8 @@ function loadSettings() { 'minHR': 40, 'maxHR': 200, 'stepGoal': 10000, + 'stepDistanceGoal': 8000, + 'stepLength': 0.8, 'batteryWarn': 30, 'showWidgets': false, 'circle1': 'hr', @@ -135,13 +137,13 @@ function drawSteps(w) { function drawStepsDistance(w) { if (!w) w = getCirclePosition("steps", w1); const steps = getSteps(); - const stepDistance = 0.8; // TODO make configurable + const stepDistance = settings.stepLength || 0.8; const stepsDistance = steps * stepDistance; g.setColor(colorGrey); g.fillCircle(w, h3, radiusOuter); - const stepDistanceGoal = settings.stepDistanceGoal || 5; + const stepDistanceGoal = settings.stepDistanceGoal || 8000; if (stepDistanceGoal > 0) { let percent = stepsDistance / stepDistanceGoal; if (stepDistanceGoal < stepsDistance) percent = 1; diff --git a/apps/circlesclock/settings.js b/apps/circlesclock/settings.js index 3ddacd29c..dc75f54af 100644 --- a/apps/circlesclock/settings.js +++ b/apps/circlesclock/settings.js @@ -40,6 +40,26 @@ }, onchange: x => save('stepGoal', x), }, + 'step length': { + value: "stepLength" in settings ? settings.stepLength : 0.8, + min: 0.1, + max : 1.5, + step: 0.01, + format: x => { + return x; + }, + onchange: x => save('stepLength', x), + }, + 'step dist goal': { + value: "stepDistanceGoal" in settings ? settings.stepDistanceGoal : 8000, + min: 2000, + max : 30000, + step: 1000, + format: x => { + return x; + }, + onchange: x => save('stepDistanceGoal', x), + }, 'battery warn': { value: "batteryWarn" in settings ? settings.batteryWarn : 30, min: 10, @@ -53,37 +73,25 @@ 'show widgets': { value: "showWidgets" in settings ? settings.showWidgets : false, format: () => (settings.showWidgets ? 'Yes' : 'No'), - onchange: () => { - settings.showWidgets = !settings.showWidgets; - save('showWidgets', settings.showWidgets); - }, + onchange: x => save('showWidgets', x), }, 'left': { value: Math.max(0,0 | valuesCircleTypes.indexOf(settings.circle1)), min: 0, max: 3, format: v => namesCircleTypes[v], - onchange: v => { - settings.circle1 = valuesCircleTypes[v]; - save('circle1', settings.circle1); - } + onchange: x => save('circle1', x), }, 'middle': { value: Math.max(0,2 | valuesCircleTypes.indexOf(settings.circle2)), min: 0, max: 3, format: v => namesCircleTypes[v], - onchange: v => { - settings.circle2 = valuesCircleTypes[v]; - save('circle2', settings.circle2); - } + onchange: x => save('circle2', x), }, 'right': { value: Math.max(0,3 | valuesCircleTypes.indexOf(settings.circle3)), min: 0, max: 3, format: v => namesCircleTypes[v], - onchange: v => { - settings.circle3 = valuesCircleTypes[v]; - save('circle3', settings.circle3); - } + onchange: x => save('circle3', x), }, '< Back': back, }); From f174cb56fbd586f7e6a357a73129f9d5d6ab244d Mon Sep 17 00:00:00 2001 From: Marco Heiming Date: Wed, 5 Jan 2022 14:14:56 +0100 Subject: [PATCH 06/29] Update README --- apps/circlesclock/README.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/apps/circlesclock/README.md b/apps/circlesclock/README.md index df47c369b..86c388440 100644 --- a/apps/circlesclock/README.md +++ b/apps/circlesclock/README.md @@ -2,17 +2,19 @@ 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: +By default the time, date and day of week is shown. + +It can show the following information (this can be configured): * Steps (requires [pedometer widget](https://banglejs.com/apps/#pedometer)) - * Heart rate (when screen is on and unlocked) - * Battery (including charging and battery low) + * Steps distance (depending on steps) + * Heart rate (automatically updates when screen is on and unlocked) + * Battery (including charging status and battery low warning) ## Screenshot ![Screenshot](screenshot.png) ## TODO * Show weather information -* Configure which information to show in each circle ## Creator Marco ([myxor](https://github.com/myxor)) From ad371e9678cb380ea064ed01cbe6b7df385b4d56 Mon Sep 17 00:00:00 2001 From: Marco Heiming Date: Wed, 5 Jan 2022 14:21:01 +0100 Subject: [PATCH 07/29] Update changelog and bump version --- apps.json | 2 +- apps/circlesclock/ChangeLog | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/apps.json b/apps.json index f116049dc..c6600ada0 100644 --- a/apps.json +++ b/apps.json @@ -5071,7 +5071,7 @@ { "id": "circlesclock", "name": "Circles clock", "shortName":"Circles clock", - "version":"0.03", + "version":"0.04", "description": "A clock with circles for different data at the bottom in a probably familiar style", "icon": "app.png", "screenshots": [{"url":"screenshot.png"}], diff --git a/apps/circlesclock/ChangeLog b/apps/circlesclock/ChangeLog index c0aa4e2f8..f416929ac 100644 --- a/apps/circlesclock/ChangeLog +++ b/apps/circlesclock/ChangeLog @@ -1,3 +1,4 @@ 0.01: New clock 0.02: Fix icon & add battery warn functionality 0.03: Theming support & minor fixes +0.04: Make configurable what to show in each circle; add step distance circle; allow switching visibility of widgets From 3ba696ed0e29c6916726412d35895c48d74d8560 Mon Sep 17 00:00:00 2001 From: Marco Heiming Date: Wed, 5 Jan 2022 14:30:02 +0100 Subject: [PATCH 08/29] Fix settings --- apps/circlesclock/settings.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/circlesclock/settings.js b/apps/circlesclock/settings.js index dc75f54af..0c42319f5 100644 --- a/apps/circlesclock/settings.js +++ b/apps/circlesclock/settings.js @@ -79,19 +79,19 @@ value: Math.max(0,0 | valuesCircleTypes.indexOf(settings.circle1)), min: 0, max: 3, format: v => namesCircleTypes[v], - onchange: x => save('circle1', x), + onchange: x => save('circle1', valuesCircleTypes[x]), }, 'middle': { value: Math.max(0,2 | valuesCircleTypes.indexOf(settings.circle2)), min: 0, max: 3, format: v => namesCircleTypes[v], - onchange: x => save('circle2', x), + onchange: x => save('circle2', valuesCircleTypes[x]), }, 'right': { value: Math.max(0,3 | valuesCircleTypes.indexOf(settings.circle3)), min: 0, max: 3, format: v => namesCircleTypes[v], - onchange: x => save('circle3', x), + onchange: x => save('circle3', valuesCircleTypes[x]), }, '< Back': back, }); From 639bc1962eee45c31b4cf0d50f5edf782ac94e1c Mon Sep 17 00:00:00 2001 From: Marco Heiming Date: Wed, 5 Jan 2022 15:28:18 +0100 Subject: [PATCH 09/29] Allow widgets to detect this is a clock --- apps/circlesclock/app.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/apps/circlesclock/app.js b/apps/circlesclock/app.js index 3099b02ea..2d6c132bb 100644 --- a/apps/circlesclock/app.js +++ b/apps/circlesclock/app.js @@ -308,7 +308,7 @@ Bangle.on('charging', function(charging) { g.clear(); - +Bangle.setUI("clock"); Bangle.loadWidgets(); if (!showWidgets) { /* @@ -324,7 +324,5 @@ if (!showWidgets) { } } - -setInterval(draw, 60000); draw(); -Bangle.setUI("clock"); +setInterval(draw, 60000); From 801237b2cfad1caf17a0d4bb496527bd4a217e8a Mon Sep 17 00:00:00 2001 From: Marco Heiming Date: Wed, 5 Jan 2022 15:35:01 +0100 Subject: [PATCH 10/29] Let's only register HRM and battery events when respective circle is visible --- apps/circlesclock/app.js | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/apps/circlesclock/app.js b/apps/circlesclock/app.js index 2d6c132bb..e10d55f17 100644 --- a/apps/circlesclock/app.js +++ b/apps/circlesclock/app.js @@ -280,31 +280,32 @@ Bangle.on('lock', function(isLocked) { drawHeartRate(); } } + if (isCircleEnabled("steps")) drawSteps(); + if (isCircleEnabled("stepsDistance")) drawStepsDistance(); } else { if (isCircleEnabled("hr")) { Bangle.setHRMPower(0, "watch"); } } - if (isCircleEnabled("hr")) drawHeartRate(); - if (isCircleEnabled("steps")) drawSteps(); - if (isCircleEnabled("stepsDistance")) drawStepsDistance(); }); -Bangle.on('HRM', function(hrm) { - if (isCircleEnabled("hr")) { - //if(hrm.confidence > 90){ - hrtValue = hrm.bpm; - if (Bangle.isLCDOn()) - drawHeartRate(); - //} else { - // hrtValue = undefined; - //} - } -}); +if (isCircleEnabled("hr")) { + Bangle.on('HRM', function(hrm) { + //if(hrm.confidence > 90){ + hrtValue = hrm.bpm; + if (Bangle.isLCDOn()) + drawHeartRate(); + //} else { + // hrtValue = undefined; + //} + }); +} -Bangle.on('charging', function(charging) { - if (isCircleEnabled("battery")) drawBattery(); -}); +if (isCircleEnabled("battery")) { + Bangle.on('charging', function(charging) { + drawBattery(); + }); +} g.clear(); From c87d1d16509ca3943db44bc1606c8757039fb3e5 Mon Sep 17 00:00:00 2001 From: Marco Heiming Date: Wed, 5 Jan 2022 19:28:32 +0100 Subject: [PATCH 11/29] Fix settings default values --- apps/circlesclock/settings.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/circlesclock/settings.js b/apps/circlesclock/settings.js index 0c42319f5..95ebc17db 100644 --- a/apps/circlesclock/settings.js +++ b/apps/circlesclock/settings.js @@ -10,6 +10,7 @@ var namesCircleTypes = ["steps", "distance", "heart", "battery"]; E.showMenu({ '': { 'title': 'circlesclock' }, + '< Back': back, 'min heartrate': { value: "minHR" in settings ? settings.minHR : 40, min: 0, @@ -76,23 +77,22 @@ onchange: x => save('showWidgets', x), }, 'left': { - value: Math.max(0,0 | valuesCircleTypes.indexOf(settings.circle1)), + value: settings.circle1 ? valuesCircleTypes.indexOf(settings.circle1) : 0, min: 0, max: 3, format: v => namesCircleTypes[v], onchange: x => save('circle1', valuesCircleTypes[x]), }, 'middle': { - value: Math.max(0,2 | valuesCircleTypes.indexOf(settings.circle2)), + value: settings.circle2 ? valuesCircleTypes.indexOf(settings.circle2) : 2, min: 0, max: 3, format: v => namesCircleTypes[v], onchange: x => save('circle2', valuesCircleTypes[x]), }, 'right': { - value: Math.max(0,3 | valuesCircleTypes.indexOf(settings.circle3)), + value: settings.circle3 ? valuesCircleTypes.indexOf(settings.circle3) : 3, min: 0, max: 3, format: v => namesCircleTypes[v], onchange: x => save('circle3', valuesCircleTypes[x]), - }, - '< Back': back, + } }); }); From 9a5937a3eb3535636e74f926d83dd41ebdd8c407 Mon Sep 17 00:00:00 2001 From: Marco Heiming Date: Wed, 5 Jan 2022 19:38:18 +0100 Subject: [PATCH 12/29] Improve widget visibility --- apps/circlesclock/app.js | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/apps/circlesclock/app.js b/apps/circlesclock/app.js index e10d55f17..a256c93ce 100644 --- a/apps/circlesclock/app.js +++ b/apps/circlesclock/app.js @@ -41,7 +41,7 @@ const colorRed = '#ff0000'; const colorGreen = '#008000'; const colorBlue = '#0000ff'; const colorYellow = '#ffff00'; -const widgetOffset = showWidgets ? 12 : 0; +const widgetOffset = showWidgets ? 14 : 0; const h = g.getHeight() - widgetOffset; const w = g.getWidth(); const hOffset = 30 - widgetOffset; @@ -55,9 +55,9 @@ const radiusOuter = 22; const radiusInner = 16; function draw() { - g.reset(); + g.clear(true); g.setColor(colorBg); - g.fillRect(0, 0, w, h); + g.fillRect(0, widgetOffset, w, h); // time g.setFont("Vector:50"); @@ -265,7 +265,7 @@ function shortValue(v) { } function getSteps() { - if (WIDGETS.wpedom !== undefined) { + if (WIDGETS && WIDGETS.wpedom !== undefined) { return WIDGETS.wpedom.getSteps(); } return 0; @@ -307,8 +307,6 @@ if (isCircleEnabled("battery")) { }); } -g.clear(); - Bangle.setUI("clock"); Bangle.loadWidgets(); if (!showWidgets) { From c15b700ef6fde7bdad924150d25504e51660e358 Mon Sep 17 00:00:00 2001 From: Marco Heiming Date: Wed, 5 Jan 2022 19:50:07 +0100 Subject: [PATCH 13/29] Fix widget drawing --- apps/circlesclock/app.js | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/apps/circlesclock/app.js b/apps/circlesclock/app.js index a256c93ce..fb4635424 100644 --- a/apps/circlesclock/app.js +++ b/apps/circlesclock/app.js @@ -56,6 +56,23 @@ const radiusInner = 16; function draw() { g.clear(true); + + if (!showWidgets) { + /* + * 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. + */ + if (WIDGETS && typeof WIDGETS === "object") { + for (let wd of WIDGETS) { + wd.draw = () => {}; + wd.area = ""; + } + } + } else { + Bangle.drawWidgets(); + } + g.setColor(colorBg); g.fillRect(0, widgetOffset, w, h); @@ -280,8 +297,7 @@ Bangle.on('lock', function(isLocked) { drawHeartRate(); } } - if (isCircleEnabled("steps")) drawSteps(); - if (isCircleEnabled("stepsDistance")) drawStepsDistance(); + draw(); } else { if (isCircleEnabled("hr")) { Bangle.setHRMPower(0, "watch"); @@ -309,19 +325,6 @@ if (isCircleEnabled("battery")) { Bangle.setUI("clock"); Bangle.loadWidgets(); -if (!showWidgets) { - /* - * 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. - */ - if (WIDGETS && typeof WIDGETS === "object") { - for (let wd of WIDGETS) { - wd.draw = () => {}; - wd.area = ""; - } - } -} draw(); setInterval(draw, 60000); From aba0d7126b26d1c24435cb89b2bfd24f4b07e581 Mon Sep 17 00:00:00 2001 From: Marco Heiming Date: Thu, 6 Jan 2022 11:08:46 +0100 Subject: [PATCH 14/29] Fix widget height --- apps/circlesclock/app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/circlesclock/app.js b/apps/circlesclock/app.js index fb4635424..319e99809 100644 --- a/apps/circlesclock/app.js +++ b/apps/circlesclock/app.js @@ -41,7 +41,7 @@ const colorRed = '#ff0000'; const colorGreen = '#008000'; const colorBlue = '#0000ff'; const colorYellow = '#ffff00'; -const widgetOffset = showWidgets ? 14 : 0; +const widgetOffset = showWidgets ? 24 : 0; const h = g.getHeight() - widgetOffset; const w = g.getWidth(); const hOffset = 30 - widgetOffset; From 66294b3c8a7a0e5ee92c7eeab3ea346e44f314d9 Mon Sep 17 00:00:00 2001 From: Marco Heiming Date: Thu, 6 Jan 2022 11:17:27 +0100 Subject: [PATCH 15/29] Round step distance --- apps/circlesclock/app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/circlesclock/app.js b/apps/circlesclock/app.js index 319e99809..d9a8d8eae 100644 --- a/apps/circlesclock/app.js +++ b/apps/circlesclock/app.js @@ -175,7 +175,7 @@ function drawStepsDistance(w) { g.setFont("Vector:12"); g.setFontAlign(0, 0); g.setColor(colorFg); - g.drawString(shortValue(stepsDistance), w + 2, h3); + g.drawString(Math.round(shortValue(stepsDistance)), w + 2, h3); g.drawImage(shoesIconGreen, w - 6, h3 + radiusOuter - 6); } From 33deb83a675b744599090325596ee015ea98d6f9 Mon Sep 17 00:00:00 2001 From: Marco H Date: Thu, 6 Jan 2022 13:01:36 +0100 Subject: [PATCH 16/29] Fix rounding of step distance --- apps/circlesclock/app.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/circlesclock/app.js b/apps/circlesclock/app.js index d9a8d8eae..099217706 100644 --- a/apps/circlesclock/app.js +++ b/apps/circlesclock/app.js @@ -155,7 +155,7 @@ function drawStepsDistance(w) { if (!w) w = getCirclePosition("steps", w1); const steps = getSteps(); const stepDistance = settings.stepLength || 0.8; - const stepsDistance = steps * stepDistance; + const stepsDistance = Math.round(steps * stepDistance); g.setColor(colorGrey); g.fillCircle(w, h3, radiusOuter); @@ -175,7 +175,7 @@ function drawStepsDistance(w) { g.setFont("Vector:12"); g.setFontAlign(0, 0); g.setColor(colorFg); - g.drawString(Math.round(shortValue(stepsDistance)), w + 2, h3); + g.drawString(shortValue(stepsDistance), w + 2, h3); g.drawImage(shoesIconGreen, w - 6, h3 + radiusOuter - 6); } From 5e7afb28273bdf6f72ad8ffae1a484b8016f63fe Mon Sep 17 00:00:00 2001 From: Marco Heiming Date: Thu, 6 Jan 2022 15:18:45 +0100 Subject: [PATCH 17/29] Increase size of circles and fonts inside Updated screenshots --- apps.json | 2 +- apps/circlesclock/README.md | 5 +++-- apps/circlesclock/app.js | 19 ++++++++++--------- apps/circlesclock/screenshot-dark.png | Bin 0 -> 3857 bytes apps/circlesclock/screenshot-light.png | Bin 0 -> 3823 bytes apps/circlesclock/screenshot.png | Bin 3576 -> 0 bytes 6 files changed, 14 insertions(+), 12 deletions(-) create mode 100644 apps/circlesclock/screenshot-dark.png create mode 100644 apps/circlesclock/screenshot-light.png delete mode 100644 apps/circlesclock/screenshot.png diff --git a/apps.json b/apps.json index f1609bf4f..a2fd1ec9b 100644 --- a/apps.json +++ b/apps.json @@ -5078,7 +5078,7 @@ "version":"0.04", "description": "A clock with circles for different data at the bottom in a probably familiar style", "icon": "app.png", - "screenshots": [{"url":"screenshot.png"}], + "screenshots": [{"url":"screenshot-dark.png"}, {"url":"screenshot-light.png"}], "dependencies": {"widpedom":"app"}, "type": "clock", "tags": "clock", diff --git a/apps/circlesclock/README.md b/apps/circlesclock/README.md index 86c388440..9004161d6 100644 --- a/apps/circlesclock/README.md +++ b/apps/circlesclock/README.md @@ -10,8 +10,9 @@ It can show the following information (this can be configured): * Heart rate (automatically updates when screen is on and unlocked) * Battery (including charging status and battery low warning) -## Screenshot -![Screenshot](screenshot.png) +## Screenshots +![Screenshot dark theme](screenshot-dark.png) +![Screenshot light theme](screenshot-light.png) ## TODO * Show weather information diff --git a/apps/circlesclock/app.js b/apps/circlesclock/app.js index 099217706..ac7ae1b3f 100644 --- a/apps/circlesclock/app.js +++ b/apps/circlesclock/app.js @@ -47,12 +47,13 @@ const w = g.getWidth(); const hOffset = 30 - widgetOffset; 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 h3 = Math.round(8 * h / 8 - hOffset - 3); 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; +const radiusOuter = 25; +const radiusInner = 18; +const circleFont = "Vector:15"; function draw() { g.clear(true); @@ -83,7 +84,7 @@ function draw() { g.drawString(locale.time(new Date(), 1), w / 10, h1 + 8); // date & dow - g.setFont("Vector:20"); + g.setFont("Vector:21"); g.setFontAlign(-1, 0); g.drawString(locale.date(new Date()), w / 10, h2); g.drawString(locale.dow(new Date()), w / 10, h2 + 22); @@ -143,7 +144,7 @@ function drawSteps(w) { g.fillPoly([w, h3, w - 15, h3 + radiusOuter + 5, w + 15, h3 + radiusOuter + 5]); - g.setFont("Vector:12"); + g.setFont(circleFont); g.setFontAlign(0, 0); g.setColor(colorFg); g.drawString(shortValue(steps), w + 2, h3); @@ -172,7 +173,7 @@ function drawStepsDistance(w) { g.fillPoly([w, h3, w - 15, h3 + radiusOuter + 5, w + 15, h3 + radiusOuter + 5]); - g.setFont("Vector:12"); + g.setFont(circleFont); g.setFontAlign(0, 0); g.setColor(colorFg); g.drawString(shortValue(stepsDistance), w + 2, h3); @@ -196,7 +197,7 @@ function drawHeartRate(w) { g.fillPoly([w, h3, w - 15, h3 + radiusOuter + 5, w + 15, h3 + radiusOuter + 5]); - g.setFont("Vector:12"); + g.setFont(circleFont); g.setFontAlign(0, 0); g.setColor(colorFg); g.drawString(hrtValue != undefined ? hrtValue : "-", w, h3); @@ -220,7 +221,7 @@ function drawBattery(w) { g.fillPoly([w, h3, w - 15, h3 + radiusOuter + 5, w + 15, h3 + radiusOuter + 5]); - g.setFont("Vector:12"); + g.setFont(circleFont); g.setFontAlign(0, 0); let icon = powerIcon; @@ -259,7 +260,7 @@ function drawGauge(cx, cy, percent, color) { g.setColor(color); - const size = 4; + const size = radiusOuter - radiusInner - 2; // draw gauge for (i = startrot; i > endrot - size; i -= size) { x = cx + r * Math.sin(radians(i)); diff --git a/apps/circlesclock/screenshot-dark.png b/apps/circlesclock/screenshot-dark.png new file mode 100644 index 0000000000000000000000000000000000000000..00c0e3399cf9a1f4fbd299e259d245e7a9519db7 GIT binary patch literal 3857 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 F{TF;GBE$dy literal 0 HcmV?d00001 diff --git a/apps/circlesclock/screenshot-light.png b/apps/circlesclock/screenshot-light.png new file mode 100644 index 0000000000000000000000000000000000000000..af47b30a40681d7515efcf0658d43784a3e87b8d GIT binary patch literal 3823 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 From ba20a7b51eecc1452c7e5fb62b4964b5d7d875ad Mon Sep 17 00:00:00 2001 From: Marco Heiming Date: Thu, 6 Jan 2022 15:37:33 +0100 Subject: [PATCH 18/29] Center clock text & better placement for date texts --- apps/circlesclock/app.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/circlesclock/app.js b/apps/circlesclock/app.js index ac7ae1b3f..b5ee61c75 100644 --- a/apps/circlesclock/app.js +++ b/apps/circlesclock/app.js @@ -79,15 +79,15 @@ function draw() { // time g.setFont("Vector:50"); - g.setFontAlign(-1, -1); + g.setFontAlign(0, -1); g.setColor(colorFg); - g.drawString(locale.time(new Date(), 1), w / 10, h1 + 8); + g.drawString(locale.time(new Date(), 1), w / 2, h1 + 8); // date & dow g.setFont("Vector:21"); g.setFontAlign(-1, 0); - g.drawString(locale.date(new Date()), w / 10, h2); - g.drawString(locale.dow(new Date()), w / 10, h2 + 22); + g.drawString(locale.date(new Date()), w > 180 ? 2 * w / 10 : w / 10, h2); + g.drawString(locale.dow(new Date()), w > 180 ? 2 * w / 10 : w / 10, h2 + 22); drawCircle(1, "steps"); drawCircle(2, "hr"); From aa47b7fa99cceb520f7684a8e05bd995fd828de1 Mon Sep 17 00:00:00 2001 From: Marco Heiming Date: Fri, 7 Jan 2022 09:53:40 +0100 Subject: [PATCH 19/29] Hopefully fix bug where no HRM data is received --- apps/circlesclock/app.js | 67 +++++++++++++++++++++------------------- 1 file changed, 35 insertions(+), 32 deletions(-) diff --git a/apps/circlesclock/app.js b/apps/circlesclock/app.js index b5ee61c75..392fa4287 100644 --- a/apps/circlesclock/app.js +++ b/apps/circlesclock/app.js @@ -9,6 +9,7 @@ const powerIconGreen = heatshrink.decompress(atob("h0OwYQNkAEDpAEDiQEDkmSAgUJkmA const powerIconRed = heatshrink.decompress(atob("h0OwYQNoAEDyAEDkgEDpIFDiVJBweSAgUJkmAAoYZDgQpEBwYAJA")); let settings; + function loadSettings() { settings = require("Storage").readJSON("circlesclock.json", 1) || { 'minHR': 40, @@ -60,10 +61,10 @@ function draw() { if (!showWidgets) { /* - * 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. - */ + * 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. + */ if (WIDGETS && typeof WIDGETS === "object") { for (let wd of WIDGETS) { wd.draw = () => {}; @@ -97,7 +98,7 @@ function draw() { function drawCircle(index, defaultType) { const type = settings['circle' + index] || defaultType; - const w = index == 1 ? w1: index == 2 ? w2 : w3; + const w = index == 1 ? w1 : index == 2 ? w2 : w3; switch (type) { case "steps": @@ -114,12 +115,13 @@ function drawCircle(index, defaultType) { break; } } + function getCirclePosition(type, defaultPos) { for (let i = 1; i <= 3; i++) { const setting = settings['circle' + i]; - if (setting == type) return i == 1 ? w1: i == 2 ? w2 : w3; + if (setting == type) return i == 1 ? w1 : i == 2 ? w2 : w3; } - return defaultPos; + return defaultPos || undefined; } function isCircleEnabled(type) { @@ -229,8 +231,7 @@ function drawBattery(w) { if (Bangle.isCharging()) { color = colorGreen; icon = powerIconGreen; - } - else { + } else { if (settings.batteryWarn != undefined && battery <= settings.batteryWarn) { color = colorRed; icon = powerIconRed; @@ -289,39 +290,41 @@ function getSteps() { return 0; } +function enableHRMSensor() { + Bangle.setHRMPower(1, "circleclock"); + if (hrtValue == undefined) { + hrtValue = '...'; + drawHeartRate(); + } +} + Bangle.on('lock', function(isLocked) { if (!isLocked) { if (isCircleEnabled("hr")) { - Bangle.setHRMPower(1, "watch"); - if (hrtValue == undefined) { - hrtValue = '...'; - drawHeartRate(); - } + enableHRMSensor(); } draw(); } else { - if (isCircleEnabled("hr")) { - Bangle.setHRMPower(0, "watch"); - } + Bangle.setHRMPower(0, "circleclock"); } }); -if (isCircleEnabled("hr")) { - Bangle.on('HRM', function(hrm) { - //if(hrm.confidence > 90){ - hrtValue = hrm.bpm; - if (Bangle.isLCDOn()) - drawHeartRate(); - //} else { - // hrtValue = undefined; - //} - }); -} -if (isCircleEnabled("battery")) { - Bangle.on('charging', function(charging) { - drawBattery(); - }); +Bangle.on('HRM', function(hrm) { + if (isCircleEnabled("hr")) { + hrtValue = hrm.bpm; + if (Bangle.isLCDOn()) + drawHeartRate(); + } +}); + + +Bangle.on('charging', function(charging) { + if (isCircleEnabled("battery")) drawBattery(); +}); + +if (isCircleEnabled("hr")) { + enableHRMSensor(); } Bangle.setUI("clock"); From 2f16365e6cf6b4ad9717770e4103b6d52a4f6fe2 Mon Sep 17 00:00:00 2001 From: Marco Heiming Date: Fri, 7 Jan 2022 10:26:45 +0100 Subject: [PATCH 20/29] Redraw background rectangle before drawing circles (fixes graphical glitch) --- apps/circlesclock/app.js | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/apps/circlesclock/app.js b/apps/circlesclock/app.js index 392fa4287..4f2fea4ab 100644 --- a/apps/circlesclock/app.js +++ b/apps/circlesclock/app.js @@ -131,6 +131,11 @@ function isCircleEnabled(type) { function drawSteps(w) { if (!w) w = getCirclePosition("steps", w1); const steps = getSteps(); + + // Draw rectangle background: + g.setColor(colorBg); + g.fillRect(w - radiusOuter - 3, h3 - radiusOuter - 3, w + radiusOuter + 3, h3 + radiusOuter + 3); + g.setColor(colorGrey); g.fillCircle(w, h3, radiusOuter); @@ -160,6 +165,10 @@ function drawStepsDistance(w) { const stepDistance = settings.stepLength || 0.8; const stepsDistance = Math.round(steps * stepDistance); + // Draw rectangle background: + g.setColor(colorBg); + g.fillRect(w - radiusOuter - 3, h3 - radiusOuter - 3, w + radiusOuter + 3, h3 + radiusOuter + 3); + g.setColor(colorGrey); g.fillCircle(w, h3, radiusOuter); @@ -185,6 +194,11 @@ function drawStepsDistance(w) { function drawHeartRate(w) { if (!w) w = getCirclePosition("hr", w2); + + // Draw rectangle background: + g.setColor(colorBg); + g.fillRect(w - radiusOuter - 3, h3 - radiusOuter - 3, w + radiusOuter + 3, h3 + radiusOuter + 3); + g.setColor(colorGrey); g.fillCircle(w, h3, radiusOuter); @@ -210,6 +224,11 @@ function drawHeartRate(w) { function drawBattery(w) { if (!w) w = getCirclePosition("battery", w3); const battery = E.getBattery(); + + // Draw rectangle background: + g.setColor(colorBg); + g.fillRect(w - radiusOuter - 3, h3 - radiusOuter - 3, w + radiusOuter + 3, h3 + radiusOuter + 3); + g.setColor(colorGrey); g.fillCircle(w, h3, radiusOuter); @@ -319,6 +338,12 @@ Bangle.on('HRM', function(hrm) { }); +Bangle.setUI("clock"); +Bangle.loadWidgets(); + +draw(); +setInterval(draw, 60000); + Bangle.on('charging', function(charging) { if (isCircleEnabled("battery")) drawBattery(); }); @@ -326,9 +351,3 @@ Bangle.on('charging', function(charging) { if (isCircleEnabled("hr")) { enableHRMSensor(); } - -Bangle.setUI("clock"); -Bangle.loadWidgets(); - -draw(); -setInterval(draw, 60000); From 96802b0bd48e50ba721b157590d23e3fad8963dd Mon Sep 17 00:00:00 2001 From: Marco Heiming Date: Fri, 7 Jan 2022 10:32:39 +0100 Subject: [PATCH 21/29] Make min- & maxHR settings more granular --- apps/circlesclock/settings.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/circlesclock/settings.js b/apps/circlesclock/settings.js index 95ebc17db..a16bb99a8 100644 --- a/apps/circlesclock/settings.js +++ b/apps/circlesclock/settings.js @@ -15,7 +15,7 @@ value: "minHR" in settings ? settings.minHR : 40, min: 0, max : 250, - step: 10, + step: 5, format: x => { return x; }, @@ -25,7 +25,7 @@ value: "maxHR" in settings ? settings.maxHR : 200, min: 20, max : 250, - step: 10, + step: 5, format: x => { return x; }, From c47cabe156e3e03756492be8ed34b8bc31854d98 Mon Sep 17 00:00:00 2001 From: Marco Heiming Date: Fri, 7 Jan 2022 10:43:06 +0100 Subject: [PATCH 22/29] Update ChangeLog --- apps/circlesclock/ChangeLog | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/circlesclock/ChangeLog b/apps/circlesclock/ChangeLog index f416929ac..4230c1468 100644 --- a/apps/circlesclock/ChangeLog +++ b/apps/circlesclock/ChangeLog @@ -1,4 +1,7 @@ 0.01: New clock 0.02: Fix icon & add battery warn functionality 0.03: Theming support & minor fixes -0.04: Make configurable what to show in each circle; add step distance circle; allow switching visibility of widgets +0.04: Make configurable what to show in each circle + Add step distance circle + Allow switching visibility of widgets + Make circles and text slightly bigger From 2397f5957acc41e9eb91c4da6e65d50901debcca Mon Sep 17 00:00:00 2001 From: Marco Heiming Date: Fri, 7 Jan 2022 13:30:09 +0100 Subject: [PATCH 23/29] Add weather functionality Improve circle position finding --- apps/circlesclock/ChangeLog | 2 +- apps/circlesclock/README.md | 4 +- apps/circlesclock/app.js | 138 +++++++++++++++++++++++++++++----- apps/circlesclock/settings.js | 10 +-- 4 files changed, 126 insertions(+), 28 deletions(-) diff --git a/apps/circlesclock/ChangeLog b/apps/circlesclock/ChangeLog index 4230c1468..ca1da6e21 100644 --- a/apps/circlesclock/ChangeLog +++ b/apps/circlesclock/ChangeLog @@ -2,6 +2,6 @@ 0.02: Fix icon & add battery warn functionality 0.03: Theming support & minor fixes 0.04: Make configurable what to show in each circle - Add step distance circle + Add step distance and weather Allow switching visibility of widgets Make circles and text slightly bigger diff --git a/apps/circlesclock/README.md b/apps/circlesclock/README.md index 9004161d6..a071efcf5 100644 --- a/apps/circlesclock/README.md +++ b/apps/circlesclock/README.md @@ -9,14 +9,12 @@ It can show the following information (this can be configured): * Steps distance (depending on steps) * Heart rate (automatically updates when screen is on and unlocked) * Battery (including charging status and battery low warning) + * Weather (requires [weather app](https://banglejs.com/apps/#weather)) ## Screenshots ![Screenshot dark theme](screenshot-dark.png) ![Screenshot light theme](screenshot-light.png) -## TODO -* Show weather information - ## Creator Marco ([myxor](https://github.com/myxor)) diff --git a/apps/circlesclock/app.js b/apps/circlesclock/app.js index 4f2fea4ab..23be307b9 100644 --- a/apps/circlesclock/app.js +++ b/apps/circlesclock/app.js @@ -1,5 +1,6 @@ const locale = require("locale"); const heatshrink = require("heatshrink"); +const storage = require("Storage"); const shoesIcon = heatshrink.decompress(atob("h0OwYJGgmAAgUBkgECgVJB4cSoAUDyEBkARDpADBhMAyQRBgVAkgmDhIUDAAuQAgY1DAAYA=")); const shoesIconGreen = heatshrink.decompress(atob("h0OwYJGhIEDgVIAgUEyQKDkmACgcggVACIeQAYMSgIRCgmApIbDiQUDAAkBkAFDGoYAD")); @@ -8,10 +9,19 @@ const powerIcon = heatshrink.decompress(atob("h0OwYQNsAED7AEDmwEDtu2AgUbtuABwXbB const powerIconGreen = heatshrink.decompress(atob("h0OwYQNkAEDpAEDiQEDkmSAgUJkmABwVJBIUEyVAAoYOCgEBFIgODABI")); const powerIconRed = heatshrink.decompress(atob("h0OwYQNoAEDyAEDkgEDpIFDiVJBweSAgUJkmAAoYZDgQpEBwYAJA")); +const weatherCloudy = heatshrink.decompress(atob("h0OwYPMgfwAgU//4FCv///+Ag4DB//gh4EC//jAgYAK+IED8EBAgXAHpQA==")); +const weatherSunny = heatshrink.decompress(atob("h0OwYKHhuAAYM2AQkA7AOD2wFCgdt20AgOA7dtwHAC4PbsAUGgFt2ApIAAgIIA==")); +const weatherPartlyCloudy = heatshrink.decompress(atob("h0OwYOLg4FEn/8AgV+g/gAgMcgE48EB48f/wJBgP/gfwgEDBAIRBC4UH/kB4AmC8F+C4X4gf/AAIaBAAgA==")); +const weatherRainy = heatshrink.decompress(atob("h0OwYKHh/AAgX8AoUB/EAuEAj/wgEDwEHCIX/wIXD8ARB/kAnED+P/8f+BgNwnARCjkOAgUH/+AAoU/IQ4A=")); +const weatherPartlyRainy = heatshrink.decompress(atob("h0OwYJGjkAnAFCj+AAgU//4FCuEA8EAg8ch/4gEB4////AAoIIBCIMD/wgCg4bBg/8BwMD+AgBh4ZBDQf/FIIABh4IBgAA==")); +const weatherSnowy = heatshrink.decompress(atob("h0OwYKHh/AAgUD+AKD/gIDn4LC/4ABBYX8DQYODgYPCAoIOCEAgpGDQRCHA=")); +const weatherFoggy = heatshrink.decompress(atob("h0OwYPMj/+AgU4gFwgED+ACBwEH8AMB/kB4AEBBAYAHg////H/+ABQl+n4LB/A9K")); +const weatherStormy = heatshrink.decompress(atob("h0OwYKHh/AAgX8AoUB/EAuEAj/wgEDwEHCIX/wIRBBwPgAQMcgE4gfwn8D/wpGCgQAQA")); + let settings; function loadSettings() { - settings = require("Storage").readJSON("circlesclock.json", 1) || { + settings = storage.readJSON("circlesclock.json", 1) || { 'minHR': 40, 'maxHR': 200, 'stepGoal': 10000, @@ -48,13 +58,12 @@ const w = g.getWidth(); const hOffset = 30 - widgetOffset; const h1 = Math.round(1 * h / 5 - hOffset); const h2 = Math.round(3 * h / 5 - hOffset); -const h3 = Math.round(8 * h / 8 - hOffset - 3); -const w1 = Math.round(w / 6); -const w2 = Math.round(3 * w / 6); -const w3 = Math.round(5 * w / 6); +const h3 = Math.round(8 * h / 8 - hOffset - 3); // circle y position +const circlePosX = [Math.round(w / 6), Math.round(3 * w / 6), Math.round(5 * w / 6)]; // cirle x positions const radiusOuter = 25; const radiusInner = 18; const circleFont = "Vector:15"; +const circleFontSmall = "Vector:13"; function draw() { g.clear(true); @@ -90,16 +99,17 @@ function draw() { g.drawString(locale.date(new Date()), w > 180 ? 2 * w / 10 : w / 10, h2); g.drawString(locale.dow(new Date()), w > 180 ? 2 * w / 10 : w / 10, h2 + 22); - drawCircle(1, "steps"); - drawCircle(2, "hr"); - drawCircle(3, "battery"); + drawCircle(1); + drawCircle(2); + drawCircle(3); } +const defaultCircleTypes = ["steps", "hr", "battery"]; -function drawCircle(index, defaultType) { - const type = settings['circle' + index] || defaultType; - const w = index == 1 ? w1 : index == 2 ? w2 : w3; - +function drawCircle(index) { + let type = settings['circle' + index]; + if (!type) type = defaultCircleTypes[index - 1]; + const w = getCirclePosition(type); switch (type) { case "steps": drawSteps(w); @@ -113,15 +123,21 @@ function drawCircle(index, defaultType) { case "battery": drawBattery(w); break; + case "weather": + drawWeather(w); + break; } } -function getCirclePosition(type, defaultPos) { +function getCirclePosition(type) { for (let i = 1; i <= 3; i++) { const setting = settings['circle' + i]; - if (setting == type) return i == 1 ? w1 : i == 2 ? w2 : w3; + if (setting == type) return circlePosX[i - 1]; } - return defaultPos || undefined; + for (let i = 0; i < defaultCircleTypes.length; i++) { + if (type == defaultCircleTypes[i]) return circlePosX[i]; + } + return undefined; } function isCircleEnabled(type) { @@ -129,7 +145,7 @@ function isCircleEnabled(type) { } function drawSteps(w) { - if (!w) w = getCirclePosition("steps", w1); + if (!w) w = getCirclePosition("steps"); const steps = getSteps(); // Draw rectangle background: @@ -160,7 +176,7 @@ function drawSteps(w) { } function drawStepsDistance(w) { - if (!w) w = getCirclePosition("steps", w1); + if (!w) w = getCirclePosition("steps"); const steps = getSteps(); const stepDistance = settings.stepLength || 0.8; const stepsDistance = Math.round(steps * stepDistance); @@ -193,7 +209,7 @@ function drawStepsDistance(w) { } function drawHeartRate(w) { - if (!w) w = getCirclePosition("hr", w2); + if (!w) w = getCirclePosition("hr"); // Draw rectangle background: g.setColor(colorBg); @@ -222,7 +238,7 @@ function drawHeartRate(w) { } function drawBattery(w) { - if (!w) w = getCirclePosition("battery", w3); + if (!w) w = getCirclePosition("battery"); const battery = E.getBattery(); // Draw rectangle background: @@ -262,6 +278,85 @@ function drawBattery(w) { g.drawImage(icon, w - 6, h3 + radiusOuter - 6); } +function drawWeather(w) { + if (!w) w = getCirclePosition("weather"); + const weather = getWeather(); + const tempString = weather ? locale.temp(weather.temp - 273.15) : undefined; + const code = weather ? weather.code : -1; + + // Draw rectangle background: + g.setColor(colorBg); + g.fillRect(w - radiusOuter - 3, h3 - radiusOuter - 3, w + radiusOuter + 3, h3 + radiusOuter + 3); + + g.setColor(colorGrey); + g.fillCircle(w, h3, radiusOuter); + + g.setColor(colorBg); + g.fillCircle(w, h3, radiusInner); + + g.fillPoly([w, h3, w - 15, h3 + radiusOuter + 5, w + 15, h3 + radiusOuter + 5]); + + const content = tempString ? tempString : "?"; + g.setFont(content.length < 4 ? circleFont : circleFontSmall); + g.setFontAlign(0, 0); + g.setColor(colorFg); + g.drawString(content, w, h3); + + if (code > 0) { + const icon = getWeatherIconByCode(code); + if (icon) g.drawImage(icon, w - 6, h3 + radiusOuter - 6); + } +} + +/* + * Choose weather icon to display based on weather conditition code + * https://openweathermap.org/weather-conditions#Weather-Condition-Codes-2 + */ +function getWeatherIconByCode(code) { + const codeGroup = Math.round(code / 100); + switch (codeGroup) { + case 2: + return weatherStormy; + case 3: + return weatherCloudy; + case 5: + switch (code) { + case 511: + return weatherSnowy; + case 520: + return weatherPartlyRainy; + case 521: + return weatherPartlyRainy; + case 522: + return weatherPartlyRainy; + case 531: + return weatherPartlyRainy; + default: + return weatherRainy; + } + break; + case 6: + return weatherSnowy; + case 7: + return weatherFoggy; + case 8: + switch (code) { + case 800: + return weatherSunny; + case 801: + return weatherPartlyCloudy; + case 802: + return weatherPartlyCloudy; + default: + return weatherCloudy; + } + break; + default: + return undefined; + } + return undefined; +} + function radians(a) { return a * Math.PI / 180; } @@ -309,6 +404,11 @@ function getSteps() { return 0; } +function getWeather() { + const jsonWeather = storage.readJSON('weather.json'); + return jsonWeather && jsonWeather.weather ? jsonWeather.weather : undefined; +} + function enableHRMSensor() { Bangle.setHRMPower(1, "circleclock"); if (hrtValue == undefined) { diff --git a/apps/circlesclock/settings.js b/apps/circlesclock/settings.js index a16bb99a8..ac4215a8a 100644 --- a/apps/circlesclock/settings.js +++ b/apps/circlesclock/settings.js @@ -6,8 +6,8 @@ settings[key] = value; storage.write(SETTINGS_FILE, settings); } - var valuesCircleTypes = ["steps", "stepsDist", "hr", "battery"]; - var namesCircleTypes = ["steps", "distance", "heart", "battery"]; + var valuesCircleTypes = ["steps", "stepsDist", "hr", "battery", "weather"]; + var namesCircleTypes = ["steps", "distance", "heart", "battery", "weather"]; E.showMenu({ '': { 'title': 'circlesclock' }, '< Back': back, @@ -78,19 +78,19 @@ }, 'left': { value: settings.circle1 ? valuesCircleTypes.indexOf(settings.circle1) : 0, - min: 0, max: 3, + min: 0, max: 4, format: v => namesCircleTypes[v], onchange: x => save('circle1', valuesCircleTypes[x]), }, 'middle': { value: settings.circle2 ? valuesCircleTypes.indexOf(settings.circle2) : 2, - min: 0, max: 3, + min: 0, max: 4, format: v => namesCircleTypes[v], onchange: x => save('circle2', valuesCircleTypes[x]), }, 'right': { value: settings.circle3 ? valuesCircleTypes.indexOf(settings.circle3) : 3, - min: 0, max: 3, + min: 0, max: 4, format: v => namesCircleTypes[v], onchange: x => save('circle3', valuesCircleTypes[x]), } From 83debe93ee54ef1d01f78e572dc2c1a2d7dee66e Mon Sep 17 00:00:00 2001 From: Marco Heiming Date: Fri, 7 Jan 2022 18:21:36 +0100 Subject: [PATCH 24/29] Bigger weather icons & a bit thinner circles --- apps/circlesclock/app.js | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/apps/circlesclock/app.js b/apps/circlesclock/app.js index 23be307b9..f93a283f2 100644 --- a/apps/circlesclock/app.js +++ b/apps/circlesclock/app.js @@ -9,14 +9,14 @@ const powerIcon = heatshrink.decompress(atob("h0OwYQNsAED7AEDmwEDtu2AgUbtuABwXbB const powerIconGreen = heatshrink.decompress(atob("h0OwYQNkAEDpAEDiQEDkmSAgUJkmABwVJBIUEyVAAoYOCgEBFIgODABI")); const powerIconRed = heatshrink.decompress(atob("h0OwYQNoAEDyAEDkgEDpIFDiVJBweSAgUJkmAAoYZDgQpEBwYAJA")); -const weatherCloudy = heatshrink.decompress(atob("h0OwYPMgfwAgU//4FCv///+Ag4DB//gh4EC//jAgYAK+IED8EBAgXAHpQA==")); -const weatherSunny = heatshrink.decompress(atob("h0OwYKHhuAAYM2AQkA7AOD2wFCgdt20AgOA7dtwHAC4PbsAUGgFt2ApIAAgIIA==")); -const weatherPartlyCloudy = heatshrink.decompress(atob("h0OwYOLg4FEn/8AgV+g/gAgMcgE48EB48f/wJBgP/gfwgEDBAIRBC4UH/kB4AmC8F+C4X4gf/AAIaBAAgA==")); -const weatherRainy = heatshrink.decompress(atob("h0OwYKHh/AAgX8AoUB/EAuEAj/wgEDwEHCIX/wIXD8ARB/kAnED+P/8f+BgNwnARCjkOAgUH/+AAoU/IQ4A=")); +const weatherCloudy = heatshrink.decompress(atob("iEQwYWTgP//+AAoMPAoPwAoN/AocfAgP//0AAgQAB/AFEABgdDAAMDDohMRA")); +const weatherSunny = heatshrink.decompress(atob("iEQwYLIg3AAgVgAQMMAo8Am3YAgUB23bAoUNAoIUBjYFCsOwBYoFDDpFgHYI1JI4gFGAAYA=")); +const weatherPartlyCloudy = heatshrink.decompress(atob("iEQwYQNv0AjgGDn4EDh///gFChwREC4MfxwIBv0//+AC4X4j4FCv/AgfwgED/wIBuAaBBwgFDgP4gf/AAXABwIEBDQQAEA==")); +const weatherRainy = heatshrink.decompress(atob("iEQwYLIg/gAgUB///wAFBh/AgfwgED/wIBuEAj4OCv0AjgaCh/4AocAnAFBFIU4EAM//gRBEAIOBhw1C/AmDAosAC4JNIAAg")); const weatherPartlyRainy = heatshrink.decompress(atob("h0OwYJGjkAnAFCj+AAgU//4FCuEA8EAg8ch/4gEB4////AAoIIBCIMD/wgCg4bBg/8BwMD+AgBh4ZBDQf/FIIABh4IBgAA==")); -const weatherSnowy = heatshrink.decompress(atob("h0OwYKHh/AAgUD+AKD/gIDn4LC/4ABBYX8DQYODgYPCAoIOCEAgpGDQRCHA=")); -const weatherFoggy = heatshrink.decompress(atob("h0OwYPMj/+AgU4gFwgED+ACBwEH8AMB/kB4AEBBAYAHg////H/+ABQl+n4LB/A9K")); -const weatherStormy = heatshrink.decompress(atob("h0OwYKHh/AAgX8AoUB/EAuEAj/wgEDwEHCIX/wIRBBwPgAQMcgE4gfwn8D/wpGCgQAQA")); +const weatherSnowy = heatshrink.decompress(atob("iEQwYROn/8AocH8AECuAFBh0Agf+CIN/4EDx/4j/x4EAgIIBwAXBAogRFDoopFGoxBGABIA=")); +const weatherFoggy = heatshrink.decompress(atob("iEQwYROn/8AgUB/EfwAFBh/AgfwgED/wIBuEABwd/4EcDQgFDgE4Fosf///8f//A/Lj/xCQIRNA=")); +const weatherStormy = heatshrink.decompress(atob("iEQwYLIg/gAgUB///wAFBh/AgfwgED/wIBuEAj4OCv0AjgaCh/4AoX8gE4AoQpBnAdBF4IRBDQMH/kOHgY7DAo4AOA==")); let settings; @@ -61,7 +61,7 @@ const h2 = Math.round(3 * h / 5 - hOffset); const h3 = Math.round(8 * h / 8 - hOffset - 3); // circle y position const circlePosX = [Math.round(w / 6), Math.round(3 * w / 6), Math.round(5 * w / 6)]; // cirle x positions const radiusOuter = 25; -const radiusInner = 18; +const radiusInner = 20; const circleFont = "Vector:15"; const circleFontSmall = "Vector:13"; @@ -292,9 +292,9 @@ function drawWeather(w) { g.fillCircle(w, h3, radiusOuter); g.setColor(colorBg); - g.fillCircle(w, h3, radiusInner); + g.fillCircle(w, h3, radiusInner + 1); // the weather circle is thinner - g.fillPoly([w, h3, w - 15, h3 + radiusOuter + 5, w + 15, h3 + radiusOuter + 5]); + g.fillPoly([w, h3, w - 25, h3 + radiusOuter + 5, w + 25, h3 + radiusOuter + 5]); const content = tempString ? tempString : "?"; g.setFont(content.length < 4 ? circleFont : circleFontSmall); @@ -304,7 +304,7 @@ function drawWeather(w) { if (code > 0) { const icon = getWeatherIconByCode(code); - if (icon) g.drawImage(icon, w - 6, h3 + radiusOuter - 6); + if (icon) g.drawImage(icon, w - 6, h3 + radiusOuter - 10); } } @@ -375,7 +375,7 @@ function drawGauge(cx, cy, percent, color) { g.setColor(color); - const size = radiusOuter - radiusInner - 2; + const size = radiusOuter - radiusInner - 3; // draw gauge for (i = startrot; i > endrot - size; i -= size) { x = cx + r * Math.sin(radians(i)); From 8bbe2a43b40a2a2f6bc48b17f934ac2c413a3a86 Mon Sep 17 00:00:00 2001 From: Marco Heiming Date: Fri, 7 Jan 2022 18:33:09 +0100 Subject: [PATCH 25/29] Same size for every circle --- apps/circlesclock/app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/circlesclock/app.js b/apps/circlesclock/app.js index f93a283f2..6d408fd59 100644 --- a/apps/circlesclock/app.js +++ b/apps/circlesclock/app.js @@ -292,7 +292,7 @@ function drawWeather(w) { g.fillCircle(w, h3, radiusOuter); g.setColor(colorBg); - g.fillCircle(w, h3, radiusInner + 1); // the weather circle is thinner + g.fillCircle(w, h3, radiusInner); g.fillPoly([w, h3, w - 25, h3 + radiusOuter + 5, w + 25, h3 + radiusOuter + 5]); From 968e7b5840fdf95f1b3b5300a964b77ab788ab8a Mon Sep 17 00:00:00 2001 From: Marco Heiming Date: Sat, 8 Jan 2022 10:25:24 +0100 Subject: [PATCH 26/29] Make text size in heart rate circle slightly bigger as it does not have any units --- apps/circlesclock/app.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/circlesclock/app.js b/apps/circlesclock/app.js index 6d408fd59..3843d5dda 100644 --- a/apps/circlesclock/app.js +++ b/apps/circlesclock/app.js @@ -63,6 +63,7 @@ const circlePosX = [Math.round(w / 6), Math.round(3 * w / 6), Math.round(5 * w / const radiusOuter = 25; const radiusInner = 20; const circleFont = "Vector:15"; +const circleFontBig = "Vector:16"; const circleFontSmall = "Vector:13"; function draw() { @@ -229,7 +230,7 @@ function drawHeartRate(w) { g.fillPoly([w, h3, w - 15, h3 + radiusOuter + 5, w + 15, h3 + radiusOuter + 5]); - g.setFont(circleFont); + g.setFont(circleFontBig); g.setFontAlign(0, 0); g.setColor(colorFg); g.drawString(hrtValue != undefined ? hrtValue : "-", w, h3); From 7ad707793f884a28d59fd37007b06f5357770829 Mon Sep 17 00:00:00 2001 From: Marco Heiming Date: Sun, 9 Jan 2022 13:42:01 +0100 Subject: [PATCH 27/29] Fix drawing of full circle --- apps/circlesclock/app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/circlesclock/app.js b/apps/circlesclock/app.js index 3843d5dda..1f6cc75ab 100644 --- a/apps/circlesclock/app.js +++ b/apps/circlesclock/app.js @@ -372,7 +372,7 @@ function drawGauge(cx, cy, percent, color) { if (percent > 1) percent = 1; var startrot = -offset; - var endrot = startrot - ((end - offset) * percent) - 15; + var endrot = startrot - ((end - offset) * percent) - 35; g.setColor(color); From 05f0d3003a32df7e1e95bfd72d679d9edc333097 Mon Sep 17 00:00:00 2001 From: Marco Heiming Date: Sun, 9 Jan 2022 13:45:50 +0100 Subject: [PATCH 28/29] Fix minor glitch in circle drawing --- apps/circlesclock/app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/circlesclock/app.js b/apps/circlesclock/app.js index 1f6cc75ab..91d4937c4 100644 --- a/apps/circlesclock/app.js +++ b/apps/circlesclock/app.js @@ -376,7 +376,7 @@ function drawGauge(cx, cy, percent, color) { g.setColor(color); - const size = radiusOuter - radiusInner - 3; + const size = radiusOuter - radiusInner - 2; // draw gauge for (i = startrot; i > endrot - size; i -= size) { x = cx + r * Math.sin(radians(i)); From 6f1b1093621a20aba705cbe483222013c416f1b4 Mon Sep 17 00:00:00 2001 From: Marco Heiming Date: Sun, 9 Jan 2022 13:46:12 +0100 Subject: [PATCH 29/29] Add TODOs to README --- apps/circlesclock/README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/circlesclock/README.md b/apps/circlesclock/README.md index a071efcf5..9aaa4bc8e 100644 --- a/apps/circlesclock/README.md +++ b/apps/circlesclock/README.md @@ -15,6 +15,10 @@ It can show the following information (this can be configured): ![Screenshot dark theme](screenshot-dark.png) ![Screenshot light theme](screenshot-light.png) +# TODO +* Add sunrise and sunset +* Display moon instead of sun during night on weather circle + ## Creator Marco ([myxor](https://github.com/myxor))