BangleApps/apps/elapsed_t/app.js

475 lines
12 KiB
JavaScript

const APP_NAME = "elapsed_t";
//const COLOUR_BLACK = 0x0;
//const COLOUR_DARK_GREY = 0x4208; // same as: g.setColor(0.25, 0.25, 0.25)
const COLOUR_GREY = 0x8410; // same as: g.setColor(0.5, 0.5, 0.5)
const COLOUR_LIGHT_GREY = 0xc618; // same as: g.setColor(0.75, 0.75, 0.75)
const COLOUR_RED = 0xf800; // same as: g.setColor(1, 0, 0)
const COLOUR_BLUE = 0x001f; // same as: g.setColor(0, 0, 1)
//const COLOUR_YELLOW = 0xffe0; // same as: g.setColor(1, 1, 0)
//const COLOUR_LIGHT_CYAN = 0x87ff; // same as: g.setColor(0.5, 1, 1)
//const COLOUR_DARK_YELLOW = 0x8400; // same as: g.setColor(0.5, 0.5, 0)
//const COLOUR_DARK_CYAN = 0x0410; // same as: g.setColor(0, 0.5, 0.5)
const COLOUR_CYAN = "#00FFFF";
const COLOUR_ORANGE = 0xfc00; // same as: g.setColor(1, 0.5, 0)
const SCREEN_WIDTH = g.getWidth();
const SCREEN_HEIGHT = g.getHeight();
const BIG_FONT_SIZE = 38;
const SMALL_FONT_SIZE = 22;
var arrowFont = atob("BwA4AcAOAHADgBwA4McfOf3e/+P+D+A+AOA="); // contains only the > character
var now = new Date();
var settings = Object.assign({
// default values
displaySeconds: true,
displayMonthsYears: true,
dateFormat: 0,
time24: true
}, require('Storage').readJSON(APP_NAME + ".settings.json", true) || {});
var temp_displaySeconds = settings.displaySeconds;
var data = Object.assign({
// default values
target: {
isSet: false,
Y: now.getFullYear(),
M: now.getMonth() + 1, // Month is zero-based, so add 1
D: now.getDate(),
h: now.getHours(),
m: now.getMinutes(),
s: 0
}
}, require('Storage').readJSON(APP_NAME + ".data.json", true) || {});
function writeData() {
require('Storage').writeJSON(APP_NAME + ".data.json", data);
}
function writeSettings() {
require('Storage').writeJSON(APP_NAME + ".settings.json", settings);
temp_displaySeconds = settings.temp_displaySeconds;
}
let inMenu = false;
Bangle.on('touch', function (zone, e) {
if (!inMenu) {
if (drawTimeout) clearTimeout(drawTimeout);
E.showMenu(menu);
inMenu = true;
}
});
function pad2(number) {
return (String(number).padStart(2, '0'));
}
function formatDateTime(date, dateFormat, time24, showSeconds) {
var formattedDateTime = {
date: "",
time: ""
};
var DD = pad2(date.getDate());
var MM = pad2(date.getMonth() + 1); // Month is zero-based
var YYYY = date.getFullYear();
var h = date.getHours();
var hh = pad2(date.getHours());
var mm = pad2(date.getMinutes());
var ss = pad2(date.getSeconds());
switch (dateFormat) {
case 0:
formattedDateTime.date = `${DD}/${MM}/${YYYY}`;
break;
case 1:
formattedDateTime.date = `${MM}/${DD}/${YYYY}`;
break;
case 2:
formattedDateTime.date = `${YYYY}-${MM}-${DD}`;
break;
default:
formattedDateTime.date = `${YYYY}-${MM}-${DD}`;
break;
}
if (time24) {
formattedDateTime.time = `${hh}:${mm}${showSeconds ? `:${ss}` : ''}`;
} else {
var ampm = (h >= 12 ? 'PM' : 'AM');
var h_ampm = h % 12;
h_ampm = (h_ampm == 0 ? 12 : h_ampm);
formattedDateTime.time = `${h_ampm}:${mm}${showSeconds ? `:${ss}` : ''} ${ampm}`;
}
return formattedDateTime;
}
function formatHourToAMPM(h){
var ampm = (h >= 12 ? 'PM' : 'AM');
var h_ampm = h % 12;
h_ampm = (h_ampm == 0 ? 12 : h_ampm);
return `${h_ampm} ${ampm}`
}
function howManyDaysInMonth(month, year) {
return new Date(year, month, 0).getDate();
}
function handleExceedingDay() {
var maxDays = howManyDaysInMonth(data.target.M, data.target.Y);
menu.Day.max = maxDays;
if (data.target.D > maxDays) {
menu.Day.value = maxDays;
data.target.D = maxDays;
}
}
var menu = {
"": {
"title": "Set target",
back: function () {
E.showMenu();
Bangle.setUI("clock");
inMenu = false;
draw();
}
},
'Day': {
value: data.target.D,
min: 1, max: 31, wrap: true,
onchange: v => {
data.target.D = v;
}
},
'Month': {
value: data.target.M,
min: 1, max: 12, noList: true, wrap: true,
onchange: v => {
data.target.M = v;
handleExceedingDay();
}
},
'Year': {
value: data.target.Y,
min: 1900, max: 2100,
onchange: v => {
data.target.Y = v;
handleExceedingDay();
}
},
'Hours': {
value: data.target.h,
min: 0, max: 23, wrap: true,
onchange: v => {
data.target.h = v;
},
format: function (v) {return(settings.time24 ? pad2(v) : formatHourToAMPM(v))}
},
'Minutes': {
value: data.target.m,
min: 0, max: 59, wrap: true,
onchange: v => {
data.target.m = v;
},
format: function (v) { return pad2(v); }
},
'Seconds': {
value: data.target.s,
min: 0, max: 59, wrap: true,
onchange: v => {
data.target.s = v;
},
format: function (v) { return pad2(v); }
},
'Save': function () {
E.showMenu();
inMenu = false;
Bangle.setUI("clock");
setTarget(true);
writeSettings();
temp_displaySeconds = settings.displaySeconds;
updateQueueMillis(settings.displaySeconds);
draw();
},
'Reset': function () {
E.showMenu();
inMenu = false;
Bangle.setUI("clock");
setTarget(false);
updateQueueMillis(settings.displaySeconds);
draw();
}
};
function setTarget(set) {
if (set) {
target = new Date(
data.target.Y,
data.target.M - 1,
data.target.D,
data.target.h,
data.target.m,
data.target.s
);
data.target.isSet = true;
} else {
target = new Date();
Object.assign(
data,
{
target: {
isSet: false,
Y: now.getFullYear(),
M: now.getMonth() + 1, // Month is zero-based, so add 1
D: now.getDate(),
h: now.getHours(),
m: now.getMinutes(),
s: 0
}
}
);
menu.Day.value = data.target.D;
menu.Month.value = data.target.M;
menu.Year.value = data.target.Y;
menu.Hours.value = data.target.h;
menu.Minutes.value = data.target.m;
menu.Seconds.value = 0;
}
writeData();
}
var target;
setTarget(data.target.isSet);
var drawTimeout;
var queueMillis = 1000;
function queueDraw() {
if (drawTimeout) clearTimeout(drawTimeout);
var delay = queueMillis - (Date.now() % queueMillis);
if (queueMillis == 60000 && signIsNegative()) {
delay += 1000;
}
drawTimeout = setTimeout(function () {
drawTimeout = undefined;
draw();
}, delay);
}
function updateQueueMillis(displaySeconds) {
if (displaySeconds) {
queueMillis = 1000;
} else {
queueMillis = 60000;
}
}
Bangle.on('lock', function (on, reason) {
if (on) { // screen is locked
temp_displaySeconds = false;
updateQueueMillis(false);
draw();
} else { // screen is unlocked
temp_displaySeconds = settings.displaySeconds;
updateQueueMillis(temp_displaySeconds);
draw();
}
});
function signIsNegative() {
var now = new Date();
return (now < target);
}
function diffToTarget() {
var diff = {
sign: "+",
Y: "0",
M: "0",
D: "0",
hh: "00",
mm: "00",
ss: "00"
};
if (!data.target.isSet) {
return (diff);
}
var now = new Date();
diff.sign = now < target ? '-' : '+';
if (settings.displayMonthsYears) {
var start;
var end;
if (now > target) {
start = target;
end = now;
} else {
start = now;
end = target;
}
diff.Y = end.getFullYear() - start.getFullYear();
diff.M = end.getMonth() - start.getMonth();
diff.D = end.getDate() - start.getDate();
diff.hh = end.getHours() - start.getHours();
diff.mm = end.getMinutes() - start.getMinutes();
diff.ss = end.getSeconds() - start.getSeconds();
// Adjust negative differences
if (diff.ss < 0) {
diff.ss += 60;
diff.mm--;
}
if (diff.mm < 0) {
diff.mm += 60;
diff.hh--;
}
if (diff.hh < 0) {
diff.hh += 24;
diff.D--;
}
if (diff.D < 0) {
var lastMonthDays = new Date(end.getFullYear(), end.getMonth(), 0).getDate();
diff.D += lastMonthDays;
diff.M--;
}
if (diff.M < 0) {
diff.M += 12;
diff.Y--;
}
} else {
var timeDifference = target - now;
timeDifference = Math.abs(timeDifference);
// Calculate days, hours, minutes, and seconds
diff.D = Math.floor(timeDifference / (1000 * 60 * 60 * 24));
diff.hh = Math.floor((timeDifference % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
diff.mm = Math.floor((timeDifference % (1000 * 60 * 60)) / (1000 * 60));
diff.ss = Math.floor((timeDifference % (1000 * 60)) / 1000);
}
// add zero padding
diff.hh = pad2(diff.hh);
diff.mm = pad2(diff.mm);
diff.ss = pad2(diff.ss);
return diff;
}
function draw() {
var now = new Date();
var nowFormatted = formatDateTime(now, settings.dateFormat, settings.time24, temp_displaySeconds);
var targetFormatted = formatDateTime(target, settings.dateFormat, settings.time24, true);
var diff = diffToTarget();
const nowY = now.getFullYear();
const nowM = now.getMonth();
const nowD = now.getDate();
const targetY = target.getFullYear();
const targetM = target.getMonth();
const targetD = target.getDate();
var diffYMD;
if (settings.displayMonthsYears)
diffYMD = `${diff.sign}${diff.Y}Y ${diff.M}M ${diff.D}D`;
else
diffYMD = `${diff.sign}${diff.D}D`;
var diff_hhmm = `${diff.hh}:${diff.mm}`;
g.clearRect(0, 24, SCREEN_WIDTH, SCREEN_HEIGHT);
//console.log("drawing");
let y = 24; //Bangle.getAppRect().y;
// draw current date
g.setFont("Vector", SMALL_FONT_SIZE).setFontAlign(-1, -1).setColor(g.theme.dark ? COLOUR_CYAN : COLOUR_BLUE);
g.drawString(nowFormatted.date, 4, y);
y += SMALL_FONT_SIZE;
// draw current time
g.setFont("Vector", SMALL_FONT_SIZE).setFontAlign(-1, -1).setColor(g.theme.dark ? COLOUR_CYAN : COLOUR_BLUE);
g.drawString(nowFormatted.time, 4, y);
y += SMALL_FONT_SIZE;
// draw arrow
g.setFontCustom(arrowFont, 62, 16, 13).setFontAlign(-1, -1).setColor(g.theme.dark ? COLOUR_ORANGE : COLOUR_RED);
g.drawString(">", 4, y + 3);
if (data.target.isSet) {
g.setFont("Vector", SMALL_FONT_SIZE).setFontAlign(-1, -1).setColor(g.theme.dark ? COLOUR_ORANGE : COLOUR_RED);
if (nowY == targetY && nowM == targetM && nowD == targetD) {
// today
g.drawString("TODAY", 4 + 16 + 6, y);
} else if (nowY == targetY && nowM == targetM && nowD - targetD == 1) {
// yesterday
g.drawString("YESTERDAY", 4 + 16 + 6, y);
} else if (nowY == targetY && nowM == targetM && targetD - nowD == 1) {
// tomorrow
g.drawString("TOMORROW", 4 + 16 + 6, y);
} else {
// general case
// draw target date
g.drawString(targetFormatted.date, 4 + 16 + 6, y);
}
y += SMALL_FONT_SIZE;
// draw target time
g.setFont("Vector", SMALL_FONT_SIZE).setFontAlign(-1, -1).setColor(g.theme.dark ? COLOUR_ORANGE : COLOUR_RED);
g.drawString(targetFormatted.time, 4, y);
y += SMALL_FONT_SIZE + 4;
} else {
// draw NOT SET
g.setFont("Vector", SMALL_FONT_SIZE).setFontAlign(-1, -1).setColor(g.theme.dark ? COLOUR_ORANGE : COLOUR_RED);
g.drawString("NOT SET", 4 + 16 + 6, y);
y += 2 * SMALL_FONT_SIZE + 4;
}
// draw separator
g.setColor(g.theme.fg);
g.drawLine(0, y - 4, SCREEN_WIDTH, y - 4);
// draw diffYMD
g.setFont("Vector", SMALL_FONT_SIZE).setFontAlign(0, -1).setColor(g.theme.fg);
g.drawString(diffYMD, SCREEN_WIDTH / 2, y);
y += SMALL_FONT_SIZE;
// draw diff_hhmm
g.setFont("Vector", BIG_FONT_SIZE).setFontAlign(0, -1).setColor(g.theme.fg);
g.drawString(diff_hhmm, SCREEN_WIDTH / 2, y);
// draw diff_ss
if (temp_displaySeconds) {
g.setFont("Vector", SMALL_FONT_SIZE).setFontAlign(-1, -1).setColor(g.theme.dark ? COLOUR_LIGHT_GREY : COLOUR_GREY);
g.drawString(diff.ss, SCREEN_WIDTH / 2 + 52, y + 13);
}
queueDraw();
}
Bangle.loadWidgets();
Bangle.drawWidgets();
Bangle.setUI("clock");
draw();