splitsw: add new stopwatch app with split timer

Signed-off-by: James Taylor <jt-git@nti.me.uk>
pull/3504/head
James Taylor 2024-07-08 19:00:00 +01:00
parent 1e82772de6
commit 9402124a3f
7 changed files with 215 additions and 0 deletions

1
apps/splitsw/ChangeLog Normal file
View File

@ -0,0 +1 @@
0.01: New App!

30
apps/splitsw/README.md Normal file
View File

@ -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!

1
apps/splitsw/app-icon.js Normal file
View File

@ -0,0 +1 @@
require("heatshrink").decompress(atob("mEw4UA///vvvvEF/muH+cDHgPABf4AElWoKhILClALH1WqAQIWHBYIABwAKEgQKD1WgBYkK1X1r4XHlWtqtVvQLG1XVBYNXHYsC1YJBBoPqC4kKEQILCvQ7EhW1BYdeBYkqytVqwCCQwkqCgILCq4LFIoILCqoLEIwIsBGQJIBBZ+pA4Na0oDBtQLGvSFCBaYjIHYR3CI5AADBYhrCAAaDHAASDGQASGCBYizCAASzFZYQACZYrjCIwb7QHgIkCvQ6EGAWq+tf1QuEGAWqAAQuFEgQKBEQw9DHIwAuA="))

167
apps/splitsw/app.js Normal file
View File

@ -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();

BIN
apps/splitsw/app.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -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}
]
}

BIN
apps/splitsw/screenshot.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB