diff --git a/apps/splitsw/ChangeLog b/apps/splitsw/ChangeLog new file mode 100644 index 000000000..5560f00bc --- /dev/null +++ b/apps/splitsw/ChangeLog @@ -0,0 +1 @@ +0.01: New App! diff --git a/apps/splitsw/README.md b/apps/splitsw/README.md new file mode 100644 index 000000000..5f8fbd54b --- /dev/null +++ b/apps/splitsw/README.md @@ -0,0 +1,30 @@ +# Stopwatch with split times + +A basic stopwatch with support for split times. + +![](screenshot.png) + +## Features + +Implemented: + +- Start stopwatch +- Stop stopwatch +- Show split times +- Reset stopwatch +- Keep display unlocked + +Future: + +- Save state and restore running stopwatch when it reopens +- View all split times +- Duplicate Start/Stop and/or Reset/Split button on the physical button +- Settings, e.g. what the physical button does, and whether to keep the backlight on + +## Creator + +James Taylor ([jt-nti](https://github.com/jt-nti)) + +## Icons + +The same icons as apps/stopwatch! diff --git a/apps/splitsw/app-icon.js b/apps/splitsw/app-icon.js new file mode 100644 index 000000000..32281b7ab --- /dev/null +++ b/apps/splitsw/app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEw4UA///vvvvEF/muH+cDHgPABf4AElWoKhILClALH1WqAQIWHBYIABwAKEgQKD1WgBYkK1X1r4XHlWtqtVvQLG1XVBYNXHYsC1YJBBoPqC4kKEQILCvQ7EhW1BYdeBYkqytVqwCCQwkqCgILCq4LFIoILCqoLEIwIsBGQJIBBZ+pA4Na0oDBtQLGvSFCBaYjIHYR3CI5AADBYhrCAAaDHAASDGQASGCBYizCAASzFZYQACZYrjCIwb7QHgIkCvQ6EGAWq+tf1QuEGAWqAAQuFEgQKBEQw9DHIwAuA=")) diff --git a/apps/splitsw/app.js b/apps/splitsw/app.js new file mode 100644 index 000000000..5d70b471d --- /dev/null +++ b/apps/splitsw/app.js @@ -0,0 +1,167 @@ +Bangle.loadWidgets(); +g.clear(true); +Bangle.drawWidgets(); + +Bangle.setLCDTimeout(undefined); + +let renderIntervalId; +let startTime; +let stopTime; +let subtotal; +let currentSplitNumber; +let splitStartTime; +let splitSubtotal; + +var Layout = require("Layout"); +var layout = new Layout( { + type:"v", c: [ + {type:"txt", pad:4, font:"20%", label:"", id:"time", fillx:1}, + {type:"h", c: [ + {type:"btn", pad:4, font:"6x8:2", label:"Start", id:"startStop", cb: l=>startStop() }, + {type:"btn", pad:4, font:"6x8:2", label:"Reset", id:"resetSplit", cb: l=>resetSplit() } + ]}, + { + type:"v", pad:4, c: [ + {type:"txt", font:"6x8:2", label:"", id:"split", fillx:1}, + {type:"txt", font:"6x8:2", label:"", id:"prevSplit", fillx:1}, + ]}, + ] +}, { + lazy: true, + back: load, +}); + +// TODO The code in this function appears in various apps so it might be +// nice to add something to the time_utils module. (There is already a +// formatDuration function but that doesn't quite work the same way.) +const getTime = function(milliseconds) { + let hrs = Math.floor(milliseconds/3600000); + let mins = Math.floor(milliseconds/60000)%60; + let secs = Math.floor(milliseconds/1000)%60; + let tnth = Math.floor(milliseconds/100)%10; + let text; + + if (hrs === 0) { + text = ("0"+mins).slice(-2) + ":" + ("0"+secs).slice(-2) + "." + tnth; + } else { + text = ("0"+hrs) + ":" + ("0"+mins).slice(-2) + ":" + ("0"+secs).slice(-2); + } + + return text; +}; + +const renderIntervalCallback = function() { + if (startTime === undefined) { + return; + } + + updateStopwatch(); +}; + +const buzz = function() { + Bangle.buzz(50, 0.5); +}; + +const startStop = function() { + buzz(); + + if (layout.startStop.label === "Start") { + start(); + } else { + stop(); + } +}; + +const start = function() { + if (stopTime === undefined) { + startTime = Date.now(); + splitStartTime = startTime; + subtotal = 0; + splitSubtotal = 0; + currentSplitNumber = 1; + } else { + subtotal += stopTime - startTime; + splitSubtotal += stopTime - splitStartTime; + startTime = Date.now(); + splitStartTime = startTime; + stopTime = undefined; + } + + layout.startStop.label = "Stop"; + layout.resetSplit.label = "Split"; + updateStopwatch(); + + renderIntervalId = setInterval(renderIntervalCallback, 100); +}; + +const stop = function() { + stopTime = Date.now(); + + layout.startStop.label = "Start"; + layout.resetSplit.label = "Reset"; + updateStopwatch(); + + if (renderIntervalId !== undefined) { + clearInterval(renderIntervalId); + renderIntervalId = undefined; + } +}; + +const resetSplit = function() { + buzz(); + + if (layout.resetSplit.label === "Reset") { + reset(); + } else { + split(); + } +}; + +const reset = function() { + layout.startStop.label = "Start"; + layout.resetSplit.label = "Reset"; + layout.split.label = ""; + layout.prevSplit.label = ""; + + startTime = undefined; + stopTime = undefined; + subtotal = 0; + currentSplitNumber = 1; + splitStartTime = undefined; + splitSubtotal = 0; + + updateStopwatch(); +}; + +const split = function() { + const splitTime = Date.now() - splitStartTime + splitSubtotal; + layout.prevSplit.label = "#" + currentSplitNumber + " " + getTime(splitTime); + + splitStartTime = Date.now(); + splitSubtotal = 0; + currentSplitNumber++; + + updateStopwatch(); +}; + +const updateStopwatch = function() { + let elapsedTime; + + if (startTime === undefined) { + elapsedTime = 0; + } else { + elapsedTime = Date.now() - startTime + subtotal; + } + + layout.time.label = getTime(elapsedTime); + + if (splitStartTime !== undefined) { + const splitTime = Date.now() - splitStartTime + splitSubtotal; + layout.split.label = "#" + currentSplitNumber + " " + getTime(splitTime); + } + + layout.render(); + // layout.debug(); +}; + +updateStopwatch(); diff --git a/apps/splitsw/app.png b/apps/splitsw/app.png new file mode 100644 index 000000000..92ffe73b7 Binary files /dev/null and b/apps/splitsw/app.png differ diff --git a/apps/splitsw/metadata.json b/apps/splitsw/metadata.json new file mode 100644 index 000000000..d5ae19347 --- /dev/null +++ b/apps/splitsw/metadata.json @@ -0,0 +1,16 @@ +{ "id": "splitsw", + "name": "Stopwatch with split times", + "shortName":"Stopwatch", + "version":"0.01", + "description": "A basic stopwatch with support for split times", + "icon": "app.png", + "tags": "tool,outdoors,health", + "supports" : ["BANGLEJS2"], + "readme": "README.md", + "screenshots": [{ "url": "screenshot.png" }], + "allow_emulator": true, + "storage": [ + {"name":"splitsw.app.js","url":"app.js"}, + {"name":"splitsw.img","url":"app-icon.js","evaluate":true} + ] +} diff --git a/apps/splitsw/screenshot.png b/apps/splitsw/screenshot.png new file mode 100644 index 000000000..184bc4fbc Binary files /dev/null and b/apps/splitsw/screenshot.png differ