From 069e0c13a918273f6c35e295cf3688734d75a615 Mon Sep 17 00:00:00 2001 From: Gabriele Monaco Date: Thu, 26 May 2022 15:29:38 +0200 Subject: [PATCH 01/15] android: added calendar sync events --- apps/android/boot.js | 15 +++++++++++++++ apps/android/metadata.json | 2 +- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/apps/android/boot.js b/apps/android/boot.js index efd7e7e46..829c1b4b0 100644 --- a/apps/android/boot.js +++ b/apps/android/boot.js @@ -90,6 +90,21 @@ sched.setAlarms(alarms); sched.reload(); }, + //TODO perhaps move those in a library (like messages), used also for viewing events? + "calendar" : function() { + var cal; + try { cal = require("Storage").readJSON("android.calendar.json"); } catch (e) {} + if (!cal) cal = {}; // first event + cal[event.id] = event; + require("Storage").writeJSON("android.calendar.json", cal); + }, + "calendar-" : function() { + var cal; + try { cal = require("Storage").readJSON("android.calendar.json"); } catch (e) {} + if (!cal) return; //nothing to remove + if (event.id in cal) delete cal[event.id]; + require("Storage").writeJSON("android.calendar.json", cal); + } }; var h = HANDLERS[event.t]; if (h) h(); else console.log("GB Unknown",event); diff --git a/apps/android/metadata.json b/apps/android/metadata.json index bf37b8407..c8e404aba 100644 --- a/apps/android/metadata.json +++ b/apps/android/metadata.json @@ -15,6 +15,6 @@ {"name":"android.img","url":"app-icon.js","evaluate":true}, {"name":"android.boot.js","url":"boot.js"} ], - "data": [{"name":"android.settings.json"}], + "data": [{"name":"android.settings.json"}, {"name":"android.calendar.json"}], "sortorder": -8 } From 8c42e81aea127cb2cb47c30ebd30a2764d857889 Mon Sep 17 00:00:00 2001 From: Gabriele Monaco Date: Thu, 26 May 2022 20:41:44 +0200 Subject: [PATCH 02/15] Added basic agenda --- apps/agenda/ChangeLog | 1 + apps/agenda/README.md | 3 + apps/agenda/agenda-icon.js | 1 + apps/agenda/agenda.js | 102 ++++++++++++++++++++++++++++++ apps/agenda/agenda.png | Bin 0 -> 7227 bytes apps/agenda/metadata.json | 16 +++++ apps/agenda/screenshot_agenda.png | Bin 0 -> 2584 bytes 7 files changed, 123 insertions(+) create mode 100644 apps/agenda/ChangeLog create mode 100644 apps/agenda/README.md create mode 100644 apps/agenda/agenda-icon.js create mode 100644 apps/agenda/agenda.js create mode 100644 apps/agenda/agenda.png create mode 100644 apps/agenda/metadata.json create mode 100644 apps/agenda/screenshot_agenda.png diff --git a/apps/agenda/ChangeLog b/apps/agenda/ChangeLog new file mode 100644 index 000000000..56dfffa0d --- /dev/null +++ b/apps/agenda/ChangeLog @@ -0,0 +1 @@ +0.01: Basic agenda with events from GB diff --git a/apps/agenda/README.md b/apps/agenda/README.md new file mode 100644 index 000000000..5141673c0 --- /dev/null +++ b/apps/agenda/README.md @@ -0,0 +1,3 @@ +# Calendar + +Basic agenda reading the events synchronised from GadgetBridge diff --git a/apps/agenda/agenda-icon.js b/apps/agenda/agenda-icon.js new file mode 100644 index 000000000..ed6690033 --- /dev/null +++ b/apps/agenda/agenda-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwwcCpMkyQC3wAIFgIRJn8JAoeQ/gRYwB0Bn57F/gCBHAgfCn8EDgdI/kSAoIR8oBkFgAFCCIysKCPM//4AKZAgR3/0Aj+Ag/ggP4gF/CPpr/Nf5r/NfYRhw4RL8IRDyEAABUJCIYC/AVI=")) \ No newline at end of file diff --git a/apps/agenda/agenda.js b/apps/agenda/agenda.js new file mode 100644 index 000000000..c7260af07 --- /dev/null +++ b/apps/agenda/agenda.js @@ -0,0 +1,102 @@ +/* CALENDAR is a list of: + {id:int, + type, + timestamp, + durationInSeconds, + title, + description, + location, + allDay: bool, + } + the file on storage has the same content but is an object indexed by id +*/ + +var FILE = "android.calendar.json" + +var fontSmall = "6x8"; +var fontMedium = g.getFonts().includes("6x15")?"6x15":"6x8:2"; +var fontBig = g.getFonts().includes("12x20")?"12x20":"6x8:2"; +var fontLarge = g.getFonts().includes("6x15")?"6x15:2":"6x8:4"; + +//FIXME maybe write the end from GB already? Not durationInSeconds here (or do while receiving?) +var cal; +try { cal = require("Storage").readJSON("android.calendar.json"); } catch (e) {} +if (!cal) //cal = {}; // first event + cal = { //FIXME test + 1: {id: 1, title:"foo", timestamp: 1653577989371, durationInSeconds: 3000, location: "somewhere"}, + 2: {id: 2, title:"last", timestamp: 1653579989371, durationInSeconds: 3000, location: "somewhere"}, + 3: {id: 3, title:"bar", timestamp: 1653578989371, durationInSeconds: 3000, location: "somewhere"} + }; + +function formatDateLong(timestamp) { + return new Date(timestamp*1000).toString(); +} +function formatDateShort(timestamp) { + return new Date(timestamp*1000).toISOString(); +} + +function showEvent(ev) { + var bodyFont = fontBig; + g.setFont(bodyFont); + var lines = []; + if (ev.title) lines = g.wrapString(ev.title, g.getWidth()-10) + var titleCnt = lines.length; + if (titleCnt) lines.push(""); // add blank line after title + lines = lines.concat( + g.wrapString(formatDateLong(ev.timestamp)+"\n", g.getWidth()-10), + g.wrapString(formatDateLong((+ev.timestamp) + (+ev.durationInSeconds))+"\n", g.getWidth()-10), + g.wrapString(ev.location, g.getWidth()-10), + ["",/*LANG*/"< Back"]); + E.showScroller({ + h : g.getFontHeight(), // height of each menu item in pixels + c : lines.length, // number of menu items + // a function to draw a menu item + draw : function(idx, r) { + // FIXME: in 2v13 onwards, clearRect(r) will work fine. There's a bug in 2v12 + g.setBgColor(idx=lines.length-2) + showEvent(ev); + }, + back : () => showList() + }); +} + +CALENDAR=Object.keys(cal) + .sort((a,b)=>cal[a].timestamp - cal[b].timestamp) + .map(k=>cal[k]); //make it an array + +function showList() { + E.showScroller({ + h : 48, + c : Math.max(CALENDAR.length,3), // workaround for 2v10.219 firmware (min 3 not needed for 2v11) + draw : function(idx, r) {"ram" + var ev = CALENDAR[idx]; + g.setColor(g.theme.fg); + g.clearRect(r.x,r.y,r.x+r.w, r.y+r.h); + if (!ev) return; + var x = r.x+2, title = ev.title, body = formatDateShort(ev.timestamp)+ + "\n"+ev.location; + var m = ev.title+"\n"+ev.location, longBody=false; + if (title) g.setFontAlign(-1,-1).setFont(fontBig).drawString(title, x,r.y+2); + if (body) { + g.setFontAlign(-1,-1).setFont("6x8"); + var l = g.wrapString(body, r.w-(x+14)); + if (l.length>3) { + l = l.slice(0,3); + l[l.length-1]+="..."; + } + longBody = l.length>2; + g.drawString(l.join("\n"), x+10,r.y+20); + } + //if (!longBody && msg.src) g.setFontAlign(1,1).setFont("6x8").drawString(msg.src, r.x+r.w-2, r.y+r.h-2); + g.setColor("#888").fillRect(r.x,r.y+r.h-1,r.x+r.w-1,r.y+r.h-1); // dividing line between items + }, + select : idx => showEvent(CALENDAR[idx]), + back : () => load() + }); +} +showList(); diff --git a/apps/agenda/agenda.png b/apps/agenda/agenda.png new file mode 100644 index 0000000000000000000000000000000000000000..ccbcce5fff4e578b44d2e1ba87d21339e5dd19e0 GIT binary patch literal 7227 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 GhyMqGu%7Dx literal 0 HcmV?d00001 diff --git a/apps/agenda/metadata.json b/apps/agenda/metadata.json new file mode 100644 index 000000000..2c1bdfe9c --- /dev/null +++ b/apps/agenda/metadata.json @@ -0,0 +1,16 @@ +{ + "id": "agenda", + "name": "Agenda", + "version": "1.01", + "description": "Simple agenda", + "icon": "agenda.png", + "screenshots": [{"url":"screenshot_agenda.png"}], + "tags": "agenda", + "supports": ["BANGLEJS","BANGLEJS2"], + "readme": "README.md", + "allow_emulator": true, + "storage": [ + {"name":"agenda.app.js","url":"agenda.js"}, + {"name":"agenda.img","url":"agenda-icon.js","evaluate":true} + ] +} diff --git a/apps/agenda/screenshot_agenda.png b/apps/agenda/screenshot_agenda.png new file mode 100644 index 0000000000000000000000000000000000000000..7ef5986d4e63537cdaed0a9daa474c3e633a485b GIT binary patch literal 2584 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 Date: Sat, 28 May 2022 19:43:32 +0200 Subject: [PATCH 03/15] Fixed layout in agenda --- apps/agenda/agenda.js | 62 ++++++++++++++++++++++++++++----------- apps/agenda/metadata.json | 2 +- 2 files changed, 46 insertions(+), 18 deletions(-) diff --git a/apps/agenda/agenda.js b/apps/agenda/agenda.js index c7260af07..6bb757629 100644 --- a/apps/agenda/agenda.js +++ b/apps/agenda/agenda.js @@ -11,7 +11,12 @@ the file on storage has the same content but is an object indexed by id */ -var FILE = "android.calendar.json" +Bangle.loadWidgets(); +Bangle.drawWidgets(); + +var FILE = "android.calendar.json"; + +var Locale = require("locale"); var fontSmall = "6x8"; var fontMedium = g.getFonts().includes("6x15")?"6x15":"6x8:2"; @@ -23,30 +28,53 @@ var cal; try { cal = require("Storage").readJSON("android.calendar.json"); } catch (e) {} if (!cal) //cal = {}; // first event cal = { //FIXME test - 1: {id: 1, title:"foo", timestamp: 1653577989371, durationInSeconds: 3000, location: "somewhere"}, + 1: {id: 1, title:"foo", timestamp: 1653577989371, durationInSeconds: 3000, location: "somewhere", description: "something very very long"}, 2: {id: 2, title:"last", timestamp: 1653579989371, durationInSeconds: 3000, location: "somewhere"}, 3: {id: 3, title:"bar", timestamp: 1653578989371, durationInSeconds: 3000, location: "somewhere"} }; -function formatDateLong(timestamp) { - return new Date(timestamp*1000).toString(); +function getDate(timestamp) { + return new Date(timestamp*1000); } -function formatDateShort(timestamp) { - return new Date(timestamp*1000).toISOString(); +function formatDateLong(date, includeDay) { + if(includeDay) + return Locale.date(date)+" "+Locale.time(date,1); + return Locale.time(date,1); +} +function formatDateShort(date) { + return Locale.date(date).replace(/\d\d\d\d/,"")+Locale.time(date,1); } +var lines = []; function showEvent(ev) { var bodyFont = fontBig; g.setFont(bodyFont); - var lines = []; + //var lines = []; if (ev.title) lines = g.wrapString(ev.title, g.getWidth()-10) var titleCnt = lines.length; + var start = getDate(ev.timestamp); + var end = getDate((+ev.timestamp) + (+ev.durationInSeconds)); + var includeDay = true; if (titleCnt) lines.push(""); // add blank line after title - lines = lines.concat( - g.wrapString(formatDateLong(ev.timestamp)+"\n", g.getWidth()-10), - g.wrapString(formatDateLong((+ev.timestamp) + (+ev.durationInSeconds))+"\n", g.getWidth()-10), - g.wrapString(ev.location, g.getWidth()-10), - ["",/*LANG*/"< Back"]); + if(start.getDay() == end.getDay() && start.getMonth() == end.getMonth()) + includeDay = false; + if(includeDay) { + lines = lines.concat( + /*LANG*/"Start:", + g.wrapString(formatDateLong(start, includeDay), g.getWidth()-10), + /*LANG*/"End:", + g.wrapString(formatDateLong(end, includeDay), g.getWidth()-10)); + } else { + lines = lines.concat( + g.wrapString(Locale.date(start), g.getWidth()-10), + g.wrapString(/*LANG*/"Start"+": "+formatDateLong(start, includeDay), g.getWidth()-10), + g.wrapString(/*LANG*/"End"+": "+formatDateLong(end, includeDay), g.getWidth()-10)); + } + if(ev.location) + lines = lines.concat(/*LANG*/"Location"+": ", g.wrapString(ev.location, g.getWidth()-10)); + if(ev.description) + lines = lines.concat("",g.wrapString(ev.description, g.getWidth()-10)); + lines = lines.concat(["",/*LANG*/"< Back"]); E.showScroller({ h : g.getFontHeight(), // height of each menu item in pixels c : lines.length, // number of menu items @@ -59,7 +87,7 @@ function showEvent(ev) { g.setFont(bodyFont).drawString(lines[idx], r.x, r.y); }, select : function(idx) { if (idx>=lines.length-2) - showEvent(ev); + showList(); }, back : () => showList() }); @@ -71,19 +99,19 @@ CALENDAR=Object.keys(cal) function showList() { E.showScroller({ - h : 48, + h : 52, c : Math.max(CALENDAR.length,3), // workaround for 2v10.219 firmware (min 3 not needed for 2v11) draw : function(idx, r) {"ram" var ev = CALENDAR[idx]; g.setColor(g.theme.fg); g.clearRect(r.x,r.y,r.x+r.w, r.y+r.h); if (!ev) return; - var x = r.x+2, title = ev.title, body = formatDateShort(ev.timestamp)+ - "\n"+ev.location; + var x = r.x+2, title = ev.title; + var body = formatDateShort(getDate(ev.timestamp))+"\n"+ev.location; var m = ev.title+"\n"+ev.location, longBody=false; if (title) g.setFontAlign(-1,-1).setFont(fontBig).drawString(title, x,r.y+2); if (body) { - g.setFontAlign(-1,-1).setFont("6x8"); + g.setFontAlign(-1,-1).setFont(fontMedium); var l = g.wrapString(body, r.w-(x+14)); if (l.length>3) { l = l.slice(0,3); diff --git a/apps/agenda/metadata.json b/apps/agenda/metadata.json index 2c1bdfe9c..6895bbc7c 100644 --- a/apps/agenda/metadata.json +++ b/apps/agenda/metadata.json @@ -1,7 +1,7 @@ { "id": "agenda", "name": "Agenda", - "version": "1.01", + "version": "3.01", "description": "Simple agenda", "icon": "agenda.png", "screenshots": [{"url":"screenshot_agenda.png"}], From 5fee259dd0dae2e8fe5e6bdf255debe68f229493 Mon Sep 17 00:00:00 2001 From: Gabriele Monaco Date: Mon, 30 May 2022 20:44:28 +0200 Subject: [PATCH 04/15] Changed calendar format to array and graying out old events --- apps/agenda/README.md | 2 +- apps/agenda/agenda-icon.js | 2 +- apps/agenda/agenda.js | 89 ++++++++++++++++++------------------- apps/agenda/agenda.png | Bin 7227 -> 3119 bytes apps/agenda/metadata.json | 2 +- apps/android/boot.js | 12 ++--- 6 files changed, 50 insertions(+), 57 deletions(-) diff --git a/apps/agenda/README.md b/apps/agenda/README.md index 5141673c0..a546e0a89 100644 --- a/apps/agenda/README.md +++ b/apps/agenda/README.md @@ -1,3 +1,3 @@ -# Calendar +# Agenda Basic agenda reading the events synchronised from GadgetBridge diff --git a/apps/agenda/agenda-icon.js b/apps/agenda/agenda-icon.js index ed6690033..891543955 100644 --- a/apps/agenda/agenda-icon.js +++ b/apps/agenda/agenda-icon.js @@ -1 +1 @@ -require("heatshrink").decompress(atob("mEwwcCpMkyQC3wAIFgIRJn8JAoeQ/gRYwB0Bn57F/gCBHAgfCn8EDgdI/kSAoIR8oBkFgAFCCIysKCPM//4AKZAgR3/0Aj+Ag/ggP4gF/CPpr/Nf5r/NfYRhw4RL8IRDyEAABUJCIYC/AVI=")) \ No newline at end of file +require("heatshrink").decompress(atob("mEwwg1yhGIxAPMBwIPFhH//GAC5n/C4oHBC5/IGwoXBHQQAKC4OIFAWOxHv9GO9wAKI4XoC4foEIIWLC4IABC4gIBFxnuE4IqBC4gARC4ZzNAAwXaxe7ACO4C625C4m4xIJBzAeCxGbCAOIFgQOBC4pOBxe4AYIPBAYQKCAYYXE3GL/ADBx/oxb3BC4X+xG4xwOBC4uP/YDB54MBf4Po3eM/4XBx/+C4pTBGIIkBLgOYAYIvB9GJBwI6BL45zCL4aCCL4h3GU64ALdYS1CI55bBAAgXFO4mMO4QDBDIO/////YxBU53IxIVB/GfDAWYa5wtC/GPAYWIL4wXBL4oSBC4jcBC4m4QIWYSwWIIQIAG/CnMMAIAC/JLCMIIvMIwZHFJAJfLC5yPHAYIRDAoy/KCIi7BMon4d4+Od4IXBxAZBEQLtB/+YxIXDL4SLCL4WPzAXCNgRFBLIKnKLIrcEI4gXNAAp3CxGZAAzCBC5KnCKAIAICxBlBC4IAJxG/C4/4wAXLhBgD/IcD3AXMGAIqDDgRGNGAoXDFxxhEI4W4FxwwCaoYWBFx4YDAAQWRAEQ")) diff --git a/apps/agenda/agenda.js b/apps/agenda/agenda.js index 6bb757629..f39e31c75 100644 --- a/apps/agenda/agenda.js +++ b/apps/agenda/agenda.js @@ -8,7 +8,6 @@ location, allDay: bool, } - the file on storage has the same content but is an object indexed by id */ Bangle.loadWidgets(); @@ -24,30 +23,26 @@ var fontBig = g.getFonts().includes("12x20")?"12x20":"6x8:2"; var fontLarge = g.getFonts().includes("6x15")?"6x15:2":"6x8:4"; //FIXME maybe write the end from GB already? Not durationInSeconds here (or do while receiving?) -var cal; -try { cal = require("Storage").readJSON("android.calendar.json"); } catch (e) {} -if (!cal) //cal = {}; // first event - cal = { //FIXME test - 1: {id: 1, title:"foo", timestamp: 1653577989371, durationInSeconds: 3000, location: "somewhere", description: "something very very long"}, - 2: {id: 2, title:"last", timestamp: 1653579989371, durationInSeconds: 3000, location: "somewhere"}, - 3: {id: 3, title:"bar", timestamp: 1653578989371, durationInSeconds: 3000, location: "somewhere"} - }; +var CALENDAR = require("Storage").readJSON("android.calendar.json",true)||[]; + +CALENDAR=CALENDAR.sort((a,b)=>a.timestamp - b.timestamp) function getDate(timestamp) { - return new Date(timestamp*1000); + return new Date(timestamp*1000); } function formatDateLong(date, includeDay) { - if(includeDay) - return Locale.date(date)+" "+Locale.time(date,1); - return Locale.time(date,1); + if(includeDay) + return Locale.date(date)+" "+Locale.time(date,1); + return Locale.time(date,1); } function formatDateShort(date) { - return Locale.date(date).replace(/\d\d\d\d/,"")+Locale.time(date,1); + return Locale.date(date).replace(/\d\d\d\d/,"")+Locale.time(date,1); } var lines = []; function showEvent(ev) { var bodyFont = fontBig; + if(!ev) return; g.setFont(bodyFont); //var lines = []; if (ev.title) lines = g.wrapString(ev.title, g.getWidth()-10) @@ -93,38 +88,40 @@ function showEvent(ev) { }); } -CALENDAR=Object.keys(cal) - .sort((a,b)=>cal[a].timestamp - cal[b].timestamp) - .map(k=>cal[k]); //make it an array - function showList() { - E.showScroller({ - h : 52, - c : Math.max(CALENDAR.length,3), // workaround for 2v10.219 firmware (min 3 not needed for 2v11) - draw : function(idx, r) {"ram" - var ev = CALENDAR[idx]; - g.setColor(g.theme.fg); - g.clearRect(r.x,r.y,r.x+r.w, r.y+r.h); - if (!ev) return; - var x = r.x+2, title = ev.title; - var body = formatDateShort(getDate(ev.timestamp))+"\n"+ev.location; - var m = ev.title+"\n"+ev.location, longBody=false; - if (title) g.setFontAlign(-1,-1).setFont(fontBig).drawString(title, x,r.y+2); - if (body) { - g.setFontAlign(-1,-1).setFont(fontMedium); - var l = g.wrapString(body, r.w-(x+14)); - if (l.length>3) { - l = l.slice(0,3); - l[l.length-1]+="..."; - } - longBody = l.length>2; - g.drawString(l.join("\n"), x+10,r.y+20); - } - //if (!longBody && msg.src) g.setFontAlign(1,1).setFont("6x8").drawString(msg.src, r.x+r.w-2, r.y+r.h-2); - g.setColor("#888").fillRect(r.x,r.y+r.h-1,r.x+r.w-1,r.y+r.h-1); // dividing line between items - }, - select : idx => showEvent(CALENDAR[idx]), - back : () => load() - }); + if(CALENDAR.length == 0) { + E.showMessage("No events"); + return; + } + E.showScroller({ + h : 52, + c : Math.max(CALENDAR.length,3), // workaround for 2v10.219 firmware (min 3 not needed for 2v11) + draw : function(idx, r) {"ram" + var ev = CALENDAR[idx]; + g.setColor(g.theme.fg); + g.clearRect(r.x,r.y,r.x+r.w, r.y+r.h); + if (!ev) return; + var isPast = ev.timestamp + ev.durationInSeconds < (new Date())/1000; + var x = r.x+2, title = ev.title; + var body = formatDateShort(getDate(ev.timestamp))+"\n"+ev.location; + var m = ev.title+"\n"+ev.location, longBody=false; + if (title) g.setFontAlign(-1,-1).setFont(fontBig) + .setColor(isPast ? "#888" : g.theme.fg).drawString(title, x,r.y+2); + if (body) { + g.setFontAlign(-1,-1).setFont(fontMedium).setColor(isPast ? "#888" : g.theme.fg); + var l = g.wrapString(body, r.w-(x+14)); + if (l.length>3) { + l = l.slice(0,3); + l[l.length-1]+="..."; + } + longBody = l.length>2; + g.drawString(l.join("\n"), x+10,r.y+20); + } + //if (!longBody && msg.src) g.setFontAlign(1,1).setFont("6x8").drawString(msg.src, r.x+r.w-2, r.y+r.h-2); + g.setColor("#888").fillRect(r.x,r.y+r.h-1,r.x+r.w-1,r.y+r.h-1); // dividing line between items + }, + select : idx => showEvent(CALENDAR[idx]), + back : () => load() + }); } showList(); diff --git a/apps/agenda/agenda.png b/apps/agenda/agenda.png index ccbcce5fff4e578b44d2e1ba87d21339e5dd19e0..c850b0e5d1a3eb98b9c9cb68968ab554119fe23f 100644 GIT binary patch literal 3119 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 GhyMqGu%7Dx diff --git a/apps/agenda/metadata.json b/apps/agenda/metadata.json index 6895bbc7c..0a9f6e44f 100644 --- a/apps/agenda/metadata.json +++ b/apps/agenda/metadata.json @@ -1,7 +1,7 @@ { "id": "agenda", "name": "Agenda", - "version": "3.01", + "version": "2.01", "description": "Simple agenda", "icon": "agenda.png", "screenshots": [{"url":"screenshot_agenda.png"}], diff --git a/apps/android/boot.js b/apps/android/boot.js index 829c1b4b0..df21a5521 100644 --- a/apps/android/boot.js +++ b/apps/android/boot.js @@ -92,17 +92,13 @@ }, //TODO perhaps move those in a library (like messages), used also for viewing events? "calendar" : function() { - var cal; - try { cal = require("Storage").readJSON("android.calendar.json"); } catch (e) {} - if (!cal) cal = {}; // first event - cal[event.id] = event; + var cal = require("Storage").readJSON("android.calendar.json",true)||[]; + cal.push(event); require("Storage").writeJSON("android.calendar.json", cal); }, "calendar-" : function() { - var cal; - try { cal = require("Storage").readJSON("android.calendar.json"); } catch (e) {} - if (!cal) return; //nothing to remove - if (event.id in cal) delete cal[event.id]; + var cal = require("Storage").readJSON("android.calendar.json",true)||return; + cal = cal.filter(e=>e.id!=event.id); require("Storage").writeJSON("android.calendar.json", cal); } }; From a50f53b15aa21d1de3dd0ffd3709b18d61056ea5 Mon Sep 17 00:00:00 2001 From: Gabriele Monaco Date: Mon, 30 May 2022 21:36:07 +0200 Subject: [PATCH 05/15] Added screenshots and correct version number --- apps/agenda/metadata.json | 4 ++-- apps/agenda/screenshot_agenda.png | Bin 2584 -> 0 bytes apps/agenda/screenshot_agenda_event1.png | Bin 0 -> 3588 bytes apps/agenda/screenshot_agenda_event2.png | Bin 0 -> 3386 bytes apps/agenda/screenshot_agenda_overview.png | Bin 0 -> 3785 bytes apps/android/boot.js | 7 +++++-- apps/android/metadata.json | 2 +- 7 files changed, 8 insertions(+), 5 deletions(-) delete mode 100644 apps/agenda/screenshot_agenda.png create mode 100644 apps/agenda/screenshot_agenda_event1.png create mode 100644 apps/agenda/screenshot_agenda_event2.png create mode 100644 apps/agenda/screenshot_agenda_overview.png diff --git a/apps/agenda/metadata.json b/apps/agenda/metadata.json index 0a9f6e44f..0b8ffaded 100644 --- a/apps/agenda/metadata.json +++ b/apps/agenda/metadata.json @@ -1,10 +1,10 @@ { "id": "agenda", "name": "Agenda", - "version": "2.01", + "version": "0.01", "description": "Simple agenda", "icon": "agenda.png", - "screenshots": [{"url":"screenshot_agenda.png"}], + "screenshots": [{"url":"screenshot_agenda_overview.png"}, {"url":"screenshot_agenda_event1.png"}, {"url":"screenshot_agenda_event2.png"}], "tags": "agenda", "supports": ["BANGLEJS","BANGLEJS2"], "readme": "README.md", diff --git a/apps/agenda/screenshot_agenda.png b/apps/agenda/screenshot_agenda.png deleted file mode 100644 index 7ef5986d4e63537cdaed0a9daa474c3e633a485b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2584 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 literal 0 HcmV?d00001 diff --git a/apps/agenda/screenshot_agenda_event2.png b/apps/agenda/screenshot_agenda_event2.png new file mode 100644 index 0000000000000000000000000000000000000000..f5edcaae8e25eaa8c014ef7a77127dd91c8a7120 GIT binary patch literal 3386 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 literal 0 HcmV?d00001 diff --git a/apps/android/boot.js b/apps/android/boot.js index df21a5521..0c7dd04b5 100644 --- a/apps/android/boot.js +++ b/apps/android/boot.js @@ -92,12 +92,15 @@ }, //TODO perhaps move those in a library (like messages), used also for viewing events? "calendar" : function() { - var cal = require("Storage").readJSON("android.calendar.json",true)||[]; + var cal = require("Storage").readJSON("android.calendar.json",true); + if (!cal || !Array.isArray(cal)) cal = []; cal.push(event); require("Storage").writeJSON("android.calendar.json", cal); }, "calendar-" : function() { - var cal = require("Storage").readJSON("android.calendar.json",true)||return; + var cal = require("Storage").readJSON("android.calendar.json",true); + //if any of those happen we are out of sync! + if (!cal || !Array.isArray(cal)) return; cal = cal.filter(e=>e.id!=event.id); require("Storage").writeJSON("android.calendar.json", cal); } diff --git a/apps/android/metadata.json b/apps/android/metadata.json index c8e404aba..27b77cf2f 100644 --- a/apps/android/metadata.json +++ b/apps/android/metadata.json @@ -2,7 +2,7 @@ "id": "android", "name": "Android Integration", "shortName": "Android", - "version": "0.10", + "version": "0.11", "description": "Display notifications/music/etc sent from the Gadgetbridge app on Android. This replaces the old 'Gadgetbridge' Bangle.js widget.", "icon": "app.png", "tags": "tool,system,messages,notifications,gadgetbridge", From e057270d01e419c5c92efa35b061afc710d5b254 Mon Sep 17 00:00:00 2001 From: Gabriele Monaco Date: Wed, 1 Jun 2022 17:39:09 +0200 Subject: [PATCH 06/15] Added settings page to force calendar sync --- apps/agenda/metadata.json | 3 ++- apps/agenda/settings.js | 36 ++++++++++++++++++++++++++++++++++++ apps/android/boot.js | 6 +++++- apps/android/metadata.json | 2 +- 4 files changed, 44 insertions(+), 3 deletions(-) create mode 100644 apps/agenda/settings.js diff --git a/apps/agenda/metadata.json b/apps/agenda/metadata.json index 0b8ffaded..ce8438686 100644 --- a/apps/agenda/metadata.json +++ b/apps/agenda/metadata.json @@ -1,7 +1,7 @@ { "id": "agenda", "name": "Agenda", - "version": "0.01", + "version": "0.02", "description": "Simple agenda", "icon": "agenda.png", "screenshots": [{"url":"screenshot_agenda_overview.png"}, {"url":"screenshot_agenda_event1.png"}, {"url":"screenshot_agenda_event2.png"}], @@ -11,6 +11,7 @@ "allow_emulator": true, "storage": [ {"name":"agenda.app.js","url":"agenda.js"}, + {"name":"agenda.settings.js","url":"settings.js"}, {"name":"agenda.img","url":"agenda-icon.js","evaluate":true} ] } diff --git a/apps/agenda/settings.js b/apps/agenda/settings.js new file mode 100644 index 000000000..7edb013b9 --- /dev/null +++ b/apps/agenda/settings.js @@ -0,0 +1,36 @@ +(function(back) { + function gbSend(message) { + Bluetooth.println(""); + Bluetooth.println(JSON.stringify(message)); + } + var CALENDAR = require("Storage").readJSON("android.calendar.json",true)||[]; + var mainmenu = { + "" : { "title" : "Agenda" }, + "< Back" : back, + /*LANG*/"Connected" : { value : NRF.getSecurityStatus().connected?/*LANG*/"Yes":/*LANG*/"No" }, + /*LANG*/"Force calendar sync" : () => { + if(NRF.getSecurityStatus().connected) { + E.showPrompt(/*LANG*/"Do you want to also clear the internal database first?", { + buttons: {/*LANG*/"Yes": 1, /*LANG*/"No": 2, /*LANG*/"Cancel": 3} + }).then((v)=>{ + switch(v) { + case 1: + require("Storage").writeJSON("android.calendar.json",[]); + CALENDAR = []; + case 2: + gbSend({t:"force_calendar_sync", ids: CALENDAR.map(e=>e.id)}); + E.showAlert(/*LANG*/"Request sent to the phone").then(()=>E.showMenu(mainmenu)); + break; + case 3: + default: + E.showMenu(mainmenu); + return; + } + }); + } else { + E.showAlert(/*LANG*/"You are not connected").then(()=>E.showMenu(mainmenu)); + } + }, + }; + E.showMenu(mainmenu); +}) diff --git a/apps/android/boot.js b/apps/android/boot.js index 0c7dd04b5..72c5bc386 100644 --- a/apps/android/boot.js +++ b/apps/android/boot.js @@ -94,7 +94,11 @@ "calendar" : function() { var cal = require("Storage").readJSON("android.calendar.json",true); if (!cal || !Array.isArray(cal)) cal = []; - cal.push(event); + var i = cal.findIndex(e=>e.id==event.id); + if(i<0) + cal.push(event); + else + cal[i] = event; require("Storage").writeJSON("android.calendar.json", cal); }, "calendar-" : function() { diff --git a/apps/android/metadata.json b/apps/android/metadata.json index 27b77cf2f..6458087e8 100644 --- a/apps/android/metadata.json +++ b/apps/android/metadata.json @@ -2,7 +2,7 @@ "id": "android", "name": "Android Integration", "shortName": "Android", - "version": "0.11", + "version": "4.01", "description": "Display notifications/music/etc sent from the Gadgetbridge app on Android. This replaces the old 'Gadgetbridge' Bangle.js widget.", "icon": "app.png", "tags": "tool,system,messages,notifications,gadgetbridge", From 9e4d58d2151795b83ee09effd10f2cad6eded415 Mon Sep 17 00:00:00 2001 From: Gabriele Monaco Date: Fri, 3 Jun 2022 08:44:13 +0200 Subject: [PATCH 07/15] Added simpler calendar management (all in single packet) --- apps/android/boot.js | 5 +++++ apps/android/metadata.json | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/apps/android/boot.js b/apps/android/boot.js index 72c5bc386..191db3838 100644 --- a/apps/android/boot.js +++ b/apps/android/boot.js @@ -91,6 +91,11 @@ sched.reload(); }, //TODO perhaps move those in a library (like messages), used also for viewing events? + //simple package with events all together + "calendarevents" : function() { + require("Storage").writeJSON("android.calendar.json", event.events); + }, + //add and remove events based on activity on phone (pebble-like) "calendar" : function() { var cal = require("Storage").readJSON("android.calendar.json",true); if (!cal || !Array.isArray(cal)) cal = []; diff --git a/apps/android/metadata.json b/apps/android/metadata.json index 6458087e8..7e4b275c5 100644 --- a/apps/android/metadata.json +++ b/apps/android/metadata.json @@ -2,7 +2,7 @@ "id": "android", "name": "Android Integration", "shortName": "Android", - "version": "4.01", + "version": "4.02", "description": "Display notifications/music/etc sent from the Gadgetbridge app on Android. This replaces the old 'Gadgetbridge' Bangle.js widget.", "icon": "app.png", "tags": "tool,system,messages,notifications,gadgetbridge", From 064b9996e7e2bd01d7fdff608bb4ff30754ae9cc Mon Sep 17 00:00:00 2001 From: Gabriele Monaco Date: Sun, 5 Jun 2022 18:55:26 +0200 Subject: [PATCH 08/15] Added periodic call to forceCalendarSync --- apps/agenda/settings.js | 1 + apps/android/boot.js | 11 +++++++++++ apps/android/metadata.json | 2 +- 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/apps/agenda/settings.js b/apps/agenda/settings.js index 7edb013b9..fe9dab2d8 100644 --- a/apps/agenda/settings.js +++ b/apps/agenda/settings.js @@ -17,6 +17,7 @@ case 1: require("Storage").writeJSON("android.calendar.json",[]); CALENDAR = []; + /* falls through */ case 2: gbSend({t:"force_calendar_sync", ids: CALENDAR.map(e=>e.id)}); E.showAlert(/*LANG*/"Request sent to the phone").then(()=>E.showMenu(mainmenu)); diff --git a/apps/android/boot.js b/apps/android/boot.js index 191db3838..a548089cb 100644 --- a/apps/android/boot.js +++ b/apps/android/boot.js @@ -125,6 +125,17 @@ if (!settings.keep) NRF.on("disconnect", () => require("messages").clearAll()); // remove all messages on disconnect setInterval(sendBattery, 10*60*1000); + // Fix calendar every 2 days (can be done manually too) + function forceCalendarSync() { + if(NRF.getSecurityStatus().connected) { + var cal = require("Storage").readJSON("android.calendar.json",true); + if (!cal || !Array.isArray(cal)) cal = []; + gbSend({t:"force_calendar_sync", ids: cal.map(e=>e.id)}); + setTimeout(forceCalendarSync, 2*24*60*60*1000); + } else + NRF.once("connect", () => setTimeout(forceCalendarSync, 4000)); + } + setTimeout(forceCalendarSync, 2*24*60*60*1000); //schedule the first // Health tracking Bangle.on('health', health=>{ gbSend({ t: "act", stp: health.steps, hrm: health.bpm }); diff --git a/apps/android/metadata.json b/apps/android/metadata.json index 7e4b275c5..27b77cf2f 100644 --- a/apps/android/metadata.json +++ b/apps/android/metadata.json @@ -2,7 +2,7 @@ "id": "android", "name": "Android Integration", "shortName": "Android", - "version": "4.02", + "version": "0.11", "description": "Display notifications/music/etc sent from the Gadgetbridge app on Android. This replaces the old 'Gadgetbridge' Bangle.js widget.", "icon": "app.png", "tags": "tool,system,messages,notifications,gadgetbridge", From 685f3710f312f097976cf241344dc179a1546b5d Mon Sep 17 00:00:00 2001 From: Gabriele Monaco Date: Wed, 8 Jun 2022 17:45:39 +0200 Subject: [PATCH 09/15] Starting forceCalendarSync from Gadgetbridge --- apps/android/boot.js | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/apps/android/boot.js b/apps/android/boot.js index a548089cb..9cdc019a6 100644 --- a/apps/android/boot.js +++ b/apps/android/boot.js @@ -112,6 +112,12 @@ if (!cal || !Array.isArray(cal)) return; cal = cal.filter(e=>e.id!=event.id); require("Storage").writeJSON("android.calendar.json", cal); + }, + //triggered by GB, send all ids + "force_calendar_sync_start" : function() { + var cal = require("Storage").readJSON("android.calendar.json",true); + if (!cal || !Array.isArray(cal)) cal = []; + gbSend({t:"force_calendar_sync", ids: cal.map(e=>e.id)}); } }; var h = HANDLERS[event.t]; @@ -125,17 +131,6 @@ if (!settings.keep) NRF.on("disconnect", () => require("messages").clearAll()); // remove all messages on disconnect setInterval(sendBattery, 10*60*1000); - // Fix calendar every 2 days (can be done manually too) - function forceCalendarSync() { - if(NRF.getSecurityStatus().connected) { - var cal = require("Storage").readJSON("android.calendar.json",true); - if (!cal || !Array.isArray(cal)) cal = []; - gbSend({t:"force_calendar_sync", ids: cal.map(e=>e.id)}); - setTimeout(forceCalendarSync, 2*24*60*60*1000); - } else - NRF.once("connect", () => setTimeout(forceCalendarSync, 4000)); - } - setTimeout(forceCalendarSync, 2*24*60*60*1000); //schedule the first // Health tracking Bangle.on('health', health=>{ gbSend({ t: "act", stp: health.steps, hrm: health.bpm }); From b793e7d6e460fb8e1ff232208220a886779079c5 Mon Sep 17 00:00:00 2001 From: Alessandro Cocco Date: Wed, 8 Jun 2022 21:03:39 +0200 Subject: [PATCH 10/15] [Nifty-A Clock] Read settings file via ClockFace --- apps/ffcniftya/app.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/apps/ffcniftya/app.js b/apps/ffcniftya/app.js index 24d26622c..2c1a54f6e 100644 --- a/apps/ffcniftya/app.js +++ b/apps/ffcniftya/app.js @@ -33,8 +33,6 @@ const clock = new ClockFace({ this.scale = g.getWidth() / this.viewport.width; this.centerTimeScaleX = this.center.x + 32 * this.scale; this.centerDatesScaleX = this.center.x + 40 * this.scale; - - this.showWeekNum = Object.assign({ showWeekNum: true }, require("Storage").readJSON("ffcniftya.json", true))["showWeekNum"]; }, draw: function (date) { const hour = date.getHours() - (this.is12Hour && date.getHours() > 12 ? 12 : 0); @@ -55,6 +53,7 @@ const clock = new ClockFace({ if (this.showWeekNum) g.drawString(format(ISO8601_week_no(date)), this.centerDatesScaleX, this.center.y + 15 * this.scale); g.drawString(monthName, this.centerDatesScaleX, this.center.y + 48 * this.scale); g.drawString(dayName, this.centerDatesScaleX, this.center.y + 66 * this.scale); - } + }, + settingsFile: "ffcniftya.json" }); clock.start(); \ No newline at end of file From d9a0884c5a06ef5461d05f60377c9cef44b114cc Mon Sep 17 00:00:00 2001 From: Alessandro Cocco Date: Wed, 8 Jun 2022 22:50:19 +0200 Subject: [PATCH 11/15] [Nifty-B Clock] Use ClockFace library --- apps/ffcniftyb/app.js | 160 +++++++++++++++++------------------------- 1 file changed, 64 insertions(+), 96 deletions(-) diff --git a/apps/ffcniftyb/app.js b/apps/ffcniftyb/app.js index 65c74dbd7..540924fa5 100644 --- a/apps/ffcniftyb/app.js +++ b/apps/ffcniftyb/app.js @@ -1,20 +1,10 @@ -const is12Hour = Object.assign({ "12hour": false }, require("Storage").readJSON("setting.json", true))["12hour"]; -const color = Object.assign({ color: 63488 }, require("Storage").readJSON("ffcniftyb.json", true)).color; // Default to RED +var scale; +var screen; +var center; +var buf; +var img; -/* Clock *********************************************/ -const scale = g.getWidth() / 176; - -const screen = { - width: g.getWidth(), - height: g.getHeight() - 24, -}; - -const center = { - x: screen.width / 2, - y: screen.height / 2, -}; - -function d02(value) { +function format(value) { return ("0" + value).substr(-2); } @@ -22,91 +12,69 @@ function renderEllipse(g) { g.fillEllipse(center.x - 5 * scale, center.y - 70 * scale, center.x + 160 * scale, center.y + 90 * scale); } -function renderText(g) { - const now = new Date(); +function renderText(g, date) { + const hour = date.getHours() - (this.is12Hour && date.getHours() > 12 ? 12 : 0); + const month = date.getMonth() + 1; - const hour = d02(now.getHours() - (is12Hour && now.getHours() > 12 ? 12 : 0)); - const minutes = d02(now.getMinutes()); - const day = d02(now.getDate()); - const month = d02(now.getMonth() + 1); - const year = now.getFullYear(); - - const month2 = require("locale").month(now, 3); - const day2 = require("locale").dow(now, 3); + const monthName = require("date_utils").month(month, 1); + const dayName = require("date_utils").dow(date.getDay(), 1); g.setFontAlign(1, 0).setFont("Vector", 90 * scale); - g.drawString(hour, center.x + 32 * scale, center.y - 31 * scale); - g.drawString(minutes, center.x + 32 * scale, center.y + 46 * scale); + g.drawString(format(hour), center.x + 32 * scale, center.y - 31 * scale); + g.drawString(format(date.getMinutes()), center.x + 32 * scale, center.y + 46 * scale); g.setFontAlign(1, 0).setFont("Vector", 16 * scale); - g.drawString(year, center.x + 80 * scale, center.y - 42 * scale); - g.drawString(month, center.x + 80 * scale, center.y - 26 * scale); - g.drawString(day, center.x + 80 * scale, center.y - 10 * scale); - g.drawString(month2, center.x + 80 * scale, center.y + 44 * scale); - g.drawString(day2, center.x + 80 * scale, center.y + 60 * scale); + g.drawString(date.getFullYear(), center.x + 80 * scale, center.y - 42 * scale); + g.drawString(format(month), center.x + 80 * scale, center.y - 26 * scale); + g.drawString(format(date.getDate()), center.x + 80 * scale, center.y - 10 * scale); + g.drawString(monthName, center.x + 80 * scale, center.y + 44 * scale); + g.drawString(dayName, center.x + 80 * scale, center.y + 60 * scale); } -const buf = Graphics.createArrayBuffer(screen.width, screen.height, 1, { - msb: true +const ClockFace = require("ClockFace"); +const clock = new ClockFace({ + init: function () { + const appRect = Bangle.appRect; + + screen = { + width: appRect.w, + height: appRect.h + }; + + center = { + x: screen.width / 2, + y: screen.height / 2 + }; + + buf = Graphics.createArrayBuffer(screen.width, screen.height, 1, { msb: true }); + + scale = g.getWidth() / screen.width; + + img = { + width: screen.width, + height: screen.height, + transparent: 0, + bpp: 1, + buffer: buf.buffer + }; + + // default to RED (see settings.js) + // don't use || to default because 0 is a valid color + this.color = this.color === undefined ? 63488 : this.color; + }, + draw: function (date) { + // render outside text with ellipse + buf.clear(); + renderText(buf.setColor(1), date); + renderEllipse(buf.setColor(0)); + g.setColor(this.color).drawImage(img, 0, 24); + + // render ellipse with inside text + buf.clear(); + renderEllipse(buf.setColor(1)); + renderText(buf.setColor(0), date); + g.setColor(this.color).drawImage(img, 0, 24); + }, + settingsFile: "ffcniftyb.json" }); - -function draw() { - - const img = { - width: screen.width, - height: screen.height, - transparent: 0, - bpp: 1, - buffer: buf.buffer - }; - - // cleat screen area - g.clearRect(0, 24, g.getWidth(), g.getHeight()); - - // render outside text with ellipse - buf.clear(); - renderText(buf.setColor(1)); - renderEllipse(buf.setColor(0)); - g.setColor(color).drawImage(img, 0, 24); - - // render ellipse with inside text - buf.clear(); - renderEllipse(buf.setColor(1)); - renderText(buf.setColor(0)); - g.setColor(color).drawImage(img, 0, 24); -} - - -/* Minute Ticker *************************************/ - -let ticker; - -function stopTick() { - if (ticker) { - clearTimeout(ticker); - ticker = undefined; - } -} - -function startTick(run) { - stopTick(); - run(); - ticker = setTimeout(() => startTick(run), 60000 - (Date.now() % 60000)); -} - -/* Init **********************************************/ - -g.clear(); -startTick(draw); - -Bangle.on("lcdPower", (on) => { - if (on) { - startTick(draw); - } else { - stopTick(); - } -}); - -Bangle.setUI("clock"); -Bangle.loadWidgets(); -Bangle.drawWidgets(); +clock.start(); \ No newline at end of file From db096ea2f829a3317d572c482d94f1196190eed4 Mon Sep 17 00:00:00 2001 From: Alessandro Cocco Date: Wed, 8 Jun 2022 22:50:39 +0200 Subject: [PATCH 12/15] [Nifty-B Clock] Update metadata and changelog --- apps/ffcniftyb/ChangeLog | 1 + apps/ffcniftyb/metadata.json | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/ffcniftyb/ChangeLog b/apps/ffcniftyb/ChangeLog index 9fc7e3c5c..83b11eb78 100644 --- a/apps/ffcniftyb/ChangeLog +++ b/apps/ffcniftyb/ChangeLog @@ -3,3 +3,4 @@ 0.03: Call setUI before loading widgets Fix bug with black being unselectable Improve settings page +0.04: Use ClockFace library diff --git a/apps/ffcniftyb/metadata.json b/apps/ffcniftyb/metadata.json index 3d26c27ea..019ae6eb3 100644 --- a/apps/ffcniftyb/metadata.json +++ b/apps/ffcniftyb/metadata.json @@ -1,7 +1,7 @@ { "id": "ffcniftyb", "name": "Nifty-B Clock", - "version": "0.03", + "version": "0.04", "description": "A nifty clock (series B) with time, date and colour configuration", "icon": "app.png", "screenshots": [{"url":"screenshot.png"}], From d07580cc907d3bd7d3de221231ccf32936394d2d Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Thu, 9 Jun 2022 10:41:03 +0100 Subject: [PATCH 13/15] Add minified layout library, which should improve layout speed a lot. --- modules/Layout.js | 8 ++++++ modules/Layout.min.js | 14 ++++++++++ tests/Layout/bin/runtest.sh | 51 ++++++++++++++++++++++--------------- 3 files changed, 53 insertions(+), 20 deletions(-) create mode 100644 modules/Layout.min.js diff --git a/modules/Layout.js b/modules/Layout.js index 19cfabe11..436b04592 100644 --- a/modules/Layout.js +++ b/modules/Layout.js @@ -2,6 +2,14 @@ // See Layout.md for documentation +/* Minify to 'Layout.min.js' by: + + * checking out: https://github.com/espruino/EspruinoDocs + * run: ../EspruinoDocs/bin/minify.js modules/Layout.js modules/Layout.min.js + +*/ + + function Layout(layout, options) { this._l = this.l = layout; // Do we have >1 physical buttons? diff --git a/modules/Layout.min.js b/modules/Layout.min.js new file mode 100644 index 000000000..7dd169eb9 --- /dev/null +++ b/modules/Layout.min.js @@ -0,0 +1,14 @@ +function p(b,k){function d(h){h.id&&(f[h.id]=h);h.type||(h.type="");h.c&&h.c.forEach(d)}this._l=this.l=b;this.physBtns=2==process.env.HWVERSION?1:3;this.options=k||{};this.lazy=this.options.lazy||!1;if(2!=process.env.HWVERSION){var a=[];function h(m){"btn"==m.type&&a.push(m);m.c&&m.c.forEach(h)}h(b);a.length&&(this.physBtns=0,this.buttons=a,this.selectedButton=-1)}if(this.options.btns)if(this.b=b=this.options.btns,this.physBtns>=b.length){let h=Math.floor(Bangle.appRect.h/ +this.physBtns);for(2b.length;)b.push({label:""});this._l.width=g.getWidth()-8;this._l={type:"h",filly:1,c:[this._l,{type:"v",pad:1,filly:1,c:b.map(m=>(m.type="txt",m.font="6x8",m.height=h,m.r=1,m))}]}}else this._l.width=g.getWidth()-32,this._l={type:"h",c:[this._l,{type:"v",c:b.map(h=>(h.type="btn",h.filly=1,h.width=32,h.r=1,h))}]},a&&a.push.apply(a,this._l.c[1].c);this.setUI();var f=this;d(this._l);this.updateNeeded=!0}function r(b, +k,d,a,f){var h=null==b.bgCol?f:g.toColor(b.bgCol);if(h!=f||"txt"==b.type||"btn"==b.type||"img"==b.type||"custom"==b.type){var m=b.c;delete b.c;var c="H"+E.CRC32(E.toJS(b));m&&(b.c=m);delete k[c]||((a[c]=[b.x,b.y,b.x+b.w-1,b.y+b.h-1]).bg=null==f?g.theme.bg:f,d&&(d.push(b),d=null))}if(b.c)for(var l of b.c)r(l,k,d,a,h)}p.prototype.setUI=function(){Bangle.setUI();if(this.buttons){Bangle.setUI({mode:"updown",back:this.options.back},k=>{var d=this.selectedButton,a=this.buttons.length;if(void 0===k&&this.buttons[d])return this.buttons[d].cb(); +this.buttons[d]&&(delete this.buttons[d].selected,this.render(this.buttons[d]));d=(d+a+k)%a;this.buttons[d]&&(this.buttons[d].selected=1,this.render(this.buttons[d]));this.selectedButton=d});var b=!0}this.options.back&&!b&&Bangle.setUI({mode:"custom",back:this.options.back});if(this.b){function k(d,a){.75=d.x&&a.y>=d.y&&a.x<=d.x+d.w&&a.y<=d.y+d.h&&(2==a.type&&d.cbl?d.cbl(a):d.cb&&d.cb(a));d.c&&d.c.forEach(f=>k(f,a))}Bangle.touchHandler=(d,a)=>k(this._l,a);Bangle.on("touch",Bangle.touchHandler)}};p.prototype.render=function(b){function k(c){"ram"; +g.reset();void 0!==c.col&&g.setColor(c.col);void 0!==c.bgCol&&g.setBgColor(c.bgCol).clearRect(c.x,c.y,c.x+c.w-1,c.y+c.h-1);d[c.type](c)}b||(b=this._l);this.updateNeeded&&this.update();var d={"":function(){},txt:function(c){if(c.wrap){g.setFont(c.font).setFontAlign(0,-1);var l=g.wrapString(c.label,c.w),e=c.y+(c.h-g.getFontHeight()*l.length>>1);l.forEach((n,q)=>g.drawString(n,c.x+(c.w>>1),e+g.getFontHeight()*q))}else g.setFont(c.font).setFontAlign(0,0,c.r).drawString(c.label,c.x+(c.w>>1),c.y+(c.h>> +1))},btn:function(c){var l=c.x+(0|c.pad),e=c.y+(0|c.pad),n=c.w-(c.pad<<1),q=c.h-(c.pad<<1);l=[l,e+4,l+4,e,l+n-5,e,l+n-1,e+4,l+n-1,e+q-5,l+n-5,e+q-1,l+4,e+q-1,l,e+q-5,l,e+4];e=c.selected?g.theme.bgH:g.theme.bg2;g.setColor(e).fillPoly(l).setColor(c.selected?g.theme.fgH:g.theme.fg2).drawPoly(l);void 0!==c.col&&g.setColor(c.col);c.src?g.setBgColor(e).drawImage("function"==typeof c.src?c.src():c.src,c.x+c.w/2,c.y+c.h/2,{scale:c.scale||void 0,rotate:.5*Math.PI*(c.r||0)}):g.setFont(c.font||"6x8:2").setFontAlign(0, +0,c.r).drawString(c.label,c.x+c.w/2,c.y+c.h/2)},img:function(c){g.drawImage("function"==typeof c.src?c.src():c.src,c.x+c.w/2,c.y+c.h/2,{scale:c.scale||void 0,rotate:.5*Math.PI*(c.r||0)})},custom:function(c){c.render(c)},h:function(c){c.c.forEach(k)},v:function(c){c.c.forEach(k)}};if(this.lazy){this.rects||(this.rects={});var a=this.rects.clone(),f=[];r(b,a,f,this.rects,null);for(var h in a)delete this.rects[h];b=Object.keys(a).map(c=>a[c]).reverse();for(var m of b)g.setBgColor(m.bg).clearRect.apply(g, +m);f.forEach(k)}else k(b)};p.prototype.forgetLazyState=function(){this.rects={}};p.prototype.layout=function(b){switch(b.type){case "h":var k=b.x+(0|b.pad),d=0,a=b.c&&b.c.reduce((e,n)=>e+(0|n.fillx),0);a||(k+=b.w-b._w>>1,a=1);var f=k;b.c.forEach(e=>{e.x=0|f;k+=e._w;d+=0|e.fillx;f=k+Math.floor(d*(b.w-b._w)/a);e.w=0|f-e.x;e.h=0|(e.filly?b.h-(b.pad<<1):e._h);e.y=0|b.y+(0|b.pad)+((1+(0|e.valign))*(b.h-(b.pad<<1)-e.h)>>1);e.c&&this.layout(e)});break;case "v":var h=b.y+(0|b.pad),m=0,c=b.c&&b.c.reduce((e, +n)=>e+(0|n.filly),0);c||(h+=b.h-b._h>>1,c=1);var l=h;b.c.forEach(e=>{e.y=0|l;h+=e._h;m+=0|e.filly;l=h+Math.floor(m*(b.h-b._h)/c);e.h=0|l-e.y;e.w=0|(e.fillx?b.w-(b.pad<<1):e._w);e.x=0|b.x+(0|b.pad)+((1+(0|e.halign))*(b.w-(b.pad<<1)-e.w)>>1);e.c&&this.layout(e)})}};p.prototype.debug=function(b,k){b||(b=this._l);k=k||1;g.setColor(k&1,k&2,k&4).drawRect(b.x+k-1,b.y+k-1,b.x+b.w-k,b.y+b.h-k);b.pad&&g.drawRect(b.x+b.pad-1,b.y+b.pad-1,b.x+b.w-b.pad,b.y+b.h-b.pad);k++;b.c&&b.c.forEach(d=>this.debug(d,k))}; +p.prototype.update=function(){function b(a){"ram";k[a.type](a);if(a.r&1){var f=a._w;a._w=a._h;a._h=f}a._w=0|Math.max(a._w+(a.pad<<1),0|a.width);a._h=0|Math.max(a._h+(a.pad<<1),0|a.height)}delete this.updateNeeded;var k={txt:function(a){a.font.endsWith("%")&&(a.font="Vector"+Math.round(g.getHeight()*a.font.slice(0,-1)/100));if(a.wrap)a._h=a._w=0;else{var f=g.setFont(a.font).stringMetrics(a.label);a._w=f.width;a._h=f.height}},btn:function(a){a.font&&a.font.endsWith("%")&&(a.font="Vector"+Math.round(g.getHeight()* +a.font.slice(0,-1)/100));var f=a.src?g.imageMetrics("function"==typeof a.src?a.src():a.src):g.setFont(a.font||"6x8:2").stringMetrics(a.label);a._h=16+f.height;a._w=20+f.width},img:function(a){var f=g.imageMetrics("function"==typeof a.src?a.src():a.src),h=a.scale||1;a._w=f.width*h;a._h=f.height*h},"":function(a){a._w=0;a._h=0},custom:function(a){a._w=0;a._h=0},h:function(a){a.c.forEach(b);a._h=a.c.reduce((f,h)=>Math.max(f,h._h),0);a._w=a.c.reduce((f,h)=>f+h._w,0);null==a.fillx&&a.c.some(f=>f.fillx)&& +(a.fillx=1);null==a.filly&&a.c.some(f=>f.filly)&&(a.filly=1)},v:function(a){a.c.forEach(b);a._h=a.c.reduce((f,h)=>f+h._h,0);a._w=a.c.reduce((f,h)=>Math.max(f,h._w),0);null==a.fillx&&a.c.some(f=>f.fillx)&&(a.fillx=1);null==a.filly&&a.c.some(f=>f.filly)&&(a.filly=1)}},d=this._l;b(d);d.fillx||d.filly?(d.w=Bangle.appRect.w,d.h=Bangle.appRect.h,d.x=Bangle.appRect.x,d.y=Bangle.appRect.y):(d.w=d._w,d.h=d._h,d.x=Bangle.appRect.w-d.w>>1,d.y=Bangle.appRect.y+(Bangle.appRect.h-d.h>>1));this.layout(d)};p.prototype.clear= +function(b){b||(b=this._l);g.reset();void 0!==b.bgCol&&g.setBgColor(b.bgCol);g.clearRect(b.x,b.y,b.x+b.w-1,b.y+b.h-1)};exports=p \ No newline at end of file diff --git a/tests/Layout/bin/runtest.sh b/tests/Layout/bin/runtest.sh index e06dec86b..9bac72283 100755 --- a/tests/Layout/bin/runtest.sh +++ b/tests/Layout/bin/runtest.sh @@ -18,24 +18,35 @@ SRCJS=$1 SRCBMP=$SRCDIR/`basename $SRCJS .js`.bmp echo "TEST $SRCJS ($SRCBMP)" -cat ../../modules/Layout.js > $TESTJS -echo 'Bangle = { setUI : function(){}, appRect:{x:0,y:0,w:176,h:176,x2:175,y2:175} };BTN1=0;process.env = process.env;process.env.HWVERSION=2;' >> $TESTJS -echo 'g = Graphics.createArrayBuffer(176,176,4);' >> $TESTJS -cat $SRCJS >> $TESTJS || exit 1 -echo 'layout.render()' >> $TESTJS -#echo 'layout.debug()' >> $TESTJS -echo 'require("fs").writeFileSync("'$TESTBMP'",g.asBMP())' >> $TESTJS +run_test () { + LAYOUTFILE=$1 + echo 'exports = {};' > $TESTJS + cat $LAYOUTFILE >> $TESTJS + echo ';' >> $TESTJS + echo 'Layout = exports;' >> $TESTJS + echo 'Bangle = { setUI : function(){}, appRect:{x:0,y:0,w:176,h:176,x2:175,y2:175} };BTN1=0;process.env = process.env;process.env.HWVERSION=2;' >> $TESTJS + echo 'g = Graphics.createArrayBuffer(176,176,4);' >> $TESTJS + cat $SRCJS >> $TESTJS || exit 1 + echo 'layout.render()' >> $TESTJS + #echo 'layout.debug()' >> $TESTJS + echo 'require("fs").writeFileSync("'$TESTBMP'",g.asBMP())' >> $TESTJS + echo ============================================= + echo TESTING $LAYOUTFILE $SRCJS + bin/espruino $TESTJS || exit 1 + if ! cmp $TESTBMP $SRCBMP >/dev/null 2>&1 + then + echo ============================================= + echo $LAYOUTFILE + echo $TESTBMP $SRCBMP differ + echo ============================================== + convert "+append" $TESTBMP $SRCBMP testresult.bmp + display testresult.bmp + exit 1 + else + echo Files are the same + exit 0 + fi +} -bin/espruino $TESTJS || exit 1 -if ! cmp $TESTBMP $SRCBMP >/dev/null 2>&1 -then - echo ============================================= - echo $TESTBMP $SRCBMP differ - echo ============================================== - convert "+append" $TESTBMP $SRCBMP testresult.bmp - display testresult.bmp - exit 1 -else - echo Files are the same - exit 0 -fi +run_test ../../modules/Layout.js +run_test ../../modules/Layout.min.js From e1cc59ec4f6a969554ccfa69c63c9cdad33b33a6 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Thu, 9 Jun 2022 17:06:52 +0100 Subject: [PATCH 14/15] bootloader CRC --- apps/fwupdate/custom.html | 1 + bin/firmwaremaker_c.js | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/fwupdate/custom.html b/apps/fwupdate/custom.html index 0321e46bc..3f8f50b3f 100644 --- a/apps/fwupdate/custom.html +++ b/apps/fwupdate/custom.html @@ -82,6 +82,7 @@ function onInit(device) { if (crc==46757280) version = "2v11.58"; if (crc==3508163280 || crc==1418074094) version = "2v12"; if (crc==4056371285) version = "2v13"; + if (crc==1038322422) version = "2v14"; if (!ok) { version += `(⚠ update required)`; } diff --git a/bin/firmwaremaker_c.js b/bin/firmwaremaker_c.js index 7940e551d..fd8072e06 100755 --- a/bin/firmwaremaker_c.js +++ b/bin/firmwaremaker_c.js @@ -1,4 +1,4 @@ -#!/usr/bin/nodejs +#!/usr/bin/node /* Mashes together a bunch of different apps into a big binary blob. We then store this *inside* the Bangle.js firmware and can use it From 0cc0a40356577ffa232526f23b147de9816bc3e0 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Fri, 10 Jun 2022 09:19:53 +0100 Subject: [PATCH 15/15] fix layout minification issue --- modules/Layout.js | 8 ++++---- modules/Layout.min.js | 24 ++++++++++++------------ 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/modules/Layout.js b/modules/Layout.js index 436b04592..fd5809a93 100644 --- a/modules/Layout.js +++ b/modules/Layout.js @@ -6,9 +6,9 @@ * checking out: https://github.com/espruino/EspruinoDocs * run: ../EspruinoDocs/bin/minify.js modules/Layout.js modules/Layout.min.js - -*/ - + +*/ + function Layout(layout, options) { this._l = this.l = layout; @@ -79,7 +79,7 @@ function Layout(layout, options) { Layout.prototype.setUI = function() { Bangle.setUI(); // remove all existing input handlers - var uiSet; + let uiSet; if (this.buttons) { // multiple buttons so we'll jus use back/next/select Bangle.setUI({mode:"updown", back:this.options.back}, dir=>{ diff --git a/modules/Layout.min.js b/modules/Layout.min.js index 7dd169eb9..4523c547c 100644 --- a/modules/Layout.min.js +++ b/modules/Layout.min.js @@ -1,14 +1,14 @@ function p(b,k){function d(h){h.id&&(f[h.id]=h);h.type||(h.type="");h.c&&h.c.forEach(d)}this._l=this.l=b;this.physBtns=2==process.env.HWVERSION?1:3;this.options=k||{};this.lazy=this.options.lazy||!1;if(2!=process.env.HWVERSION){var a=[];function h(m){"btn"==m.type&&a.push(m);m.c&&m.c.forEach(h)}h(b);a.length&&(this.physBtns=0,this.buttons=a,this.selectedButton=-1)}if(this.options.btns)if(this.b=b=this.options.btns,this.physBtns>=b.length){let h=Math.floor(Bangle.appRect.h/ this.physBtns);for(2b.length;)b.push({label:""});this._l.width=g.getWidth()-8;this._l={type:"h",filly:1,c:[this._l,{type:"v",pad:1,filly:1,c:b.map(m=>(m.type="txt",m.font="6x8",m.height=h,m.r=1,m))}]}}else this._l.width=g.getWidth()-32,this._l={type:"h",c:[this._l,{type:"v",c:b.map(h=>(h.type="btn",h.filly=1,h.width=32,h.r=1,h))}]},a&&a.push.apply(a,this._l.c[1].c);this.setUI();var f=this;d(this._l);this.updateNeeded=!0}function r(b, -k,d,a,f){var h=null==b.bgCol?f:g.toColor(b.bgCol);if(h!=f||"txt"==b.type||"btn"==b.type||"img"==b.type||"custom"==b.type){var m=b.c;delete b.c;var c="H"+E.CRC32(E.toJS(b));m&&(b.c=m);delete k[c]||((a[c]=[b.x,b.y,b.x+b.w-1,b.y+b.h-1]).bg=null==f?g.theme.bg:f,d&&(d.push(b),d=null))}if(b.c)for(var l of b.c)r(l,k,d,a,h)}p.prototype.setUI=function(){Bangle.setUI();if(this.buttons){Bangle.setUI({mode:"updown",back:this.options.back},k=>{var d=this.selectedButton,a=this.buttons.length;if(void 0===k&&this.buttons[d])return this.buttons[d].cb(); -this.buttons[d]&&(delete this.buttons[d].selected,this.render(this.buttons[d]));d=(d+a+k)%a;this.buttons[d]&&(this.buttons[d].selected=1,this.render(this.buttons[d]));this.selectedButton=d});var b=!0}this.options.back&&!b&&Bangle.setUI({mode:"custom",back:this.options.back});if(this.b){function k(d,a){.75=d.x&&a.y>=d.y&&a.x<=d.x+d.w&&a.y<=d.y+d.h&&(2==a.type&&d.cbl?d.cbl(a):d.cb&&d.cb(a));d.c&&d.c.forEach(f=>k(f,a))}Bangle.touchHandler=(d,a)=>k(this._l,a);Bangle.on("touch",Bangle.touchHandler)}};p.prototype.render=function(b){function k(c){"ram"; -g.reset();void 0!==c.col&&g.setColor(c.col);void 0!==c.bgCol&&g.setBgColor(c.bgCol).clearRect(c.x,c.y,c.x+c.w-1,c.y+c.h-1);d[c.type](c)}b||(b=this._l);this.updateNeeded&&this.update();var d={"":function(){},txt:function(c){if(c.wrap){g.setFont(c.font).setFontAlign(0,-1);var l=g.wrapString(c.label,c.w),e=c.y+(c.h-g.getFontHeight()*l.length>>1);l.forEach((n,q)=>g.drawString(n,c.x+(c.w>>1),e+g.getFontHeight()*q))}else g.setFont(c.font).setFontAlign(0,0,c.r).drawString(c.label,c.x+(c.w>>1),c.y+(c.h>> -1))},btn:function(c){var l=c.x+(0|c.pad),e=c.y+(0|c.pad),n=c.w-(c.pad<<1),q=c.h-(c.pad<<1);l=[l,e+4,l+4,e,l+n-5,e,l+n-1,e+4,l+n-1,e+q-5,l+n-5,e+q-1,l+4,e+q-1,l,e+q-5,l,e+4];e=c.selected?g.theme.bgH:g.theme.bg2;g.setColor(e).fillPoly(l).setColor(c.selected?g.theme.fgH:g.theme.fg2).drawPoly(l);void 0!==c.col&&g.setColor(c.col);c.src?g.setBgColor(e).drawImage("function"==typeof c.src?c.src():c.src,c.x+c.w/2,c.y+c.h/2,{scale:c.scale||void 0,rotate:.5*Math.PI*(c.r||0)}):g.setFont(c.font||"6x8:2").setFontAlign(0, -0,c.r).drawString(c.label,c.x+c.w/2,c.y+c.h/2)},img:function(c){g.drawImage("function"==typeof c.src?c.src():c.src,c.x+c.w/2,c.y+c.h/2,{scale:c.scale||void 0,rotate:.5*Math.PI*(c.r||0)})},custom:function(c){c.render(c)},h:function(c){c.c.forEach(k)},v:function(c){c.c.forEach(k)}};if(this.lazy){this.rects||(this.rects={});var a=this.rects.clone(),f=[];r(b,a,f,this.rects,null);for(var h in a)delete this.rects[h];b=Object.keys(a).map(c=>a[c]).reverse();for(var m of b)g.setBgColor(m.bg).clearRect.apply(g, -m);f.forEach(k)}else k(b)};p.prototype.forgetLazyState=function(){this.rects={}};p.prototype.layout=function(b){switch(b.type){case "h":var k=b.x+(0|b.pad),d=0,a=b.c&&b.c.reduce((e,n)=>e+(0|n.fillx),0);a||(k+=b.w-b._w>>1,a=1);var f=k;b.c.forEach(e=>{e.x=0|f;k+=e._w;d+=0|e.fillx;f=k+Math.floor(d*(b.w-b._w)/a);e.w=0|f-e.x;e.h=0|(e.filly?b.h-(b.pad<<1):e._h);e.y=0|b.y+(0|b.pad)+((1+(0|e.valign))*(b.h-(b.pad<<1)-e.h)>>1);e.c&&this.layout(e)});break;case "v":var h=b.y+(0|b.pad),m=0,c=b.c&&b.c.reduce((e, -n)=>e+(0|n.filly),0);c||(h+=b.h-b._h>>1,c=1);var l=h;b.c.forEach(e=>{e.y=0|l;h+=e._h;m+=0|e.filly;l=h+Math.floor(m*(b.h-b._h)/c);e.h=0|l-e.y;e.w=0|(e.fillx?b.w-(b.pad<<1):e._w);e.x=0|b.x+(0|b.pad)+((1+(0|e.halign))*(b.w-(b.pad<<1)-e.w)>>1);e.c&&this.layout(e)})}};p.prototype.debug=function(b,k){b||(b=this._l);k=k||1;g.setColor(k&1,k&2,k&4).drawRect(b.x+k-1,b.y+k-1,b.x+b.w-k,b.y+b.h-k);b.pad&&g.drawRect(b.x+b.pad-1,b.y+b.pad-1,b.x+b.w-b.pad,b.y+b.h-b.pad);k++;b.c&&b.c.forEach(d=>this.debug(d,k))}; -p.prototype.update=function(){function b(a){"ram";k[a.type](a);if(a.r&1){var f=a._w;a._w=a._h;a._h=f}a._w=0|Math.max(a._w+(a.pad<<1),0|a.width);a._h=0|Math.max(a._h+(a.pad<<1),0|a.height)}delete this.updateNeeded;var k={txt:function(a){a.font.endsWith("%")&&(a.font="Vector"+Math.round(g.getHeight()*a.font.slice(0,-1)/100));if(a.wrap)a._h=a._w=0;else{var f=g.setFont(a.font).stringMetrics(a.label);a._w=f.width;a._h=f.height}},btn:function(a){a.font&&a.font.endsWith("%")&&(a.font="Vector"+Math.round(g.getHeight()* -a.font.slice(0,-1)/100));var f=a.src?g.imageMetrics("function"==typeof a.src?a.src():a.src):g.setFont(a.font||"6x8:2").stringMetrics(a.label);a._h=16+f.height;a._w=20+f.width},img:function(a){var f=g.imageMetrics("function"==typeof a.src?a.src():a.src),h=a.scale||1;a._w=f.width*h;a._h=f.height*h},"":function(a){a._w=0;a._h=0},custom:function(a){a._w=0;a._h=0},h:function(a){a.c.forEach(b);a._h=a.c.reduce((f,h)=>Math.max(f,h._h),0);a._w=a.c.reduce((f,h)=>f+h._w,0);null==a.fillx&&a.c.some(f=>f.fillx)&& -(a.fillx=1);null==a.filly&&a.c.some(f=>f.filly)&&(a.filly=1)},v:function(a){a.c.forEach(b);a._h=a.c.reduce((f,h)=>f+h._h,0);a._w=a.c.reduce((f,h)=>Math.max(f,h._w),0);null==a.fillx&&a.c.some(f=>f.fillx)&&(a.fillx=1);null==a.filly&&a.c.some(f=>f.filly)&&(a.filly=1)}},d=this._l;b(d);d.fillx||d.filly?(d.w=Bangle.appRect.w,d.h=Bangle.appRect.h,d.x=Bangle.appRect.x,d.y=Bangle.appRect.y):(d.w=d._w,d.h=d._h,d.x=Bangle.appRect.w-d.w>>1,d.y=Bangle.appRect.y+(Bangle.appRect.h-d.h>>1));this.layout(d)};p.prototype.clear= -function(b){b||(b=this._l);g.reset();void 0!==b.bgCol&&g.setBgColor(b.bgCol);g.clearRect(b.x,b.y,b.x+b.w-1,b.y+b.h-1)};exports=p \ No newline at end of file +k,d,a,f){var h=null==b.bgCol?f:g.toColor(b.bgCol);if(h!=f||"txt"==b.type||"btn"==b.type||"img"==b.type||"custom"==b.type){var m=b.c;delete b.c;var c="H"+E.CRC32(E.toJS(b));m&&(b.c=m);delete k[c]||((a[c]=[b.x,b.y,b.x+b.w-1,b.y+b.h-1]).bg=null==f?g.theme.bg:f,d&&(d.push(b),d=null))}if(b.c)for(var l of b.c)r(l,k,d,a,h)}p.prototype.setUI=function(){Bangle.setUI();let b;this.buttons&&(Bangle.setUI({mode:"updown",back:this.options.back},k=>{var d=this.selectedButton,a=this.buttons.length;if(void 0===k&& +this.buttons[d])return this.buttons[d].cb();this.buttons[d]&&(delete this.buttons[d].selected,this.render(this.buttons[d]));d=(d+a+k)%a;this.buttons[d]&&(this.buttons[d].selected=1,this.render(this.buttons[d]));this.selectedButton=d}),b=!0);this.options.back&&!b&&Bangle.setUI({mode:"custom",back:this.options.back});if(this.b){function k(d,a){.75=d.x&&a.y>=d.y&&a.x<=d.x+d.w&&a.y<=d.y+d.h&&(2==a.type&&d.cbl?d.cbl(a):d.cb&&d.cb(a));d.c&&d.c.forEach(f=>k(f,a))}Bangle.touchHandler=(d,a)=>k(this._l,a);Bangle.on("touch",Bangle.touchHandler)}}; +p.prototype.render=function(b){function k(c){"ram";g.reset();void 0!==c.col&&g.setColor(c.col);void 0!==c.bgCol&&g.setBgColor(c.bgCol).clearRect(c.x,c.y,c.x+c.w-1,c.y+c.h-1);d[c.type](c)}b||(b=this._l);this.updateNeeded&&this.update();var d={"":function(){},txt:function(c){if(c.wrap){g.setFont(c.font).setFontAlign(0,-1);var l=g.wrapString(c.label,c.w),e=c.y+(c.h-g.getFontHeight()*l.length>>1);l.forEach((n,q)=>g.drawString(n,c.x+(c.w>>1),e+g.getFontHeight()*q))}else g.setFont(c.font).setFontAlign(0, +0,c.r).drawString(c.label,c.x+(c.w>>1),c.y+(c.h>>1))},btn:function(c){var l=c.x+(0|c.pad),e=c.y+(0|c.pad),n=c.w-(c.pad<<1),q=c.h-(c.pad<<1);l=[l,e+4,l+4,e,l+n-5,e,l+n-1,e+4,l+n-1,e+q-5,l+n-5,e+q-1,l+4,e+q-1,l,e+q-5,l,e+4];e=c.selected?g.theme.bgH:g.theme.bg2;g.setColor(e).fillPoly(l).setColor(c.selected?g.theme.fgH:g.theme.fg2).drawPoly(l);void 0!==c.col&&g.setColor(c.col);c.src?g.setBgColor(e).drawImage("function"==typeof c.src?c.src():c.src,c.x+c.w/2,c.y+c.h/2,{scale:c.scale||void 0,rotate:.5*Math.PI* +(c.r||0)}):g.setFont(c.font||"6x8:2").setFontAlign(0,0,c.r).drawString(c.label,c.x+c.w/2,c.y+c.h/2)},img:function(c){g.drawImage("function"==typeof c.src?c.src():c.src,c.x+c.w/2,c.y+c.h/2,{scale:c.scale||void 0,rotate:.5*Math.PI*(c.r||0)})},custom:function(c){c.render(c)},h:function(c){c.c.forEach(k)},v:function(c){c.c.forEach(k)}};if(this.lazy){this.rects||(this.rects={});var a=this.rects.clone(),f=[];r(b,a,f,this.rects,null);for(var h in a)delete this.rects[h];b=Object.keys(a).map(c=>a[c]).reverse(); +for(var m of b)g.setBgColor(m.bg).clearRect.apply(g,m);f.forEach(k)}else k(b)};p.prototype.forgetLazyState=function(){this.rects={}};p.prototype.layout=function(b){switch(b.type){case "h":var k=b.x+(0|b.pad),d=0,a=b.c&&b.c.reduce((e,n)=>e+(0|n.fillx),0);a||(k+=b.w-b._w>>1,a=1);var f=k;b.c.forEach(e=>{e.x=0|f;k+=e._w;d+=0|e.fillx;f=k+Math.floor(d*(b.w-b._w)/a);e.w=0|f-e.x;e.h=0|(e.filly?b.h-(b.pad<<1):e._h);e.y=0|b.y+(0|b.pad)+((1+(0|e.valign))*(b.h-(b.pad<<1)-e.h)>>1);e.c&&this.layout(e)});break; +case "v":var h=b.y+(0|b.pad),m=0,c=b.c&&b.c.reduce((e,n)=>e+(0|n.filly),0);c||(h+=b.h-b._h>>1,c=1);var l=h;b.c.forEach(e=>{e.y=0|l;h+=e._h;m+=0|e.filly;l=h+Math.floor(m*(b.h-b._h)/c);e.h=0|l-e.y;e.w=0|(e.fillx?b.w-(b.pad<<1):e._w);e.x=0|b.x+(0|b.pad)+((1+(0|e.halign))*(b.w-(b.pad<<1)-e.w)>>1);e.c&&this.layout(e)})}};p.prototype.debug=function(b,k){b||(b=this._l);k=k||1;g.setColor(k&1,k&2,k&4).drawRect(b.x+k-1,b.y+k-1,b.x+b.w-k,b.y+b.h-k);b.pad&&g.drawRect(b.x+b.pad-1,b.y+b.pad-1,b.x+b.w-b.pad,b.y+ +b.h-b.pad);k++;b.c&&b.c.forEach(d=>this.debug(d,k))};p.prototype.update=function(){function b(a){"ram";k[a.type](a);if(a.r&1){var f=a._w;a._w=a._h;a._h=f}a._w=0|Math.max(a._w+(a.pad<<1),0|a.width);a._h=0|Math.max(a._h+(a.pad<<1),0|a.height)}delete this.updateNeeded;var k={txt:function(a){a.font.endsWith("%")&&(a.font="Vector"+Math.round(g.getHeight()*a.font.slice(0,-1)/100));if(a.wrap)a._h=a._w=0;else{var f=g.setFont(a.font).stringMetrics(a.label);a._w=f.width;a._h=f.height}},btn:function(a){a.font&& +a.font.endsWith("%")&&(a.font="Vector"+Math.round(g.getHeight()*a.font.slice(0,-1)/100));var f=a.src?g.imageMetrics("function"==typeof a.src?a.src():a.src):g.setFont(a.font||"6x8:2").stringMetrics(a.label);a._h=16+f.height;a._w=20+f.width},img:function(a){var f=g.imageMetrics("function"==typeof a.src?a.src():a.src),h=a.scale||1;a._w=f.width*h;a._h=f.height*h},"":function(a){a._w=0;a._h=0},custom:function(a){a._w=0;a._h=0},h:function(a){a.c.forEach(b);a._h=a.c.reduce((f,h)=>Math.max(f,h._h),0);a._w= +a.c.reduce((f,h)=>f+h._w,0);null==a.fillx&&a.c.some(f=>f.fillx)&&(a.fillx=1);null==a.filly&&a.c.some(f=>f.filly)&&(a.filly=1)},v:function(a){a.c.forEach(b);a._h=a.c.reduce((f,h)=>f+h._h,0);a._w=a.c.reduce((f,h)=>Math.max(f,h._w),0);null==a.fillx&&a.c.some(f=>f.fillx)&&(a.fillx=1);null==a.filly&&a.c.some(f=>f.filly)&&(a.filly=1)}},d=this._l;b(d);d.fillx||d.filly?(d.w=Bangle.appRect.w,d.h=Bangle.appRect.h,d.x=Bangle.appRect.x,d.y=Bangle.appRect.y):(d.w=d._w,d.h=d._h,d.x=Bangle.appRect.w-d.w>>1,d.y= +Bangle.appRect.y+(Bangle.appRect.h-d.h>>1));this.layout(d)};p.prototype.clear=function(b){b||(b=this._l);g.reset();void 0!==b.bgCol&&g.setBgColor(b.bgCol);g.clearRect(b.x,b.y,b.x+b.w-1,b.y+b.h-1)};exports=p