diff --git a/apps/info/ChangeLog b/apps/info/ChangeLog
new file mode 100644
index 000000000..07afedd21
--- /dev/null
+++ b/apps/info/ChangeLog
@@ -0,0 +1 @@
+0.01: Release
\ No newline at end of file
diff --git a/apps/info/README.md b/apps/info/README.md
new file mode 100644
index 000000000..007a9794e
--- /dev/null
+++ b/apps/info/README.md
@@ -0,0 +1,17 @@
+# Info
+
+A very simple app that shows information on 3 different screens.
+Go to the next screen via tab right, go to the previous screen
+via tab left and reload the data via tab in the middle of the
+screen. Very useful if combined with pattern launcher ;)
+
+
+
+
+
+
+## Contributors
+- [David Peer](https://github.com/peerdavid).
+
+## Thanks To
+Info icons created by Freepik - Flaticon
diff --git a/apps/info/info.app.js b/apps/info/info.app.js
new file mode 100644
index 000000000..c61a88045
--- /dev/null
+++ b/apps/info/info.app.js
@@ -0,0 +1,108 @@
+var s = require("Storage");
+const locale = require('locale');
+var ENV = process.env;
+var W = g.getWidth(), H = g.getHeight();
+var screen = 0;
+const maxScreen = 2;
+
+function getVersion(file) {
+ var j = s.readJSON(file,1);
+ var v = ("object"==typeof j)?j.version:false;
+ return v?((v?"v"+v:"Unknown")):"NO ";
+}
+
+
+function drawData(name, value, y){
+ g.drawString(name, 5, y);
+ g.drawString(value, 100, y);
+}
+
+function getSteps(){
+ try{
+ return Bangle.getHealthStatus("day").steps;
+ } catch(e) {
+ return ">= 2v12";
+ }
+}
+
+function getBpm(){
+ try{
+ return Math.round(Bangle.getHealthStatus("day").bpm) + "bpm";
+ } catch(e) {
+ return ">= 2v12";
+ }
+}
+
+function drawInfo() {
+ g.reset().clearRect(Bangle.appRect);
+ var h=18, y = h;//-h;
+
+ // Header
+ g.setFont("Vector", h+2).setFontAlign(0,-1);
+ g.drawString("--==|| INFO ||==--", W/2, 0);
+ g.setFont("Vector",h).setFontAlign(-1,-1);
+
+ // Dynamic data
+ if(screen == 0){
+ drawData("Steps", getSteps(), y+=h);
+ drawData("HRM", getBpm(), y+=h);
+ drawData("Battery", E.getBattery() + "%", y+=h);
+ drawData("Voltage", E.getAnalogVRef().toFixed(2) + "V", y+=h);
+ drawData("IntTemp.", locale.temp(parseInt(E.getTemperature())), y+=h);
+ }
+
+ if(screen == 1){
+ drawData("Charging?", Bangle.isCharging() ? "Yes" : "No", y+=h);
+ drawData("Bluetooth", NRF.getSecurityStatus().connected ? "Conn." : "Disconn.", y+=h);
+ drawData("GPS", Bangle.isGPSOn() ? "On" : "Off", y+=h);
+ drawData("Compass", Bangle.isCompassOn() ? "On" : "Off", y+=h);
+ drawData("HRM", Bangle.isHRMOn() ? "On" : "Off", y+=h);
+ }
+
+ // Static data
+ if(screen == 2){
+ drawData("Firmw.", ENV.VERSION, y+=h);
+ drawData("Boot.", getVersion("boot.info"), y+=h);
+ drawData("Settings", getVersion("setting.info"), y+=h);
+ drawData("Storage", "", y+=h);
+ drawData(" Total", ENV.STORAGE>>10, y+=h);
+ drawData(" Free", require("Storage").getFree()>>10, y+=h);
+ }
+
+ if(Bangle.isLocked()){
+ g.setFont("Vector",h-2).setFontAlign(-1,-1);
+ g.drawString("Locked", 0, H-h+2);
+ }
+
+ g.setFont("Vector",h-2).setFontAlign(1,-1);
+ g.drawString((screen+1) + "/3", W, H-h+2);
+}
+
+drawInfo();
+setWatch(_=>load(), BTN1);
+
+Bangle.on('touch', function(btn, e){
+ var left = parseInt(g.getWidth() * 0.3);
+ var right = g.getWidth() - left;
+ var isLeft = e.x < left;
+ var isRight = e.x > right;
+
+ if(isRight){
+ screen = (screen + 1) % (maxScreen+1);
+ }
+
+ if(isLeft){
+ screen -= 1;
+ screen = screen < 0 ? maxScreen : screen;
+ }
+
+ drawInfo();
+});
+
+Bangle.on('lock', function(isLocked) {
+ drawInfo();
+});
+
+Bangle.loadWidgets();
+for (let wd of WIDGETS) {wd.draw=()=>{};wd.area="";}
+// Bangle.drawWidgets();
\ No newline at end of file
diff --git a/apps/info/info.icon.js b/apps/info/info.icon.js
new file mode 100644
index 000000000..8dbab8357
--- /dev/null
+++ b/apps/info/info.icon.js
@@ -0,0 +1 @@
+require("heatshrink").decompress(atob("mEwwcBkmSpICDBwcJBYwCDpAhFggRJGg8SCI+ABgU//gSDCI4JBj//AAX4JRAIBg4QDAAPgBIJWGgIQFAAI+BLglAgEPCI/wEgJoEgYQHAAPANwhWFAApcBCIWQgAQJAAMAgSMDCJiSCwB6GQA6eCn5TFL4q5BUgIRF/wuBv4RGkCeGO4IREUgMBCJCVGCISwIWw0BYRLIICLBHHCJRrGCIQIFR44I5LIoRaPpARcdIwRJfYMBCJuACKUkgE/a5f8gEJCJD7FCIeAg78FAAvggFJCIMACJZOBCIOQCJsCCIOSgEfCBP4gESCIZTFOIwRDoDIGaguSCIVIgCkFTwcAggRDpIYBQAx6BgAOCAQYIBLghWBTwQRFFgIABXIIFDBwgCDBYQAENAYCFLgIAEKwpKIIhA="))
diff --git a/apps/info/info.png b/apps/info/info.png
new file mode 100644
index 000000000..c73813025
Binary files /dev/null and b/apps/info/info.png differ
diff --git a/apps/info/metadata.json b/apps/info/metadata.json
new file mode 100644
index 000000000..f05f0e134
--- /dev/null
+++ b/apps/info/metadata.json
@@ -0,0 +1,19 @@
+{
+ "id": "info",
+ "name": "Info",
+ "version": "0.01",
+ "description": "An application that displays information such as battery level, steps etc.",
+ "icon": "info.png",
+ "type": "app",
+ "tags": "tool",
+ "readme": "README.md",
+ "supports": ["BANGLEJS2"],
+ "screenshots": [
+ {"url":"screenshot_1.png"},
+ {"url":"screenshot_2.png"},
+ {"url":"screenshot_3.png"}],
+ "storage": [
+ {"name":"info.app.js","url":"info.app.js"},
+ {"name":"info.img","url":"info.icon.js","evaluate":true}
+ ]
+}
diff --git a/apps/info/screenshot_1.png b/apps/info/screenshot_1.png
new file mode 100644
index 000000000..97d42a896
Binary files /dev/null and b/apps/info/screenshot_1.png differ
diff --git a/apps/info/screenshot_2.png b/apps/info/screenshot_2.png
new file mode 100644
index 000000000..2d25dd4e6
Binary files /dev/null and b/apps/info/screenshot_2.png differ
diff --git a/apps/info/screenshot_3.png b/apps/info/screenshot_3.png
new file mode 100644
index 000000000..782e4a195
Binary files /dev/null and b/apps/info/screenshot_3.png differ
diff --git a/apps/neonx/ChangeLog b/apps/neonx/ChangeLog
index af7f83942..7ac033fe8 100644
--- a/apps/neonx/ChangeLog
+++ b/apps/neonx/ChangeLog
@@ -1 +1,2 @@
0.01: Initial release
+0.02: Optional fullscreen mode
\ No newline at end of file
diff --git a/apps/neonx/README.md b/apps/neonx/README.md
index d836dfab3..f205b702f 100644
--- a/apps/neonx/README.md
+++ b/apps/neonx/README.md
@@ -4,8 +4,8 @@
|---------------------------------|--------------------------------------|
|
Neon X | Neon IO X |
-This is a clock based on Pebble's Neon X and Neon IO X watchfaces by Sam Jerichow.
-Can be switched between in the Settings menu, which can be accessed through
+This is a clock based on Pebble's Neon X and Neon IO X watchfaces by Sam Jerichow.
+Can be switched between in the Settings menu, which can be accessed through
the app/widget settings menu of the Bangle.js
## Settings
@@ -14,7 +14,11 @@ the app/widget settings menu of the Bangle.js
Activate the Neon IO X clock look, a bit hard to read until one gets used to it.
### Thickness
-The thickness of watch lines, from 1 to 5.
+The thickness of watch lines, from 1 to 6.
### Date on touch
Shows the current date as DD MM on touch and reverts back to time after 5 seconds or with another touch.
+
+### Fullscreen
+Shows the watchface in fullscreen mode.
+Note: In fullscreen mode, widgets are hidden, but still loaded.
\ No newline at end of file
diff --git a/apps/neonx/metadata.json b/apps/neonx/metadata.json
index 41b16d11b..ffa4d1b8e 100644
--- a/apps/neonx/metadata.json
+++ b/apps/neonx/metadata.json
@@ -2,7 +2,7 @@
"id": "neonx",
"name": "Neon X & IO X Clock",
"shortName": "Neon X Clock",
- "version": "0.01",
+ "version": "0.02",
"description": "Pebble Neon X & Neon IO X for Bangle.js",
"icon": "neonx.png",
"type": "clock",
diff --git a/apps/neonx/neonx.app.js b/apps/neonx/neonx.app.js
index 967fc8582..4ef0986fe 100644
--- a/apps/neonx/neonx.app.js
+++ b/apps/neonx/neonx.app.js
@@ -34,6 +34,7 @@ const colors = {
const is12hour = (require("Storage").readJSON("setting.json",1)||{})["12hour"]||false;
const screenWidth = g.getWidth();
+const screenHeight = g.getHeight();
const halfWidth = screenWidth / 2;
const scale = screenWidth / 240;
const REFRESH_RATE = 10E3;
@@ -58,16 +59,19 @@ function drawLine(poly, thickness){
}
}
-let settings = require('Storage').readJSON('neonx.json', 1);
-
-if (!settings) {
- settings = {
- thickness: 4,
- io: 0,
- showDate: 1
- };
+let settings = {
+ thickness: 4,
+ io: 0,
+ showDate: 1,
+ fullscreen: false,
+};
+let saved_settings = require('Storage').readJSON('neonx.json', 1) || settings;
+for (const key in saved_settings) {
+ settings[key] = saved_settings[key]
}
+
+
function drawClock(num){
let tx, ty;
@@ -79,13 +83,15 @@ function drawClock(num){
g.setColor(colors[settings.io ? 'io' : 'x'][y][x]);
if (!settings.io) {
- tx = (x * 100 + 18) * newScale;
- ty = (y * 100 + 32) * newScale;
+ newScale *= settings.fullscreen ? 1.18 : 1.0;
+ let dx = settings.fullscreen ? 0 : 18
+ tx = (x * 100 + dx) * newScale;
+ ty = (y * 100 + dx*2) * newScale;
} else {
- newScale = 0.33 + current * 0.4;
+ newScale = 0.33 + current * (settings.fullscreen ? 0.48 : 0.4);
- tx = (halfWidth - 139) * newScale + halfWidth;
- ty = (halfWidth - 139) * newScale + halfWidth + 12;
+ tx = (halfWidth - 139) * newScale + halfWidth + (settings.fullscreen ? 2 : 0);
+ ty = (halfWidth - 139) * newScale + halfWidth + (settings.fullscreen ? 2 : 12);
}
for (let i = 0; i < digits[num[y][x]].length; i++) {
@@ -116,7 +122,11 @@ function draw(date){
l2 = ('0' + d.getMinutes()).substr(-2);
}
- g.clearRect(0,24,240,240);
+ if(settings.fullscreen){
+ g.clearRect(0,0,screenWidth,screenHeight);
+ } else {
+ g.clearRect(0,24,240,240);
+ }
drawClock([l1, l2]);
}
@@ -150,4 +160,9 @@ Bangle.on('lcdPower', function(on){
});
Bangle.loadWidgets();
-Bangle.drawWidgets();
+
+if(settings.fullscreen){
+ for (let wd of WIDGETS) {wd.draw=()=>{};wd.area="";}
+} else {
+ Bangle.drawWidgets();
+}
\ No newline at end of file
diff --git a/apps/neonx/neonx.settings.js b/apps/neonx/neonx.settings.js
index 0e205e03b..3af2e0fa5 100644
--- a/apps/neonx/neonx.settings.js
+++ b/apps/neonx/neonx.settings.js
@@ -7,7 +7,8 @@
neonXSettings = {
thickness: 4,
io: 0,
- showDate: 1
+ showDate: 1,
+ fullscreen: false,
};
updateSettings();
@@ -17,7 +18,7 @@
if (!neonXSettings) resetSettings();
- let thicknesses = [1, 2, 3, 4, 5];
+ let thicknesses = [1, 2, 3, 4, 5, 6];
const menu = {
"" : { "title":"Neon X & IO"},
@@ -48,7 +49,15 @@
neonXSettings.showDate = v;
updateSettings();
}
- }
+ },
+ 'Fullscreen': {
+ value: false | neonXSettings.fullscreen,
+ format: () => (neonXSettings.fullscreen ? 'Yes' : 'No'),
+ onchange: () => {
+ neonXSettings.fullscreen = !neonXSettings.fullscreen;
+ updateSettings();
+ },
+ },
};
E.showMenu(menu);
})
diff --git a/apps/pastel/ChangeLog b/apps/pastel/ChangeLog
index d133697b3..a77fa758f 100644
--- a/apps/pastel/ChangeLog
+++ b/apps/pastel/ChangeLog
@@ -16,3 +16,4 @@
0.14: incorporated lazybones idle timer, configuration settings to come
0.15: fixed tendancy for mylocation to default to London
added setting to enable/disable idle timer warning
+0.16: make check_idle boolean setting work properly with new B2 menu
diff --git a/apps/pastel/metadata.json b/apps/pastel/metadata.json
index da3c18eae..f04a7ae54 100644
--- a/apps/pastel/metadata.json
+++ b/apps/pastel/metadata.json
@@ -2,7 +2,7 @@
"id": "pastel",
"name": "Pastel Clock",
"shortName": "Pastel",
- "version": "0.15",
+ "version": "0.16",
"description": "A Configurable clock with custom fonts, background and weather display. Has a cyclic information line that includes, day, date, battery, sunrise and sunset times",
"icon": "pastel.png",
"dependencies": {"mylocation":"app","weather":"app"},
diff --git a/apps/pastel/pastel.settings.js b/apps/pastel/pastel.settings.js
index 26dafd271..afe461f15 100644
--- a/apps/pastel/pastel.settings.js
+++ b/apps/pastel/pastel.settings.js
@@ -38,38 +38,28 @@
},
},
'Show Grid': {
- value: s.grid,
- format: () => (s.grid ? 'Yes' : 'No'),
- onchange: () => {
- s.grid = !s.grid;
+ value: !!s.grid,
+ format: v => v ? /*LANG*/"Yes":/*LANG*/"No",
+ onchange: v => {
+ s.grid = v;
save();
},
},
'Show Weather': {
- value: s.weather,
- format: () => (s.weather ? 'Yes' : 'No'),
- onchange: () => {
- s.weather = !s.weather;
+ value: !!s.weather,
+ format: v => v ? /*LANG*/"Yes":/*LANG*/"No",
+ onchange: v => {
+ s.weather = v;
save();
},
},
- // for use when the new menu system goes live
- /*
'Idle Warning': {
- value: s.idle_check,
- onchange : v => {
+ value: !!s.idle_check,
+ format: v => v ? /*LANG*/"Yes":/*LANG*/"No",
+ onchange: v => {
s.idle_check = v;
save();
},
- },
- */
- 'Idle Warning': {
- value: s.idle_check,
- format: () => (s.idle_check ? 'Yes' : 'No'),
- onchange: () => {
- s.idle_check = !s.idle_check;
- save();
- },
}
})
})
diff --git a/apps/timecal/ChangeLog b/apps/timecal/ChangeLog
new file mode 100644
index 000000000..43bff461d
--- /dev/null
+++ b/apps/timecal/ChangeLog
@@ -0,0 +1,9 @@
+0.01: Initial creation of the clock face time and calendar
+0.02: Feature Request #1154 and some findings...
+ -> get rendered time from optimisations
+ -> *BATT SAFE* only update once a minute instead of once a second
+ -> *RAM optimized* clean code, corrected minute update (timout, no intervall)
+ -> locale: weekday name (first two characters) from locale
+ -> added settings to render cal view begin day (-1: today, 0:sunday, 1:monday [default])
+0.03: a lot of more settings for outline, colors and highlights
+0.04: finalized README, fixed settings cancel, fixed border-setting
\ No newline at end of file
diff --git a/apps/timecal/README.md b/apps/timecal/README.md
new file mode 100644
index 000000000..d26f9ba4d
--- /dev/null
+++ b/apps/timecal/README.md
@@ -0,0 +1,22 @@
+# Calendar Clock
+
+## Features
+Shows the
+* Date
+* Time (hh:mm) - respecting 12/24 (uses locale string)
+* 3 weeks calendar view (last,current and next week)
+
+### The settings menu
+Calendar View can be customized
+* < Save: Exist and save the current settings
+* Show date: Choose if and how the date is displayed: none, locale (default), monthfull or monthshort.yearshort #weeknum with 0 prefixed
+* Start wday: Set day of week start. Values: 0=Sunday, 1=Monday,...,6=Saturday or -1=Relative to today (default 0: Sunday)
+* Su color: Set Sundays color. Values: none (default), red, green or blue
+* Border: show or none (default)
+* Submenu Today settings - choose how today is highlighted
+ * < Back:
+ * Color: none, red (default), green or blue
+ * Marker: Outline today graphically. Values: none (default), circle, rect(angle)
+ * Mrk.Color: Circle/rectangle color: red (default), green or blue
+ * Mrk.Size: Circle/rectangle thickness in pixel: min:1, max: 10, default:3
+* < Cancel: Exit and no change. Nevertheless missing default settings and superflous settings will be removed and saved.
diff --git a/apps/timecal/metadata.json b/apps/timecal/metadata.json
index 3237dd08a..4dd8a8ca0 100644
--- a/apps/timecal/metadata.json
+++ b/apps/timecal/metadata.json
@@ -1,13 +1,16 @@
{ "id": "timecal",
"name": "TimeCal",
"shortName":"TimeCal",
+ "version":"0.04",
+ "description": "TimeCal shows the date/time along with a 3 week calendar",
"icon": "icon.png",
- "version":"0.01",
- "description": "TimeCal shows the Time along with a 3 week calendar",
- "tags": "clock",
"type": "clock",
+ "tags": "clock,calendar",
"supports":["BANGLEJS2"],
+ "readme": "README.md",
+ "allow_emulator":true,
"storage": [
- {"name":"timecal.app.js","url":"timecal.app.js"}
+ {"name":"timecal.app.js","url":"timecal.app.js"},
+ {"name":"timecal.settings.js","url":"timecal.settings.js"}
]
}
diff --git a/apps/timecal/testing/timecal.app.test.js b/apps/timecal/testing/timecal.app.test.js
new file mode 100644
index 000000000..e41f3d848
--- /dev/null
+++ b/apps/timecal/testing/timecal.app.test.js
@@ -0,0 +1,798 @@
+//Clock renders date, time and pre,current,next week calender view
+class TimeCalClock{
+ DATE_FONT_SIZE(){ return 20; }
+ TIME_FONT_SIZE(){ return 40; }
+
+ /**
+ * @param{Date} date optional the date (e.g. for testing)
+ * @param{Settings} settings optional settings to use e.g. for testing
+ */
+ constructor(date, settings){
+ if (date)
+ this.date=date;
+
+ if (settings)
+ this._settings = settings;
+ else
+ this._settings = require("Storage").readJSON("timecal.settings.json", 1) || {};
+
+ const defaults = {
+ shwDate:1, //0:none, 1:locale, 2:month, 3:monthshort.year #week
+
+ wdStrt:0, //identical to getDay() 0->Su, 1->Mo, ... //Issue #1154: weekstart So/Mo, -1 for use today
+
+ tdyNumClr:3, //0:fg, 1:red=#E00, 2:green=#0E0, 3:blue=#00E
+ tdyMrkr:0, //0:none, 1:circle, 2:rectangle, 3:filled
+ tdyMrkClr:2, //1:red=#E00, 2:green=#0E0, 3:blue=#00E
+ tdyMrkPxl:3, //px
+
+ suClr:1, //0:fg, 1:red=#E00, 2:green=#0E0, 3:blue=#00E
+ //phColor:"#E00", //public holiday
+
+ calBrdr:false
+ };
+ for (const k in this._settings) if (!defaults.hasOwnProperty(k)) delete this._settings[k]; //remove invalid settings
+ for (const k in defaults) if(!this._settings.hasOwnProperty(k)) this._settings[k] = defaults[k]; //assign missing defaults
+
+ g.clear();
+ Bangle.setUI("clock");
+ Bangle.loadWidgets();
+ Bangle.drawWidgets();
+
+ this.centerX = Bangle.appRect.w/2;
+ this.nrgb = [g.theme.fg, "#E00", "#0E0", "#00E"]; //fg, r ,g , b
+
+ this.ABR_DAY=[];
+ if (require("locale") && require("locale").dow)
+ for (let d=0; d<=6; d++) {
+ var refDay=new Date();
+ refDay.setFullYear(1972);
+ refDay.setMonth(0);
+ refDay.setDate(2+d);
+ this.ABR_DAY.push(require("locale").dow(refDay));
+
+ }
+ else
+ this.ABR_DAY=["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
+ }
+
+ /**
+ * @returns {Object} current settings object
+ */
+ settings(){
+ return this._settings;
+ }
+
+
+ /*
+ * Run forest run
+ **/
+ draw(){
+ this.drawTime();
+
+ if (this.TZOffset===undefined || this.TZOffset!==d.getTimezoneOffset())
+ this.drawDateAndCal();
+ }
+
+ /**
+ * draw given or current time from date
+ * overwatch timezone changes
+ * schedules itself to update
+ */
+ drawTime(){
+ d=this.date ? this.date : new Date();
+ const Y=Bangle.appRect.y+this.DATE_FONT_SIZE()+10;
+
+ d=d?d :new Date();
+
+ g.setFontAlign(0, -1).setFont("Vector", this.TIME_FONT_SIZE()).setColor(g.theme.fg)
+ .clearRect(Bangle.appRect.x, Y, Bangle.appRect.x2, Y+this.TIME_FONT_SIZE()-7)
+ .drawString(("0" + require("locale").time(d, 1)).slice(-5), this.centerX, Y, true);
+ //.drawRect(Bangle.appRect.x, Y, Bangle.appRect.x2, Y+this.TIME_FONT_SIZE()-7); //DEV-Option
+
+ setTimeout(this.draw.bind(this), 60000-(d.getSeconds()*1000)-d.getMilliseconds());
+ }
+
+ /**
+ * draws given date and cal
+ * @param{Date} d provide date or uses today
+ */
+ drawDateAndCal(){
+ d=this.date ? this.date : new Date();
+
+ this.TZOffset=d.getTimezoneOffset();
+ this.drawDate();
+ this.drawCal();
+
+ if (this.tOutD) //abort exisiting
+ clearTimeout(this.tOutD);
+ this.tOutD=setTimeout(this.drawDateAndCal.bind(this), 86400000-(d.getHours()*24*60*1000)-(d.getMinutes()*60*1000)-d.getSeconds()-d.getMilliseconds());
+ }
+
+ /**
+ * draws given date as defiend in settings
+ */
+ drawDate(){
+ d=this.date ? this.date : new Date();
+
+ const FONT_SIZE=20;
+ const Y=Bangle.appRect.y;
+ var render=false;
+ var dateStr = "";
+ if (this.settings().shwDate>0) { //skip if exactly -none
+ const dateSttngs = ["","l","M","m.Y #W"];
+ for (let c of dateSttngs[this.settings().shwDate]) { //add part as configured
+ switch (c){
+ case "l":{ //locale
+ render=true;
+ dateStr+=require("locale").date(d,1);
+ break;
+ }
+ case "m":{ //month e.g. Jan.
+ render=true;
+ dateStr+=require("locale").month(d,1);
+ break;
+ }
+ case "M":{ //month e.g. January
+ render=true;
+ dateStr+=require("locale").month(d,0);
+ break;
+ }
+ case "y":{ //year e.g. 22
+ render=true;
+ dateStr+=d.getFullYear().slice(-2);
+ break;
+ }
+ case "Y":{ //year e.g. 2022
+ render=true;
+ dateStr+=d.getFullYear();
+ break;
+ }
+ case "w":{ //week e.g. #2
+ dateStr+=(this.ISO8601calWeek(d));
+ break;
+ }
+ case "W":{ //week e.g. #02
+ dateStr+=("0"+this.ISO8601calWeek(d)).slice(-2);
+ break;
+ }
+ default: //append c
+ dateStr+=c;
+ render=dateStr.length>0;
+ break; //noop
+ }
+ }
+ }
+ if (render){
+ g.setFont("Vector", FONT_SIZE).setColor(g.theme.fg).setFontAlign(0, -1).clearRect(Bangle.appRect.x, Y, Bangle.appRect.x2, Y+FONT_SIZE-3).drawString(dateStr,this.centerX,Y);
+ }
+ //g.drawRect(Bangle.appRect.x, Y, Bangle.appRect.x2, Y+FONT_SIZE-3); //DEV-Option
+ }
+
+ /**
+ * draws calender week view (-1,0,1) for given date
+ */
+ drawCal(){
+ d=this.date ? this.date : new Date();
+
+ const DAY_NAME_FONT_SIZE=10;
+ const CAL_Y=Bangle.appRect.y+this.DATE_FONT_SIZE()+10+this.TIME_FONT_SIZE()+3;
+ const CAL_AREA_H=Bangle.appRect.h-CAL_Y+24; //+24: top widegtes only
+ const CELL_W=Bangle.appRect.w/7; //cell width
+ const CELL_H=(CAL_AREA_H-DAY_NAME_FONT_SIZE)/3; //cell heigth
+ const DAY_NUM_FONT_SIZE=Math.min(CELL_H-1,15); //size down, max 15
+
+ g.setFont("Vector", DAY_NAME_FONT_SIZE).setColor(g.theme.fg).setFontAlign(-1, -1).clearRect(Bangle.appRect.x, CAL_Y, Bangle.appRect.x2, CAL_Y+CAL_AREA_H);
+
+ //draw grid & Headline
+ const dNames = this.ABR_DAY.map((a) => a.length<=2 ? a : a.substr(0, 2)); //force shrt 2
+ for(var dNo=0; dNo=0 ? (dNo+this.settings().wdStrt)%7 : (dNo+d.getDay()+4)%7;
+ const dName=dNames[dIdx];
+ if(dNo>0)
+ g.drawLine(dNo*CELL_W, CAL_Y, dNo*CELL_W, CAL_Y+CAL_AREA_H-1);
+
+ if (dIdx==0) g.setColor(this.nrgb[this.settings().suClr]); //sunday maybe colorize txt
+ g.drawString(dName, dNo*CELL_W+(CELL_W-g.stringWidth(dName))/2+2, CAL_Y+1).setColor(g.theme.fg);
+ }
+
+ var nextY=CAL_Y+DAY_NAME_FONT_SIZE;
+
+ for(i=0; i<3; i++){
+ const y=nextY+i*CELL_H;
+ g.drawLine(Bangle.appRect.x, y, Bangle.appRect.x2, y);
+ }
+
+ g.setFont("Vector", DAY_NUM_FONT_SIZE);
+
+ //write days
+ const tdyDate=d.getDate();
+ const days=this.settings().wdStrt>=0 ? 7+((7+d.getDay()-this.settings().wdStrt)%7) : 10;//start day (week before=7 days + days in this week realtive to week start) or fixed 7+3 days
+ var rD=new Date(d.getTime());
+ rD.setDate(rD.getDate()-days);
+ var rDate=rD.getDate();
+ for(var y=0; y<3; y++){
+ for(var x=0; x",
+ cases: [
+ {
+ value: "required,",
+ beforeTxt: "optional,",
+ beforeExpression: "optional,",
+ afterText: "optional,",
+ afterExpression: "optional,"
+ }
+ ],
+ constructorParams: ["optional: ","|TEST_SETTINGS|","..."], //TEST_SETTINGS will be replcaed with each current {setting: case}
+ functionNames: ["required, ", "..."],
+ functionParams: ["optional: ","|TEST_SETTINGS|","..."]
+ };
+ }
+
+ constructor(data){
+
+ this._validate(data);
+
+ this.setting = data.setting;
+ this.cases = data.cases.map((entry) => {
+ return {
+ value: entry.value,
+ beforeTxt: entry.beforeTxt||"",
+ beforeExpression: entry.beforeExpression||true,
+ afterTxt: entry.afterTxt||"",
+ afterExpression: entry.afterExpression||true
+ };
+ });
+ this.constructorParams = data.constructorParams;
+ this.functionNames = data.functionNames;
+ this.functionParams = data.functionParams;
+ }
+
+ /**
+ * validates the given data config
+ */
+ _validate(data){
+ //validate given config
+ if (!data.setting) throw new EmptyMandatoryError("setting", data, this.TEST_SETTING_SAMPLE());
+ if (!(data.cases instanceof Array) || data.cases.length==0) throw new EmptyMandatoryError("cases", data, this.TEST_SETTING_SAMPLE());
+ if (!(data.functionNames instanceof Array) || data.functionNames==0) throw new EmptyMandatoryError("functionNames", data, this.TEST_SETTING_SAMPLE());
+
+ data.cases.forEach((entry,idx) => {
+ if (entry.value === undefined) throw new EmptyMandatoryError("cases["+idx+"].value", entry, this.TEST_SETTING_SAMPLE());
+ });
+ }
+}
+
+/*************************************************************************/
+
+/**
+ * Testing a Bangle object
+ */
+class BangleTestRunner{
+ /**
+ * create for ObjClass
+ * @param {Class} objClass
+ * @param {LogSeverity} minSeverity to Log
+ */
+ constructor(objClass, minSeverity){
+ this.TESTCASE_MSG_BEFORE_TIMEOUT = 1000; //5s
+ this.TESTCASE_RUN_TIMEOUT = 1000; //5s
+ this.TESTCASE_MSG_AFTER_TIMEOUT = 1000; //5s
+
+ this.oClass = objClass;
+ this.minSvrty = minSeverity;
+ this.tests = [];
+
+ this.currentCaseNum = this.currentTestNum = this.currentTest = this.currentCase = undefined;
+ }
+
+ /**
+ * add a Setting Test, return instance for chaining
+ * @param {TestSetting}
+ */
+ addTestSettings(sttngs) {
+ this.tests.push(new TestSetting(sttngs));
+ return this;
+ }
+
+ /**
+ * Test execution of all tests
+ */
+ execute() {
+ this._init();
+ while (this._nextTest()) {
+ this._beforeTest();
+ while (this._nextCase()) {
+ this._beforeCase();
+ this._runCase();
+ this._afterCase();
+ }
+ this._afterTest();
+ this._firstCase();
+ }
+ this._exit();
+ }
+
+ /**
+ * global prepare - before all test
+ */
+ _init() {
+ console.log(this._nowTime(), ">>init");
+ this.currentTestNum=-1;
+ this.currentCaseNum=-1;
+ }
+
+ /**
+ * before each test
+ */
+ _beforeTest() {
+ console.log(this._nowTime(), ">>test #" + this.currentTestNum);
+ }
+
+ /**
+ * befor each testcase
+ */
+ _beforeCase() {
+ console.log(this.currentTest);
+ console.log(this._nowTime(), ">>case #" + this.currentTestNum + "." + this.currentCaseNum + "/" + (this.currentTest.cases.length-1));
+ if (this.currentTest instanceof TestSetting)
+ console.log(this.currentTest.setting+"="+this.currentCase.value+"/n"+(this.currentCase.beforeTxt ? "#"+this.currentCase.beforeTxt : ""));
+ }
+
+ /**
+ * testcase runner
+ */
+ _runCase() {
+ console.log(this._nowTime(), ">>running...");
+ var returns = [];
+ this.currentTest.functionNames.forEach((fName) => {
+ var settings={}; settings[this.currentTest.setting] = this.currentCase.value;
+ var cParams = this.currentTest.constructorParams||[];
+ cParams = cParams.map((v) => (v && v instanceof String && v==="|TEST_SETTINGS|") ? settings : v);//replace settings in call params
+ var fParams = this.currentTest.functionParams||[];
+ fParams = fParams.map((v) => (v && v instanceof String && v==="|TEST_SETTINGS|") ? settings : v);//replace settings in call params
+
+ var creatorFunc = new Function("console.log('Constructor params:', arguments); return new " + this.oClass + "(arguments[0],arguments[1],arguments[2],arguments[3],arguments[4],arguments[5],arguments[6],arguments[7],arguments[8],arguments[9])"); //prepare spwan arguments[0],arguments[1]
+ let instance = creatorFunc.call(this.oClass, cParams[0], cParams[1], cParams[2], cParams[3], cParams[4], cParams[5], cParams[6], cParams[7], cParams[8], cParams[9]); //spwan
+
+ console.log(">>"+this.oClass+"["+fName+"]()");
+
+ console.log('Instance:', instance);
+ console.log('Function params:', fParams);
+ returns.push(instance[fName](fParams[0], fParams[1], fParams[2], fParams[3], fParams[4], fParams[5], fParams[6], fParams[7], fParams[8], fParams[9])); //run method and store result
+ g.dump();
+ console.log("<<"+this.oClass+"["+fName+"]()");
+ });
+ console.log(this._nowTime(), "<<...running");
+ }
+
+ /**
+ * after each testcase
+ */
+ _afterCase() {
+ if (this.currentTest instanceof TestSetting)
+ if (this.currentCase.afterTxt.length>0)
+ console.log("++EXPECTED:" + this.currentCase.afterTxt + "EXPECTED++");
+ console.log(this._nowTime(), "< setTimeout(resolve, sec));
+ }
+
+ _waits(sec) {
+ this._delay(1).then();
+ }
+
+ _log() {
+
+ }
+
+ _nextTest() {
+ if (this.currentTestNum>=-1 && (this.currentTestNum+1)=-1 && (this.currentCaseNum+1)Su, 1->Mo, ... //Issue #1154: weekstart So/Mo, -1 for use today
+
+ tdyNumClr:3, //0:fg, 1:red=#E00, 2:green=#0E0, 3:blue=#00E
+ tdyMrkr:0, //0:none, 1:circle, 2:rectangle, 3:filled
+ tdyMrkClr:2, //1:red=#E00, 2:green=#0E0, 3:blue=#00E
+ tdyMrkPxl:3, //px
+
+ suClr:1, //0:fg, 1:red=#E00, 2:green=#0E0, 3:blue=#00E
+ //phColor:"#E00", //public holiday
+
+ calBrdr:false
+ };
+ for (const k in this._settings) if (!defaults.hasOwnProperty(k)) delete this._settings[k]; //remove invalid settings
+ for (const k in defaults) if(!this._settings.hasOwnProperty(k)) this._settings[k] = defaults[k]; //assign missing defaults
+
+ g.clear();
+ Bangle.setUI("clock");
+ Bangle.loadWidgets();
+ Bangle.drawWidgets();
+
+ this.centerX = Bangle.appRect.w/2;
+ this.nrgb = [g.theme.fg, "#E00", "#0E0", "#00E"]; //fg, r ,g , b
+
+ this.ABR_DAY=[];
+ if (require("locale") && require("locale").dow)
+ for (let d=0; d<=6; d++) {
+ var refDay=new Date();
+ refDay.setFullYear(1972);
+ refDay.setMonth(0);
+ refDay.setDate(2+d);
+ this.ABR_DAY.push(require("locale").dow(refDay));
-function drawCal(d){
- var calStart = 101;
- var cellSize = g.getWidth() / 7;
- var halfSize = cellSize / 2;
- g.clearRect(0,calStart,g.getWidth(),g.getHeight());
- g.drawLine(0,calStart,g.getWidth(),calStart);
- var days = ["Mo","Tu","We","Th","Fr","Sa","Su"];
- g.setFont("Vector",10);
- g.setColor(fontColor);
- g.setFontAlign(-1,-1,0);
- for(var i = 0; i < days.length;i++){
- g.drawString(days[i],i*cellSize+5,calStart -11);
- if(i!=0){
- g.drawLine(i*cellSize,calStart,i*cellSize,g.getHeight());
- }
- }
- var cellHeight = (g.getHeight() -calStart ) / 3;
- for(var i = 0;i < 3;i++){
- var starty = calStart + i * cellHeight;
- g.drawLine(0,starty,g.getWidth(),starty);
- }
-
- g.setFont("Vector",15);
-
- var dayOfWeek = d.getDay();
- var dayRem = d.getDay() - 1;
- if(dayRem <0){
- dayRem = 0;
- }
-
- var start = new Date();
- start.setDate(start.getDate()-(7+dayRem));
- g.setFontAlign(0,-1,0);
- for (var y = 0;y < 3; y++){
- for(var x = 0;x < 7; x++){
- if(start.getDate() === d.getDate()){
- g.setColor(accentColor);
- }else{
- g.setColor(fontColor);
}
- g.drawString(start.getDate(),x*cellSize +(cellSize / 2) + 2,calStart+(cellHeight*y) + 5);
- start.setDate(start.getDate()+1);
+ else
+ this.ABR_DAY=["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
+ }
+
+ /**
+ * @returns {Object} current settings object
+ */
+ settings(){
+ return this._settings;
+ }
+
+
+ /*
+ * Run forest run
+ **/
+ draw(){
+ this.drawTime();
+
+ if (this.TZOffset===undefined || this.TZOffset!==d.getTimezoneOffset())
+ this.drawDateAndCal();
}
+
+ /**
+ * draw given or current time from date
+ * overwatch timezone changes
+ * schedules itself to update
+ */
+ drawTime(){
+ d=this.date ? this.date : new Date();
+ const Y=Bangle.appRect.y+this.DATE_FONT_SIZE()+10;
+
+ d=d?d :new Date();
+
+ g.setFontAlign(0, -1).setFont("Vector", this.TIME_FONT_SIZE()).setColor(g.theme.fg)
+ .clearRect(Bangle.appRect.x, Y, Bangle.appRect.x2, Y+this.TIME_FONT_SIZE()-7)
+ .drawString(("0" + require("locale").time(d, 1)).slice(-5), this.centerX, Y, true);
+ //.drawRect(Bangle.appRect.x, Y, Bangle.appRect.x2, Y+this.TIME_FONT_SIZE()-7); //DEV-Option
+
+ setTimeout(this.draw.bind(this), 60000-(d.getSeconds()*1000)-d.getMilliseconds());
+ }
+
+ /**
+ * draws given date and cal
+ * @param{Date} d provide date or uses today
+ */
+ drawDateAndCal(){
+ d=this.date ? this.date : new Date();
+
+ this.TZOffset=d.getTimezoneOffset();
+ this.drawDate();
+ this.drawCal();
+
+ if (this.tOutD) //abort exisiting
+ clearTimeout(this.tOutD);
+ this.tOutD=setTimeout(this.drawDateAndCal.bind(this), 86400000-(d.getHours()*24*60*1000)-(d.getMinutes()*60*1000)-d.getSeconds()-d.getMilliseconds());
+ }
+
+ /**
+ * draws given date as defiend in settings
+ */
+ drawDate(){
+ d=this.date ? this.date : new Date();
+
+ const FONT_SIZE=20;
+ const Y=Bangle.appRect.y;
+ var render=false;
+ var dateStr = "";
+ if (this.settings().shwDate>0) { //skip if exactly -none
+ const dateSttngs = ["","l","M","m.Y #W"];
+ for (let c of dateSttngs[this.settings().shwDate]) { //add part as configured
+ switch (c){
+ case "l":{ //locale
+ render=true;
+ dateStr+=require("locale").date(d,1);
+ break;
+ }
+ case "m":{ //month e.g. Jan.
+ render=true;
+ dateStr+=require("locale").month(d,1);
+ break;
+ }
+ case "M":{ //month e.g. January
+ render=true;
+ dateStr+=require("locale").month(d,0);
+ break;
+ }
+ case "y":{ //year e.g. 22
+ render=true;
+ dateStr+=d.getFullYear().slice(-2);
+ break;
+ }
+ case "Y":{ //year e.g. 2022
+ render=true;
+ dateStr+=d.getFullYear();
+ break;
+ }
+ case "w":{ //week e.g. #2
+ dateStr+=(this.ISO8601calWeek(d));
+ break;
+ }
+ case "W":{ //week e.g. #02
+ dateStr+=("0"+this.ISO8601calWeek(d)).slice(-2);
+ break;
+ }
+ default: //append c
+ dateStr+=c;
+ render=dateStr.length>0;
+ break; //noop
+ }
+ }
+ }
+ if (render){
+ g.setFont("Vector", FONT_SIZE).setColor(g.theme.fg).setFontAlign(0, -1).clearRect(Bangle.appRect.x, Y, Bangle.appRect.x2, Y+FONT_SIZE-3).drawString(dateStr,this.centerX,Y);
+ }
+ //g.drawRect(Bangle.appRect.x, Y, Bangle.appRect.x2, Y+FONT_SIZE-3); //DEV-Option
+ }
+
+ /**
+ * draws calender week view (-1,0,1) for given date
+ */
+ drawCal(){
+ d=this.date ? this.date : new Date();
+
+ const DAY_NAME_FONT_SIZE=10;
+ const CAL_Y=Bangle.appRect.y+this.DATE_FONT_SIZE()+10+this.TIME_FONT_SIZE()+3;
+ const CAL_AREA_H=Bangle.appRect.h-CAL_Y+24; //+24: top widegtes only
+ const CELL_W=Bangle.appRect.w/7; //cell width
+ const CELL_H=(CAL_AREA_H-DAY_NAME_FONT_SIZE)/3; //cell heigth
+ const DAY_NUM_FONT_SIZE=Math.min(CELL_H-1,15); //size down, max 15
+
+ g.setFont("Vector", DAY_NAME_FONT_SIZE).setColor(g.theme.fg).setFontAlign(-1, -1).clearRect(Bangle.appRect.x, CAL_Y, Bangle.appRect.x2, CAL_Y+CAL_AREA_H);
+
+ //draw grid & Headline
+ const dNames = this.ABR_DAY.map((a) => a.length<=2 ? a : a.substr(0, 2)); //force shrt 2
+ for(var dNo=0; dNo=0 ? (dNo+this.settings().wdStrt)%7 : (dNo+d.getDay()+4)%7;
+ const dName=dNames[dIdx];
+ if(dNo>0)
+ g.drawLine(dNo*CELL_W, CAL_Y, dNo*CELL_W, CAL_Y+CAL_AREA_H-1);
+
+ if (dIdx==0) g.setColor(this.nrgb[this.settings().suClr]); //sunday maybe colorize txt
+ g.drawString(dName, dNo*CELL_W+(CELL_W-g.stringWidth(dName))/2+2, CAL_Y+1).setColor(g.theme.fg);
+ }
+
+ var nextY=CAL_Y+DAY_NAME_FONT_SIZE;
+
+ for(i=0; i<3; i++){
+ const y=nextY+i*CELL_H;
+ g.drawLine(Bangle.appRect.x, y, Bangle.appRect.x2, y);
+ }
+
+ g.setFont("Vector", DAY_NUM_FONT_SIZE);
+
+ //write days
+ const tdyDate=d.getDate();
+ const days=this.settings().wdStrt>=0 ? 7+((7+d.getDay()-this.settings().wdStrt)%7) : 10;//start day (week before=7 days + days in this week realtive to week start) or fixed 7+3 days
+ var rD=new Date(d.getTime());
+ rD.setDate(rD.getDate()-days);
+ var rDate=rD.getDate();
+ for(var y=0; y<3; y++){
+ for(var x=0; xSu, 1->Mo, ... //Issue #1154: weekstart So/Mo, -1 for use today
+
+ tdyNumClr:3, //0:fg, 1:red=#E00, 2:green=#0E0, 3:blue=#00E
+ tdyMrkr:0, //0:none, 1:circle, 2:rectangle, 3:filled
+ tdyMrkClr:2, //1:red=#E00, 2:green=#0E0, 3:blue=#00E
+ tdyMrkPxl:3, //px
+
+ suClr:1, //0:fg, 1:red=#E00, 2:green=#0E0, 3:blue=#00E
+ //phColor:"#E00", //public holiday
+
+ calBrdr:false
+ };
+ validSttngs = require("Storage").readJSON("timecal.validSttngs.json", 1) || {};
+ for (const k in validSttngs) if (!DEFAULTS.hasOwnProperty(k)) delete this.validSttngs[k]; //remove invalid settings
+ for (const k in DEFAULTS) if(!validSttngs.hasOwnProperty(k)) validSttngs[k] = validSttngs[k]; //assign missing defaults
+
+ var changedSttngs = Object.assign({}, validSttngs);
+
+ var saveExitSettings = () => {
+ require('Storage').writeJSON(FILE, changedSttngs);
+ exit();
+ };
+
+ var cancelExitSettings = () => {
+ require('Storage').writeJSON(FILE, validSttngs);
+ exit();
+ };
+
+ var showMainMenu = () => {
+ E.showMenu({
+ "": {
+ "title": "TimeCal "+ /*LANG*/"settings"
+ },
+ /*LANG*/"< Save": () => saveExitSettings(),
+ /*LANG*/"Show date": {
+ value: validSttngs.shwDate,
+ min: 0, max: 3,
+ format: v => [/*LANG*/"none", /*LANG*/"locale", /*LANG*/"M", /*LANG*/"m.Y #W"][v],
+ onchange: v => validSttngs.shwDate = v
+ },
+ /*LANG*/"Start wday": {
+ value: validSttngs.wdStrt,
+ min: -1, max: 6,
+ format: v => v>=0 ? ABR_DAY[v] : /*LANG*/"today",
+ onchange: v => validSttngs.wdStrt = v
+ },
+ /*LANG*/"Su color": {
+ value: validSttngs.suClr,
+ min: 0, max: 3,
+ format: v => [/*LANG*/"none", /*LANG*/"red", /*LANG*/"green", /*LANG*/"blue"][v],
+ onchange: v => validSttngs.suClr = v
+ },
+ /*LANG*/"Border": {
+ value: validSttngs.calBrdr,
+ format: v => v ? /*LANG*/"show" : /*LANG*/"none",
+ onchange: v => validSttngs.calBrdr = v
+ },
+ /*LANG*/"Today settings": () => {
+ showTodayMenu();
+ },
+ /*LANG*/"< Cancel": () => cancelExitSettings()
+ });
+ };
+
+ var showTodayMenu = () => {
+ E.showMenu({
+ "": {
+ "title": /*LANG*/"Today settings"
+ },
+ "< Back": () => showMainMenu(),
+ /*LANG*/"Color": {
+ value: validSttngs.tdyNumClr,
+ min: 0, max: 3,
+ format: v => [/*LANG*/"none", /*LANG*/"red", /*LANG*/"green", /*LANG*/"blue"][v],
+ onchange: v => validSttngs.tdyNumClr = v
+ },
+ /*LANG*/"Marker": {
+ value: validSttngs.tdyMrkr,
+ min: 0, max: 3,
+ format: v => [/*LANG*/"none", /*LANG*/"circle", /*LANG*/"rectangle", /*LANG*/"filled"][v],
+ onchange: v => validSttngs.tdyMrkr = v
+ },
+ /*LANG*/"Mrk.Color": {
+ value: validSttngs.tdyMrkClr,
+ min: 0, max: 2,
+ format: v => [/*LANG*/"red", /*LANG*/"green", /*LANG*/"blue"][v],
+ onchange: v => validSttngs.tdyMrkClr = v
+ },
+ /*LANG*/"Mrk.Size": {
+ value: validSttngs.tdyMrkPxl,
+ min: 1, max: 10,
+ format: v => v+"px",
+ onchange: v => validSttngs.tdyMrkPxl = v
+ },
+ /*LANG*/"< Cancel": () => cancelExitSettings()
+ });
+ };
+
+ showMainMenu();
+});
diff --git a/apps/widbars/ChangeLog b/apps/widbars/ChangeLog
index 4c21f3ace..61e28e6e4 100644
--- a/apps/widbars/ChangeLog
+++ b/apps/widbars/ChangeLog
@@ -1 +1,3 @@
0.01: New Widget!
+0.02: Battery bar turns yellow on charge
+ Memory status bar does not trigger garbage collect
diff --git a/apps/widbars/metadata.json b/apps/widbars/metadata.json
index e8d52c90a..a9981305c 100644
--- a/apps/widbars/metadata.json
+++ b/apps/widbars/metadata.json
@@ -1,7 +1,7 @@
{
"id": "widbars",
"name": "Bars Widget",
- "version": "0.01",
+ "version": "0.02",
"description": "Display several measurements as vertical bars.",
"icon": "icon.png",
"screenshots": [{"url":"screenshot.png"}],
diff --git a/apps/widbars/widget.js b/apps/widbars/widget.js
index a1134f31f..cceeb0897 100644
--- a/apps/widbars/widget.js
+++ b/apps/widbars/widget.js
@@ -42,19 +42,25 @@
if (top) g .clearRect(x,y, x+w-1,y+top-1); // erase above bar
if (f) g.setColor(col).fillRect(x,y+top, x+w-1,y+h-1); // even for f=0.001 this is still 1 pixel high
}
+ let batColor='#0f0';
function draw() {
g.reset();
const x = this.x, y = this.y,
- m = process.memory();
+ m = process.memory(false);
let b=0;
// ==HRM== bar(x+(w*b++),y,'#f00'/*red */,bpm/200); // >200 seems very unhealthy; if we have no valid bpm this will just be empty space
// ==Temperature== bar(x+(w*b++),y,'#ff0'/*yellow */,E.getTemperature()/50); // you really don't want to wear a watch that's hotter than 50°C
bar(x+(w*b++),y,g.theme.dark?'#0ff':'#00f'/*cyan/blue*/,1-(require('Storage').getFree() / process.env.STORAGE));
bar(x+(w*b++),y,'#f0f'/*magenta*/,m.usage/m.total);
- bar(x+(w*b++),y,'#0f0'/*green */,E.getBattery()/100);
+ bar(x+(w*b++),y,batColor,E.getBattery()/100);
}
let redraw;
+ Bangle.on('charging', function(charging) {
+ batColor=charging?'#ff0':'#0f0';
+ WIDGETS["bars"].draw();
+ });
+
Bangle.on('lcdPower', on => {
if (redraw) clearInterval(redraw)
redraw = undefined;