15
apps.json
|
@ -4457,6 +4457,21 @@
|
||||||
{"name":"timecal.app.js","url":"timecal.app.js"}
|
{"name":"timecal.app.js","url":"timecal.app.js"}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"id":"intervalTimer",
|
||||||
|
"name":"Interval Timer",
|
||||||
|
"shortName":"Interval Timer",
|
||||||
|
"icon": "app.png",
|
||||||
|
"version":"0.01",
|
||||||
|
"description": "Interval Timer for workouts, HIIT, or whatever else.",
|
||||||
|
"tags": "timer, interval, hiit, workout",
|
||||||
|
"readme":"README.md",
|
||||||
|
"supports":["BANGLEJS2"],
|
||||||
|
"storage": [
|
||||||
|
{"name":"intervalTimer.app.js","url":"app.js"},
|
||||||
|
{"name":"intervalTimer.img","url":"app-icon.js","evaluate":true}
|
||||||
|
]
|
||||||
|
},
|
||||||
{ "id": "93dub",
|
{ "id": "93dub",
|
||||||
"name": "93 Dub",
|
"name": "93 Dub",
|
||||||
"shortName":"93 Dub",
|
"shortName":"93 Dub",
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
0.01: First Release
|
|
@ -0,0 +1,34 @@
|
||||||
|
# Interval Timer
|
||||||
|
|
||||||
|
An interval timer for workouts and whatever else!
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
First set the active time (i.e. the number of seconds to perform exercises).
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
Next set the rest time (i.e. number of seconds to rest between exercises).
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
Finally choose the number of sets to perform.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
Active time will be shown in red, rest time in green. The watch will buzz whenever active or rest time gets to 0.
|
||||||
|
|
||||||
|

|
||||||
|

|
||||||
|
|
||||||
|
You can press the physical button during timer countdown to pause the timer.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
View after all sets are completed. Press menu to change settings or restart to start timer again with the same settings.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## Creator
|
||||||
|
|
||||||
|
James Gough
|
|
@ -0,0 +1 @@
|
||||||
|
require("heatshrink").decompress(atob("mEwwg96hWq1WgDCgXWxGZzOICqQABC4QABCyIXFDBsICIeJyfznAFBwAWPC4Of///mYYMCwgXBl4XB/4xCFxwABn4XCDAQwICw2ICwf/+YwJxGDHoQXHGARGIn/4C5QwBJAwQDC5QLCIw6GEC5BIGIwQLBJAgXGJAwXEJAgXPHgoXIEYIXFLwRIFC484C4h2DJAoIFPA+Ix4MGAAJoDHYgXKf4QXUJAYJGC5p5CF6hIBO44XNABIXGEw4AIU4rXFC5jvFc5AAHxAXGQwwAHQAIXcPCB2FC4RgOB4IXFJBxGHJB5GHJAYwKFwIXIJAIwKFwJGHGAYYICwIuIGAeImYWFmYJBFxIYEwZjC+YtCCxZJDAA4WMDBIWODIwVRAH4AXA=="))
|
|
@ -0,0 +1,306 @@
|
||||||
|
/**
|
||||||
|
|
||||||
|
Interval Timer
|
||||||
|
|
||||||
|
An app for the Bangle.js watch
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
var Layout = require("Layout");
|
||||||
|
|
||||||
|
// Globals
|
||||||
|
var timerMode; // 'active' || 'rest'
|
||||||
|
var numSets = 1;
|
||||||
|
var activeTime = 20;
|
||||||
|
var restTime = 10;
|
||||||
|
var counter;
|
||||||
|
var setsRemaining;
|
||||||
|
var counterInterval;
|
||||||
|
var outOfTimeTimeout;
|
||||||
|
var timerIsPaused;
|
||||||
|
var timerLayout;
|
||||||
|
|
||||||
|
/** Called to initialize the timer layout */
|
||||||
|
function initTimerLayout() {
|
||||||
|
timerLayout = new Layout( {
|
||||||
|
type:"v", c: [
|
||||||
|
{type:"txt", font:"40%", pad: 10, label:"00:00", id:"time" },
|
||||||
|
{type:"txt", font:"6x8:2", label:"0", id:"set" }
|
||||||
|
]
|
||||||
|
}, {btns: [
|
||||||
|
{label: "Stop", cb: l => {
|
||||||
|
if (timerIsPaused){
|
||||||
|
timerIsPaused = false;
|
||||||
|
resumeTimer();
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
timerIsPaused = true;
|
||||||
|
pauseTimer();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Pauses the timer by clearing the counterInterval */
|
||||||
|
function pauseTimer() {
|
||||||
|
if (counterInterval){
|
||||||
|
clearTimeout(counterInterval);
|
||||||
|
counterInterval = undefined;
|
||||||
|
}
|
||||||
|
// update layout to display "Paused"
|
||||||
|
timerLayout.clear(timerLayout.time);
|
||||||
|
timerLayout.time.label = "||";
|
||||||
|
timerLayout.clear(timerLayout.set);
|
||||||
|
timerLayout.set.label = "Paused";
|
||||||
|
timerLayout.render();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Reumes the timer by setting the counterInterval again */
|
||||||
|
function resumeTimer() {
|
||||||
|
if (!counterInterval){
|
||||||
|
counterInterval = setInterval(countDown, 1000);
|
||||||
|
}
|
||||||
|
// display the timer values again.
|
||||||
|
timerLayout.clear(timerLayout.time);
|
||||||
|
timerLayout.time.label = counter;
|
||||||
|
timerLayout.clear(timerLayout.set);
|
||||||
|
timerLayout.set.label = `Sets: ${setsRemaining}`;
|
||||||
|
timerLayout.render();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Display 'Done' view, called when all sets are completed */
|
||||||
|
function outOfTime() {
|
||||||
|
var stopLayout = new Layout( {
|
||||||
|
type:"v", c: [
|
||||||
|
{type:"txt", font:"30%", label:"Done!", id:"time" },
|
||||||
|
]
|
||||||
|
}, {btns: [
|
||||||
|
// menu button allows user to modify times and sets
|
||||||
|
{label:"Menu", cb: l=> {
|
||||||
|
if (outOfTimeTimeout){
|
||||||
|
clearTimeout(outOfTimeTimeout);
|
||||||
|
outOfTimeTimeout = undefined;
|
||||||
|
}
|
||||||
|
//stopLayout.remove();
|
||||||
|
setup();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// restart button runs timer again with the same settings
|
||||||
|
{label:"Restart", cb: l=> {
|
||||||
|
if (outOfTimeTimeout){
|
||||||
|
clearTimeout(outOfTimeTimeout);
|
||||||
|
outOfTimeTimeout = undefined;
|
||||||
|
}
|
||||||
|
//stopLayout.remove();
|
||||||
|
timerMode = 'active';
|
||||||
|
startTimer();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]});
|
||||||
|
|
||||||
|
if (counterInterval) return;
|
||||||
|
setsRemaining = numSets;
|
||||||
|
g.clear();
|
||||||
|
stopLayout.render();
|
||||||
|
Bangle.buzz(500);
|
||||||
|
Bangle.beep(200, 4000)
|
||||||
|
.then(() => new Promise(resolve => setTimeout(resolve,200)))
|
||||||
|
.then(() => Bangle.beep(200, 3000));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Function called by the counterInterval at each second.
|
||||||
|
Updates the timer display values.
|
||||||
|
*/
|
||||||
|
function countDown() {
|
||||||
|
// Out of time
|
||||||
|
if (counter<=0) {
|
||||||
|
if(timerMode === 'active'){
|
||||||
|
timerMode = 'rest';
|
||||||
|
startTimer();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
--setsRemaining;
|
||||||
|
if (setsRemaining === 0){
|
||||||
|
clearInterval(counterInterval);
|
||||||
|
counterInterval = undefined;
|
||||||
|
//setWatch(startTimer, (process.env.HWVERSION==2) ? BTN1 : BTN2);
|
||||||
|
outOfTime();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
timerMode = 'active';
|
||||||
|
startTimer();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
timerLayout.clear(timerLayout.time);
|
||||||
|
timerLayout.time.label = counter;
|
||||||
|
timerLayout.render();
|
||||||
|
counter--;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Start the interval timer. */
|
||||||
|
function startTimer() {
|
||||||
|
timerIsPaused = false;
|
||||||
|
g.clear();
|
||||||
|
if(timerMode === 'active'){
|
||||||
|
counter = activeTime;
|
||||||
|
timerLayout.time.col = '#f00';
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
counter = restTime;
|
||||||
|
timerLayout.time.col = '#0f0';
|
||||||
|
}
|
||||||
|
|
||||||
|
timerLayout.clear(timerLayout.set);
|
||||||
|
timerLayout.set.label = `Sets: ${setsRemaining}`;
|
||||||
|
timerLayout.render();
|
||||||
|
Bangle.buzz();
|
||||||
|
countDown();
|
||||||
|
if (!counterInterval){
|
||||||
|
counterInterval = setInterval(countDown, 1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Menu step in which user sets the number of sets to be performed. */
|
||||||
|
function setNumSets(){
|
||||||
|
g.clear();
|
||||||
|
var menuLayout = new Layout( {
|
||||||
|
type:"v", c: [
|
||||||
|
{type:"txt", font:"6x8:2", label:"Number Sets", id:"title" },
|
||||||
|
{type:"txt", font:"30%", pad: 20, label: numSets, id:"value" },
|
||||||
|
{type:"btn", font:"6x8:2", label:"Back", cb: l => {
|
||||||
|
setRestTime();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}, {btns: [
|
||||||
|
{label:"+", cb: l=> {
|
||||||
|
incrementNumSets();
|
||||||
|
}},
|
||||||
|
{label:"Go", cb: l=> {
|
||||||
|
setsRemaining = numSets;
|
||||||
|
initTimerLayout();
|
||||||
|
startTimer();
|
||||||
|
}},
|
||||||
|
{label:"-", cb: l=>{
|
||||||
|
decrementNumSets();
|
||||||
|
}}
|
||||||
|
]});
|
||||||
|
menuLayout.render();
|
||||||
|
|
||||||
|
const incrementNumSets = () => {
|
||||||
|
++numSets;
|
||||||
|
menuLayout.clear(menuLayout.numSets);
|
||||||
|
menuLayout.value.label = numSets;
|
||||||
|
menuLayout.render();
|
||||||
|
};
|
||||||
|
|
||||||
|
const decrementNumSets = () => {
|
||||||
|
if(numSets === 1){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
--numSets;
|
||||||
|
menuLayout.clear(menuLayout.numSets);
|
||||||
|
menuLayout.value.label = numSets;
|
||||||
|
menuLayout.render();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Menu step in which user sets the number of seconds of rest time for each set. */
|
||||||
|
function setRestTime(){
|
||||||
|
g.clear();
|
||||||
|
var menuLayout = new Layout( {
|
||||||
|
type:"v", c: [
|
||||||
|
{type:"txt", font:"6x8:2", label:"Rest Time", id:"title" },
|
||||||
|
{type:"txt", font:"30%", pad: 20, label: restTime, id:"value" },
|
||||||
|
{type:"btn", font:"6x8:2", label:"Back", cb: l => {
|
||||||
|
setActiveTime();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}, {btns: [
|
||||||
|
{label:"+", cb: l=> {
|
||||||
|
incrementRestTime();
|
||||||
|
}},
|
||||||
|
{label:"OK", cb: l=>setNumSets()},
|
||||||
|
{label:"-", cb: l=>{
|
||||||
|
decrementRestTime();
|
||||||
|
}}
|
||||||
|
]});
|
||||||
|
menuLayout.render();
|
||||||
|
|
||||||
|
const incrementRestTime = () => {
|
||||||
|
restTime += 5;
|
||||||
|
menuLayout.clear(menuLayout.restTime);
|
||||||
|
menuLayout.value.label = restTime;
|
||||||
|
menuLayout.render();
|
||||||
|
};
|
||||||
|
|
||||||
|
const decrementRestTime = () => {
|
||||||
|
if(restTime === 0){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
restTime -= 5;
|
||||||
|
menuLayout.clear(menuLayout.restTime);
|
||||||
|
menuLayout.value.label = restTime;
|
||||||
|
menuLayout.render();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Menu step in which user sets the number of seconds of active time for each set. */
|
||||||
|
function setActiveTime(){
|
||||||
|
g.clear();
|
||||||
|
var menuLayout = new Layout( {
|
||||||
|
type:"v", c: [
|
||||||
|
{type:"txt", font:"6x8:2", label:"Active Time", id:"title" },
|
||||||
|
{type:"txt", font:"30%", pad: 20, label: activeTime, id:"value" }
|
||||||
|
]
|
||||||
|
}, {btns: [
|
||||||
|
{font:"20%", label:"+", fillx:1, cb: l=> {
|
||||||
|
incrementActiveTime();
|
||||||
|
}},
|
||||||
|
{label:"OK", cb: l => setRestTime()},
|
||||||
|
{type:"btn", font:"20%", label:"-", fillx:1, cb: l=> {
|
||||||
|
decrementActiveTime();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]});
|
||||||
|
menuLayout.render();
|
||||||
|
|
||||||
|
const incrementActiveTime = () => {
|
||||||
|
activeTime += 5;
|
||||||
|
menuLayout.clear(menuLayout.activeTime);
|
||||||
|
menuLayout.value.label = activeTime;
|
||||||
|
menuLayout.render();
|
||||||
|
};
|
||||||
|
|
||||||
|
const decrementActiveTime = () => {
|
||||||
|
if(activeTime === 0){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
activeTime -= 5;
|
||||||
|
menuLayout.clear(menuLayout.activeTime);
|
||||||
|
menuLayout.value.label = activeTime;
|
||||||
|
menuLayout.render();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Start the setup menu, walks through setting active time, rest time, and number of sets. */
|
||||||
|
function setup(){
|
||||||
|
if (timerLayout){
|
||||||
|
// remove timerLayout, otherwise it's pause button callback will still be registered
|
||||||
|
timerLayout.remove(timerLayout);
|
||||||
|
timerLayout = undefined;
|
||||||
|
}
|
||||||
|
Bangle.setUI(); // remove all existing input handlers
|
||||||
|
timerMode = 'active';
|
||||||
|
setActiveTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
// this keeps the watch LCD lit up
|
||||||
|
Bangle.setLCDPower(1);
|
||||||
|
setup();
|
After Width: | Height: | Size: 1.8 KiB |
After Width: | Height: | Size: 2.3 KiB |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 2.2 KiB |
After Width: | Height: | Size: 2.3 KiB |
After Width: | Height: | Size: 2.2 KiB |
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 1.6 KiB |