From 0c947ee3c0d826c8284993cc1228138387eedc36 Mon Sep 17 00:00:00 2001 From: David Volovskiy Date: Sun, 18 May 2025 06:54:58 -0400 Subject: [PATCH 01/22] Bugfix where leaving prompt draws the rings incorrectly --- apps/daisy/app.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/daisy/app.js b/apps/daisy/app.js index d8e6ceb9c..c6101bac9 100644 --- a/apps/daisy/app.js +++ b/apps/daisy/app.js @@ -519,6 +519,9 @@ function dismissPrompt() { warned = false; lastStep = getTime(); Bangle.buzz(100); + // Reset the prevRings to force all rings to update + prevRing = Array(3).fill().map(() => ({ start: null, end: null, max: null })); + g.clear(); draw(false); } From 620ff4098fca561a11bb3316c34b80adc719bf3d Mon Sep 17 00:00:00 2001 From: David Volovskiy Date: Sat, 17 May 2025 08:14:37 -0400 Subject: [PATCH 02/22] Added multiple rings --- apps/daisy/app.js | 301 +++++++++++++++++++++++++++++++++-------- apps/daisy/settings.js | 119 ++++++++++------ 2 files changed, 322 insertions(+), 98 deletions(-) diff --git a/apps/daisy/app.js b/apps/daisy/app.js index c6101bac9..ae8d76c76 100644 --- a/apps/daisy/app.js +++ b/apps/daisy/app.js @@ -17,16 +17,22 @@ let warned = 0; let idle = false; let IDLE_MINUTES = 26; -let pal1; // palette for 0-49% -let pal2; // palette for 50-100% +var pals = Array(3).fill().map(() => ( + { pal1: null, // palette for 0-49% + pal2: null // palette for 50-100% + })); + +let palbg; const infoLine = (3*h/4) - 6; const infoWidth = 56; const infoHeight = 11; const ringEdge = 4; +const ringIterOffset = 10; const ringThick = 6; let nextUpdateMs; var drawingSteps = false; -var prevRing = {start: null, end: null, max: null}; +var innerMostRing = 0; +var prevRing = Array(3).fill().map(() => ({ start: null, end: null, max: null })); function log_debug(o) { //print(o); @@ -35,12 +41,36 @@ function log_debug(o) { var hrmImg = require("heatshrink").decompress(atob("i0WgIKHgPh8Ef5/g///44CBz///1///5A4PnBQk///wA4PBA4MDA4MH/+Ah/8gEP4EAjw0GA")); // https://www.1001fonts.com/rounded-fonts.html?page=3 +//one ring Graphics.prototype.setFontBloggerSansLight46 = function(scale) { // Actual height 46 (45 - 0) this.setFontCustom(atob("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB4AAAAAAAA/AAAAAAAAPwAAAAAAAD4AAAAAAAAeAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AAAAAAAH/gAAAAAAP/wAAAAAAf/gAAAAAAf/AAAAAAA//AAAAAAB/+AAAAAAD/8AAAAAAH/4AAAAAAH/wAAAAAAP/gAAAAAAf/gAAAAAA//AAAAAAB/+AAAAAAA/8AAAAAAAP4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///8AAAAP////4AAAP/////AAAH/////4AAD+AAAB/AAA8AAAAHwAAeAAAAA+AAHgAAAAHgADwAAAAB4AA8AAAAAPAAPAAAAADwADwAAAAA8AA8AAAAAPAAPAAAAADwAB4AAAAB4AAeAAAAAeAAHwAAAAPgAA/AAAAPwAAH/////4AAA/////8AAAH////+AAAAf///+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYAAAAAAAAPAAAAAAAAHwAAAAAAAB4AAAAAAAA+AAAAAAAAfAAAAAAAAHgAAAAAAAD4AAAAAAAB8AAAAAAAAeAAAAAAAAPgAAAAAAADwAAAAAAAB//////4AAf//////AAH//////gAA//////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAAD4AAHAAAAD+AAD4AAAB/gAA8AAAB/4AAfAAAA/+AAHgAAAf3gAB4AAAPx4AA8AAAH4eAAPAAAD4HgADwAAB8B4AA8AAA+AeAAPAAAfAHgADwAAPgB4AA8AAHwAeAAHgAD4AHgAB4AD8AB4AAfAB+AAeAAD8B/AAHgAAf//gAB4AAH//wAAeAAAf/wAAHgAAB/wAAA4AAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA4AADgAAAAPAAB4AAAADwAAeAAAAA+AAHgAAAAHgAB4ABgAB4AAeAA8AAeAAHgA/AADwAB4AfwAA8AAeAP8AAPAAHgH/AADwAB4H7wAA8AAeD48AAPAAHh8PAAHgAB5+BwAB4AAe/AeAA+AAH/AHwAfAAB/gA/AfgAAfwAH//wAAHwAA//4AAA4AAH/8AAAAAAAf4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABwAAAAAAAD+AAAAAAAD/gAAAAAAH/4AAAAAAH/+AAAAAAP/ngAAAAAP/h4AAAAAf/AeAAAAAf/AHgAAAA/+AB4AAAA/+AAeAAAB/8AAHgAAA/8AAB4AAAP4AAAeAAAB4AAAHgAAAAAAAB4AAAAAAAAeAAAAAAP///4AAAAH////AAAAA////gAAAAP///4AAAAAAB4AAAAAAAAeAAAAAAAAHgAAAAAAABwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADgAAAAD4AA8AAD///gAPAAB///4AD4AAf//+AAeAAH+APAAHgAB4AHgAA4AAeAB4AAOAAHgAcAADwAB4AHAAA8AAeADwAAPAAHgAcAADwAB4AHAAA8AAeAB4AAeAAHgAeAAHgAB4AHwAD4AAeAA+AB8AAHgAP4B+AAB4AB///gAAOAAP//gAABAAA//wAAAAAAD/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/gAAAAAB///4AAAAD////wAAAD////+AAAB/////4AAA/gPgB/AAAfgDwAHwAAPgA8AA+AADwAeAAHgAB4AHgAB4AAeAB4AAfAAHgAeAADwABwAHgAA8AAcAB4AAPAAHAAeAAHwAB4AHgAB4AAeAB8AAeAAHgAPAAPgAB4AD8APwAAOAAfwP4AADgAD//8AAAAAAf/+AAAAAAB/+AAAAAAAH8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADgAAAAAAAB4AAAAAAAAeAAAAAAAAHgAAAAAAAB4AAAAA4AAeAAAAB/AAHgAAAB/wAB4AAAB/4AAeAAAD/4AAHgAAD/wAAB4AAH/wAAAeAAH/gAAAHgAP/gAAAB4AP/AAAAAeAf/AAAAAHgf+AAAAAB4/+AAAAAAe/8AAAAAAH/8AAAAAAB/4AAAAAAAf4AAAAAAADwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/gAAAA/AB/+AAAA/8B//wAAA//gf/+AAAf/8PgPgAAH4fngB8AAD4B/wAPgAA8AP8AB4AAeAB+AAeAAHgAfgADwAB4ADwAA8AAcAA8AAPAAHAAPAADwAB4ADwAA8AAeAB+AAPAAHgAfgAHgAB8AP8AB4AAPgH/AA+AAD8H54AfAAAf/8fgPwAAD/+D//4AAAf/Af/8AAAB/AD/+AAAAAAAP+AAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHwAAAAAAAf/wAAAAAAf/+AAAAAAP//4AAwAAH//+AAeAAD+APwAHgAA+AA+AB4AAfAAHgAOAAHgAB4ADwAB4AAPAA8AAeAADwAPAAHgAA8ADwAB4AAPAA8AAeAADwAPAAHgAA8AHgAB8AAeAB4AAPgAHgA+AAD8ADwA/AAAfwA8A/gAAD/wef/wAAAf////4AAAB////4AAAAH///wAAAAAD/+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8AB4AAAAAfgA/AAAAAH4APwAAAAB+AD4AAAAAPAAeAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=="), 46, atob("DRAcHBwcHBwcHBwcDQ=="), 56+(scale<<8)+(1<<16)); return this; }; +//Two Rings +Graphics.prototype.setFontBloggerSansLight42 = function() { + // Actual height 28 (31 - 4) + // 1 BPP + return this.setFontCustom( + atob('AAAAAAAAAAAAAAAAAAAAAAAAAHwAAAAAHwAAAAAHwAAAAAHwAAAAADgAAAAAAAAAAAAAwAAAAAHwAAAAA/wAAAAH+AAAAA/wAAAAH+AAAAA/wAAAAH+AAAAA/wAAAAD+AAAAADwAAAAACAAAAAAAAAAAAAAAAAAAAAAP8AAAAD//wAAAP//8AAA////AAB////gAB4AAPgADwAADwADgAAAwADAAAAwADAAAAwADAAAAwADgAAAwADwAADwAB8AAPgAB////gAA////AAAP//8AAAD//wAAAAP4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAMAAAQAAYAAAwAAYAAAwAA4AAAwAAwAAAwAB////wAD////wAD////wAD////wAAAAAAwAAAAAAwAAAAAAwAAAAAAwAAAAAAQAAAAAAQAAAAAAAAAAAAAAAAAAAAAAB8AADwAB+AAHwAD8AAPwADgAAfwADAAA7wADAABzwADAABzwADAAHjwADAAPDwADAAeDwADgA8DwAD4H4DwAB//wDwAB//gDwAA/+ADwAAP8ADwAAAAABwAAAAAAAAAAAAAAAAAAAAAAAAAAfgAB8AAfwAD8AABwADgAABwADAAAAwADADAAwADADAAwADADAAwADADAAwADAHAAwADgHgBwADwfgBwAB//4DgAB/8//gAA/4//AAAfwf+AAAAAP8AAAAABgAAAAAAAAAAAAAAAAAAADwAAAAAPwAAAAAfwAAAAA9wAAAADxwAAAAHhwAAAAeBwAAAA8BwAAADwBwAAAHgBwAAAfABwAAA8ABwAAB////wAD////wAD////wAD////wAAAABwAAAAABwAAAAABwAAAAABwAAAAAAAAAAAAAAAAAAAAAAAAAAAfgAD//AfgAD//AHwAD//ABwADwHAAwADwHAAwADwGAAwADwGAAwADwGAAwADwHAAwADwHABwADwHABwADwDgDgADwD//gADwB//AADgB/+AAAAAf8AAAAADAAAAAAAAAAAAAAAAAAAAAAAAAA//gAAAH//8AAAP//+AAAf///AAA/DAfgAB4DAHwABwHABwADgGAAwADgGAAwADAGAAwADAHAAwADAHAAwADAHgBwADgH8fgAD4D//gAD8D//AAAAA/+AAAAAf4AAAAAAAAAAAAAAAAAAAAAAAD8AAAAAD+AAAAAD8AAAAADwAAAwADwAADwADwAAPwADwAA/gADwAD8AADwAPwAADwA/AAADwD8AAADwPwAAADw/AAAADz4AAAAD/gAAAAD+AAAAAD4AAAAADgAAAAAAAAAAAAAAAAAAAAAADgAAAHgP8AAAf4f/AAA/8//gAB////gAD8/wDwADgHgBwADAHAAwADADAAwADADAAwADADAAwADAHAAwADgHgBwAB8/wDwAB////gAA/8//gAAf4f/AAAHgP8AAAAADgAAAAAAAAAAAAAAAAAD8AAAAAP/AHgAA//gPwAB//wDwAB/f4AwADwB4AwADgA4AwADAAYAwADAAYAwADAAYAwADAAYBwADgA4DwADwAwHgAB+Aw/gAB////AAA///+AAAf//4AAAD//gAAAADgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMADgAAAeAHwAAA/AHwAAA/AHwAAAeAHwAAAAABAAAAAAAAAA'), + 46, + atob("CQ0VFBQVFhUVFRUVCg=="), + 42|65536 + ); +} +// Three rings +Graphics.prototype.setFontBloggerSansLight38 = function() { + // Actual height 25 (28 - 4) + // 1 BPP + return this.setFontCustom( + atob('AAAAAAAAAAAAAAAAAwAAAAAeAAAAAPgAAAAD4AAAAAcAAAAAAAAAAAAYAAAAA+AAAAB/AAAAD+AAAAH8AAAAP4AAAAP4AAAAfwAAAA/gAAAAPAAAAACAAAAAAAAAAAAAAAAAAAA/4AAAB//wAAB///AAA///8AAfgA/AAPAAB4ADAAAGAAwAABgAMAAAYADAAAGAA4AABgAPAAB4AB+AD8AAP//+AAB///AAAH//gAAAP+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAACAAGAAAgABgAAYAAwAAGAAcAABgAH///4AD///+AA////gAP///4AAAAAGAAAAABgAAAAAYAAAAACAAAAAAgAAAAAAAAAAAAAAAAADgAHwAB4AD8AA+AA4AAfgAMAAG4ADAADOAAwABjgAMAA44ADAAcOAAwAeDgAOAPA4AB8/gOAAf/wDgAD/4A4AAf4AOAAB4ADgAAAAAAAAAAAAAAAAAAAAHwAH4AD8AA+AA8AABgAMAAAYADAGAGAAwBgBgAMAYAYADAGAGAAwDgBgAOA4AYAD5/AOAAf+8PAAH/n/wAA/x/4AABgP8AAAAA8AAAAAAAAAAABgAAAAA8AAAAA/AAAAAdwAAAAecAAAAPHAAAAHBwAAAHgcAAADgHAAADwBwAAB4AcAAA8AHAAA////gAP///4AD///+AAAABwAAAAAcAAAAAHAAAAABwAAAAAAAAAAAAAAAAAAAAAAAAHwAD/8B+AA//ADgAOAwAYADgMAGAA4DABgAOAwAYADgMAGAA4DABgAOA4A4ADgOAOAA4B4PAAOAf/wADgD/4AAAAf8AAAAB4AAAAAAAAAAAAAAAAA+AAAAD//AAAD//8AAB///gAA/2f8AAfBgHAAHAwA4ADgMAGAAwDABgAMAwAYADAMAGAAwDgDgAMA8B4ADwP/8AA+B//AAHgP/AAAAA/AAAAAAAAAAAAAAAAAAAAAA/AAAAAPwAAAADwAACAA4AADgAOAAD4ADgAD8AA4AD8AAOAD8AADgD8AAA4D8AAAOD8AAADj4AAAA74AAAAP4AAAAD4AAAAA4AAAAAAAAAAAAAAAAAAAAHwAAB8H/AAA/z/4AAf+//AAH/+B4ADgeAOAAwDgBgAMAwAYADAMAGAAwDABgAMA4AYADgeAOAAf/4PgAH/v/wAA/z/8AAHwP8AAAAB8AAAAAAAAAAAAAAAAfgAAAAf+A+AAP/wPgAH/8AYADwHgGAA4A4BgAMAOAYADABgGAAwAYBgAMAGA4ADgDgeAA8AwPAAH+N/wAA///4AAH//4AAAf/8AAAAfwAAAAAAAAAAAAAAAAAAAAAAAAAAAAADgBwAAB8A+AAAfAPgAAHgB4AAAwAMAAAAAAAAA=='), + 46, + atob("CAwTEhITFBMTExMTCQ=="), + 38|65536 + ); +} + Graphics.prototype.setFontRoboto20 = function(scale) { // Actual height 21 (20 - 0) this.setFontCustom(atob("AAAAAAAAAAAAAAAAAAAAAAAAH/zA/+YAAAAAAAHwAAwAAHwAA+AAAAAAAAAAAQACDAAYbADP4B/8A/zAGYZADH4A/+A/7AHYYADCAAAAAAAQAeHgH4eBzgwMMHnhw88GGBw4wHj+AcPgAAAAAAAAAAB4AA/gAGMAAwhwGMcAfuABzgABzgAc+AOMYBhBAAMYAB/AAHwAAAAAHwD5+A/8YGPDAw8YGPzA/HYD4fAADwAB/AAOYAABAAAAHwAA4AAAAAAAAAAH/gD//B8A+cAA7AADAAAAAAAYAAbwAHHgHwf/4A/8AAAAEAABiAAGwAA8AA/AAH+AAGwAByAAEAAAAAAAMAABgAAMAABgAH/wA/+AAMAABgAAMAABgAAAAAAAIAAfAADwAAAABgAAMAABgAAMAABgAAAAAAAAAAAAADAAAYAAAAAAAAADgAB8AB+AA+AA+AA/AAHAAAgAAAAAAB8AB/8Af/wHAHAwAYGADAwAYHAHAf/wB/8AAAAAAAAAAABgAAcAADAAAYAAH//A//4AAAAAAAAAAAAAAAAAAAAABwDAeA4HAPAwHYGBzAwcYHHDAfwYB8DAAAYAAAAAAABgOAcBwHADAwwYGGDAwwYHPHAf/wB58AAAAAAAAADAAB4AAfAAPYAHjAB4YA8DAH//A//4AAYAADAAAAAAAAAEMA/xwH+HAxgYGMDAxgYGODAw/4GD+AAHAAAAAAAAAf8AP/wD2HA5wYGMDAxgYGOHAA/wAD8AAAAAAAAAAAGAAAwAAGADAwB4GB+Aw+AGfAA/gAHwAAwAAAAAAADAB5+Af/wHPDAwwYGGDAwwYHPHAfvwB58AAAAAAAAAAAB+AAf4AHDjAwMYGBjAwM4HDOAf/gB/4AAAAAAAAAAAAYDADAYAAAAAAAAAAYDAfAYHwAAAABAAAcAADgAA+AAGwAB3AAMYABjgAYMAAAAAAAAAAAAAAABmAAMwABmAAMwABmAAMwABmAAMwAAiAAAAAAAAAYMADjgAMYAB3AAGwAA2AADgAAcAABAAAAAAAAAMAADgAA4AAGBzAweYGHAA/wAD8AAEAAAAwAB/4A/PwOAGDgAYYPxmH/Mw4ZmMDMxgZmM+Mx/5mHDAYAIDgDAPBwAf8AAMAAAAAAAYAAfAAPwAP4AH+AH4wA8GAH4wAP2AAPwAAfwAAfAAAYAAAAAAAAAAA//4H//AwwYGGDAwwYGGDAwwYH/HAf/wB58AAAAADAAH/AD/+AcBwHADAwAYGADAwAYGADA4A4DweAODgAAAAAAAAAAAAAAH//A//4GADAwAYGADAwAYGADAYAwD4+AP/gAfwAAAAAAAAAAAH//A//4GDDAwYYGDDAwYYGDDAwYYGCDAgAYAAAAAAAH//A//4GDAAwYAGDAAwYAGDAAwYAGAAAAAAAAAAH/AD/8AcBwHAHAwAYGADAwYYGDDA4YYDz/AOfwAAAAAAAAAAA//4H//A//4ADAAAYAADAAAYAADAAAYAADAA//4H//AAAAAAAAAAAAAAA//4H//AAAAAAAAABAAAeAAB4AADAAAYAADAAAYAAHA//wH/8AAAAAAAAAAAAAAA//4H//AAcAAPAAD4AA/wAOPADg8A4B4GAHAgAYAAAAAAAH//A//4AADAAAYAADAAAYAADAAAYAADAAAAAAAA//4H//A+AAB+AAD8AAD8AAH4AAPAAH4AH4AD8AD8AA+AAH//A//4AAAAAAAH//A//4H//AeAAB8AADwAAPgAAeAAA8AADwH//A//4AAAAAAAAAAAH/AB/8AeDwHAHAwAYGADAwAYGADA4A4DweAP/gA/4AAAAAAAAAAAH//A//4GBgAwMAGBgAwMAGBgAwcAH/AAfwAA8AAAAAA/4AP/gDgOA4A4GADAwAYGADAwAYHAHgeD+B/8wD+GAAAAAAAAAAA//4H//AwYAGDAAwYAGDgAweAHH8Afz4B8HAAAIAAYAPDwD8OA5w4GGDAwwYGHDAwYYHDnAePwBw8AAAAGAAAwAAGAAAwAAGAAA//4H//AwAAGAAAwAAGAAAwAAAAAAAAAH/4A//wAAPAAAYAADAAAYAADAAAYAAPA//wH/8AAAAAAAAgAAHAAA/AAB/AAD+AAD+AAD4AAfAAfwAfwAfwAH4AA4AAEAAA+AAH/AAH/gAD/AAD4AD+AH+AH8AA+AAH+AAD+AAD/AAD4AH/AP/AH+AA8AAAAAAAAAGADA4A4HweAPPgA/wAB8AAfwAPvgDweA8B4GADAAAIGAAA4AAHwAAPgAAfAAA/4AH/AD4AB8AA+AAHgAAwAAAAAAAAAGADAwB4GAfAwPYGDzAx4YGeDA/AYHwDA4AYGADAAAAAAAA///3//+wAA2AAGAAAGAAA+AAD8AAD8AAD4AAH4AAHgAAMAAAAwAA2AAG///3//+AAAAAAAAAAAOAAHwAD4AA8AAD8AADwAAGAAAAAAABgAAMAABgAAMAABgAAMAABgAAMAABgAAAEAAAwAADAAAIAAAAAAAAAAEeABn4Ad3ADMYAZjADMYAZmAB/4AP/AAAAAAAA//4H//ABgwAYDADAYAYDADg4AP+AA/gABwAAAAAAAAA/gAP+ADg4AYDADAYAYDADAYAOOABxwAAAAAEAAH8AB/wAcHADAYAYDADAYAcDA//4H//AAAAAAAAAAAAH8AB/wAdnADMYAZjADMYAZjAB84AHmAAMAAMAABgAB//gf/8HMAAxgAGIAAAAAAH8IB/zAcHMDAZgYDMDAZgcHcD//Af/wAAAAAAAAAAH//A//4AMAADAAAYAADAAAcAAD/4AP/AAAAAAAAAAAGf/Az/4AAAAAAAAAAMz//mf/4AAAAAAAAAAH//A//4ABwAAeAAH4ABzwAcPACAYAABAAAAAAAA//4H//AAAAAAAAAAAAf/AD/4AMAADAAAYAADAAAcAAD/4AP/ABgAAYAADAAAYAADgAAP/AA/4AAAAAAAAf/AD/4AMAADAAAYAADAAAcAAD/4AP/AAAAAAAAAAAAH8AB/wAcHADAYAYDADAYAYDADx4AP+AA/gAAAAAAAAf/8D//gYDADAYAYDADAYAcHAB/wAH8AAEAAAAAAEAAH8AB/wAcHADAYAYDADAYAYDAD//gf/8AAAAAAAAAAAf/AD/4AcAADAAAYAACAAAAEAB5wAfnADMYAZjADGYAYzADn4AOeAAAAAAAADAAAYAAf/wD//ADAYAYDAAAAAAAAD/gAf/AAA4AADAAAYAADAAAwAf/AD/4AAAAAAAAYAAD4AAP4AAP4AAPAAH4AH4AD8AAcAAAAAAQAADwAAf4AAf4AAPAAP4AP4ADwAAfgAA/gAA/AAD4AH+AD+AAeAAAAAAAAACAYAcHADzwAH8AAfAAH8ADx4AcHACAIAcAMD4BgP4MAP/AAPwAP4AP4AD4AAcAAAAAAAAADAYAYHADD4AY7ADOYAfjADwYAcDADAYAAAAADAAA4AH//B/v8cABzAACAAAH//w//+AAAAAAACAACcAAx/n+H//AA4AAHAAAAAAAAAAAAAOAADgAAYAADAAAcAABgAAGAAAwAAGAADwAAcAAAAA"), 32, atob("BQUHDQwPDQQHBwkMBAYGCQwMDAwMDAwMDAwFBAsMCwoTDg0ODgwMDg8GDA0LEg8ODQ4NDA0ODRMNDQ0GCQYJCQYLDAsMCwcMDAUFCwUSDAwMDAcLBwwKEAoKCgcFBw4A"), 21+(scale<<8)+(1<<16)); @@ -48,29 +78,75 @@ Graphics.prototype.setFontRoboto20 = function(scale) { }; function assignPalettes() { - if (g.theme.dark) { - // palette for 0-49% - pal1 = new Uint16Array([g.theme.bg, g.toColor(settings.gy), g.toColor(settings.fg), g.toColor("#00f")]); - // palette for 50-100% - pal2 = new Uint16Array([g.theme.bg, g.toColor(settings.fg), g.toColor(settings.gy), g.toColor("#00f")]); - } else { - // palette for 0-49% - pal1 = new Uint16Array([g.theme.bg, g.theme.fg, g.toColor(settings.fg), g.toColor("#00f")]); - // palette for 50-100% - pal2 = new Uint16Array([g.theme.bg, g.toColor(settings.fg), g.theme.fg, g.toColor("#00f")]); + palbg = new Uint16Array([g.toColor(g.theme.bg)]); + for (let i = 0; i < settings.rings.length; i++) { + let ring = settings.rings[i]; + if (g.theme.dark) { + // palette for 0-49% + pals[i].pal1 = new Uint16Array([g.theme.bg, g.toColor(ring.gy), g.toColor(ring.fg), g.toColor("#00f")]); + // palette for 50-100% + pals[i].pal2 = new Uint16Array([g.theme.bg, g.toColor(ring.fg), g.toColor(ring.gy), g.toColor("#00f")]); + } else { + // palette for 0-49% + pals[i].pal1 = new Uint16Array([g.theme.bg, g.theme.fg, g.toColor(ring.fg), g.toColor("#00f")]); + // palette for 50-100% + pals[i].pal2 = new Uint16Array([g.theme.bg, g.toColor(ring.fg), g.theme.fg, g.toColor("#00f")]); + if (ring.type !== 'Full') pals[i].pal1 = pals[i].pal2; // In light mode, we only want the full circle's filled portion to be black + } } } +function rotate_points(end, max) { + const midH = h/2; + const midW = w/2; + const off = 5; + const points = [midW-off,0, midW+off,0, midW+off,midH, midW-off,midH]; + var rotate = (2 * Math.PI) / (max / end); + var rotated_arr = []; + for (let i = 0; i < points.length; i += 2) { + let x = points[i]; + let y = points[i + 1]; + x -= midW; + y -= midH; + let x_new = x * Math.cos(rotate) - y * Math.sin(rotate); + let y_new = x * Math.sin(rotate) + y * Math.cos(rotate); + x = x_new + midW; + y = y_new + midH; + rotated_arr.push(x); + rotated_arr.push(y); + } + return rotated_arr; +} + function setSmallFont20() { g.setFontRoboto20(); } function setLargeFont() { - g.setFontBloggerSansLight46(1); -} + switch (innerMostRing) { + case 3: + g.setFontBloggerSansLight38(); + break; + case 2: + g.setFontBloggerSansLight42(); + break; + default: + g.setFontBloggerSansLight46(1); + break; + } + } function setSmallFont() { - g.setFont('Vector', 16); + let size = 16; + switch (innerMostRing) { + case 3: + size = 9; + break; + case 2: + size = 13; + break; + } + g.setFont('Vector', size); } function getSteps() { @@ -88,14 +164,29 @@ function getSteps() { function loadSettings() { settings = require("Storage").readJSON(SETTINGS_FILE,1)||{}; - settings.gy = settings.gy||'#020'; - settings.fg = settings.fg||'#0f0'; + + settings.rings[0].gy = settings.rings[0].gy||'#020'; + settings.rings[0].fg = settings.rings[0].fg||'#0f0'; + settings.rings[0].type = settings.rings[0].type||'Full'; + settings.rings[0].ring = settings.rings[0].ring||'Steps'; + settings.rings[0].step_target = settings.rings[0].step_target||10000; + + 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].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].step_target = settings.rings[2].step_target||10000; + 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"]); - settings.ring = settings.ring||'Steps'; settings.idxInfo = settings.idxInfo||0; - settings.step_target = settings.step_target||10000; assignPalettes(); } @@ -108,12 +199,12 @@ function loadLocation() { } function extractTime(d){ - var h = d.getHours(), m = d.getMinutes(); + var hh = d.getHours(), mm = d.getMinutes(); if (settings.hr_12) { - h = h % 12; - if (h == 0) h = 12; + hh = hh % 12; + if (hh == 0) hh = 12; } - return(("0"+h).substr(-2) + ":" + ("0"+m).substr(-2)); + return(("0"+hh).substr(-2) + ":" + ("0"+mm).substr(-2)); } var sunRise = "00:00"; @@ -226,9 +317,21 @@ function prevInfo(idx) { } function clearInfo() { + + var width = infoWidth; + var height = infoHeight; + switch (innerMostRing) { + case 3: + width -= 20; + height -= 3; + break; + case 2: + width -= 8; + height -= 2; + break; + } g.setColor(g.theme.bg); - //g.setColor(g.theme.fg); - g.fillRect((w/2) - infoWidth, infoLine - infoHeight, (w/2) + infoWidth, infoLine + infoHeight); + g.fillRect((w/2) - width, infoLine - height, (w/2) + width, infoLine + height); } function drawInfo() { @@ -262,12 +365,14 @@ function drawHrm() { g.drawString(hrmCurrent, (w/2) + 10, infoLine); } -function draw(drawRingOnly) { +function draw(updateSeconds) { if (!idle) { - if (drawRingOnly) { - drawGaugeImage(new Date()); + if (updateSeconds) { + let date = new Date(); + drawAllRings(date, updateSeconds); } else { + g.clear(); drawClock(); } } @@ -276,16 +381,16 @@ function draw(drawRingOnly) { queueDraw(); } -function drawGaugeImage(date) { +function getGaugeImage(date, ringType, step_target) { var hh = date.getHours(); var mm = date.getMinutes(); var ring_fill; var invertRing = false; var ring_max = 100; - switch (settings.ring) { + switch (ringType) { case 'Hours': - ring_fill = ((hh % 12) * 60) + mm; - ring_max = 720; + ring_fill = hh % 12; + ring_max = 12; break; case 'Minutes': ring_fill = mm; @@ -301,7 +406,7 @@ function drawGaugeImage(date) { break; case 'Steps': ring_fill = getSteps(); - ring_max = settings.step_target; + ring_max = step_target; break; case 'Battery': ring_fill = E.getBattery(); @@ -325,14 +430,38 @@ function drawGaugeImage(date) { start = ring_max - end; end = ring_max; } - if (end !== prevRing.end || start !== prevRing.start || ring_max !== prevRing.max) { - drawRing(start, end, ring_max); - prevRing.start = start; - prevRing.end = end; - prevRing.max = ring_max; - log_debug("Redrew ring at " + hh + ":" + mm); - } log_debug("Start: "+ start + " end: " +end); + return [start, end, ring_max]; +} + +function drawIfChanged(start, end, ring_max, idx, type) { + if (end === prevRing[idx].end && start === prevRing[idx].start && ring_max === prevRing[idx].max) return; + switch (type) { + case 'Full': + drawRing(start, end, ring_max, idx); + break; + case 'Semi': + drawSemi(start, end, ring_max, idx); + break; + case 'C': + drawC(end, ring_max, idx); + break; + } + prevRing[idx].start = start; + prevRing[idx].end = end; + prevRing[idx].max = ring_max; + log_debug("Redrew ring #" + idx); +} + +function drawAllRings(date, updateSeconds) { + for (let i = 0; i < settings.rings.length; i++) { + 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'; + result = getGaugeImage(date, ring.ring, ring.step_target); + drawIfChanged(result[0], result[1], result[2], i, ring.type); + } } function drawClock() { @@ -348,11 +477,11 @@ function drawClock() { g.reset(); g.setColor(g.theme.bg); - g.fillEllipse(ringEdge+ringThick,ringEdge+ringThick,w-ringEdge-ringThick,h-ringEdge-ringThick); // Clears the text within the circle - drawGaugeImage(date); + innerMostRing = getInnerMostRing(); + drawAllRings(date, false); setLargeFont(); - g.setColor(settings.fg); + g.setColor(settings.rings[0].fg); g.setFontAlign(1,0); // right aligned g.drawString(hh, (w/2) - 1, h/2); @@ -439,29 +568,79 @@ function polyArray(start, end, max) { return array; } -function drawRing(start, end, max) { +function drawRing(start, end, max, idx) { // Create persistent `buf` inside the function scope if (!drawRing._buf) { drawRing._buf = Graphics.createArrayBuffer(w, h, 2, { msb: true }); } const buf = drawRing._buf; let img = { width: w, height: h, transparent: 0, - bpp: 2, palette: pal1, buffer: buf.buffer }; + bpp: 2, palette: pals[idx].pal1, buffer: buf.buffer }; + let edge = ringEdge + (idx * ringIterOffset); buf.clear(); - buf.setColor(1).fillEllipse(ringEdge,ringEdge,w-ringEdge,h-ringEdge); - buf.setColor(0).fillEllipse(ringEdge+ringThick,ringEdge+ringThick,w-ringEdge-ringThick,h-ringEdge-ringThick); - img.palette = pal2; + 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 = pals[idx].pal2; g.drawImage(img, 0, 0); // Draws a filled-in circle if((end - start) >= max) return; // No need to add the unfilled circle buf.clear(); - buf.setColor(1).fillEllipse(ringEdge,ringEdge,w-ringEdge,h-ringEdge); - buf.setColor(0).fillEllipse(ringEdge+ringThick,ringEdge+ringThick,w-ringEdge-ringThick,h-ringEdge-ringThick); + 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(start, end, max)); // Masks the filled-in part of the segment over the unfilled part - img.palette = pal1; + img.palette = pals[idx].pal1; g.drawImage(img, 0, 0); // Draws the unfilled-in segment return; } +function drawSemi(start, end, max, idx) { + // Create persistent `buf` inside the function scope + 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 }; + 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; + 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 + 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; + g.drawImage(img, 0, 0); // Draws the unfilled-in segment + return; +} + +function drawC(end, max, idx) { + // Create persistent `buf` inside the function scope + if (!drawC._buf) { + drawC._buf = Graphics.createArrayBuffer(w, h, 2, { msb: true }); + } + const buf = drawC._buf; + let img = { width: w, height: h, transparent: 0, + bpp: 2, palette: pals[idx].pal1, 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; + g.drawImage(img, 0, 0); // Draws a filled-in circle with the bg color, clearing it + 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); + var vertices = rotate_points(end, max); + buf.setColor(0).fillPoly(vertices); + img.palette = pals[idx].pal1; + rotate = (2 * Math.PI) / (max / end); + g.drawImage(img, 0, 0); // Draws the unfilled-in segment + return; +} + ///////////////// IDLE TIMER ///////////////////////////////////// @@ -603,7 +782,7 @@ function getDelayMs(prevDelayMs, ring_setting, now) { const sec_batt = [20, 50]; const sec_delay = [10000, 2000, 1000]; const deadband = 5; - if (ring_setting == 'Seconds') { + if (ring_setting.some(ring => ring.ring === 'Seconds')) { const nearNextMinute = (now % 60000) >= (60000 - prevDelayMs); if (nearNextMinute) { let batt = E.getBattery(); @@ -634,7 +813,7 @@ var drawTimeout; // schedule a draw for the next minute or every sec_update ms function queueDraw() { let now = Date.now(); - var nextUpdateRet = getDelayMs(nextUpdateMs, settings.ring, now); + var nextUpdateRet = getDelayMs(nextUpdateMs, settings.rings, now); nextUpdateMs = nextUpdateRet[0]; let delay = nextUpdateMs - (now % nextUpdateMs); if (drawTimeout) clearTimeout(drawTimeout); @@ -645,6 +824,17 @@ function queueDraw() { }, delay); } +function getInnerMostRing() { + var innerMost = 0; + for (let i = settings.rings.length - 1; i >= 0; i--) { + if (settings.rings[i].type !== "None") { + innerMost = i+1; + break; + } + } + return innerMost; +} + // Stop updates when LCD is off, restart when on Bangle.on('lcdPower',on=>{ if (on) { @@ -669,9 +859,10 @@ Bangle.setUI("clockupdown", btn=> { loadSettings(); loadLocation(); +innerMostRing = getInnerMostRing(); var infoMode = infoList[settings.idxInfo]; updateSunRiseSunSet(new Date(), location.lat, location.lon, true); -nextUpdateMs = getDelayMs(1000, settings.ring, Date.now())[0]; +nextUpdateMs = getDelayMs(1000, settings.rings, Date.now())[0]; g.clear(); Bangle.loadWidgets(); diff --git a/apps/daisy/settings.js b/apps/daisy/settings.js index 741d4f3ea..139c24da7 100644 --- a/apps/daisy/settings.js +++ b/apps/daisy/settings.js @@ -2,14 +2,21 @@ const SETTINGS_FILE = "daisy.json"; // initialize with default settings... - let s = {'gy' : '#020', - 'fg' : '#0f0', - 'color': 'Green', - 'check_idle' : true, - 'batt_hours' : false, - 'ring' : 'Steps', - 'idxInfo' : 0, - 'step_target' : 10000}; + let defaultRing = () => ({ + 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, + }; // ...and overwrite them with any saved values // This way saved values are preserved if a new version adds more settings @@ -20,73 +27,99 @@ 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] || {}); +} + function save() { settings = s; storage.write(SETTINGS_FILE, settings); } -var color_options = ['Green','Orange','Cyan','Purple','Red','Blue']; -var fg_code = ['#0f0','#ff0','#0ff','#f0f','#f00','#00f']; -var gy_code = ['#020','#220','#022','#202','#200','#002']; +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]; - function showMainMenu() { - let appMenu = { - '': { 'title': 'Daisy Clock' }, - '< Back': back, + function showRingMenu(ringIndex) { + const ring = s.rings[ringIndex]; + let ringMenu = { + '': { title: `Ring ${ringIndex + 1}` }, + '< Back': showMainMenu, 'Color': { - value: 0 | color_options.indexOf(s.color), + value: 0 | color_options.indexOf(ring.color), min: 0, max: color_options.length - 1, format: v => color_options[v], onchange: v => { - s.color = color_options[v]; - s.fg = fg_code[v]; - s.gy = gy_code[v]; + ring.color = color_options[v]; + ring.fg = fg_code[v]; + ring.gy = gy_code[v]; save(); } }, - 'Ring Display': { - value: 0 | ring_options.indexOf(s.ring), + '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 = s.ring; - s.ring = ring_options[v]; + let prev = ring.ring; + ring.ring = ring_options[v]; save(); - if (prev != s.ring && (prev === 'Steps' || s.ring === 'Steps')) { + 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(showMainMenu, 0); + setTimeout(showRingMenu, 0, ringIndex); } }, } }; - if (s.ring == 'Steps') { - appMenu[/*LANG*/"Step Target"] = { - value: 0 | step_options.indexOf(s.step_target), + 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 => { - s.step_target = step_options[v]; + ring.step_target = step_options[v]; save(); }, }; - } - appMenu['Idle Warning'] = { - value: !!s.idle_check, - onchange: v => { - s.idle_check = v; - save(); - }, - }; - appMenu['Battery Life Format'] = { - value: !!s.batt_hours, - format: value => value?"Days":"%", - onchange: v => { - s.batt_hours = v; - save(); + } + E.showMenu(ringMenu); + } + + function showMainMenu() { + let appMenu = { + '': { title: 'Daisy Clock' }, + '< Back': back, + 'Ring 1': () => showRingMenu(0), + 'Ring 2': () => showRingMenu(1), + 'Ring 3': () => showRingMenu(2), + 'Idle Warning' : { + value: !!s.idle_check, + onchange: v => { + s.idle_check = v; + save(); + }, }, + 'Battery Life Format' : { + value: !!s.batt_hours, + format: value => value?"Days":"%", + onchange: v => { + s.batt_hours = v; + save(); + }, + } }; E.showMenu(appMenu); } From d7f0113a86a044ef809d001d22d1ce0c26cf22c7 Mon Sep 17 00:00:00 2001 From: David Volovskiy Date: Sun, 18 May 2025 07:54:26 -0400 Subject: [PATCH 03/22] 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); } From 20f5f6ed7ca85025fbc6484b94a572565240154a Mon Sep 17 00:00:00 2001 From: David Volovskiy Date: Sun, 18 May 2025 09:35:08 -0400 Subject: [PATCH 04/22] Fixed steps redraw --- apps/daisy/app.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/daisy/app.js b/apps/daisy/app.js index f59e64ebf..00302b60a 100644 --- a/apps/daisy/app.js +++ b/apps/daisy/app.js @@ -371,7 +371,6 @@ function drawInfo() { var line = dims[0]; var height = dims[2]; if (infoMode == "ID_HRM") { - clearInfo(); g.setColor('#f00'); // red drawHeartIcon(line, height); } else { @@ -402,7 +401,7 @@ function draw(updateSeconds) { if (!idle) { if (updateSeconds) { let date = new Date(); - drawAllRings(date, updateSeconds); + drawAllRings(date, 'Seconds'); } else { drawClock(); @@ -485,11 +484,11 @@ function drawIfChanged(start, end, ring_max, idx, type) { log_debug("Redrew ring #" + idx); } -function drawAllRings(date, updateSeconds) { +function drawAllRings(date, drawOnlyThisType) { for (let i = 0; i < settings.rings.length; i++) { let ring = settings.rings[i]; if (ring.type == "None") continue; - if (ring.ring != "Seconds" && updateSeconds) continue; + if (drawOnlyThisType != null && ring.ring != drawOnlyThisType) continue; 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); @@ -512,7 +511,7 @@ function drawClock() { 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); + drawAllRings(date, null); setLargeFont(); g.setColor(settings.fg); @@ -537,10 +536,11 @@ function drawSteps() { if (drawingSteps) return; drawingSteps = true; clearInfo(); + var dims = getInfoDims(); setSmallFont(); g.setFontAlign(0,0); g.setColor(g.theme.fg); - g.drawString('STEPS ' + getSteps(), w/2, (3*h/4) - 4); + g.drawString('STEPS ' + getSteps(), w/2, dims[0]); drawingSteps = false; } From 120984269ceb3fe5f09f3fc61069704e5244797b Mon Sep 17 00:00:00 2001 From: David Volovskiy Date: Sun, 18 May 2025 09:47:54 -0400 Subject: [PATCH 05/22] Ring redraws wihen stepping and steps intervals lowered for fewer redraws. --- apps/daisy/app.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/daisy/app.js b/apps/daisy/app.js index 00302b60a..162e6068a 100644 --- a/apps/daisy/app.js +++ b/apps/daisy/app.js @@ -436,8 +436,8 @@ function getGaugeImage(date, ringType, step_target) { ring_max = 1440; break; case 'Steps': - ring_fill = getSteps(); - ring_max = step_target; + ring_max = 100; + ring_fill = ring_max * (getSteps() / step_target); break; case 'Battery': ring_fill = E.getBattery(); @@ -541,6 +541,7 @@ function drawSteps() { g.setFontAlign(0,0); g.setColor(g.theme.fg); g.drawString('STEPS ' + getSteps(), w/2, dims[0]); + drawAllRings(new Date(), 'Steps'); drawingSteps = false; } From 9cf748aa88ea6a571095a420c621497e5abafb7c Mon Sep 17 00:00:00 2001 From: David Volovskiy Date: Sun, 18 May 2025 10:05:27 -0400 Subject: [PATCH 06/22] Updated version info --- apps/daisy/ChangeLog | 3 ++- apps/daisy/README.md | 10 ++++++++-- apps/daisy/metadata.json | 2 +- apps/daisy/screenshot_daisy4.png | Bin 0 -> 3507 bytes 4 files changed, 11 insertions(+), 4 deletions(-) create mode 100644 apps/daisy/screenshot_daisy4.png diff --git a/apps/daisy/ChangeLog b/apps/daisy/ChangeLog index c797845c5..0f7e01ccb 100644 --- a/apps/daisy/ChangeLog +++ b/apps/daisy/ChangeLog @@ -13,4 +13,5 @@ 0.13: Fixed Battery estimate Default to percentage and improved setting string 0.14: Use `power_usage` module 0.15: Ring can now show hours, minute, or seconds hand, day/night left, or battery; Allowed for 12hr time; Ring now goes up in 5% increments; Step goal can be changed; The info that is set on the watchface will retain when leaving the face -0.16: Ring is now dynamically-created, rather than displaying pre-rendered rings; Seconds update every second; Ability to see Day ring; Settings options moved around to avoid popping of Steps option disappearing when not used; In Sun setting, ring is fully illuminated between during all of sunrise and sunset. \ No newline at end of file +0.16: Ring is now dynamically-created, rather than displaying pre-rendered rings; Seconds update every second; Ability to see Day ring; Settings options moved around to avoid popping of Steps option disappearing when not used; In Sun setting, ring is fully illuminated between during all of sunrise and sunset. +0.17: Made the display show three rings with different ring displays. \ No newline at end of file diff --git a/apps/daisy/README.md b/apps/daisy/README.md index f42d34e2c..66c5d4ce8 100644 --- a/apps/daisy/README.md +++ b/apps/daisy/README.md @@ -17,10 +17,10 @@ See [#1248](https://github.com/espruino/BangleApps/issues/1248) * Uses mylocation.json from MyLocation app to calculate sunrise and sunset times for your location * If your Sunrise, Sunset times look odd make sure you have setup your location using [MyLocation](https://banglejs.com/apps/?id=mylocation) -* The screen is updated every minute to save battery power, unless the ring is set to display seconds, then it updates every 3 seconds. +* The screen is updated every minute to save battery power, unless a ring is set to display seconds or steps. * Uses the [BloggerSansLight](https://www.1001fonts.com/rounded-fonts.html?page=3) font, which if free for commercial use * You need to run >2V22 to show the battery estimate in hours -* In the settings, the ring can be set to: +* In the settings, the rings can be set to: * Hours - Displays the ring as though it's the hour hand on an analog clock. * Minutes - Displays the ring as though it's the minute hand on an analog clock. * Seconds - Displays the ring as though it's the seconds hand on an analog clock. This option uses far more battery than any other option as it updates the screen 60 times more often. @@ -28,6 +28,11 @@ See [#1248](https://github.com/espruino/BangleApps/issues/1248) * Steps - Displays the ring as the amount of steps taken that day out of Step Target setting. * Battery - Displays the ring as the amount of battery percentage left. * Sun - Displays the ring as the amount of time that has passed from sunrise to sunset in the day and the amount of time between sunset and sunrise at night. +* The rings have the following displays + * None - Don't display the ring at all. + * Full - Display a full circle, where the filled-in part of the circle's color differs with the unfilled section. + * Semi - Similar to full, but the unfilled section does not display. + * C - Displays a full circle with a notch. ## Future Development * Use mini icons in the information line rather that text @@ -37,5 +42,6 @@ See [#1248](https://github.com/espruino/BangleApps/issues/1248) ## Screenshots ![](screenshot_daisy1.png) ![](screenshot_daisy3.png) +![](screenshot_daisy4.png) It is worth looking at the real thing though as the screenshots do not do it justice. diff --git a/apps/daisy/metadata.json b/apps/daisy/metadata.json index 59b533020..caa66d1b7 100644 --- a/apps/daisy/metadata.json +++ b/apps/daisy/metadata.json @@ -1,6 +1,6 @@ { "id": "daisy", "name": "Daisy", - "version": "0.16", + "version": "0.17", "dependencies": {"mylocation":"app"}, "description": "A beautiful digital clock with large ring gauge, 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/screenshot_daisy4.png b/apps/daisy/screenshot_daisy4.png new file mode 100644 index 0000000000000000000000000000000000000000..bad317df24d2b4425b1bbf0748aeab4c4bc30b3f GIT binary patch literal 3507 zcmV;k4NUThP)Px?ZAnByRCr$Po!fTXIt)aU|NrQAIgVOI5s4YxcoFh))~QL57;KIxTDCtwK0f|@ z)L$vEr~;n_@S>HgX@4nD02c^LD^LJ0UA~%p0c>I5&!3Nv&(DvK-hY|+uUPd*DNq1Y zaw!_W;I{r1*i8is;IlM{qe_l@eccLgtA9aVH*ryH{fO(~z|uq?4D&M`IKpXL&Md(f z@%n>+ekQ;X(6nM^IPinF8G8d9?X;c?AsX~eU3qVSJpmgT%MrFUK7TD>AkR z(3^m~7r;pIcWh$;dU24~23YI3i4db~xp9OJc-6pd0*T_*!#wd~Yk4|mrshgJuzJ9F zE$>EH%Yheg+^fi1j(RxIjApTz8AuE!&BpKbxd48U<7!LDaCUp_Bz@=u9bgiO=K@$; z)ra;&S))Nl15W_)8~`uuynoPQcNW>F0|=UFh{Ga5#UQcnG6%r1Il4sm0F|AH25f}6 z>pZ#)q5%hiJQm=Iop%JV65uS*D0|1aO$O0G10Ws?uvD?+*Jp&bB>@97%HL}&vl}Nv zJO*INc@x2130e!xyFxq$;6y-ML+t?W@4c*aM)v*=7WB`wrATt(T!05VZv?c=r95*n zN%KNMo*m*`fYGJz+|C1B2?*yYe}#*l_YM%}06frnEf9==Ho~Q)JP?r8P8__I$N@OQ zo`jfMaHV1oNafd%5xF4{H%}>~&Vdle0zANZHN{;4T2E(gp1zEc08cshUsStxh|#chPvXihUpcj)U73)_mAxlooi+rCehSO#?*{Pu9F$5>2XNr211lbtZ8e4!VC&!paSFh&3|vFa z<%=7kTB8bRYC%CvHEz#(8VA-0h8CmR=@ejVLNn>G7uEr+)1%vqy<`PUp+ep$z}AI= zm}-1q9uDB3y)P?Lk(R3fQy-d1qYHBY2kO=msZJdNMF&GO0KY;~5L1nRPnZKZ$brw( zI*V2Cf`lbB^MaUq_#HTr-~dh#s)m?X0S02qSPk0<4B+5r9_B4s&8&5Gyeh*yEAh)% zDcXOIi~(GAECs$5@Ni+zZ3G5z!rr$CSwjI2fM1zoW5*lj^lkUQu(+CXUHFT|6CMpo(!tM?n;JmNI>wGtnw4k9pT-f7gF5Q9ajfxaGDR&(aE<1}Q22~>coC(I>f z*U~A3vja0LHcuHq6T>kzg}HgTs^QuSgwz&Gks*h_>DUOF%vo;8h)% zal>9)CJyPs*#O_Yfh0js`qNi)cas8dz*9~k+>>ix$MDPf;s7&{Ww>xije&jeJ;06* z9FiCUFmkljy7VvLz$m~O@JdI7YR6XtjH&~)O9PmNu6OBYV-fAWwh(~yx0iM`Ou&Hd zwN?YXq5~5U{i{W*k7uk);R|43CH%Ma`^KlMYxo}6eN`gchgTbR3vup~0I*a>t5e?T zZjC9;*}c}~z=GrhZsgcEGEnGxanTqOpwjE}04&Xvc-=jz3_I} zjzR#G76uZ7ndeFq~ujSlPy-tz!P3kS4wUzH;qSjyAceUITh!SjsO zE`jrB9v|hv*F7uZfW$*MU4{$bFL~U}N)52&IK=DjN%h8NKw{cT`Fh4WjpgZ@p0Ub- zzusryeo|Co=-UE*HbWn$eD$)-2LzaX7w!z*Rj=1;jE2tw7@`Ghl+8tU|=V(w*%YjQV~D}LI4KFE(ZogswT1m zApn;H%feR+9|b}H2BuaH42V=sWCcP1p2dOdMotD`NvJz_S9}dS>?SncMTf zp|77gl%4~=`{>Z!6^i{xQN&sZ1DKfXG!8s!8*znD3+Mq}uYc>X zX3h)X;|jt!`1yEIf)jxp(cYs?nENU?!vOZk`VwQ76?}I^=v}H?fZpw+B?rHAtw~Dk<9ErF8(H3`=*rE6Q~nap#aIz}E>$ zrwOfX#ON(V7`z6)Fo0mB?K z2|A~lAV%l>#CD-|QtW+o00&hrRGgqWKPl|Y_2IS5vwgi53cn~=xML#(W^55SIln%WcR zqMizG04F{GCup83bV5Ee46%czJ^%;oZLS5D#6H^BS+Tq{(zOia!v|nlGq)Cq_yuuW z?%nkB1vqe}olCM?5!_a{5GY-@1Ri_=&Z-3Qqk-kd{f};)OSYm`F#reLZE8*@YF|7U z-UJR}0G`l^-QEUG%*`?svR&9=fyV%xu=mlPQtS@$6yPS-KL%inbr||G#oG=MyJD}dN02|!Y+Er87RbbvZH@5CM01sH17Dt}(=0*!`%Ay=t-yDG1 zW#!!7Qv8uHuR3q%@^!=I0z7b~zEto4;;N>{;s31j5{hM(Z?)fM#^| z9*b#o4(#}20G?pwdhC%|v7_3jgF8|E#sC~uNn_lVTsa+Dqqb4q#{w*^WaIY_TSS`? z=3&rIT&J-BTL??;I|Aroz$R;J8Ey`MCtl%_xE^3n3+e)OnFC;nl6t)qXecljzzeMS zN078o9p(b~5p-0No(jwj@Ip@DS(Nlx3+p^L!0DB&0asIC4S-RH7^T4c002ovPDHLkV1k>-cpLx# literal 0 HcmV?d00001 From 3cef967c40d1cf4266b76f07f42c450c50aa3a01 Mon Sep 17 00:00:00 2001 From: David Volovskiy Date: Sun, 18 May 2025 10:18:19 -0400 Subject: [PATCH 07/22] Hide steps when type is None --- apps/daisy/settings.js | 102 ++++++++++++++++++++--------------------- 1 file changed, 51 insertions(+), 51 deletions(-) diff --git a/apps/daisy/settings.js b/apps/daisy/settings.js index f43a778c4..f2510d2f8 100644 --- a/apps/daisy/settings.js +++ b/apps/daisy/settings.js @@ -60,61 +60,61 @@ function save() { 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, - '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); - } - } - }, - }; - 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(); - } - }; - 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); + 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); + } } }, }; - } - 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(); - }, + 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(); + } }; - } + 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); } From 12ffb9bbac8443e9fe041b8cd41b8b4afc9fbe35 Mon Sep 17 00:00:00 2001 From: David Volovskiy Date: Sun, 18 May 2025 11:00:35 -0400 Subject: [PATCH 08/22] Steps don't check and update on every step --- apps/daisy/app.js | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/apps/daisy/app.js b/apps/daisy/app.js index 162e6068a..4c7335724 100644 --- a/apps/daisy/app.js +++ b/apps/daisy/app.js @@ -437,7 +437,8 @@ function getGaugeImage(date, ringType, step_target) { break; case 'Steps': ring_max = 100; - ring_fill = ring_max * (getSteps() / step_target); + ring_fill = getSteps(); + ring_max = step_target; break; case 'Battery': ring_fill = E.getBattery(); @@ -536,12 +537,22 @@ function drawSteps() { if (drawingSteps) return; drawingSteps = true; clearInfo(); + const minStepPctUpdate = 3; // If the current step less percent than last updated, don't redraw var dims = getInfoDims(); setSmallFont(); g.setFontAlign(0,0); g.setColor(g.theme.fg); - g.drawString('STEPS ' + getSteps(), w/2, dims[0]); - drawAllRings(new Date(), 'Steps'); + var steps = getSteps(); + g.drawString('STEPS ' + steps, w/2, dims[0]); + for (let i = 0; i < settings.rings.length; i++) { + let ring = settings.rings[i]; + if(ring.type == "None" || ring.ring != 'Steps') continue; + var percentChanged = 100 * ((steps - prevRing[idx].end) / ring.step_target); + if(percentChanged >= minStepPctUpdate) { + drawAllRings(new Date(), 'Steps'); + break; + } + } drawingSteps = false; } From 3f57a859aba25fa40c726dd9a5906c486efcc876 Mon Sep 17 00:00:00 2001 From: David Volovskiy Date: Sun, 18 May 2025 11:46:15 -0400 Subject: [PATCH 09/22] Seperated drawing of steps and rings on step --- apps/daisy/app.js | 51 ++++++++++++++++++++++++++++++----------------- 1 file changed, 33 insertions(+), 18 deletions(-) diff --git a/apps/daisy/app.js b/apps/daisy/app.js index 4c7335724..3b0b52b11 100644 --- a/apps/daisy/app.js +++ b/apps/daisy/app.js @@ -32,6 +32,7 @@ const ringThick = 6; let nextUpdateMs; var drawingSteps = false; var innerMostRing = 0; +var prevStepDisplayed = 0; var prevRing = Array(3).fill().map(() => ({ start: null, end: null, max: null })); function log_debug(o) { @@ -307,7 +308,7 @@ const infoData = { ID_DAY: { calc: () => {var d = require("locale").dow(new Date()).toLowerCase(); return d[0].toUpperCase() + d.substring(1);} }, ID_SR: { calc: () => 'SUNRISE ' + sunRise }, ID_SS: { calc: () => 'SUNSET ' + sunSet }, - ID_STEP: { calc: () => 'STEPS ' + getSteps() }, + ID_STEP: { calc: () => {var steps = getSteps(); prevStepDisplayed = steps; return 'STEPS ' + steps;}}, ID_BATT: { calc: batteryString}, ID_HRM: { calc: () => hrmCurrent } }; @@ -533,27 +534,35 @@ function drawClock() { drawCount++; } +function checkRedrawSteps(steps) { + var redrawText = false; + var redrawRings = false; + const minStepText = 10; // In number of steps + const minStepPctUpdate = 3; // If the current step is less percent than last updated, don't redraw the rings + if (infoMode == "ID_STEP") { + if (minStepText >= (steps - prevStepDisplayed)) { + redrawText = true; + } + } + for (let i = 0; i < settings.rings.length; i++) { + let ring = settings.rings[i]; + if(ring.type == "None" || ring.ring != 'Steps') continue; + let percentChanged = 100 * ((steps - prevRing[i].end) / ring.step_target); + if(percentChanged >= minStepPctUpdate) { + redrawRings = true; + break; + } + } + return [redrawText, redrawRings]; +} + function drawSteps() { - if (drawingSteps) return; - drawingSteps = true; clearInfo(); - const minStepPctUpdate = 3; // If the current step less percent than last updated, don't redraw var dims = getInfoDims(); setSmallFont(); g.setFontAlign(0,0); g.setColor(g.theme.fg); - var steps = getSteps(); - g.drawString('STEPS ' + steps, w/2, dims[0]); - for (let i = 0; i < settings.rings.length; i++) { - let ring = settings.rings[i]; - if(ring.type == "None" || ring.ring != 'Steps') continue; - var percentChanged = 100 * ((steps - prevRing[idx].end) / ring.step_target); - if(percentChanged >= minStepPctUpdate) { - drawAllRings(new Date(), 'Steps'); - break; - } - } - drawingSteps = false; + g.drawString((infoData[infoMode].calc().toUpperCase()), w/2, dims[0]); } ///////////////// GAUGE images ///////////////////////////////////// @@ -780,8 +789,14 @@ Bangle.on('step', s => { } idle = false; warned = 0; - - if (infoMode == "ID_STEP") drawSteps(); + if (drawingSteps) return; + var steps = getSteps(); + ret = checkRedrawSteps(steps); + if (!ret[0] && !ret[1]) return; + drawingSteps = true; + if (ret[0]) drawSteps(); + if (ret[1]) drawAllRings(new Date(), 'Steps'); + drawingSteps = false; }); function checkIdle() { From bad49674b178a023d69c4df051d00c82672260ba Mon Sep 17 00:00:00 2001 From: David Volovskiy Date: Sun, 18 May 2025 12:04:38 -0400 Subject: [PATCH 10/22] Don't redrae rinds under 10 steps --- apps/daisy/app.js | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/apps/daisy/app.js b/apps/daisy/app.js index 3b0b52b11..64c3cff43 100644 --- a/apps/daisy/app.js +++ b/apps/daisy/app.js @@ -537,18 +537,17 @@ function drawClock() { function checkRedrawSteps(steps) { var redrawText = false; var redrawRings = false; - const minStepText = 10; // In number of steps - const minStepPctUpdate = 3; // If the current step is less percent than last updated, don't redraw the rings + const minStepToUpdate = 10; // In number of steps as a minumum to update either the rings or text. + const minStepPctUpdateRings = 3; // If the current step is less percent than last updated, don't redraw the rings + if (minStepToUpdate < (steps - prevStepDisplayed)) return [redrawText, redrawRings]; if (infoMode == "ID_STEP") { - if (minStepText >= (steps - prevStepDisplayed)) { - redrawText = true; - } + redrawText = true; } for (let i = 0; i < settings.rings.length; i++) { let ring = settings.rings[i]; if(ring.type == "None" || ring.ring != 'Steps') continue; let percentChanged = 100 * ((steps - prevRing[i].end) / ring.step_target); - if(percentChanged >= minStepPctUpdate) { + if(percentChanged >= minStepPctUpdateRings) { redrawRings = true; break; } From 981826c25bcf9d36dcebb639a100791962bbb99f Mon Sep 17 00:00:00 2001 From: David Volovskiy Date: Sun, 18 May 2025 13:34:19 -0400 Subject: [PATCH 11/22] bugfix on steps display update --- apps/daisy/app.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/daisy/app.js b/apps/daisy/app.js index 64c3cff43..c06e11f90 100644 --- a/apps/daisy/app.js +++ b/apps/daisy/app.js @@ -539,7 +539,8 @@ function checkRedrawSteps(steps) { var redrawRings = false; const minStepToUpdate = 10; // In number of steps as a minumum to update either the rings or text. const minStepPctUpdateRings = 3; // If the current step is less percent than last updated, don't redraw the rings - if (minStepToUpdate < (steps - prevStepDisplayed)) return [redrawText, redrawRings]; + if (minStepToUpdate > (steps - prevStepDisplayed)) return [redrawText, redrawRings]; + prevStepDisplayed = steps; if (infoMode == "ID_STEP") { redrawText = true; } From f62dd11d25e8358a07f945a53ed652e3379ec58f Mon Sep 17 00:00:00 2001 From: David Volovskiy Date: Sun, 18 May 2025 13:47:32 -0400 Subject: [PATCH 12/22] Decoupled updating ring and text --- apps/daisy/app.js | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/apps/daisy/app.js b/apps/daisy/app.js index c06e11f90..c42cc5b6a 100644 --- a/apps/daisy/app.js +++ b/apps/daisy/app.js @@ -29,6 +29,8 @@ const infoHeightDefault = 11; const ringEdge = 4; const ringIterOffset = 10; const ringThick = 6; +const minStepToUpdate = 10; // In number of steps as a minumum to update the text. +const minStepPctUpdateRings = 3; // If the current step is less percent than last updated, don't redraw the rings let nextUpdateMs; var drawingSteps = false; var innerMostRing = 0; @@ -537,11 +539,7 @@ function drawClock() { function checkRedrawSteps(steps) { var redrawText = false; var redrawRings = false; - const minStepToUpdate = 10; // In number of steps as a minumum to update either the rings or text. - const minStepPctUpdateRings = 3; // If the current step is less percent than last updated, don't redraw the rings - if (minStepToUpdate > (steps - prevStepDisplayed)) return [redrawText, redrawRings]; - prevStepDisplayed = steps; - if (infoMode == "ID_STEP") { + if (infoMode == "ID_STEP" && (minStepToUpdate <= (steps - prevStepDisplayed))) { redrawText = true; } for (let i = 0; i < settings.rings.length; i++) { From 7a2a9ad3f47355341595f2c60bc9d07fc742b8ce Mon Sep 17 00:00:00 2001 From: David Volovskiy Date: Sun, 18 May 2025 14:39:38 -0400 Subject: [PATCH 13/22] Blk/Wht color works in Full circle --- apps/daisy/app.js | 11 ++++++++--- apps/daisy/settings.js | 8 ++++---- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/apps/daisy/app.js b/apps/daisy/app.js index c42cc5b6a..3e44b3379 100644 --- a/apps/daisy/app.js +++ b/apps/daisy/app.js @@ -85,7 +85,12 @@ function assignPalettes() { palbg = new Uint16Array([g.toColor(g.theme.bg)]); for (let i = 0; i < settings.rings.length; i++) { let ring = settings.rings[i]; - if (g.theme.dark) { + if (ring.type == 'Full' && ring.color == 'Blk/Wht') { + // BLK/WHT is the outside in light mode, so all of it gets filled in. + // Using the dark theme stops it from being a one-color circle. + pals[i].pal1 = new Uint16Array([g.theme.bg, g.toColor(ring.gy), g.toColor(ring.fg), g.toColor("#00f")]); + pals[i].pal2 = new Uint16Array([g.theme.bg, g.toColor(ring.fg), g.toColor(ring.gy), g.toColor("#00f")]); + } else if (g.theme.dark) { // palette for 0-49% pals[i].pal1 = new Uint16Array([g.theme.bg, g.toColor(ring.gy), g.toColor(ring.fg), g.toColor("#00f")]); // palette for 50-100% @@ -193,8 +198,9 @@ function loadSettings() { settings.rings[2].step_target = settings.rings[2].step_target||10000; for (let i = 0; i < settings.rings.length; i++) { + // Needed in case the user swaps themes if (settings.rings[i].color == 'Blk/Wht') { - settings.rings[i].gy = g.theme.fg; + settings.rings[i].gy = g.theme.dark ? '#222' : '#888'; settings.rings[i].fg = g.theme.fg; } } @@ -493,7 +499,6 @@ function drawAllRings(date, drawOnlyThisType) { let ring = settings.rings[i]; if (ring.type == "None") continue; if (drawOnlyThisType != null && ring.ring != drawOnlyThisType) continue; - 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); } diff --git a/apps/daisy/settings.js b/apps/daisy/settings.js index f2510d2f8..e9e7d28ff 100644 --- a/apps/daisy/settings.js +++ b/apps/daisy/settings.js @@ -22,8 +22,8 @@ s.rings[1] = { color: 'Blk/Wht', - fg: g.theme.fg, - gy: g.theme.fg, + fg: null, + gy: null, ring: 'Minutes', type: 'None', step_target: 10000, @@ -53,8 +53,8 @@ function save() { } 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 fg_code = ['#0ff','#0f0','#ff0','#f0f','#f00','#00f', null]; + var gy_code = ['#022','#020','#220','#202','#200','#002', null]; 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]; From 2e2f0c9b2b7715aee2c77e8d259689c646353cec Mon Sep 17 00:00:00 2001 From: David Volovskiy Date: Sun, 18 May 2025 16:32:30 -0400 Subject: [PATCH 14/22] Capped end variable to 100% --- apps/daisy/app.js | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/daisy/app.js b/apps/daisy/app.js index 3e44b3379..e407efb06 100644 --- a/apps/daisy/app.js +++ b/apps/daisy/app.js @@ -467,6 +467,7 @@ function getGaugeImage(date, ringType, step_target) { } var start = 0; var end = Math.round(ring_fill); + if ((end - start) > ring_max) end = ring_max; // Capping end var so the ring doesn't need to update if already full. if (invertRing) { start = ring_max - end; end = ring_max; From 68743be7ad49a05db6b6e77da514fb4188b1c17b Mon Sep 17 00:00:00 2001 From: David Volovskiy Date: Thu, 22 May 2025 08:33:41 -0400 Subject: [PATCH 15/22] Adjusted width for 100% batt --- apps/daisy/app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/daisy/app.js b/apps/daisy/app.js index e407efb06..f537663a8 100644 --- a/apps/daisy/app.js +++ b/apps/daisy/app.js @@ -350,7 +350,7 @@ function getInfoDims() { line -= 7; break; case 3: - width -= 10; + width -= 9; height -= 6; line -= 10; break; From 6d1d6397ed64644fb7dad25bdf724daa7e2eaac3 Mon Sep 17 00:00:00 2001 From: David Volovskiy Date: Thu, 22 May 2025 18:52:02 -0400 Subject: [PATCH 16/22] Always clear idle if it was set --- apps/daisy/app.js | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/apps/daisy/app.js b/apps/daisy/app.js index f537663a8..623b6764d 100644 --- a/apps/daisy/app.js +++ b/apps/daisy/app.js @@ -758,15 +758,26 @@ BUTTON.prototype.draw = function() { g.drawRect(this.x, this.y, (this.x + this.w), (this.y + this.h)); }; +function redrawWholeFace() { + // Reset the prevRings to force all rings to update + prevRing = Array(3).fill().map(() => ({ start: null, end: null, max: null })); + g.clear(); + draw(false); +} + function dismissPrompt() { idle = false; warned = false; lastStep = getTime(); Bangle.buzz(100); - // Reset the prevRings to force all rings to update - prevRing = Array(3).fill().map(() => ({ start: null, end: null, max: null })); - g.clear(); - draw(false); + redrawWholeFace(); +} + +function resetIdle() { + if (idle == false) return; + // redraw if we had been idle + dismissPrompt(); + idle = false; } var dismissBtn = new BUTTON("big",0, 3*h/4 ,w, h/4, "#0ff", dismissPrompt, "Dismiss"); @@ -787,11 +798,7 @@ Bangle.on('touch', function(button, xy) { // if we get a step then we are not idle Bangle.on('step', s => { lastStep = getTime(); - // redraw if we had been idle - if (idle == true) { - dismissPrompt(); - } - idle = false; + resetIdle(); warned = 0; if (drawingSteps) return; var steps = getSteps(); @@ -806,7 +813,7 @@ Bangle.on('step', s => { function checkIdle() { log_debug("checkIdle()"); if (!settings.idle_check) { - idle = false; + resetIdle(); warned = false; return; } @@ -825,7 +832,7 @@ function checkIdle() { } idle = true; } else { - idle = false; + resetIdle(); warned = 0; } } @@ -936,10 +943,9 @@ var infoMode = infoList[settings.idxInfo]; updateSunRiseSunSet(new Date(), location.lat, location.lon, true); nextUpdateMs = getDelayMs(1000, settings.rings, Date.now())[0]; -g.clear(); Bangle.loadWidgets(); /* * we are not drawing the widgets as we are taking over the whole screen */ widget_utils.hide(); -draw(false); +redrawWholeFace() From 77c57fc5e953950bc25d0d1d7f706c71dd85b219 Mon Sep 17 00:00:00 2001 From: David Volovskiy Date: Fri, 23 May 2025 18:39:56 -0400 Subject: [PATCH 17/22] Font is outermost --- apps/daisy/app.js | 31 ++++++++++++++++++++----------- apps/daisy/settings.js | 11 ----------- 2 files changed, 20 insertions(+), 22 deletions(-) diff --git a/apps/daisy/app.js b/apps/daisy/app.js index 623b6764d..b7db28072 100644 --- a/apps/daisy/app.js +++ b/apps/daisy/app.js @@ -34,6 +34,7 @@ const minStepPctUpdateRings = 3; // If the current step is less percent than la let nextUpdateMs; var drawingSteps = false; var innerMostRing = 0; +var outerMostRing = 0; var prevStepDisplayed = 0; var prevRing = Array(3).fill().map(() => ({ start: null, end: null, max: null })); @@ -518,13 +519,13 @@ function drawClock() { g.reset(); g.setColor(g.theme.bg); - innerMostRing = getInnerMostRing(); + getInnerOuterMostRing(); 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, null); setLargeFont(); - g.setColor(settings.fg); + g.setColor(settings.rings[outerMostRing - 1].fg); g.setFontAlign(1,0); // right aligned g.drawString(hh, (w/2) - 1, h/2); @@ -902,15 +903,23 @@ function queueDraw() { }, delay); } -function getInnerMostRing() { - var innerMost = 0; - for (let i = settings.rings.length - 1; i >= 0; i--) { - if (settings.rings[i].type !== "None") { - innerMost = i+1; - break; +function getInnerOuterMostRing() { + let innerMost = 0; + let outerMost = 0; + for (let i = 0; i < settings.rings.length; i++) { + let j = settings.rings.length - 1 - i; + if (outerMost === 0 && settings.rings[i].type !== "None") { + outerMost = i + 1; + } + if (innerMost === 0 && settings.rings[j].type !== "None") { + innerMost = j + 1; + } + if (outerMost !== 0 && innerMost !== 0) { + break; } } - return innerMost; + innerMostRing = innerMost; + outerMostRing = outerMost; } // Stop updates when LCD is off, restart when on @@ -938,7 +947,7 @@ Bangle.setUI("clockupdown", btn=> { loadSettings(); loadLocation(); -innerMostRing = getInnerMostRing(); +getInnerOuterMostRing(); var infoMode = infoList[settings.idxInfo]; updateSunRiseSunSet(new Date(), location.lat, location.lon, true); nextUpdateMs = getDelayMs(1000, settings.rings, Date.now())[0]; @@ -948,4 +957,4 @@ Bangle.loadWidgets(); * we are not drawing the widgets as we are taking over the whole screen */ widget_utils.hide(); -redrawWholeFace() +redrawWholeFace(); diff --git a/apps/daisy/settings.js b/apps/daisy/settings.js index e9e7d28ff..dbf9ee36b 100644 --- a/apps/daisy/settings.js +++ b/apps/daisy/settings.js @@ -4,7 +4,6 @@ // default settings let s = { rings: [{}, {}, {}], - color: 'Green', fg: '#0f0', check_idle: true, batt_hours: false, @@ -125,16 +124,6 @@ function save() { 'Ring 1': () => showRingMenu(0), 'Ring 2': () => showRingMenu(1), 'Ring 3': () => showRingMenu(2), - 'Hour Color': { - value: 0 | color_options.indexOf(s.color), - min: 0, max: color_options.length - 1, - format: v => color_options[v], - onchange: v => { - s.color = color_options[v]; - s.fg = fg_code[v]; - save(); - }, - }, 'Battery Life Format' : { value: !!s.batt_hours, format: value => value?"Days":"%", From a1927e95c368ccf3c36e0e069cd64acd523d26c8 Mon Sep 17 00:00:00 2001 From: David Volovskiy Date: Fri, 23 May 2025 19:23:58 -0400 Subject: [PATCH 18/22] Font option readded with inner and outer --- apps/daisy/app.js | 18 +++++++++++++++--- apps/daisy/settings.js | 13 +++++++++++++ 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/apps/daisy/app.js b/apps/daisy/app.js index b7db28072..fc65ec7e2 100644 --- a/apps/daisy/app.js +++ b/apps/daisy/app.js @@ -206,7 +206,20 @@ function loadSettings() { } } - settings.fg = settings.fg||'#0ff'; + getInnerOuterMostRing(); + settings.color = settings.color||'Outer'; + settings.fg = settings.fg||'#0f0'; + switch (settings.color) { + case 'Outer': + if (outerMostRing == 0) break; + settings.fg = settings.rings[outerMostRing - 1].fg; + break; + case 'Inner': + if (innerMostRing == 0) break; + settings.fg = settings.rings[innerMostRing - 1].fg; + break; + } + 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"]); @@ -525,7 +538,7 @@ function drawClock() { drawAllRings(date, null); setLargeFont(); - g.setColor(settings.rings[outerMostRing - 1].fg); + g.setColor(settings.fg); g.setFontAlign(1,0); // right aligned g.drawString(hh, (w/2) - 1, h/2); @@ -947,7 +960,6 @@ Bangle.setUI("clockupdown", btn=> { loadSettings(); loadLocation(); -getInnerOuterMostRing(); var infoMode = infoList[settings.idxInfo]; updateSunRiseSunSet(new Date(), location.lat, location.lon, true); nextUpdateMs = getDelayMs(1000, settings.rings, Date.now())[0]; diff --git a/apps/daisy/settings.js b/apps/daisy/settings.js index dbf9ee36b..1fe60dda0 100644 --- a/apps/daisy/settings.js +++ b/apps/daisy/settings.js @@ -4,6 +4,7 @@ // default settings let s = { rings: [{}, {}, {}], + color: 'Outer', fg: '#0f0', check_idle: true, batt_hours: false, @@ -57,6 +58,8 @@ function save() { 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]; + var color_options_font = ['Outer', 'Inner'].concat(color_options); + var fg_code_font = [null, null].concat(color_options); function showRingMenu(ringIndex) { const ring = s.rings[ringIndex]; @@ -124,6 +127,16 @@ function save() { 'Ring 1': () => showRingMenu(0), 'Ring 2': () => showRingMenu(1), 'Ring 3': () => showRingMenu(2), + 'Hour Color': { + value: 0 | color_options_font.indexOf(s.color), + min: 0, max: color_options_font.length - 1, + format: v => color_options_font[v], + onchange: v => { + s.color = color_options_font[v]; + s.fg = fg_code_font[v]; + save(); + }, + }, 'Battery Life Format' : { value: !!s.batt_hours, format: value => value?"Days":"%", From f6629aa3fc9eff51b9eea281fe11fd26e18e6de7 Mon Sep 17 00:00:00 2001 From: David Volovskiy Date: Sat, 24 May 2025 10:33:25 -0400 Subject: [PATCH 19/22] Fixed up info width overwrite; settings default funciton added --- apps/daisy/app.js | 10 +++---- apps/daisy/settings.js | 60 +++++++++++++++++++++--------------------- 2 files changed, 35 insertions(+), 35 deletions(-) diff --git a/apps/daisy/app.js b/apps/daisy/app.js index fc65ec7e2..8cf105d34 100644 --- a/apps/daisy/app.js +++ b/apps/daisy/app.js @@ -24,8 +24,8 @@ var pals = Array(3).fill().map(() => ( let palbg; const infoLineDefault = (3*h/4) - 6; -const infoWidthDefault = 56; -const infoHeightDefault = 11; +const infoWidthDefault = 64; +const infoHeightDefault = 8; const ringEdge = 4; const ringIterOffset = 10; const ringThick = 6; @@ -359,13 +359,13 @@ function getInfoDims() { var height = infoHeightDefault; switch (innerMostRing) { case 2: - width -= 8; + width -= 10; height -= 2; line -= 7; break; case 3: - width -= 9; - height -= 6; + width -= 17; + height -= 3; line -= 10; break; } diff --git a/apps/daisy/settings.js b/apps/daisy/settings.js index 1fe60dda0..52ba83d99 100644 --- a/apps/daisy/settings.js +++ b/apps/daisy/settings.js @@ -1,43 +1,43 @@ (function(back) { const SETTINGS_FILE = "daisy.json"; - // default settings - let s = { - rings: [{}, {}, {}], + function getDefaultSettings() { + return { + rings: [ + { + color: 'Green', + fg: '#0f0', + gy: '#020', + ring: 'Steps', + type: 'Full', + step_target: 10000, + }, + { + color: 'Blk/Wht', + fg: null, + gy: null, + ring: 'Minutes', + type: 'None', + step_target: 10000, + }, + { + color: 'Green', + fg: '#0f0', + gy: '#020', + ring: 'Hours', + type: 'None', + step_target: 10000, + } + ], color: 'Outer', 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, - }; - - s.rings[1] = { - color: 'Blk/Wht', - fg: null, - gy: null, - ring: 'Minutes', - type: 'None', - step_target: 10000, - }; - - s.rings[2] = { - color: 'Green', - fg: '#0f0', - gy: '#020', - ring: 'Hours', - type: 'None', - step_target: 10000, - }; - +let s = getDefaultSettings(); // ...and overwrite them with any saved values // This way saved values are preserved if a new version adds more settings const storage = require('Storage'); From 69cc8ea73ebcbc06fe0d7a35e9ff8165ccc74b48 Mon Sep 17 00:00:00 2001 From: David Volovskiy Date: Sat, 24 May 2025 11:08:02 -0400 Subject: [PATCH 20/22] Linter fixes --- apps/daisy/app.js | 4 ++-- apps/daisy/settings.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/daisy/app.js b/apps/daisy/app.js index 8cf105d34..79dcaaa95 100644 --- a/apps/daisy/app.js +++ b/apps/daisy/app.js @@ -514,7 +514,7 @@ function drawAllRings(date, drawOnlyThisType) { let ring = settings.rings[i]; if (ring.type == "None") continue; if (drawOnlyThisType != null && ring.ring != drawOnlyThisType) continue; - result = getGaugeImage(date, ring.ring, ring.step_target); + var result = getGaugeImage(date, ring.ring, ring.step_target); drawIfChanged(result[0], result[1], result[2], i, ring.type); } } @@ -816,7 +816,7 @@ Bangle.on('step', s => { warned = 0; if (drawingSteps) return; var steps = getSteps(); - ret = checkRedrawSteps(steps); + var ret = checkRedrawSteps(steps); if (!ret[0] && !ret[1]) return; drawingSteps = true; if (ret[0]) drawSteps(); diff --git a/apps/daisy/settings.js b/apps/daisy/settings.js index 52ba83d99..e2234e8c1 100644 --- a/apps/daisy/settings.js +++ b/apps/daisy/settings.js @@ -115,7 +115,7 @@ function save() { save(); }, }; - }; + } } E.showMenu(ringMenu); } From 83c829781b778b2c015c9a709f95377abc7d79a0 Mon Sep 17 00:00:00 2001 From: David Volovskiy Date: Sun, 1 Jun 2025 19:27:24 -0400 Subject: [PATCH 21/22] Added fullest color to ring setting --- apps/daisy/app.js | 19 +++++++++++++++++++ apps/daisy/settings.js | 2 +- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/apps/daisy/app.js b/apps/daisy/app.js index 79dcaaa95..47c72ab2b 100644 --- a/apps/daisy/app.js +++ b/apps/daisy/app.js @@ -538,6 +538,8 @@ function drawClock() { drawAllRings(date, null); setLargeFont(); + if (settings.color == 'Fullest') + settings.fg = settings.rings[getFullestRing()].fg; g.setColor(settings.fg); g.setFontAlign(1,0); // right aligned g.drawString(hh, (w/2) - 1, h/2); @@ -917,6 +919,7 @@ function queueDraw() { } function getInnerOuterMostRing() { + // Outputs 1 through 3 let innerMost = 0; let outerMost = 0; for (let i = 0; i < settings.rings.length; i++) { @@ -935,6 +938,22 @@ function getInnerOuterMostRing() { outerMostRing = outerMost; } +function getFullestRing() { + // Outputs 0 through 2 + let largestPercent = 0; + let fullestRing = 0; + for (let i = 0; i < settings.rings.length; i++) { + if (settings.rings[i].type !== "None") { + let percent = (prevRing[i].end - prevRing[i].start) / prevRing[i].max; + if (largestPercent < percent) { + largestPercent = percent; + fullestRing = i; + } + } + } + return fullestRing; +} + // Stop updates when LCD is off, restart when on Bangle.on('lcdPower',on=>{ if (on) { diff --git a/apps/daisy/settings.js b/apps/daisy/settings.js index e2234e8c1..6a829be2f 100644 --- a/apps/daisy/settings.js +++ b/apps/daisy/settings.js @@ -58,7 +58,7 @@ function save() { 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]; - var color_options_font = ['Outer', 'Inner'].concat(color_options); + var color_options_font = ['Outer', 'Inner', 'Fullest'].concat(color_options); var fg_code_font = [null, null].concat(color_options); function showRingMenu(ringIndex) { From 090cb2197c299672fd605a97dcff8b68026bd63b Mon Sep 17 00:00:00 2001 From: David Volovskiy Date: Tue, 3 Jun 2025 08:35:17 -0400 Subject: [PATCH 22/22] Fullest ring now updates on seconds --- apps/daisy/app.js | 35 ++++++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/apps/daisy/app.js b/apps/daisy/app.js index 47c72ab2b..d3e21ecc7 100644 --- a/apps/daisy/app.js +++ b/apps/daisy/app.js @@ -420,11 +420,34 @@ function drawHrm() { g.drawString(hrmCurrent, (w/2) + 10, line); } +function drawHour(date) { + // Run setLargeFont before running this function + var hh = date.getHours(); + if (settings.hr_12) { + hh = hh % 12; + if (hh == 0) hh = 12; + } + hh = hh.toString().padStart(2, '0'); + if (settings.color == 'Fullest') { + settings.fg = settings.rings[getFullestRing()].fg; + } + g.setColor(settings.fg); + g.setFontAlign(1,0); // right aligned + g.drawString(hh, (w/2) - 1, h/2); +} + function draw(updateSeconds) { if (!idle) { if (updateSeconds) { let date = new Date(); drawAllRings(date, 'Seconds'); + if (settings.color == 'Fullest') { + let fgNew = settings.rings[getFullestRing()].fg; + if (settings.fg != fgNew) { + setLargeFont(); + drawHour(date); + } + } } else { drawClock(); @@ -521,13 +544,7 @@ function drawAllRings(date, drawOnlyThisType) { function drawClock() { var date = new Date(); - var hh = date.getHours(); var mm = date.getMinutes(); - if (settings.hr_12) { - hh = hh % 12; - if (hh == 0) hh = 12; - } - hh = hh.toString().padStart(2, '0'); mm = mm.toString().padStart(2, '0'); g.reset(); @@ -538,11 +555,7 @@ function drawClock() { drawAllRings(date, null); setLargeFont(); - if (settings.color == 'Fullest') - settings.fg = settings.rings[getFullestRing()].fg; - g.setColor(settings.fg); - g.setFontAlign(1,0); // right aligned - g.drawString(hh, (w/2) - 1, h/2); + drawHour(date); g.setColor(g.theme.fg); g.setFontAlign(-1,0); // left aligned