Merge branch 'master' of github.com:espruino/BangleApps
commit
16f6c577b9
|
|
@ -0,0 +1 @@
|
||||||
|
0.01: Release
|
||||||
|
|
@ -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
|
||||||
|
<a href="https://www.flaticon.com/free-icons/info" title="info icons">Info icons created by Freepik - Flaticon</a>
|
||||||
|
|
@ -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();
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
require("heatshrink").decompress(atob("mEwwcBkmSpICDBwcJBYwCDpAhFggRJGg8SCI+ABgU//gSDCI4JBj//AAX4JRAIBg4QDAAPgBIJWGgIQFAAI+BLglAgEPCI/wEgJoEgYQHAAPANwhWFAApcBCIWQgAQJAAMAgSMDCJiSCwB6GQA6eCn5TFL4q5BUgIRF/wuBv4RGkCeGO4IREUgMBCJCVGCISwIWw0BYRLIICLBHHCJRrGCIQIFR44I5LIoRaPpARcdIwRJfYMBCJuACKUkgE/a5f8gEJCJD7FCIeAg78FAAvggFJCIMACJZOBCIOQCJsCCIOSgEfCBP4gESCIZTFOIwRDoDIGaguSCIVIgCkFTwcAggRDpIYBQAx6BgAOCAQYIBLghWBTwQRFFgIABXIIFDBwgCDBYQAENAYCFLgIAEKwpKIIhA="))
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 1.5 KiB |
|
|
@ -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}
|
||||||
|
]
|
||||||
|
}
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 3.5 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 3.3 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 3.4 KiB |
|
|
@ -1 +1,2 @@
|
||||||
0.01: Initial release
|
0.01: Initial release
|
||||||
|
0.02: Optional fullscreen mode
|
||||||
|
|
@ -4,8 +4,8 @@
|
||||||
|---------------------------------|--------------------------------------|
|
|---------------------------------|--------------------------------------|
|
||||||
| <center>Neon X</center> | <center>Neon IO X</center> |
|
| <center>Neon X</center> | <center>Neon IO X</center> |
|
||||||
|
|
||||||
This is a clock based on Pebble's Neon X and Neon IO X watchfaces by Sam Jerichow.
|
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
|
Can be switched between in the Settings menu, which can be accessed through
|
||||||
the app/widget settings menu of the Bangle.js
|
the app/widget settings menu of the Bangle.js
|
||||||
|
|
||||||
## Settings
|
## 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.
|
Activate the Neon IO X clock look, a bit hard to read until one gets used to it.
|
||||||
|
|
||||||
### Thickness
|
### Thickness
|
||||||
The thickness of watch lines, from 1 to 5.
|
The thickness of watch lines, from 1 to 6.
|
||||||
|
|
||||||
### Date on touch
|
### Date on touch
|
||||||
Shows the current date as DD MM on touch and reverts back to time after 5 seconds or with another 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.
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
"id": "neonx",
|
"id": "neonx",
|
||||||
"name": "Neon X & IO X Clock",
|
"name": "Neon X & IO X Clock",
|
||||||
"shortName": "Neon X Clock",
|
"shortName": "Neon X Clock",
|
||||||
"version": "0.01",
|
"version": "0.02",
|
||||||
"description": "Pebble Neon X & Neon IO X for Bangle.js",
|
"description": "Pebble Neon X & Neon IO X for Bangle.js",
|
||||||
"icon": "neonx.png",
|
"icon": "neonx.png",
|
||||||
"type": "clock",
|
"type": "clock",
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,7 @@ const colors = {
|
||||||
|
|
||||||
const is12hour = (require("Storage").readJSON("setting.json",1)||{})["12hour"]||false;
|
const is12hour = (require("Storage").readJSON("setting.json",1)||{})["12hour"]||false;
|
||||||
const screenWidth = g.getWidth();
|
const screenWidth = g.getWidth();
|
||||||
|
const screenHeight = g.getHeight();
|
||||||
const halfWidth = screenWidth / 2;
|
const halfWidth = screenWidth / 2;
|
||||||
const scale = screenWidth / 240;
|
const scale = screenWidth / 240;
|
||||||
const REFRESH_RATE = 10E3;
|
const REFRESH_RATE = 10E3;
|
||||||
|
|
@ -58,16 +59,19 @@ function drawLine(poly, thickness){
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let settings = require('Storage').readJSON('neonx.json', 1);
|
let settings = {
|
||||||
|
thickness: 4,
|
||||||
if (!settings) {
|
io: 0,
|
||||||
settings = {
|
showDate: 1,
|
||||||
thickness: 4,
|
fullscreen: false,
|
||||||
io: 0,
|
};
|
||||||
showDate: 1
|
let saved_settings = require('Storage').readJSON('neonx.json', 1) || settings;
|
||||||
};
|
for (const key in saved_settings) {
|
||||||
|
settings[key] = saved_settings[key]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function drawClock(num){
|
function drawClock(num){
|
||||||
let tx, ty;
|
let tx, ty;
|
||||||
|
|
||||||
|
|
@ -79,13 +83,15 @@ function drawClock(num){
|
||||||
g.setColor(colors[settings.io ? 'io' : 'x'][y][x]);
|
g.setColor(colors[settings.io ? 'io' : 'x'][y][x]);
|
||||||
|
|
||||||
if (!settings.io) {
|
if (!settings.io) {
|
||||||
tx = (x * 100 + 18) * newScale;
|
newScale *= settings.fullscreen ? 1.18 : 1.0;
|
||||||
ty = (y * 100 + 32) * newScale;
|
let dx = settings.fullscreen ? 0 : 18
|
||||||
|
tx = (x * 100 + dx) * newScale;
|
||||||
|
ty = (y * 100 + dx*2) * newScale;
|
||||||
} else {
|
} else {
|
||||||
newScale = 0.33 + current * 0.4;
|
newScale = 0.33 + current * (settings.fullscreen ? 0.48 : 0.4);
|
||||||
|
|
||||||
tx = (halfWidth - 139) * newScale + halfWidth;
|
tx = (halfWidth - 139) * newScale + halfWidth + (settings.fullscreen ? 2 : 0);
|
||||||
ty = (halfWidth - 139) * newScale + halfWidth + 12;
|
ty = (halfWidth - 139) * newScale + halfWidth + (settings.fullscreen ? 2 : 12);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let i = 0; i < digits[num[y][x]].length; i++) {
|
for (let i = 0; i < digits[num[y][x]].length; i++) {
|
||||||
|
|
@ -116,7 +122,11 @@ function draw(date){
|
||||||
l2 = ('0' + d.getMinutes()).substr(-2);
|
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]);
|
drawClock([l1, l2]);
|
||||||
}
|
}
|
||||||
|
|
@ -150,4 +160,9 @@ Bangle.on('lcdPower', function(on){
|
||||||
});
|
});
|
||||||
|
|
||||||
Bangle.loadWidgets();
|
Bangle.loadWidgets();
|
||||||
Bangle.drawWidgets();
|
|
||||||
|
if(settings.fullscreen){
|
||||||
|
for (let wd of WIDGETS) {wd.draw=()=>{};wd.area="";}
|
||||||
|
} else {
|
||||||
|
Bangle.drawWidgets();
|
||||||
|
}
|
||||||
|
|
@ -7,7 +7,8 @@
|
||||||
neonXSettings = {
|
neonXSettings = {
|
||||||
thickness: 4,
|
thickness: 4,
|
||||||
io: 0,
|
io: 0,
|
||||||
showDate: 1
|
showDate: 1,
|
||||||
|
fullscreen: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
updateSettings();
|
updateSettings();
|
||||||
|
|
@ -17,7 +18,7 @@
|
||||||
|
|
||||||
if (!neonXSettings) resetSettings();
|
if (!neonXSettings) resetSettings();
|
||||||
|
|
||||||
let thicknesses = [1, 2, 3, 4, 5];
|
let thicknesses = [1, 2, 3, 4, 5, 6];
|
||||||
|
|
||||||
const menu = {
|
const menu = {
|
||||||
"" : { "title":"Neon X & IO"},
|
"" : { "title":"Neon X & IO"},
|
||||||
|
|
@ -48,7 +49,15 @@
|
||||||
neonXSettings.showDate = v;
|
neonXSettings.showDate = v;
|
||||||
updateSettings();
|
updateSettings();
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
'Fullscreen': {
|
||||||
|
value: false | neonXSettings.fullscreen,
|
||||||
|
format: () => (neonXSettings.fullscreen ? 'Yes' : 'No'),
|
||||||
|
onchange: () => {
|
||||||
|
neonXSettings.fullscreen = !neonXSettings.fullscreen;
|
||||||
|
updateSettings();
|
||||||
|
},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
E.showMenu(menu);
|
E.showMenu(menu);
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -16,3 +16,4 @@
|
||||||
0.14: incorporated lazybones idle timer, configuration settings to come
|
0.14: incorporated lazybones idle timer, configuration settings to come
|
||||||
0.15: fixed tendancy for mylocation to default to London
|
0.15: fixed tendancy for mylocation to default to London
|
||||||
added setting to enable/disable idle timer warning
|
added setting to enable/disable idle timer warning
|
||||||
|
0.16: make check_idle boolean setting work properly with new B2 menu
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
"id": "pastel",
|
"id": "pastel",
|
||||||
"name": "Pastel Clock",
|
"name": "Pastel Clock",
|
||||||
"shortName": "Pastel",
|
"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",
|
"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",
|
"icon": "pastel.png",
|
||||||
"dependencies": {"mylocation":"app","weather":"app"},
|
"dependencies": {"mylocation":"app","weather":"app"},
|
||||||
|
|
|
||||||
|
|
@ -38,38 +38,28 @@
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
'Show Grid': {
|
'Show Grid': {
|
||||||
value: s.grid,
|
value: !!s.grid,
|
||||||
format: () => (s.grid ? 'Yes' : 'No'),
|
format: v => v ? /*LANG*/"Yes":/*LANG*/"No",
|
||||||
onchange: () => {
|
onchange: v => {
|
||||||
s.grid = !s.grid;
|
s.grid = v;
|
||||||
save();
|
save();
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
'Show Weather': {
|
'Show Weather': {
|
||||||
value: s.weather,
|
value: !!s.weather,
|
||||||
format: () => (s.weather ? 'Yes' : 'No'),
|
format: v => v ? /*LANG*/"Yes":/*LANG*/"No",
|
||||||
onchange: () => {
|
onchange: v => {
|
||||||
s.weather = !s.weather;
|
s.weather = v;
|
||||||
save();
|
save();
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
// for use when the new menu system goes live
|
|
||||||
/*
|
|
||||||
'Idle Warning': {
|
'Idle Warning': {
|
||||||
value: s.idle_check,
|
value: !!s.idle_check,
|
||||||
onchange : v => {
|
format: v => v ? /*LANG*/"Yes":/*LANG*/"No",
|
||||||
|
onchange: v => {
|
||||||
s.idle_check = v;
|
s.idle_check = v;
|
||||||
save();
|
save();
|
||||||
},
|
},
|
||||||
},
|
|
||||||
*/
|
|
||||||
'Idle Warning': {
|
|
||||||
value: s.idle_check,
|
|
||||||
format: () => (s.idle_check ? 'Yes' : 'No'),
|
|
||||||
onchange: () => {
|
|
||||||
s.idle_check = !s.idle_check;
|
|
||||||
save();
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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.
|
||||||
|
|
@ -1,13 +1,16 @@
|
||||||
{ "id": "timecal",
|
{ "id": "timecal",
|
||||||
"name": "TimeCal",
|
"name": "TimeCal",
|
||||||
"shortName":"TimeCal",
|
"shortName":"TimeCal",
|
||||||
|
"version":"0.04",
|
||||||
|
"description": "TimeCal shows the date/time along with a 3 week calendar",
|
||||||
"icon": "icon.png",
|
"icon": "icon.png",
|
||||||
"version":"0.01",
|
|
||||||
"description": "TimeCal shows the Time along with a 3 week calendar",
|
|
||||||
"tags": "clock",
|
|
||||||
"type": "clock",
|
"type": "clock",
|
||||||
|
"tags": "clock,calendar",
|
||||||
"supports":["BANGLEJS2"],
|
"supports":["BANGLEJS2"],
|
||||||
|
"readme": "README.md",
|
||||||
|
"allow_emulator":true,
|
||||||
"storage": [
|
"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"}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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<dNames.length; dNo++){
|
||||||
|
const dIdx=this.settings().wdStrt>=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<dNames.length; x++){
|
||||||
|
if(rDate===tdyDate){ //today
|
||||||
|
g.setColor(this.nrgb[this.settings().tdyMrkClr]); //today marker color or fg color
|
||||||
|
switch(this.settings().tdyMrkr){ //0:none, 1:circle, 2:rectangle, 3:filled
|
||||||
|
case 1:
|
||||||
|
for(m=1; m<=this.settings().tdyMrkPxl&&m<CELL_H-1&&m<CELL_W-1; m++)
|
||||||
|
g.drawCircle(x*CELL_W+(CELL_W/2)+1, nextY+(CELL_H*y)+(CELL_H/2)+1, Math.min((CELL_W-m)/2, (CELL_H-m)/2)-2);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
for(m=1; m<=this.settings().tdyMrkPxl&&m<CELL_H-1&&m<CELL_W-1; m++)
|
||||||
|
g.drawRect(x*CELL_W+m, nextY+CELL_H+m, x*CELL_W+CELL_W-m, nextY+CELL_H+CELL_H-m);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
g.fillRect(x*CELL_W+1, nextY+CELL_H+1, x*CELL_W+CELL_W-1, nextY+CELL_H+CELL_H-1);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
g.setColor(this.nrgb[this.settings().tdyNumClr]); //today color or fg color
|
||||||
|
}else if(this.settings().suClr && rD.getDay()==0){ //sundays
|
||||||
|
g.setColor(this.nrgb[this.settings().suClr]);
|
||||||
|
}else{ //default
|
||||||
|
g.setColor(g.theme.fg);
|
||||||
|
}
|
||||||
|
g.drawString(rDate, x*CELL_W+((CELL_W-g.stringWidth(rDate))/2)+2, nextY+((CELL_H-DAY_NUM_FONT_SIZE+2)/2)+(CELL_H*y));
|
||||||
|
rD.setDate(rDate+1);
|
||||||
|
rDate=rD.getDate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (this.settings().calBrdr) {
|
||||||
|
g.setColor(g.theme.fg).drawRect(Bangle.appRect.x, CAL_Y, Bangle.appRect.x2, CAL_Y+CAL_AREA_H-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* calculates current ISO8601 week number e.g. 2
|
||||||
|
* @param{Date} date for the date
|
||||||
|
* @returns{Number}} e.g. 2
|
||||||
|
*/
|
||||||
|
ISO8601calWeek(date){ //copied from: https://gist.github.com/IamSilviu/5899269#gistcomment-3035480
|
||||||
|
var tdt = new Date(date.valueOf());
|
||||||
|
var dayn = (date.getDay() + 6) % 7;
|
||||||
|
tdt.setDate(tdt.getDate() - dayn + 3);
|
||||||
|
var firstThursday = tdt.valueOf();
|
||||||
|
tdt.setMonth(0, 1);
|
||||||
|
if (tdt.getDay() !== 4){
|
||||||
|
tdt.setMonth(0, 1 + ((4 - tdt.getDay()) + 7) % 7);
|
||||||
|
}
|
||||||
|
return Number(1 + Math.ceil((firstThursday - tdt) / 604800000));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//*************************************************************************************
|
||||||
|
//*************************************************************************************
|
||||||
|
//*************************************************************************************
|
||||||
|
//Copy ABOVE the src code of clock-app class and load via espruino WEB IDE
|
||||||
|
//*************************************************************************************
|
||||||
|
//*************************************************************************************
|
||||||
|
//*************************************************************************************
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Severity for logging
|
||||||
|
*/
|
||||||
|
const LogSeverity={
|
||||||
|
DEBUG: 5,
|
||||||
|
INFO: 4,
|
||||||
|
WARNING: 3,
|
||||||
|
ERROR: 2,
|
||||||
|
EXCEPTION: 1
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exception: Mandatory Field not provided
|
||||||
|
*/
|
||||||
|
class EmptyMandatoryError extends Error{
|
||||||
|
/**
|
||||||
|
* Create Exception
|
||||||
|
* @param {String} name of the field
|
||||||
|
* @param {*} given data e.g. an object
|
||||||
|
* @param {*} expected *optional* an working example
|
||||||
|
*/
|
||||||
|
constructor(name, given, expected) {
|
||||||
|
this.field = name;
|
||||||
|
this.got = given;
|
||||||
|
this.message = "Missing mandatory '"+ name +"'. given '"+JSON.stringify(given)+"'";
|
||||||
|
if (expected) {
|
||||||
|
this.message+= " != expected: '"+JSON.stringify(expected)+"'";
|
||||||
|
this.sample = expected;
|
||||||
|
}
|
||||||
|
Error(this.message);
|
||||||
|
}
|
||||||
|
|
||||||
|
toString() {
|
||||||
|
return this.message;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exception: Invalid Function
|
||||||
|
*/
|
||||||
|
class InvalidMethodName extends Error{
|
||||||
|
/**
|
||||||
|
* Create Exception
|
||||||
|
* @param {String} name of the field
|
||||||
|
* @param {*} given data e.g. an object
|
||||||
|
* @param {*} expected *optional* an working example
|
||||||
|
*/
|
||||||
|
constructor(className, methodName) {
|
||||||
|
this.class = className;
|
||||||
|
this.method = methodName;
|
||||||
|
this.message = "Function '"+methodName+"' not found in '"+className+"'";
|
||||||
|
Error(this.message);
|
||||||
|
}
|
||||||
|
|
||||||
|
toString() {
|
||||||
|
return this.message;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* All Test Masterclass
|
||||||
|
*/
|
||||||
|
class Test{
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test Settings - use this if you want e.g. test draw/render function(s)
|
||||||
|
*/
|
||||||
|
class TestSetting extends Test{
|
||||||
|
TEST_SETTING_SAMPLE() {
|
||||||
|
return {
|
||||||
|
setting: "<settingName>",
|
||||||
|
cases: [
|
||||||
|
{
|
||||||
|
value: "required,<settingValue>",
|
||||||
|
beforeTxt: "optional,<textToDisplayBeforeTest>",
|
||||||
|
beforeExpression: "optional,<expressionExpectedTrue>",
|
||||||
|
afterText: "optional,<textToDisplayAfterTest>",
|
||||||
|
afterExpression: "optional,<expressionExpectedTrue>"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
constructorParams: ["optional: <cpar1>","|TEST_SETTINGS|","..."], //TEST_SETTINGS will be replcaed with each current {setting: case}
|
||||||
|
functionNames: ["required, <function under test>", "..."],
|
||||||
|
functionParams: ["optional: <fpar1>","|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(), "<<case #" + this.currentTestNum + "." + this.currentCaseNum + "/" + (this.currentTest.cases.length-1));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* after each test
|
||||||
|
*/
|
||||||
|
_afterTest() {
|
||||||
|
console.log(this._nowTime(), "<<test #" + this.currentTestNum);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* after all tests
|
||||||
|
*/
|
||||||
|
_exit() {
|
||||||
|
console.log(this._nowTime(), "<<exit");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* delays for x seconds
|
||||||
|
* @param {Number} sec to delay
|
||||||
|
*/
|
||||||
|
_delay(sec) {
|
||||||
|
return new Promise(resolve => setTimeout(resolve, sec));
|
||||||
|
}
|
||||||
|
|
||||||
|
_waits(sec) {
|
||||||
|
this._delay(1).then();
|
||||||
|
}
|
||||||
|
|
||||||
|
_log() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
_nextTest() {
|
||||||
|
if (this.currentTestNum>=-1 && (this.currentTestNum+1)<this.tests.length) {
|
||||||
|
this.currentTestNum++; this.currentTest = this.tests[this.currentTestNum];
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
_firstCase() {
|
||||||
|
this.currentCaseNum=-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
_nextCase() {
|
||||||
|
if (this.currentCaseNum>=-1 && (this.currentCaseNum+1)<this.currentTest.cases.length) {
|
||||||
|
this.currentCaseNum++; this.currentCase = this.currentTest.cases[this.currentCaseNum];
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
_nowTime() {
|
||||||
|
d = new Date();
|
||||||
|
return(("0" + d.getHours()).slice(-2) + ":" + ("0" + d.getMinutes()).slice(-2) + ":" + ("0" + d.getSeconds()).slice(-2) + "." + ("00" + d.getMilliseconds()).slice(-3));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* TEST all Settings
|
||||||
|
*/
|
||||||
|
new BangleTestRunner("TimeCalClock", LogSeverity.INFO)
|
||||||
|
/*
|
||||||
|
.addTestSettings({
|
||||||
|
setting: "shwDate",
|
||||||
|
cases: [
|
||||||
|
{ value: 0, beforeTxt:"No date display?", afterTxt: "top area should be 'emtpy'" },
|
||||||
|
{ value: 1, beforeTxt:"Locale date display?", afterTxt: "date should be 06/05/1234" },
|
||||||
|
{ value: 2, beforeTxt:"Month longname?", afterTxt: "date should be June" },
|
||||||
|
{ value: 3, beforeTxt:"Monthshort yearshort #week", afterTxt: "date should be Jun.34 #23" }
|
||||||
|
],
|
||||||
|
constructorParams: [new Date(1234,5,6,7,8,9),"|TEST_SETTINGS|"],
|
||||||
|
functionNames: ["drawDate"],
|
||||||
|
functionParams: [],
|
||||||
|
})
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
.addTestSettings({
|
||||||
|
setting: "wdStrt",
|
||||||
|
cases: [
|
||||||
|
{ value: 0, beforeTxt:"Week start Sunday?" , afterTxt: "Calendar first day is Sunday" },
|
||||||
|
{ value: 1, beforeTxt:"Week start Monday?" , afterTxt: "Calendar first day is Monday"},
|
||||||
|
{ value: 2, beforeTxt:"Week start Tuesday?" , afterTxt: "Calendar first day is Tuesday"},
|
||||||
|
{ value: 3, beforeTxt:"Week start Wednesday?" , afterTxt: "Calendar first day is Wednesday"},
|
||||||
|
{ value: 4, beforeTxt:"Week start Thursday?" , afterTxt: "Calendar first day is Thursday"},
|
||||||
|
{ value: 5, beforeTxt:"Week start Friday?" , afterTxt: "Calendar first day is Friday"},
|
||||||
|
{ value: 6, beforeTxt:"Week start Saturday?" , afterTxt: "Calendar first day is Saturday"},
|
||||||
|
],
|
||||||
|
constructorParams: [new Date(1234,5,3,7,8,9),"|TEST_SETTINGS|"],
|
||||||
|
functionNames: ["drawCal"],
|
||||||
|
functionParams: [],
|
||||||
|
})
|
||||||
|
.addTestSettings({
|
||||||
|
setting: "wdStrt",
|
||||||
|
cases: [
|
||||||
|
{ value: 0, beforeTxt:"Week start Sunday?" , afterTxt: "Calendar first day is Sunday" },
|
||||||
|
{ value: 1, beforeTxt:"Week start Monday?" , afterTxt: "Calendar first day is Monday"},
|
||||||
|
{ value: 2, beforeTxt:"Week start Tuesday?" , afterTxt: "Calendar first day is Tuesday"},
|
||||||
|
{ value: 3, beforeTxt:"Week start Wednesday?" , afterTxt: "Calendar first day is Wednesday"},
|
||||||
|
{ value: 4, beforeTxt:"Week start Thursday?" , afterTxt: "Calendar first day is Thursday"},
|
||||||
|
{ value: 5, beforeTxt:"Week start Friday?" , afterTxt: "Calendar first day is Friday"},
|
||||||
|
{ value: 6, beforeTxt:"Week start Saturday?" , afterTxt: "Calendar first day is Saturday"},
|
||||||
|
],
|
||||||
|
constructorParams: [new Date(1234,5,4,7,8,9),"|TEST_SETTINGS|"],
|
||||||
|
functionNames: ["drawCal"],
|
||||||
|
functionParams: [],
|
||||||
|
})
|
||||||
|
.addTestSettings({
|
||||||
|
setting: "wdStrt",
|
||||||
|
cases: [
|
||||||
|
{ value: 0, beforeTxt:"Week start Sunday?" , afterTxt: "Calendar first day is Sunday" },
|
||||||
|
{ value: 1, beforeTxt:"Week start Monday?" , afterTxt: "Calendar first day is Monday"},
|
||||||
|
{ value: 2, beforeTxt:"Week start Tuesday?" , afterTxt: "Calendar first day is Tuesday"},
|
||||||
|
{ value: 3, beforeTxt:"Week start Wednesday?" , afterTxt: "Calendar first day is Wednesday"},
|
||||||
|
{ value: 4, beforeTxt:"Week start Thursday?" , afterTxt: "Calendar first day is Thursday"},
|
||||||
|
{ value: 5, beforeTxt:"Week start Friday?" , afterTxt: "Calendar first day is Friday"},
|
||||||
|
{ value: 6, beforeTxt:"Week start Saturday?" , afterTxt: "Calendar first day is Saturday"},
|
||||||
|
],
|
||||||
|
constructorParams: [new Date(1234,5,5,7,8,9),"|TEST_SETTINGS|"],
|
||||||
|
functionNames: ["drawCal"],
|
||||||
|
functionParams: [],
|
||||||
|
})
|
||||||
|
.addTestSettings({
|
||||||
|
setting: "wdStrt",
|
||||||
|
cases: [
|
||||||
|
{ value: 0, beforeTxt:"Week start Sunday?" , afterTxt: "Calendar first day is Sunday" },
|
||||||
|
{ value: 1, beforeTxt:"Week start Monday?" , afterTxt: "Calendar first day is Monday"},
|
||||||
|
{ value: 2, beforeTxt:"Week start Tuesday?" , afterTxt: "Calendar first day is Tuesday"},
|
||||||
|
{ value: 3, beforeTxt:"Week start Wednesday?" , afterTxt: "Calendar first day is Wednesday"},
|
||||||
|
{ value: 4, beforeTxt:"Week start Thursday?" , afterTxt: "Calendar first day is Thursday"},
|
||||||
|
{ value: 5, beforeTxt:"Week start Friday?" , afterTxt: "Calendar first day is Friday"},
|
||||||
|
{ value: 6, beforeTxt:"Week start Saturday?" , afterTxt: "Calendar first day is Saturday"},
|
||||||
|
],
|
||||||
|
constructorParams: [new Date(1234,5,6,7,8,9),"|TEST_SETTINGS|"],
|
||||||
|
functionNames: ["drawCal"],
|
||||||
|
functionParams: [],
|
||||||
|
})
|
||||||
|
.addTestSettings({
|
||||||
|
setting: "wdStrt",
|
||||||
|
cases: [
|
||||||
|
{ value: 0, beforeTxt:"Week start Sunday?" , afterTxt: "Calendar first day is Sunday" },
|
||||||
|
{ value: 1, beforeTxt:"Week start Monday?" , afterTxt: "Calendar first day is Monday"},
|
||||||
|
{ value: 2, beforeTxt:"Week start Tuesday?" , afterTxt: "Calendar first day is Tuesday"},
|
||||||
|
{ value: 3, beforeTxt:"Week start Wednesday?" , afterTxt: "Calendar first day is Wednesday"},
|
||||||
|
{ value: 4, beforeTxt:"Week start Thursday?" , afterTxt: "Calendar first day is Thursday"},
|
||||||
|
{ value: 5, beforeTxt:"Week start Friday?" , afterTxt: "Calendar first day is Friday"},
|
||||||
|
{ value: 6, beforeTxt:"Week start Saturday?" , afterTxt: "Calendar first day is Saturday"},
|
||||||
|
],
|
||||||
|
constructorParams: [new Date(1234,5,7,7,8,9),"|TEST_SETTINGS|"],
|
||||||
|
functionNames: ["drawCal"],
|
||||||
|
functionParams: [],
|
||||||
|
})
|
||||||
|
.addTestSettings({
|
||||||
|
setting: "wdStrt",
|
||||||
|
cases: [
|
||||||
|
{ value: 0, beforeTxt:"Week start Sunday?" , afterTxt: "Calendar first day is Sunday" },
|
||||||
|
{ value: 1, beforeTxt:"Week start Monday?" , afterTxt: "Calendar first day is Monday"},
|
||||||
|
{ value: 2, beforeTxt:"Week start Tuesday?" , afterTxt: "Calendar first day is Tuesday"},
|
||||||
|
{ value: 3, beforeTxt:"Week start Wednesday?" , afterTxt: "Calendar first day is Wednesday"},
|
||||||
|
{ value: 4, beforeTxt:"Week start Thursday?" , afterTxt: "Calendar first day is Thursday"},
|
||||||
|
{ value: 5, beforeTxt:"Week start Friday?" , afterTxt: "Calendar first day is Friday"},
|
||||||
|
{ value: 6, beforeTxt:"Week start Saturday?" , afterTxt: "Calendar first day is Saturday"},
|
||||||
|
],
|
||||||
|
constructorParams: [new Date(1234,5,8,7,8,9),"|TEST_SETTINGS|"],
|
||||||
|
functionNames: ["drawCal"],
|
||||||
|
functionParams: [],
|
||||||
|
})
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
.addTestSettings({
|
||||||
|
setting: "wdStrt",
|
||||||
|
cases: [
|
||||||
|
{ value: -1, beforeTxt:"Sunday in mid?" , afterTxt: "Calendar focus today: Sunday" },
|
||||||
|
],
|
||||||
|
constructorParams: [new Date(1234,5,3,7,8,9),"|TEST_SETTINGS|"],
|
||||||
|
functionNames: ["drawCal"],
|
||||||
|
functionParams: [],
|
||||||
|
})
|
||||||
|
.addTestSettings({
|
||||||
|
setting: "wdStrt",
|
||||||
|
cases: [
|
||||||
|
{ value: -1, beforeTxt:"Monday in mid?" , afterTxt: "Calendar focus today: Monday" },
|
||||||
|
],
|
||||||
|
constructorParams: [new Date(1234,5,4,7,8,9),"|TEST_SETTINGS|"],
|
||||||
|
functionNames: ["drawCal"],
|
||||||
|
functionParams: [],
|
||||||
|
})
|
||||||
|
.addTestSettings({
|
||||||
|
setting: "wdStrt",
|
||||||
|
cases: [
|
||||||
|
{ value: -1, beforeTxt:"Tuesday in mid?" , afterTxt: "Calendar focus today: Tuesday" },
|
||||||
|
],
|
||||||
|
constructorParams: [new Date(1234,5,5,7,8,9),"|TEST_SETTINGS|"],
|
||||||
|
functionNames: ["drawCal"],
|
||||||
|
functionParams: [],
|
||||||
|
})
|
||||||
|
.addTestSettings({
|
||||||
|
setting: "wdStrt",
|
||||||
|
cases: [
|
||||||
|
{ value: -1, beforeTxt:"Wednesday in mid?" , afterTxt: "Calendar focus today: Wednesday" },
|
||||||
|
],
|
||||||
|
constructorParams: [new Date(1234,5,6,7,8,9),"|TEST_SETTINGS|"],
|
||||||
|
functionNames: ["drawCal"],
|
||||||
|
functionParams: [],
|
||||||
|
})
|
||||||
|
.addTestSettings({
|
||||||
|
setting: "wdStrt",
|
||||||
|
cases: [
|
||||||
|
{ value: -1, beforeTxt:"Thursday in mid?" , afterTxt: "Calendar focus today: Thursday" },
|
||||||
|
],
|
||||||
|
constructorParams: [new Date(1234,5,7,7,8,9),"|TEST_SETTINGS|"],
|
||||||
|
functionNames: ["drawCal"],
|
||||||
|
functionParams: [],
|
||||||
|
})
|
||||||
|
.addTestSettings({
|
||||||
|
setting: "wdStrt",
|
||||||
|
cases: [
|
||||||
|
{ value: -1, beforeTxt:"Friday in mid?" , afterTxt: "Calendar focus today: Friday" },
|
||||||
|
],
|
||||||
|
constructorParams: [new Date(1234,5,8,7,8,9),"|TEST_SETTINGS|"],
|
||||||
|
functionNames: ["drawCal"],
|
||||||
|
functionParams: [],
|
||||||
|
})
|
||||||
|
.addTestSettings({
|
||||||
|
setting: "wdStrt",
|
||||||
|
cases: [
|
||||||
|
{ value: -1, beforeTxt:"Saturday in mid?" , afterTxt: "Calendar focus today: Saturday" },
|
||||||
|
],
|
||||||
|
constructorParams: [new Date(1234,5,9,7,8,9),"|TEST_SETTINGS|"],
|
||||||
|
functionNames: ["drawCal"],
|
||||||
|
functionParams: [],
|
||||||
|
})
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
.addTestSettings({
|
||||||
|
setting: "tdyNumClr",
|
||||||
|
cases: [
|
||||||
|
{ value: 1, beforeTxt:"Today color: red?" , afterTxt: "Today is marked red" },
|
||||||
|
{ value: 2, beforeTxt:"Today color: green?" , afterTxt: "Today is marked green" },
|
||||||
|
{ value: 3, beforeTxt:"Today color: blue?" , afterTxt: "Today is marked blue" },
|
||||||
|
],
|
||||||
|
constructorParams: [new Date(),"|TEST_SETTINGS|"],
|
||||||
|
functionNames: ["drawCal"],
|
||||||
|
functionParams: [],
|
||||||
|
})
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
.addTestSettings({
|
||||||
|
setting: "tdyMrkr",
|
||||||
|
cases: [
|
||||||
|
{ value: 1, beforeTxt:"Today highlight cricle?" , afterTxt: "Today circled." },
|
||||||
|
{ value: 2, beforeTxt:"Today highlight rectangle?" , afterTxt: "Today rectangled." },
|
||||||
|
{ value: 3, beforeTxt:"Today highlight filled?" , afterTxt: "Today filled." },
|
||||||
|
],
|
||||||
|
constructorParams: [new Date(),"|TEST_SETTINGS|"],
|
||||||
|
functionNames: ["drawCal"],
|
||||||
|
functionParams: [],
|
||||||
|
})
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
.addTestSettings({
|
||||||
|
setting: "suClr",
|
||||||
|
cases: [
|
||||||
|
{ value: 1, beforeTxt:"Sundays color: red?" , afterTxt: "Sundays are red" },
|
||||||
|
{ value: 2, beforeTxt:"Sundays color: green?" , afterTxt: "Sundays are green" },
|
||||||
|
{ value: 3, beforeTxt:"Sundays color: blue?" , afterTxt: "Sundays are blue" },
|
||||||
|
],
|
||||||
|
constructorParams: [new Date(),"|TEST_SETTINGS|"],
|
||||||
|
functionNames: ["drawCal"],
|
||||||
|
functionParams: [],
|
||||||
|
})
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
.addTestSettings({
|
||||||
|
setting: "calBrdr",
|
||||||
|
cases: [
|
||||||
|
{ value: false, beforeTxt:"Calendar without border?" , afterTxt: "No outer border." },
|
||||||
|
{ value: true, beforeTxt:"Calendar with border?" , afterTxt: "Outer border." },
|
||||||
|
],
|
||||||
|
constructorParams: [new Date(),"|TEST_SETTINGS|"],
|
||||||
|
functionNames: ["drawCal"],
|
||||||
|
functionParams: [],
|
||||||
|
})
|
||||||
|
*/
|
||||||
|
.execute();
|
||||||
|
|
@ -1,94 +1,274 @@
|
||||||
var center = g.getWidth() / 2;
|
//Clock renders date, time and pre,current,next week calender view
|
||||||
var lastDayDraw;
|
class TimeCalClock{
|
||||||
var lastTimeDraw;
|
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;
|
||||||
|
|
||||||
var fontColor = g.theme.fg;
|
if (settings)
|
||||||
var accentColor = "#FF0000";
|
this._settings = settings;
|
||||||
var locale = require("locale");
|
else
|
||||||
|
this._settings = require("Storage").readJSON("timecal.settings.json", 1) || {};
|
||||||
|
|
||||||
function loop() {
|
const defaults = {
|
||||||
var d = new Date();
|
shwDate:1, //0:none, 1:locale, 2:month, 3:monthshort.year #week
|
||||||
var cleared = false;
|
|
||||||
if(lastDayDraw != d.getDate()){
|
wdStrt:0, //identical to getDay() 0->Su, 1->Mo, ... //Issue #1154: weekstart So/Mo, -1 for use today
|
||||||
lastDayDraw = d.getDate();
|
|
||||||
drawDate(d);
|
tdyNumClr:3, //0:fg, 1:red=#E00, 2:green=#0E0, 3:blue=#00E
|
||||||
drawCal(d);
|
tdyMrkr:0, //0:none, 1:circle, 2:rectangle, 3:filled
|
||||||
}
|
tdyMrkClr:2, //1:red=#E00, 2:green=#0E0, 3:blue=#00E
|
||||||
|
tdyMrkPxl:3, //px
|
||||||
if(lastTimeDraw != d.getMinutes() || cleared){
|
|
||||||
lastTimeDraw = d.getMinutes();
|
suClr:1, //0:fg, 1:red=#E00, 2:green=#0E0, 3:blue=#00E
|
||||||
drawTime(d);
|
//phColor:"#E00", //public holiday
|
||||||
}
|
|
||||||
}
|
calBrdr:false
|
||||||
function drawTime(d){
|
};
|
||||||
var hour = ("0" + d.getHours()).slice(-2);
|
for (const k in this._settings) if (!defaults.hasOwnProperty(k)) delete this._settings[k]; //remove invalid settings
|
||||||
var min = ("0" + d.getMinutes()).slice(-2);
|
for (const k in defaults) if(!this._settings.hasOwnProperty(k)) this._settings[k] = defaults[k]; //assign missing defaults
|
||||||
g.setFontAlign(0,-1,0);
|
|
||||||
g.setFont("Vector",40);
|
g.clear();
|
||||||
g.setColor(fontColor);
|
Bangle.setUI("clock");
|
||||||
g.clearRect(0,50,g.getWidth(),90);
|
Bangle.loadWidgets();
|
||||||
g.drawString(hour + ":" + min,center,50);
|
Bangle.drawWidgets();
|
||||||
}
|
|
||||||
function drawDate(d){
|
this.centerX = Bangle.appRect.w/2;
|
||||||
var day = ("0" + d.getDate()).slice(-2);
|
this.nrgb = [g.theme.fg, "#E00", "#0E0", "#00E"]; //fg, r ,g , b
|
||||||
var month = ("0" + d.getMonth()).slice(-2);
|
|
||||||
var dateStr = locale.date(d,1);
|
this.ABR_DAY=[];
|
||||||
g.clearRect(0,24,g.getWidth(),44);
|
if (require("locale") && require("locale").dow)
|
||||||
g.setFont("Vector",20);
|
for (let d=0; d<=6; d++) {
|
||||||
g.setColor(fontColor);
|
var refDay=new Date();
|
||||||
g.setFontAlign(0,-1,0);
|
refDay.setFullYear(1972);
|
||||||
g.drawString(dateStr,center,24);
|
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);
|
else
|
||||||
start.setDate(start.getDate()+1);
|
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<dNames.length; dNo++){
|
||||||
|
const dIdx=this.settings().wdStrt>=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<dNames.length; x++){
|
||||||
|
if(rDate===tdyDate){ //today
|
||||||
|
g.setColor(this.nrgb[this.settings().tdyMrkClr]); //today marker color or fg color
|
||||||
|
switch(this.settings().tdyMrkr){ //0:none, 1:circle, 2:rectangle, 3:filled
|
||||||
|
case 1:
|
||||||
|
for(m=1; m<=this.settings().tdyMrkPxl&&m<CELL_H-1&&m<CELL_W-1; m++)
|
||||||
|
g.drawCircle(x*CELL_W+(CELL_W/2)+1, nextY+(CELL_H*y)+(CELL_H/2)+1, Math.min((CELL_W-m)/2, (CELL_H-m)/2)-2);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
for(m=1; m<=this.settings().tdyMrkPxl&&m<CELL_H-1&&m<CELL_W-1; m++)
|
||||||
|
g.drawRect(x*CELL_W+m, nextY+CELL_H+m, x*CELL_W+CELL_W-m, nextY+CELL_H+CELL_H-m);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
g.fillRect(x*CELL_W+1, nextY+CELL_H+1, x*CELL_W+CELL_W-1, nextY+CELL_H+CELL_H-1);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
g.setColor(this.nrgb[this.settings().tdyNumClr]); //today color or fg color
|
||||||
|
}else if(this.settings().suClr && rD.getDay()==0){ //sundays
|
||||||
|
g.setColor(this.nrgb[this.settings().suClr]);
|
||||||
|
}else{ //default
|
||||||
|
g.setColor(g.theme.fg);
|
||||||
|
}
|
||||||
|
g.drawString(rDate, x*CELL_W+((CELL_W-g.stringWidth(rDate))/2)+2, nextY+((CELL_H-DAY_NUM_FONT_SIZE+2)/2)+(CELL_H*y));
|
||||||
|
rD.setDate(rDate+1);
|
||||||
|
rDate=rD.getDate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (this.settings().calBrdr) {
|
||||||
|
g.setColor(g.theme.fg).drawRect(Bangle.appRect.x, CAL_Y, Bangle.appRect.x2, CAL_Y+CAL_AREA_H-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* calculates current ISO8601 week number e.g. 2
|
||||||
|
* @param{Date} date for the date
|
||||||
|
* @returns{Number}} e.g. 2
|
||||||
|
*/
|
||||||
|
ISO8601calWeek(date){ //copied from: https://gist.github.com/IamSilviu/5899269#gistcomment-3035480
|
||||||
|
var tdt = new Date(date.valueOf());
|
||||||
|
var dayn = (date.getDay() + 6) % 7;
|
||||||
|
tdt.setDate(tdt.getDate() - dayn + 3);
|
||||||
|
var firstThursday = tdt.valueOf();
|
||||||
|
tdt.setMonth(0, 1);
|
||||||
|
if (tdt.getDay() !== 4){
|
||||||
|
tdt.setMonth(0, 1 + ((4 - tdt.getDay()) + 7) % 7);
|
||||||
|
}
|
||||||
|
return Number(1 + Math.ceil((firstThursday - tdt) / 604800000));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
g.clear();
|
timeCalClock = new TimeCalClock(); timeCalClock.draw();
|
||||||
Bangle.setUI("clock");
|
|
||||||
Bangle.loadWidgets();
|
//hook on settime to redraw immediatly
|
||||||
Bangle.drawWidgets();
|
var _setTime = setTime;
|
||||||
loop();
|
var setTime = function(t) {
|
||||||
setInterval(loop,1000);
|
_setTime(t);
|
||||||
|
timeCalClock.draw(true);
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,109 @@
|
||||||
|
// Settings menu for Time calendar clock
|
||||||
|
(function(exit) {
|
||||||
|
ABR_DAY = require("locale") && require("locale").abday ? require("locale").abday : ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
|
||||||
|
|
||||||
|
var FILE = "timecal.validSttngs.json";
|
||||||
|
|
||||||
|
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
|
||||||
|
};
|
||||||
|
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();
|
||||||
|
});
|
||||||
|
|
@ -1 +1,3 @@
|
||||||
0.01: New Widget!
|
0.01: New Widget!
|
||||||
|
0.02: Battery bar turns yellow on charge
|
||||||
|
Memory status bar does not trigger garbage collect
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"id": "widbars",
|
"id": "widbars",
|
||||||
"name": "Bars Widget",
|
"name": "Bars Widget",
|
||||||
"version": "0.01",
|
"version": "0.02",
|
||||||
"description": "Display several measurements as vertical bars.",
|
"description": "Display several measurements as vertical bars.",
|
||||||
"icon": "icon.png",
|
"icon": "icon.png",
|
||||||
"screenshots": [{"url":"screenshot.png"}],
|
"screenshots": [{"url":"screenshot.png"}],
|
||||||
|
|
|
||||||
|
|
@ -42,19 +42,25 @@
|
||||||
if (top) g .clearRect(x,y, x+w-1,y+top-1); // erase above bar
|
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
|
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() {
|
function draw() {
|
||||||
g.reset();
|
g.reset();
|
||||||
const x = this.x, y = this.y,
|
const x = this.x, y = this.y,
|
||||||
m = process.memory();
|
m = process.memory(false);
|
||||||
let b=0;
|
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
|
// ==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
|
// ==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,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,'#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;
|
let redraw;
|
||||||
|
Bangle.on('charging', function(charging) {
|
||||||
|
batColor=charging?'#ff0':'#0f0';
|
||||||
|
WIDGETS["bars"].draw();
|
||||||
|
});
|
||||||
|
|
||||||
Bangle.on('lcdPower', on => {
|
Bangle.on('lcdPower', on => {
|
||||||
if (redraw) clearInterval(redraw)
|
if (redraw) clearInterval(redraw)
|
||||||
redraw = undefined;
|
redraw = undefined;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue