const dataFile = "chrono_data.json"; let chronoTime = require("Storage").readJSON(dataFile) || {start: 0, elapsed: 0, laps: [], mode: undefined}; const midX = Bangle.appRect.x + Bangle.appRect.x2 / 2; const midY = Bangle.appRect.y + Bangle.appRect.y2 / 2; const buttonH = 50; const buttonsRect = {x: Bangle.appRect.x, y: Bangle.appRect.y2 - buttonH, x2: Bangle.appRect.x2, y2: Bangle.appRect.y2}; const timeRect = {x: Bangle.appRect.x + 3, y: buttonsRect.y - 55, x2: Bangle.appRect.x2 - 3, y2: buttonsRect.y - 10}; const lapsRect = {x: Bangle.appRect.x, y: Bangle.appRect.y, x2: Bangle.appRect.x2, y2: timeRect.y - 3}; const lapsFont = "Vector:25"; const timeFont = "Vector:40"; const lapsStrW = g.setFont(lapsFont).stringWidth("00:00.0"); const timeStrW = g.setFont(timeFont).stringWidth("00:00.0"); let updateIntID; const drawButton = function(button) { g.setFont("Vector:27").setFontAlign(0,0).setColor(0, 1, 1); g.fillRect({x: button.x, y: button.y, x2: button.x + button.w - 1, y2: button.y + button.h - 1, r: 12}); g.setColor(0, 0, 0).fillRect({x: button.x + 3, y: button.y + 3, x2: button.x + button.w - 4, y2: button.y + button.h - 4, r: 9}); g.setColor(-1); g.setFontAlign(0,0).drawString(button.label, button.x + (button.w / 2), button.y + (button.h / 2)); }; const clearButtons = function() { g.clearRect(buttonsRect); }; const startButton = {x: Bangle.appRect.x, y: Bangle.appRect.y2 - buttonH, w: Bangle.appRect.w, h: buttonH, label: "Start"}; const lapButton = {x: Bangle.appRect.x, y: Bangle.appRect.y2 - buttonH, w: (Bangle.appRect.w / 2) - 2, h: buttonH, label: "Lap"}; const pauseButton = {x: this.midX + 1, y: Bangle.appRect.y2 - buttonH, w: (Bangle.appRect.w / 2) - 2, h: buttonH, label: "Stop"}; const resetButton = {x: Bangle.appRect.x, y: Bangle.appRect.y2 - buttonH, w: (Bangle.appRect.w / 2) - 2, h: buttonH, label: "Reset"}; const smallStartButton = {x: this.midX + 2, y: Bangle.appRect.y2 - buttonH, w: (Bangle.appRect.w / 2) - 2, h: buttonH, label: "Start"}; const drawTime = function(timeStr) { g.setBgColor(0, 0.25, 0.25); g.clearRect(timeRect); g.setFont(timeFont).setFontAlign(0,1); g.drawString(timeStr, midX, timeRect.y2); g.setBgColor(0, 0, 0); }; const ms2str = function(ms) { const h = Math.floor(ms / 3600000); const m = Math.floor((ms / 60000) % 60); const s = Math.floor((ms / 1000) % 60); const tnth = Math.floor((ms % 1000) / 100); const format = (timePart) => (timePart < 10) ? "0" + timePart : timePart; return (h > 0 ? format(h) + ":" : "") + format(m) + ":" + format(s) + (h > 0 ? "" : "." + tnth); }; const keepUpdated = function(shouldUpdate) { if (updateIntID) clearInterval(updateIntID); if (shouldUpdate) { updateIntID = setInterval(()=> { chronoTime.elapsed = getElapsed(); drawTime(ms2str(chronoTime.elapsed)); }, 100); } }; const start = function() { chronoTime.mode = "running"; if (chronoTime.start === 0) chronoTime.start = Date.now(); saveState(); keepUpdated(true); clearButtons(); drawButton(lapButton); drawButton(pauseButton); }; const pause = function() { chronoTime.mode = "stopped"; const now = Date.now(); chronoTime.elapsed = now - chronoTime.start; saveState(); keepUpdated(false); drawTime(ms2str(chronoTime.elapsed)); clearButtons(); drawButton(resetButton); drawButton(smallStartButton); }; const getElapsed = function() { return Date.now() - chronoTime.start; } const restart = function() { chronoTime.mode = "running"; chronoTime.start = Date.now() - chronoTime.elapsed; saveState(); keepUpdated(true); clearButtons(); drawButton(lapButton); drawButton(pauseButton); } const reset = function() { chronoTime.start = 0; chronoTime.elapsed = 0; chronoTime.laps = []; chronoTime.mode = undefined; saveState(); g.clearRect(lapsRect); drawTime(ms2str(chronoTime.elapsed)); clearButtons(); drawButton(startButton); }; const saveState = function() { require("Storage").writeJSON(dataFile, chronoTime); }; const lapScreen = { fh: g.setFont(lapsFont).getFontHeight(), numX: midX - (timeStrW / 2) + 5, strX: midX + (timeStrW / 2) - 5, } lapScreen.y0 = lapsRect.y2 - (chronoTime.laps.length * lapScreen.fh); const addLap = function() { chronoTime.laps.push(chronoTime.elapsed); lapScreen.y0 = lapsRect.y2 - (chronoTime.laps.length * lapScreen.fh); saveState(); }; const drawLaps = function() { g.setFont(lapsFont); g.clearRect(lapsRect); g.setClipRect(lapsRect.x, lapsRect.y, lapsRect.x2, lapsRect.y2); let y = lapScreen.y0; let lapNum = 1; for (let lap of chronoTime.laps) { if (y + lapScreen.fh > lapsRect.y) { g.setColor(0.5, 0.5, 0.5).setFontAlign(-1, -1).drawString(lapNum, lapScreen.numX, y); g.setColor(-1).setFontAlign(1, -1).drawString(ms2str(lap), lapScreen.strX, y); } y += lapScreen.fh; lapNum++; } g.setClipRect(Bangle.appRect.x, Bangle.appRect.y, Bangle.appRect.x2, Bangle.appRect.y2); }; const dragHandler = function(d) { const minY = lapsRect.y2 - (chronoTime.laps.length * lapScreen.fh); const maxY = minY > lapsRect.y ? lapsRect.y2 - (chronoTime.laps.length * lapScreen.fh) : lapsRect.y; if (d.dy && d.b) { lapScreen.y0 += d.dy; if (lapScreen.y0 < minY - 20) { // overscroll lapScreen.y0 = minY - 20; } else if (lapScreen.y0 > maxY + 20) { lapScreen.y0 = maxY + 20; } } else if (!d.b) { if (lapScreen.y0 < minY) { lapScreen.y0 = minY; } else if (lapScreen.y0 > maxY) { lapScreen.y0 = maxY; } } drawLaps(d.dy); }; const buttonHandler = function(_n, e) { if (e.y < Bangle.appRect.y2 - buttonH) { return; } else if (e.x < midX) { // button 1 switch (chronoTime.mode) { case undefined: start(); break; case "running": addLap(); drawLaps(); break; case "stopped": reset(); chronoTime.mode = undefined; break; } } else if (e.x > midX) { // button 2 switch (chronoTime.mode) { case undefined: start(); break; case "running": pause(); break; case "stopped": restart(); break; } } }; const main = function() { g.clear(); if (chronoTime.mode == "running") { chronoTime.elapsed = getElapsed(); start(); drawLaps(); } else if (chronoTime.mode == "stopped") { pause(); drawLaps(); } else if (chronoTime.mode == undefined){ drawTime(ms2str(chronoTime.elapsed)); drawButton(startButton); } Bangle.setUI({mode: "custom", touch: (_n, e) => buttonHandler(_n, e), drag: (e) => dragHandler(e), btn: (_n) => Bangle.showClock() }); }; main();