From d7f0113a86a044ef809d001d22d1ce0c26cf22c7 Mon Sep 17 00:00:00 2001 From: David Volovskiy Date: Sun, 18 May 2025 07:54:26 -0400 Subject: [PATCH] Three ring bugfixes and changes --- apps/daisy/app.js | 121 +++++++++++++++++++---------- apps/daisy/settings.js | 168 ++++++++++++++++++++++++----------------- 2 files changed, 180 insertions(+), 109 deletions(-) diff --git a/apps/daisy/app.js b/apps/daisy/app.js index ae8d76c76..f59e64ebf 100644 --- a/apps/daisy/app.js +++ b/apps/daisy/app.js @@ -23,9 +23,9 @@ var pals = Array(3).fill().map(() => ( })); let palbg; -const infoLine = (3*h/4) - 6; -const infoWidth = 56; -const infoHeight = 11; +const infoLineDefault = (3*h/4) - 6; +const infoWidthDefault = 56; +const infoHeightDefault = 11; const ringEdge = 4; const ringIterOffset = 10; const ringThick = 6; @@ -58,7 +58,8 @@ Graphics.prototype.setFontBloggerSansLight42 = function() { atob("CQ0VFBQVFhUVFRUVCg=="), 42|65536 ); -} +}; + // Three rings Graphics.prototype.setFontBloggerSansLight38 = function() { // Actual height 25 (28 - 4) @@ -69,7 +70,7 @@ Graphics.prototype.setFontBloggerSansLight38 = function() { atob("CAwTEhITFBMTExMTCQ=="), 38|65536 ); -} +}; Graphics.prototype.setFontRoboto20 = function(scale) { // Actual height 21 (20 - 0) @@ -138,13 +139,17 @@ function setLargeFont() { function setSmallFont() { let size = 16; + if (infoMode == "ID_HRM" ) { + g.setFont('Vector', size); + return; + } switch (innerMostRing) { - case 3: - size = 9; - break; case 2: size = 13; break; + case 3: + size = 12; + break; } g.setFont('Vector', size); } @@ -164,6 +169,7 @@ function getSteps() { function loadSettings() { settings = require("Storage").readJSON(SETTINGS_FILE,1)||{}; + settings.rings = settings.rings || [{}, {}, {}]; settings.rings[0].gy = settings.rings[0].gy||'#020'; settings.rings[0].fg = settings.rings[0].fg||'#0f0'; @@ -173,16 +179,24 @@ function loadSettings() { settings.rings[1].gy = settings.rings[1].gy||'#020'; settings.rings[1].fg = settings.rings[1].fg||'#0f0'; - settings.rings[1].type = settings.rings[1].type||'Semi'; + settings.rings[1].type = settings.rings[1].type||'None'; settings.rings[1].ring = settings.rings[1].ring||'Minutes'; settings.rings[1].step_target = settings.rings[1].step_target||10000; settings.rings[2].gy = settings.rings[2].gy||'#020'; settings.rings[2].fg = settings.rings[2].fg||'#0f0'; - settings.rings[2].type = 'None'; - settings.rings[2].ring = settings.rings[2].ring||'Seconds'; + settings.rings[2].type = settings.rings[2].type||'None'; + settings.rings[2].ring = settings.rings[2].ring||'Hours'; settings.rings[2].step_target = settings.rings[2].step_target||10000; + for (let i = 0; i < settings.rings.length; i++) { + if (settings.rings[i].color == 'Blk/Wht') { + settings.rings[i].gy = g.theme.fg; + settings.rings[i].fg = g.theme.fg; + } + } + + settings.fg = settings.fg||'#0ff'; settings.idle_check = (settings.idle_check === undefined ? true : settings.idle_check); settings.batt_hours = (settings.batt_hours === undefined ? false : settings.batt_hours); settings.hr_12 = (global_settings["12hour"] === undefined ? false : global_settings["12hour"]); @@ -316,22 +330,36 @@ function prevInfo(idx) { return idx; } -function clearInfo() { - - var width = infoWidth; - var height = infoHeight; +function getInfoDims() { + var line = infoLineDefault; + var width = infoWidthDefault; + var height = infoHeightDefault; switch (innerMostRing) { - case 3: - width -= 20; - height -= 3; - break; case 2: width -= 8; height -= 2; + line -= 7; + break; + case 3: + width -= 10; + height -= 6; + line -= 10; break; } + if (infoMode == "ID_HRM") { + width = 30; + height = infoHeightDefault; + } + return[line, width, height]; +} + +function clearInfo() { + var dims = getInfoDims(); + var line = dims[0]; + var width = dims[1]; + var height = dims[2]; g.setColor(g.theme.bg); - g.fillRect((w/2) - width, infoLine - height, (w/2) + width, infoLine + height); + g.fillRect((w/2) - width, line - height, (w/2) + width, line + height); } function drawInfo() { @@ -339,18 +367,20 @@ function drawInfo() { g.setColor(g.theme.fg); setSmallFont(); g.setFontAlign(0,0); - + var dims = getInfoDims(); + var line = dims[0]; + var height = dims[2]; if (infoMode == "ID_HRM") { clearInfo(); g.setColor('#f00'); // red - drawHeartIcon(); + drawHeartIcon(line, height); } else { - g.drawString((infoData[infoMode].calc().toUpperCase()), w/2, infoLine); + g.drawString((infoData[infoMode].calc().toUpperCase()), w/2, line); } } -function drawHeartIcon() { - g.drawImage(hrmImg, (w/2) - infoHeight - 20, infoLine - infoHeight); +function drawHeartIcon(line, height) { + g.drawImage(hrmImg, (w/2) - height - 20, line - height); } function drawHrm() { @@ -358,11 +388,14 @@ function drawHrm() { var d = new Date(); clearInfo(); g.setColor(d.getSeconds()&1 ? '#f00' : g.theme.bg); - drawHeartIcon(); + var dims = getInfoDims(); + var line = dims[0]; + var height = dims[2]; + drawHeartIcon(line, height); setSmallFont(); g.setFontAlign(-1,0); // left g.setColor(hrmConfidence >= 50 ? g.theme.fg : '#f00'); - g.drawString(hrmCurrent, (w/2) + 10, infoLine); + g.drawString(hrmCurrent, (w/2) + 10, line); } function draw(updateSeconds) { @@ -372,7 +405,6 @@ function draw(updateSeconds) { drawAllRings(date, updateSeconds); } else { - g.clear(); drawClock(); } } @@ -389,8 +421,8 @@ function getGaugeImage(date, ringType, step_target) { var ring_max = 100; switch (ringType) { case 'Hours': - ring_fill = hh % 12; - ring_max = 12; + ring_fill = ((hh % 12) * 60) + mm; + ring_max = 12 * 60; break; case 'Minutes': ring_fill = mm; @@ -458,7 +490,7 @@ function drawAllRings(date, updateSeconds) { let ring = settings.rings[i]; if (ring.type == "None") continue; if (ring.ring != "Seconds" && updateSeconds) continue; - if (ring.type == 'Full' && ring.color == 'Fore') ring.type = 'Semi'; + if (ring.type == 'Full' && ring.color == 'Blk/Wht') ring.type = 'Semi'; result = getGaugeImage(date, ring.ring, ring.step_target); drawIfChanged(result[0], result[1], result[2], i, ring.type); } @@ -478,10 +510,12 @@ function drawClock() { g.reset(); g.setColor(g.theme.bg); innerMostRing = getInnerMostRing(); + let edge = ringEdge + (innerMostRing * ringIterOffset); + g.fillEllipse(edge+ringThick,edge+ringThick,w-edge-ringThick,h-edge-ringThick); // Clears the text within the circle drawAllRings(date, false); setLargeFont(); - g.setColor(settings.rings[0].fg); + g.setColor(settings.fg); g.setFontAlign(1,0); // right aligned g.drawString(hh, (w/2) - 1, h/2); @@ -521,7 +555,8 @@ function resetHrm() { if (infoMode == "ID_HRM") { clearInfo(); g.setColor('#f00'); // red - drawHeartIcon(); + var dims = getInfoDims(); + drawHeartIcon(dims[0], dims[2]); } } @@ -594,24 +629,29 @@ function drawRing(start, end, max, idx) { function drawSemi(start, end, max, idx) { // Create persistent `buf` inside the function scope + var fullCircle = (end - start) >= max; if (!drawSemi._buf) { drawSemi._buf = Graphics.createArrayBuffer(w, h, 2, { msb: true }); } const buf = drawSemi._buf; let img = { width: w, height: h, transparent: 0, - bpp: 2, palette: pals[idx].pal1, buffer: buf.buffer }; + bpp: 2, palette: pals[idx].pal2, buffer: buf.buffer }; let edge = ringEdge + (idx * ringIterOffset); buf.clear(); buf.setColor(1).fillEllipse(edge,edge,w-edge,h-edge); buf.setColor(0).fillEllipse(edge+ringThick,edge+ringThick,w-edge-ringThick,h-edge-ringThick); - img.palette = palbg; + if (fullCircle) + img.palette = pals[idx].pal2; + else + img.palette = palbg; g.drawImage(img, 0, 0); // Draws a filled-in circle with the bg color, clearing it - if((end - start) >= max) return; // No need to add the unfilled circle + if(end == start) return; //If the ring should be completely empty + if(fullCircle) return; // No need to add the unfilled circle buf.clear(); buf.setColor(1).fillEllipse(edge,edge,w-edge,h-edge); buf.setColor(0).fillEllipse(edge+ringThick,edge+ringThick,w-edge-ringThick,h-edge-ringThick); buf.setColor(0).fillPoly(polyArray(end, start, max)); // Masks the filled-in part of the segment over the unfilled part - img.palette = pals[idx].pal1; + img.palette = pals[idx].pal2; g.drawImage(img, 0, 0); // Draws the unfilled-in segment return; } @@ -623,7 +663,7 @@ function drawC(end, max, idx) { } const buf = drawC._buf; let img = { width: w, height: h, transparent: 0, - bpp: 2, palette: pals[idx].pal1, buffer: buf.buffer }; + bpp: 2, palette: pals[idx].pal2, buffer: buf.buffer }; let edge = ringEdge + (idx * ringIterOffset); buf.clear(); buf.setColor(1).fillEllipse(edge,edge,w-edge,h-edge); @@ -633,10 +673,10 @@ function drawC(end, max, idx) { buf.clear(); buf.setColor(1).fillEllipse(edge,edge,w-edge,h-edge); buf.setColor(0).fillEllipse(edge+ringThick,edge+ringThick,w-edge-ringThick,h-edge-ringThick); + if (end > max) end = max; var vertices = rotate_points(end, max); buf.setColor(0).fillPoly(vertices); - img.palette = pals[idx].pal1; - rotate = (2 * Math.PI) / (max / end); + img.palette = pals[idx].pal2; g.drawImage(img, 0, 0); // Draws the unfilled-in segment return; } @@ -846,6 +886,7 @@ Bangle.on('lcdPower',on=>{ }); Bangle.setUI("clockupdown", btn=> { + clearInfo(); // Used to clear infobox in case we're going to the HRM if (btn<0) settings.idxInfo = prevInfo(settings.idxInfo); if (btn>0) settings.idxInfo = nextInfo(settings.idxInfo); // power HRM on/off accordingly diff --git a/apps/daisy/settings.js b/apps/daisy/settings.js index 139c24da7..f43a778c4 100644 --- a/apps/daisy/settings.js +++ b/apps/daisy/settings.js @@ -1,21 +1,41 @@ (function(back) { const SETTINGS_FILE = "daisy.json"; - // initialize with default settings... - let defaultRing = () => ({ + // default settings + let s = { + rings: [{}, {}, {}], + color: 'Green', + fg: '#0f0', + check_idle: true, + batt_hours: false, + idxInfo: 0, + }; + + s.rings[0] = { color: 'Green', fg: '#0f0', gy: '#020', ring: 'Steps', type: 'Full', step_target: 10000, - }); + }; - let s = { - rings: [defaultRing(), defaultRing(), defaultRing()], - check_idle: true, - batt_hours: false, - idxInfo: 0, + s.rings[1] = { + color: 'Blk/Wht', + fg: g.theme.fg, + gy: g.theme.fg, + ring: 'Minutes', + type: 'None', + step_target: 10000, + }; + + s.rings[2] = { + color: 'Green', + fg: '#0f0', + gy: '#020', + ring: 'Hours', + type: 'None', + step_target: 10000, }; // ...and overwrite them with any saved values @@ -24,12 +44,7 @@ const storage = require('Storage'); let settings = storage.readJSON(SETTINGS_FILE, 1) || s; const saved = settings || {}; for (const key in saved) { -s[key] = saved[key]; -} - -// Fill in any missing ring defaults -for (let i = 0; i < 3; i++) { - s.rings[i] = Object.assign(defaultRing(), s.rings[i] || {}); + s[key] = saved[key]; } function save() { @@ -37,62 +52,67 @@ function save() { storage.write(SETTINGS_FILE, settings); } -var color_options = ['Green','Orange','Cyan','Purple','Red','Blue', 'Fore']; -var fg_code = ['#0f0','#ff0','#0ff','#f0f','#f00','#00f', g.theme.fg]; -var gy_code = ['#020','#220','#022','#202','#200','#002', g.theme.fg]; -var ring_options = ['Hours', 'Minutes', 'Seconds', 'Day', 'Sun', 'Steps', 'Battery']; -var step_options = [100, 1000, 5000, 10000, 15000, 20000]; + var color_options = ['Cyan','Green','Orange','Purple','Red','Blue', 'Blk/Wht']; + var fg_code = ['#0ff','#0f0','#ff0','#f0f','#f00','#00f', g.theme.fg]; + var gy_code = ['#022','#020','#220','#202','#200','#002', g.theme.fg]; + var ring_options = ['Hours', 'Minutes', 'Seconds', 'Day', 'Sun', 'Steps', 'Battery']; + var ring_types = ['None', 'Full', 'Semi', 'C']; + var step_options = [100, 1000, 5000, 10000, 15000, 20000]; function showRingMenu(ringIndex) { - const ring = s.rings[ringIndex]; - let ringMenu = { - '': { title: `Ring ${ringIndex + 1}` }, - '< Back': showMainMenu, - 'Color': { - value: 0 | color_options.indexOf(ring.color), - min: 0, max: color_options.length - 1, - format: v => color_options[v], - onchange: v => { - ring.color = color_options[v]; - ring.fg = fg_code[v]; - ring.gy = gy_code[v]; - save(); + const ring = s.rings[ringIndex]; + let ringMenu = { + '': { title: `Ring ${ringIndex + 1}` }, + '< Back': showMainMenu, + 'Type': { + value: ring_types.indexOf(ring.type), + min: 0, max: ring_types.length - 1, + format: v => ring_types[v], + onchange: v => { + let prev = ring.type; + ring.type = ring_types[v]; + save(); + if (prev != ring.type && (prev === 'None' || ring.type === 'None')) { + setTimeout(showRingMenu, 0, ringIndex); } - }, - 'Type': { - value: ring_types.indexOf(ring.type), - min: 0, max: ring_types.length - 1, - format: v => ring_types[v], - onchange: v => { - ring.type = ring_types[v]; - save(); - } - }, - 'Display': { - value: 0 | ring_options.indexOf(ring.ring), - min: 0, max: ring_options.length - 1, - format: v => ring_options[v], - onchange: v => { - let prev = ring.ring; - ring.ring = ring_options[v]; - save(); - if (prev != ring.ring && (prev === 'Steps' || ring.ring === 'Steps')) { - // redisplay the menu with/without ring setting - // Reference https://github.com/orgs/espruino/discussions/7697 - setTimeout(showRingMenu, 0, ringIndex); - } - }, + } + }, + }; + if (ring.type != 'None') { + ringMenu['Color'] = { + value: 0 | color_options.indexOf(ring.color), + min: 0, max: color_options.length - 1, + format: v => color_options[v], + onchange: v => { + ring.color = color_options[v]; + ring.fg = fg_code[v]; + ring.gy = gy_code[v]; + save(); } }; - if (ring.ring == 'Steps') { - ringMenu[/*LANG*/"Step Target"] = { - value: 0 | step_options.indexOf(ring.step_target), - min: 0, max: step_options.length - 1, - format: v => step_options[v], - onchange: v => { - ring.step_target = step_options[v]; - save(); - }, + ringMenu['Display'] = { + value: 0 | ring_options.indexOf(ring.ring), + min: 0, max: ring_options.length - 1, + format: v => ring_options[v], + onchange: v => { + let prev = ring.ring; + ring.ring = ring_options[v]; + save(); + if (prev != ring.ring && (prev === 'Steps' || ring.ring === 'Steps')) { + setTimeout(showRingMenu, 0, ringIndex); + } + }, + }; + } + if (ring.ring == 'Steps') { + ringMenu[/*LANG*/"Step Target"] = { + value: 0 | step_options.indexOf(ring.step_target), + min: 0, max: step_options.length - 1, + format: v => step_options[v], + onchange: v => { + ring.step_target = step_options[v]; + save(); + }, }; } E.showMenu(ringMenu); @@ -105,10 +125,13 @@ var step_options = [100, 1000, 5000, 10000, 15000, 20000]; 'Ring 1': () => showRingMenu(0), 'Ring 2': () => showRingMenu(1), 'Ring 3': () => showRingMenu(2), - 'Idle Warning' : { - value: !!s.idle_check, + 'Hour Color': { + value: 0 | color_options.indexOf(s.color), + min: 0, max: color_options.length - 1, + format: v => color_options[v], onchange: v => { - s.idle_check = v; + s.color = color_options[v]; + s.fg = fg_code[v]; save(); }, }, @@ -119,7 +142,14 @@ var step_options = [100, 1000, 5000, 10000, 15000, 20000]; s.batt_hours = v; save(); }, - } + }, + 'Idle Warning' : { + value: !!s.idle_check, + onchange: v => { + s.idle_check = v; + save(); + }, + }, }; E.showMenu(appMenu); }