Files
bangle/antonclk/antonclk.app.js
2026-03-09 14:12:12 -06:00

423 lines
11 KiB
JavaScript

{ // must be inside our own scope here so that when we are unloaded everything disappears
// we also define functions using 'let fn = function() {..}' for the same reason. function decls are global
const STATE_IDLE = 0;
const STATE_MENU_OPEN = 3;
let apiKey = require("Storage").readJSON("apikey.json", null);
if (!apiKey) {
require("Storage").writeJSON("apikey.json", "NEEDTOSET");
}
let watchState = STATE_IDLE;
let stopWatch = require("Storage").readJSON("mystopwatch.json", true) || {start1: null, elapsed1: null, start2: null, elapsed2: null};
let saveStopWatch = function() {
require("Storage").writeJSON("mystopwatch.json", stopWatch);
}
let stopWatchTimer = null;
let myMessage = "";
let temperature = "";
let drawTimer = null;
let menu = require("Storage").readJSON("menu.json", true);
let subMenu = null;
let menuCommand = "";
let drawStopWatches = function () {
if (watchState != STATE_IDLE) return;
var w = g.getWidth();
var x = w / 2;
var y = g.getHeight() / 2;
if (stopWatch.start1 || stopWatch.elapsed1) {
let Tt1 = (stopWatch.elapsed1 || 0);
if (stopWatch.start1) {
Tt1 += Date.now() - stopWatch.start1;
}
let Ttxt1 = timeToText(Tt1);
g.clearRect(0, y-60, w, y-34);
g.setColor(g.theme.fg);
g.setFontAlign(0, 0).setFont("Vector", 26).drawString("S1: " + Ttxt1, x, y-45);
}
if (stopWatch.start2 || stopWatch.elapsed2) {
let Tt2 = (stopWatch.elapsed2 || 0);
if (stopWatch.start2) {
Tt2 += Date.now() - stopWatch.start2;
}
let Ttxt2 = timeToText(Tt2);
g.clearRect(0, y+61, w, y+88);
g.setColor(g.theme.fg);
g.setFontAlign(0, 0).setFont("Vector", 26).drawString("S2: " + Ttxt2, x, y+76);
}
}
let paintFace = function() {
if (watchState != STATE_IDLE) return;
var x = g.getWidth() / 2;
var y = g.getHeight() / 2;
g.reset().clearRect(Bangle.appRect); // clear whole background (w/o widgets)
var date = new Date();
var timeStr = require("locale").time(date, 1); // Hour and minute
g.setFontAlign(0, 0).setFont("Vector", 60).drawString(timeStr, x, y); // Used to be Anton, +20
var utc_sec = getTime();
var utc = utc_sec % 86400;
var utcHour = Math.floor(utc / 3600);
var utcMinute = Math.floor((utc % 3600) / 60);
var utcStr = utcHour.toString().padStart(2, '0') + ":" + utcMinute.toString().padStart(2, '0');
g.setFontAlign(0, 0).setFont("Vector", 36).drawString(utcStr, x-25, y+43);
var tz_offset = date.toString().indexOf("GMT");
var tz = date.toString().substring(tz_offset+3, tz_offset+6);
g.setFontAlign(0, 0).setFont("Vector", 24).drawString(tz, x+60, y+43);
// Show date and day of week
const days = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
var dateStr = date.getDate() + " " + days[date.getDay()] + " " + temperature;
// don't draw date string if stopwatch 2 is running
if (!stopWatch.start2 && !stopWatch.elapsed2) {
g.setFontAlign(0, 0).setFont("Vector", 26).drawString(dateStr, x, y+76);
}
//var wrapped = g.wrapString(myMessage, g.getWidth()-10).join("\n");
// don't draw message if stopwatch 1 is running
if (!stopWatch.start1 && !stopWatch.elapsed1) {
g.setFontAlign(0, 0).setFont("Vector", 26).drawString(myMessage, x, y-45);
}
drawStopWatches();
};
// Actually draw the watch face
let draw = function() {
if (Bangle.http){
Bangle.http("https://api.home.dns.t0.vc/bangle", {timeout:3000}).then(event => {
let result = JSON.parse(event.resp);
myMessage = result.context;
temperature = result.temperature;
if (watchState == STATE_IDLE) {
if (paintFace) paintFace();
}
}).catch((e)=>{
myMessage = "GET error";
if (paintFace) paintFace();
});
}
// queue next draw
if (drawTimer) clearTimeout(drawTimer);
drawTimer = setTimeout(function() {
drawTimer = undefined;
draw();
}, 60000 - (Date.now() % 60000));
};
let timeToText = function(t) {
let hrs = Math.floor(t/3600000);
let mins = Math.floor(t/60000)%60;
let secs = Math.floor(t/1000)%60;
let tnth = Math.floor(t/100)%10;
let text;
if (hrs === 0) {
text = ("0"+mins).substr(-2) + ":" + ("0"+secs).substr(-2) + "." + tnth;
} else {
text = ("0"+hrs) + ":" + ("0"+mins).substr(-2) + ":" + ("0"+secs).substr(-2);
}
return text;
};
let handleSwipe = function(dir1, dir2) {
var direction;
if (dir1 == 1) {
direction = "right";
} else if (dir1 == -1) {
direction = "left";
} else if (dir2 == 1) {
direction = "down";
} else if (dir2 == -1) {
direction = "up";
} else {
direction = "none";
}
if (Bangle.http){
const headers = {"Authorization": "Bearer " + apiKey};
const options = {timeout:3000, method: "post", body: direction, headers: headers};
Bangle.http("https://api.home.dns.t0.vc/bangle", options).then(event => {
myMessage = "Sent " + direction;
if (paintFace) paintFace();
}).catch((e)=>{
myMessage = "POST error";
if (paintFace) paintFace();
});
}
};
let drawMenu = function(menu) {
const keys = Object.keys(menu);
g.reset().clearRect(Bangle.appRect);
g.drawLine(88, 0, 88, 175); // |
g.drawLine(0, 88, 175, 88); // --
const wrap = function(text) {
return g.wrapString(text, 80).join("\n");
};
g.setFontAlign(0, 0).setFont("Vector", 26).drawString(wrap(keys[0]), 50, 50); // 0
g.setFontAlign(0, 0).setFont("Vector", 26).drawString(wrap(keys[1]), 130, 50); // 1
g.setFontAlign(0, 0).setFont("Vector", 26).drawString(wrap(keys[2]), 50, 130); // 2
g.setFontAlign(0, 0).setFont("Vector", 26).drawString(wrap(keys[3]), 130, 130); // 3
};
let startSW1 = function() {
console.log("Starting stopwatch 1...");
stopWatch.start1 = Date.now();
if (!stopWatch.elapsed1) {
stopWatch.elapsed1 = 0;
}
saveStopWatch();
if (!stopWatchTimer) {
drawStopWatches();
stopWatchTimer = setInterval(drawStopWatches, 100);
}
}
let startSW2 = function() {
console.log("Starting stopwatch 2...");
stopWatch.start2 = Date.now();
if (!stopWatch.elapsed2) {
stopWatch.elapsed2 = 0;
}
saveStopWatch();
if (!stopWatchTimer) {
drawStopWatches();
stopWatchTimer = setInterval(drawStopWatches, 100);
}
}
let pauseSW1 = function() {
if (!stopWatch.start1) return;
stopWatch.elapsed1 += Date.now() - stopWatch.start1;
stopWatch.start1 = null;
saveStopWatch();
if (!stopWatch.start2) {
if (stopWatchTimer) {
clearInterval(stopWatchTimer);
stopWatchTimer = null;
}
}
};
let stopSW1 = function() {
stopWatch.start1 = null;
stopWatch.elapsed1 = null;
saveStopWatch();
if (!stopWatch.start2) {
if (stopWatchTimer) {
clearInterval(stopWatchTimer);
stopWatchTimer = null;
}
}
};
let pauseSW2 = function() {
if (!stopWatch.start2) return;
stopWatch.elapsed2 += Date.now() - stopWatch.start2;
stopWatch.start2 = null;
saveStopWatch();
if (!stopWatch.start1) {
if (stopWatchTimer) {
clearInterval(stopWatchTimer);
stopWatchTimer = null;
}
}
};
let stopSW2 = function() {
stopWatch.start2 = null;
stopWatch.elapsed2 = null;
saveStopWatch();
if (!stopWatch.start1) {
if (stopWatchTimer) {
clearInterval(stopWatchTimer);
stopWatchTimer = null;
}
}
};
let handleTouch = function(button, xy) {
console.log(button, xy);
const touchX = xy.x;
const touchY = xy.y;
const pressed = xy.type == 0;
// 0 1
// 2 3
let quad = -1;
if (touchY < 110) {
if (touchX < 110) {
quad = 0;
} else {
quad = 1;
}
} else {
if (touchX < 110) {
quad = 2;
} else {
quad = 3;
}
}
//console.log("quad:", quad);
if (watchState == STATE_IDLE && pressed) {
watchState = STATE_MENU_OPEN;
subMenu = menu;
menuCommand = "";
}
const keys = Object.keys(subMenu);
const key = keys[quad];
if (key == "stop watch") {
subMenu = {};
const sw2key = stopWatch.start2 ? 'pause2' : 'start2';
subMenu[sw2key] = null;
subMenu["stop2"] = null;
const sw1key = stopWatch.start1 ? 'pause1' : 'start1';
subMenu[sw1key] = null;
subMenu["stop1"] = null;
} else {
subMenu = subMenu[key];
}
menuCommand += key + ",";
console.log("submenu:", subMenu);
if (subMenu) {
drawMenu(subMenu);
} else {
watchState = STATE_IDLE;
console.log("menuCommand:", menuCommand);
Bangle.drawWidgets();
Bangle.buzz(100, 0.2);
if (menuCommand == "commands,util,pull menu,") {
console.log("Pulling new menu...");
menu = null;
require("Storage").writeJSON("menu.json", menu);
} else if (menuCommand == "states,stop watch,start1,") {
startSW1();
} else if (menuCommand == "states,stop watch,start2,") {
startSW2();
} else if (menuCommand == "states,stop watch,pause1,") {
pauseSW1();
} else if (menuCommand == "states,stop watch,pause2,") {
pauseSW2();
} else if (menuCommand == "states,stop watch,stop1,") {
stopSW1();
} else if (menuCommand == "states,stop watch,stop2,") {
stopSW2();
} else {
if (Bangle.http){
const headers = {"Authorization": "Bearer " + apiKey};
const options = {timeout:3000, method: "post", body: menuCommand, headers: headers};
Bangle.http("https://api.home.dns.t0.vc/menu", options).then(event => {
myMessage = "ok";
if (paintFace) paintFace();
}).catch((e)=>{
myMessage = "POST error";
if (paintFace) paintFace();
});
}
}
myMessage = key;
if (paintFace) paintFace();
}
};
let handleTwist = function() {
console.log("twisted");
if (watchState == STATE_MENU_OPEN) {
watchState = STATE_IDLE;
myMessage = "cancelled";
if (paintFace) paintFace();
Bangle.drawWidgets();
}
};
if (Bangle.http && !menu){
Bangle.http("https://api.home.dns.t0.vc/menu", {timeout:3000}).then(event => {
menu = JSON.parse(event.resp);
require("Storage").writeJSON("menu.json", menu);
}).catch((e)=>{
myMessage = "Menu error";
if (paintFace) paintFace();
});
}
Bangle.on('swipe', handleSwipe);
//Bangle.on('drag', handleDrag);
Bangle.on('touch', handleTouch);
Bangle.on('twist', handleTwist);
// Show launcher when middle button pressed
Bangle.setUI({
mode : "clock",
remove : function() {
// Called to unload all of the clock app
Bangle.removeListener('swipe', handleSwipe);
//Bangle.removeListener('drag', handleDrag);
Bangle.removeListener('touch', handleTouch);
Bangle.removeListener('twist', handleTwist);
if (drawTimer) clearTimeout(drawTimer);
drawTimer = undefined;
if (stopWatchTimer) clearTimeout(stopWatchTimer);
stopWatchTimer = undefined;
paintFace = undefined; // http request may resolve after font's been unloaded, so unset
}});
// Load widgets
Bangle.loadWidgets();
paintFace();
drawStopWatches();
if (stopWatch.start1 || stopWatch.start2) {
if (!stopWatchTimer) {
stopWatchTimer = setInterval(drawStopWatches, 100);
}
}
draw();
setTimeout(Bangle.drawWidgets,0);
}