2023-02-25 17:43:59 +00:00
|
|
|
{ // must be inside our own scope here so that when we are unloaded everything disappears
|
|
|
|
|
|
|
|
/************************************************
|
|
|
|
* Includes
|
|
|
|
*/
|
|
|
|
const locale = require('locale');
|
|
|
|
const storage = require('Storage');
|
|
|
|
const clock_info = require("clock_info");
|
|
|
|
const widget_utils = require("widget_utils");
|
|
|
|
|
|
|
|
/************************************************
|
|
|
|
* Globals
|
|
|
|
*/
|
2023-02-25 18:03:59 +00:00
|
|
|
const SETTINGS_FILE = "bwclklite.setting.json";
|
2023-02-25 17:43:59 +00:00
|
|
|
const W = g.getWidth();
|
|
|
|
const H = g.getHeight();
|
|
|
|
|
|
|
|
/************************************************
|
|
|
|
* Settings
|
|
|
|
*/
|
|
|
|
let settings = {
|
|
|
|
screen: "Normal",
|
|
|
|
showLock: true,
|
|
|
|
hideColon: false,
|
|
|
|
menuPosX: 0,
|
|
|
|
menuPosY: 0,
|
|
|
|
};
|
|
|
|
|
|
|
|
let saved_settings = storage.readJSON(SETTINGS_FILE, 1) || settings;
|
|
|
|
for (const key in saved_settings) {
|
|
|
|
settings[key] = saved_settings[key];
|
|
|
|
}
|
|
|
|
|
|
|
|
let isFullscreen = function() {
|
2023-02-25 17:52:29 +00:00
|
|
|
let s = settings.screen.toLowerCase();
|
2023-02-25 17:43:59 +00:00
|
|
|
if(s == "dynamic"){
|
|
|
|
return Bangle.isLocked();
|
|
|
|
} else {
|
|
|
|
return s == "full";
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
let getLineY = function(){
|
|
|
|
return H/5*2 + (isFullscreen() ? 0 : 8);
|
2023-02-25 17:52:29 +00:00
|
|
|
};
|
2023-02-25 17:43:59 +00:00
|
|
|
|
|
|
|
/************************************************
|
|
|
|
* Assets
|
|
|
|
*/
|
|
|
|
let imgLock = function() {
|
|
|
|
return {
|
|
|
|
width : 16, height : 16, bpp : 1,
|
|
|
|
transparent : 0,
|
|
|
|
buffer : E.toArrayBuffer(atob("A8AH4A5wDDAYGBgYP/w//D/8Pnw+fD58Pnw//D/8P/w="))
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/************************************************
|
|
|
|
* Clock Info
|
|
|
|
*/
|
|
|
|
let clockInfoItems = clock_info.load();
|
|
|
|
|
|
|
|
// Add some custom clock-infos
|
|
|
|
let weekOfYear = function() {
|
2023-02-25 17:52:29 +00:00
|
|
|
let date = new Date();
|
2023-02-25 17:43:59 +00:00
|
|
|
date.setHours(0, 0, 0, 0);
|
|
|
|
// Thursday in current week decides the year.
|
|
|
|
date.setDate(date.getDate() + 3 - (date.getDay() + 6) % 7);
|
|
|
|
// January 4 is always in week 1.
|
2023-02-25 17:52:29 +00:00
|
|
|
let week1 = new Date(date.getFullYear(), 0, 4);
|
2023-02-25 17:43:59 +00:00
|
|
|
// Adjust to Thursday in week 1 and count number of weeks from date to week1.
|
|
|
|
return 1 + Math.round(((date.getTime() - week1.getTime()) / 86400000
|
|
|
|
- 3 + (week1.getDay() + 6) % 7) / 7);
|
2023-02-25 17:52:29 +00:00
|
|
|
};
|
2023-02-25 17:43:59 +00:00
|
|
|
|
|
|
|
clockInfoItems[0].items.unshift({ name : "weekofyear",
|
|
|
|
get : function() { return { text : "Week " + weekOfYear(),
|
2023-02-25 17:52:29 +00:00
|
|
|
img : null};},
|
2023-02-25 17:43:59 +00:00
|
|
|
show : function() {},
|
|
|
|
hide : function() {},
|
2023-02-25 17:52:29 +00:00
|
|
|
});
|
2023-02-25 17:43:59 +00:00
|
|
|
|
|
|
|
// Empty for large time
|
|
|
|
clockInfoItems[0].items.unshift({ name : "nop",
|
|
|
|
get : function() { return { text : null,
|
2023-02-25 17:52:29 +00:00
|
|
|
img : null};},
|
2023-02-25 17:43:59 +00:00
|
|
|
show : function() {},
|
|
|
|
hide : function() {},
|
2023-02-25 17:52:29 +00:00
|
|
|
});
|
2023-02-25 17:43:59 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let clockInfoMenu = clock_info.addInteractive(clockInfoItems, {
|
2023-02-25 18:03:59 +00:00
|
|
|
app: "bwclklite",
|
2023-02-25 17:43:59 +00:00
|
|
|
x : 0,
|
|
|
|
y: 135,
|
|
|
|
w: W,
|
|
|
|
h: H-135,
|
|
|
|
draw : (itm, info, options) => {
|
2023-02-25 17:52:29 +00:00
|
|
|
let hideClkInfo = info.text == null;
|
2023-02-25 17:43:59 +00:00
|
|
|
|
|
|
|
g.setColor(g.theme.fg);
|
|
|
|
g.fillRect(options.x, options.y, options.x+options.w, options.y+options.h);
|
|
|
|
|
|
|
|
g.setFontAlign(0,0);
|
|
|
|
g.setColor(g.theme.bg);
|
|
|
|
|
|
|
|
if (options.focus){
|
2023-02-25 17:52:29 +00:00
|
|
|
let y = hideClkInfo ? options.y+20 : options.y+2;
|
|
|
|
let h = hideClkInfo ? options.h-20 : options.h-2;
|
2023-02-25 17:43:59 +00:00
|
|
|
g.drawRect(options.x, y, options.x+options.w-2, y+h-1); // show if focused
|
|
|
|
g.drawRect(options.x+1, y+1, options.x+options.w-3, y+h-2); // show if focused
|
|
|
|
}
|
|
|
|
|
|
|
|
// In case we hide the clkinfo, we show the time again as the time should
|
|
|
|
// be drawn larger.
|
|
|
|
if(hideClkInfo){
|
|
|
|
drawTime();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set text and font
|
2023-02-25 17:52:29 +00:00
|
|
|
let image = info.img;
|
|
|
|
let text = String(info.text);
|
2023-02-25 17:43:59 +00:00
|
|
|
if(text.split('\n').length > 1){
|
2023-02-25 17:52:29 +00:00
|
|
|
g.setFont("6x8"); //g.setMiniFont();
|
2023-02-25 17:43:59 +00:00
|
|
|
} else {
|
2023-02-25 17:52:29 +00:00
|
|
|
g.setFont("6x8:3"); //g.setSmallFont();
|
2023-02-25 17:43:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Compute sizes
|
2023-02-25 17:52:29 +00:00
|
|
|
let strWidth = g.stringWidth(text);
|
|
|
|
let imgWidth = image == null ? 0 : 24;
|
|
|
|
let midx = options.x+options.w/2;
|
2023-02-25 17:43:59 +00:00
|
|
|
|
|
|
|
// Draw
|
|
|
|
if (image) {
|
2023-02-25 17:52:29 +00:00
|
|
|
let scale = imgWidth / image.width;
|
2023-02-25 17:43:59 +00:00
|
|
|
g.drawImage(image, midx-parseInt(imgWidth*1.3/2)-parseInt(strWidth/2), options.y+6, {scale: scale});
|
|
|
|
}
|
|
|
|
g.drawString(text, midx+parseInt(imgWidth*1.3/2), options.y+20);
|
|
|
|
|
|
|
|
// In case we are in focus and the focus box changes (fullscreen yes/no)
|
|
|
|
// we draw the time again. Otherwise it could happen that a while line is
|
|
|
|
// not cleared correctly.
|
|
|
|
if(options.focus) drawTime();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
/************************************************
|
|
|
|
* Draw
|
|
|
|
*/
|
|
|
|
let draw = function() {
|
|
|
|
// Queue draw again
|
|
|
|
queueDraw();
|
|
|
|
|
|
|
|
// Draw clock
|
|
|
|
drawDate();
|
|
|
|
drawTime();
|
|
|
|
drawLock();
|
|
|
|
drawWidgets();
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
let drawDate = function() {
|
|
|
|
// Draw background
|
2023-02-25 17:52:29 +00:00
|
|
|
let y = getLineY();
|
2023-02-25 17:43:59 +00:00
|
|
|
g.reset().clearRect(0,0,W,y);
|
|
|
|
|
|
|
|
// Draw date
|
|
|
|
y = parseInt(y/2)+4;
|
|
|
|
y += isFullscreen() ? 0 : 8;
|
2023-02-25 17:52:29 +00:00
|
|
|
let date = new Date();
|
|
|
|
let dateStr = date.getDate();
|
2023-02-25 17:43:59 +00:00
|
|
|
dateStr = ("0" + dateStr).substr(-2);
|
2023-02-25 17:52:29 +00:00
|
|
|
g.setFont("6x8:4"); //g.setMediumFont(); // Needed to compute the width correctly
|
|
|
|
let dateW = g.stringWidth(dateStr);
|
2023-02-25 17:43:59 +00:00
|
|
|
|
2023-02-25 17:52:29 +00:00
|
|
|
g.setFont("6x8:3"); //g.setSmallFont();
|
|
|
|
let dayStr = locale.dow(date, true);
|
|
|
|
let monthStr = locale.month(date, 1);
|
|
|
|
let dayW = Math.max(g.stringWidth(dayStr), g.stringWidth(monthStr));
|
|
|
|
let fullDateW = dateW + 10 + dayW;
|
2023-02-25 17:43:59 +00:00
|
|
|
|
|
|
|
g.setFontAlign(-1,0);
|
|
|
|
g.drawString(dayStr, W/2 - fullDateW/2 + 10 + dateW, y-12);
|
|
|
|
g.drawString(monthStr, W/2 - fullDateW/2 + 10 + dateW, y+11);
|
|
|
|
|
2023-02-25 17:52:29 +00:00
|
|
|
g.setFont("6x8:4"); //g.setMediumFont();
|
2023-02-25 17:43:59 +00:00
|
|
|
g.setColor(g.theme.fg);
|
|
|
|
g.drawString(dateStr, W/2 - fullDateW / 2, y+2);
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
let drawTime = function() {
|
2023-02-25 17:52:29 +00:00
|
|
|
let hideClkInfo = clockInfoMenu.menuA == 0 && clockInfoMenu.menuB == 0;
|
2023-02-25 17:43:59 +00:00
|
|
|
|
|
|
|
// Draw background
|
2023-02-25 17:52:29 +00:00
|
|
|
let y1 = getLineY();
|
|
|
|
let y = y1;
|
|
|
|
let date = new Date();
|
2023-02-25 17:43:59 +00:00
|
|
|
|
2023-02-25 17:52:29 +00:00
|
|
|
let hours = String(date.getHours());
|
|
|
|
let minutes = date.getMinutes();
|
2023-02-25 17:43:59 +00:00
|
|
|
minutes = minutes < 10 ? String("0") + minutes : minutes;
|
2023-02-25 17:52:29 +00:00
|
|
|
let colon = settings.hideColon ? "" : ":";
|
|
|
|
let timeStr = hours + colon + minutes;
|
2023-02-25 17:43:59 +00:00
|
|
|
|
|
|
|
// Set y coordinates correctly
|
|
|
|
y += parseInt((H - y)/2) + 5;
|
|
|
|
|
|
|
|
if (hideClkInfo){
|
2023-02-25 17:52:29 +00:00
|
|
|
g.setFont("6x8:5"); //g.setLargeFont();
|
2023-02-25 17:43:59 +00:00
|
|
|
} else {
|
|
|
|
y -= 15;
|
2023-02-25 17:52:29 +00:00
|
|
|
g.setFont("6x8:4"); //g.setMediumFont();
|
2023-02-25 17:43:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Clear region and draw time
|
|
|
|
g.setColor(g.theme.fg);
|
|
|
|
g.fillRect(0,y1,W,y+20 + (hideClkInfo ? 1 : 0) + (isFullscreen() ? 3 : 0));
|
|
|
|
|
|
|
|
g.setColor(g.theme.bg);
|
|
|
|
g.setFontAlign(0,0);
|
|
|
|
g.drawString(timeStr, W/2, y);
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
let drawLock = function() {
|
|
|
|
if(settings.showLock && Bangle.isLocked()){
|
|
|
|
g.setColor(g.theme.fg);
|
|
|
|
g.drawImage(imgLock(), W-16, 2);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
let drawWidgets = function() {
|
|
|
|
if(isFullscreen()){
|
|
|
|
widget_utils.hide();
|
|
|
|
} else {
|
|
|
|
Bangle.drawWidgets();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/************************************************
|
|
|
|
* Listener
|
|
|
|
*/
|
|
|
|
// timeout used to update every minute
|
|
|
|
let drawTimeout;
|
|
|
|
|
|
|
|
// schedule a draw for the next minute
|
|
|
|
let queueDraw = function() {
|
|
|
|
if (drawTimeout) clearTimeout(drawTimeout);
|
|
|
|
drawTimeout = setTimeout(function() {
|
|
|
|
drawTimeout = undefined;
|
|
|
|
draw();
|
|
|
|
}, 60000 - (Date.now() % 60000));
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// Stop updates when LCD is off, restart when on
|
|
|
|
let lcdListenerBw = function(on) {
|
|
|
|
if (on) {
|
|
|
|
draw(); // draw immediately, queue redraw
|
|
|
|
} else { // stop draw timer
|
|
|
|
if (drawTimeout) clearTimeout(drawTimeout);
|
|
|
|
drawTimeout = undefined;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
Bangle.on('lcdPower', lcdListenerBw);
|
|
|
|
|
|
|
|
let lockListenerBw = function(isLocked) {
|
|
|
|
if (drawTimeout) clearTimeout(drawTimeout);
|
|
|
|
drawTimeout = undefined;
|
|
|
|
|
|
|
|
if(!isLocked && settings.screen.toLowerCase() == "dynamic"){
|
|
|
|
// If we have to show the widgets again, we load it from our
|
|
|
|
// cache and not through Bangle.loadWidgets as its much faster!
|
|
|
|
widget_utils.show();
|
|
|
|
}
|
|
|
|
|
|
|
|
draw();
|
|
|
|
};
|
|
|
|
Bangle.on('lock', lockListenerBw);
|
|
|
|
|
|
|
|
let charging = function(charging){
|
|
|
|
// Jump to battery
|
|
|
|
clockInfoMenu.setItem(0, 2);
|
|
|
|
drawTime();
|
2023-02-25 17:52:29 +00:00
|
|
|
};
|
2023-02-25 17:43:59 +00:00
|
|
|
Bangle.on('charging', charging);
|
|
|
|
|
|
|
|
let kill = function(){
|
|
|
|
clockInfoMenu.remove();
|
|
|
|
delete clockInfoMenu;
|
|
|
|
};
|
|
|
|
E.on("kill", kill);
|
|
|
|
|
|
|
|
/************************************************
|
|
|
|
* Startup Clock
|
|
|
|
*/
|
|
|
|
|
|
|
|
// Show launcher when middle button pressed
|
|
|
|
Bangle.setUI({
|
|
|
|
mode : "clock",
|
|
|
|
remove : function() {
|
|
|
|
// Called to unload all of the clock app
|
|
|
|
Bangle.removeListener('lcdPower', lcdListenerBw);
|
|
|
|
Bangle.removeListener('lock', lockListenerBw);
|
|
|
|
Bangle.removeListener('charging', charging);
|
|
|
|
if (drawTimeout) clearTimeout(drawTimeout);
|
|
|
|
drawTimeout = undefined;
|
|
|
|
// save settings
|
|
|
|
kill();
|
|
|
|
E.removeListener("kill", kill);
|
2023-02-25 17:52:29 +00:00
|
|
|
Bangle.removeListener('charging', charging);
|
2023-02-25 17:43:59 +00:00
|
|
|
widget_utils.show();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
// Load widgets and draw clock the first time
|
|
|
|
Bangle.loadWidgets();
|
|
|
|
|
|
|
|
// Draw first time
|
2023-02-25 17:52:29 +00:00
|
|
|
g.setColor(g.theme.fg).fillRect(0,135,W,H); // Otherwise this rect will wait for clock_info before updating
|
2023-02-25 17:43:59 +00:00
|
|
|
draw();
|
|
|
|
|
|
|
|
} // End of app scope
|