var DEBUG = false; var FILE = "touchtimer.data.json"; var main = () => { var settings = readSettings(); var button1 = new Button({ x1: 1, y1: 35, x2: 58, y2: 70 }, 1); var button2 = new Button({ x1: 60, y1: 35, x2: 116, y2: 70 }, 2); var button3 = new Button({ x1: 118, y1: 35, x2: 174, y2: 70 }, 3); var button4 = new Button({ x1: 1, y1: 72, x2: 58, y2: 105 }, 4); var button5 = new Button({ x1: 60, y1: 72, x2: 116, y2: 105 }, 5); var button6 = new Button({ x1: 118, y1: 72, x2: 174, y2: 105 }, 6); var button7 = new Button({ x1: 1, y1: 107, x2: 58, y2: 140 }, 7); var button8 = new Button({ x1: 60, y1: 107, x2: 116, y2: 140 }, 8); var button9 = new Button({ x1: 118, y1: 107, x2: 174, y2: 140 }, 9); var buttonOK = new Button({ x1: 1, y1: 142, x2: 58, y2: 174 }, "OK"); var button0 = new Button({ x1: 60, y1: 142, x2: 116, y2: 174 }, 0); var buttonDelete = new Button({ x1: 118, y1: 142, x2: 174, y2: 174 }, "<-"); var timerNumberButtons = [ button1, button2, button3, button4, button5, button6, button7, button8, button9, button0, ]; var timerInputButtons = [ button1, button2, button3, button4, button5, button6, button7, button8, button9, buttonOK, button0, buttonDelete, ]; var buttonStartPause = new Button( { x1: 1, y1: 35, x2: 174, y2: 105 }, "START" ); var buttonStop = new Button({ x1: 1, y1: 107, x2: 174, y2: 174 }, "STOP"); var timerRunningButtons = [buttonStartPause, buttonStop]; var timerEdit = new TimerEdit(); timerNumberButtons.forEach((numberButton) => { numberButton.setOnClick((number) => { log("number button clicked"); log(number); timerEdit.appendNumber(number); timerEdit.draw(); }); }); buttonDelete.setOnClick(() => { log("delete button clicked"); timerEdit.removeNumber(); timerEdit.draw(); }); buttonOK.setOnClick(() => { if (timerEdit.timeStr.length === 0) { return; } g.clear(); timerEdit.draw(); timerInputButtons.forEach((button) => button.disable()); timerRunningButtons.forEach((button) => { button.enable(); button.draw(); }); }); var timerIntervalId = undefined; var buzzIntervalId = undefined; var timerCountDown = undefined; buttonStartPause.setOnClick(() => { if (buttonStartPause.value === "PAUSE") { if (timerCountDown) { timerCountDown.pause(); } buttonStartPause.value = "START"; buttonStartPause.draw(); if (timerIntervalId) { clearInterval(timerIntervalId); timerIntervalId = undefined; } if (buzzIntervalId) { clearInterval(buzzIntervalId); buzzIntervalId = undefined; } return; } if (buttonStartPause.value === "START") { if (!timerCountDown) { timerCountDown = new TimerCountDown(timerEdit.timeStr); } else { timerCountDown.unpause(); } buttonStartPause.value = "PAUSE"; buttonStartPause.draw(); timerIntervalId = setInterval(() => { timerCountDown.draw(); // Buzz lightly when there are less then 5 seconds left if (settings.countDownBuzz) { var remainingSeconds = timerCountDown.getAdjustedTime().seconds; var remainingMinutes = timerCountDown.getAdjustedTime().minutes; var remainingHours = timerCountDown.getAdjustedTime().hours; if ( remainingSeconds <= 5 && remainingSeconds > 0 && remainingMinutes <= 0 && remainingHours <= 0) { Bangle.buzz(); } } if (timerCountDown.isFinished()) { buttonStartPause.value = "FINISHED!"; buttonStartPause.draw(); if (timerIntervalId) { clearInterval(timerIntervalId); timerIntervalId = undefined; } var buzzCount = 1; Bangle.buzz(settings.buzzDuration * 1000, 1); buzzIntervalId = setInterval(() => { if (buzzCount >= settings.buzzCount) { clearInterval(buzzIntervalId); buzzIntervalId = undefined; buttonStartPause.value = "REPEAT"; buttonStartPause.draw(); buttonStartPause.value = "START"; timerCountDown = undefined; timerEdit.draw(); return; } else { Bangle.buzz(settings.buzzDuration * 1000, 1); buzzCount++; } }, settings.buzzDuration * 1000 + settings.pauseBetween * 1000); } }, 1000); return; } }); buttonStop.setOnClick(() => { if (timerCountDown) { timerCountDown = undefined; } if (timerIntervalId) { clearInterval(timerIntervalId); timerIntervalId = undefined; } if (buzzIntervalId) { clearInterval(buzzIntervalId); buzzIntervalId = undefined; } buttonStartPause.value = "START"; buttonStartPause.draw(); g.clear(); timerEdit.reset(); timerEdit.draw(); timerRunningButtons.forEach((button) => button.disable()); timerInputButtons.forEach((button) => { button.enable(); button.draw(); }); }); // initalize g.clear(); timerEdit.draw(); timerInputButtons.forEach((button) => { button.enable(); button.draw(); }); }; // lib functions var log = (message) => { if (DEBUG) { console.log(JSON.stringify(message)); } }; var touchHandlers = []; Bangle.on("touch", (_button, xy) => { log("touch"); log(xy); var x = Math.min(Math.max(xy.x, 1), 174); var y = Math.min(Math.max(xy.y, 1), 174); touchHandlers.forEach((touchHandler) => { touchHandler(x, y); }); }); var BUTTON_BORDER_WITH = 2; class Button { constructor(position, value) { this.position = position; this.value = value; this.touchHandler = undefined; this.highlightTimeoutId = undefined; } draw(highlight) { g.setColor(g.theme.fg); g.fillRect( this.position.x1, this.position.y1, this.position.x2, this.position.y2 ); if (highlight) { g.setColor(g.theme.bgH); } else { g.setColor(g.theme.bg); } g.fillRect( this.position.x1 + BUTTON_BORDER_WITH, this.position.y1 + BUTTON_BORDER_WITH, this.position.x2 - BUTTON_BORDER_WITH, this.position.y2 - BUTTON_BORDER_WITH ); g.setColor(g.theme.fg); g.setFontAlign(0, 0); g.setFont("Vector", 35); g.drawString( this.value, this.position.x1 + (this.position.x2 - this.position.x1) / 2 + 2, this.position.y1 + (this.position.y2 - this.position.y1) / 2 + 2 ); } setOnClick(callback) { this.touchHandler = (x, y) => { if ( x >= this.position.x1 && x <= this.position.x2 && y >= this.position.y1 && y <= this.position.y2 ) { this.draw(true); this.highlightTimeoutId = setTimeout(() => { this.draw(); this.highlightTimeoutId = undefined; }, 100); setTimeout(() => callback(this.value), 25); } }; } disable() { log("disable button"); log(this.value); var touchHandlerIndex = touchHandlers.indexOf(this.touchHandler); if (touchHandlerIndex > -1) { log("clearing touch handler"); touchHandlers.splice(touchHandlerIndex, 1); } if (this.highlightTimeoutId) { log("clearing higlight timeout"); clearTimeout(this.highlightTimeoutId); this.highlightTimeoutId = undefined; } } enable() { if (this.touchHandler) { touchHandlers.push(this.touchHandler); } } } class TimerEdit { constructor() { this.timeStr = ""; } appendNumber(number) { if (number === 0 && this.timeStr.length === 0) { return; } if (this.timeStr.length <= 6) { this.timeStr = this.timeStr + number; } } removeNumber() { if (this.timeStr.length > 0) { this.timeStr = this.timeStr.slice(0, -1); } } reset() { this.timeStr = ""; } draw() { log("drawing timer edit"); var timeStrPadded = this.timeStr.padStart(6, "0"); var timeStrDisplay = "" + timeStrPadded.slice(0, 2) + "h " + timeStrPadded.slice(2, 4) + "m " + timeStrPadded.slice(4, 6) + "s"; log(timeStrPadded); log(timeStrDisplay); g.clearRect(0, 0, 176, 34); g.setColor(g.theme.fg); g.setFontAlign(-1, -1); g.setFont("Vector:26x40"); g.drawString(timeStrDisplay, 2, 0); } } class TimerCountDown { constructor(timeStr) { log("creating timer"); this.timeStr = timeStr; log(this.timeStr); this.start = Math.floor(Date.now() / 1000); log(this.start); this.pausedTime = undefined; } getAdjustedTime() { var elapsedTime = Math.floor(Date.now() / 1000) - this.start; var timeStrPadded = this.timeStr.padStart(6, "0"); var timeStrHours = parseInt(timeStrPadded.slice(0, 2), 10); var timeStrMinutes = parseInt(timeStrPadded.slice(2, 4), 10); var timeStrSeconds = parseInt(timeStrPadded.slice(4, 6), 10); var hours = timeStrHours; var minutes = timeStrMinutes; var seconds = timeStrSeconds - elapsedTime; if (seconds < 0) { var neededMinutes = Math.ceil(Math.abs(seconds) / 60); seconds = seconds + neededMinutes * 60; minutes = minutes - neededMinutes; if (minutes < 0) { var neededHours = Math.ceil(Math.abs(minutes) / 60); minutes = minutes + neededHours * 60; hours = hours - neededHours; } } if (hours < 0 || minutes < 0 || seconds < 0) { hours = 0; minutes = 0; seconds = 0; } return { hours: hours, minutes: minutes, seconds: seconds }; } pause() { this.pausedTime = Math.floor(Date.now() / 1000); } unpause() { if (this.pausedTime) { this.start += Math.floor(Date.now() / 1000) - this.pausedTime; } this.pausedTime = undefined; } draw() { log("drawing timer count down"); var adjustedTime = this.getAdjustedTime(); var hours = adjustedTime.hours; var minutes = adjustedTime.minutes; var seconds = adjustedTime.seconds; var timeStrDisplay = "" + hours.toString().padStart(2, "0") + "h " + minutes.toString().padStart(2, "0") + "m " + seconds.toString().padStart(2, "0") + "s"; log(timeStrDisplay); g.clearRect(0, 0, 176, 34); g.setColor(g.theme.fg); g.setFontAlign(-1, -1); g.setFont("Vector:26x40"); g.drawString(timeStrDisplay, 2, 0); } isFinished() { var adjustedTime = this.getAdjustedTime(); var hours = adjustedTime.hours; var minutes = adjustedTime.minutes; var seconds = adjustedTime.seconds; if (hours <= 0 && minutes <= 0 && seconds <= 0) { return true; } else { return false; } } } var readSettings = () => { log("reading settings"); var settings = require("Storage").readJSON(FILE, 1) || { buzzCount: 3, buzzDuration: 1, pauseBetween: 1, }; log(settings); return settings; }; // start main function main();