1
0
Fork 0
BangleApps/apps/run/app.js

195 lines
5.6 KiB
JavaScript
Raw Normal View History

// Use widget utils to show/hide widgets
let wu = require("widget_utils");
let runInterval;
let karvonnenActive = false;
// Run interface wrapped in a function
let ExStats = require("exstats");
let B2 = process.env.HWVERSION===2;
let Layout = require("Layout");
let locale = require("locale");
let fontHeading = "6x8:2";
let fontValue = B2 ? "6x15:2" : "6x8:3";
let headingCol = "#888";
let fixCount = 0;
let isMenuDisplayed = false;
g.reset().clear();
2022-01-12 15:46:38 +00:00
Bangle.loadWidgets();
Bangle.drawWidgets();
wu.show();
2022-01-12 15:46:38 +00:00
// ---------------------------
let settings = Object.assign({
2022-03-01 06:16:24 +00:00
record: true,
B1: "dist",
B2: "time",
B3: "pacea",
B4: "bpm",
B5: "step",
B6: "caden",
2022-03-05 06:15:35 +00:00
paceLength: 1000,
notify: {
dist: {
value: 0,
2022-03-05 09:28:23 +00:00
notifications: [],
},
2022-03-05 09:07:10 +00:00
step: {
value: 0,
2022-03-05 09:28:23 +00:00
notifications: [],
},
time: {
value: 0,
2022-03-05 09:28:23 +00:00
notifications: [],
},
},
2023-02-21 09:17:07 +00:00
HRM: {
min: 65,
max: 170,
}
}, require("Storage").readJSON("run.json", 1) || {});
let statIDs = [settings.B1,settings.B2,settings.B3,settings.B4,settings.B5,settings.B6].filter(s=>s!=="");
let exs = ExStats.getStats(statIDs, settings);
2022-01-12 15:46:38 +00:00
// ---------------------------
// Called to start/stop running
2022-01-12 15:46:38 +00:00
function onStartStop() {
let running = !exs.state.active;
let prepPromises = [];
// start/stop recording
// Do this first in case recorder needs to prompt for
2022-03-05 23:01:53 +00:00
// an overwrite before we start tracking exstats
if (settings.record && WIDGETS["recorder"]) {
if (running) {
isMenuDisplayed = true;
2022-03-05 20:38:23 +00:00
prepPromises.push(
WIDGETS["recorder"].setRecording(true).then(() => {
isMenuDisplayed = false;
layout.setUI(); // grab our input handling again
2022-03-05 20:38:23 +00:00
layout.forgetLazyState();
layout.render();
})
);
2022-03-27 20:42:13 +00:00
} else {
2022-03-05 20:38:23 +00:00
prepPromises.push(
WIDGETS["recorder"].setRecording(false)
);
}
}
if (!prepPromises.length) // fix for Promise.all bug in 2v12
prepPromises.push(Promise.resolve());
2022-03-27 20:42:13 +00:00
2022-03-05 20:38:23 +00:00
Promise.all(prepPromises)
.then(() => {
if (running) {
exs.start();
} else {
exs.stop();
}
layout.button.label = running ? "STOP" : "START";
layout.status.label = running ? "RUN" : "STOP";
layout.status.bgCol = running ? "#0f0" : "#f00";
// if stopping running, don't clear state
// so we can at least refer to what we've done
layout.render();
});
2022-01-12 15:46:38 +00:00
}
let lc = [];
// Load stats in pair by pair
for (let i=0;i<statIDs.length;i+=2) {
let sa = exs.stats[statIDs[i+0]]
let sb = exs.stats[statIDs[i+1]];
lc.push({ type:"h", filly:1, c:[
sa?{type:"txt", font:fontHeading, label:sa.title.toUpperCase(), fillx:1, col:headingCol }:{},
sb?{type:"txt", font:fontHeading, label:sb.title.toUpperCase(), fillx:1, col:headingCol }:{}
]}, { type:"h", filly:1, c:[
sa?{type:"txt", font:fontValue, label:sa.getString(), id:sa.id, fillx:1 }:{},
sb?{type:"txt", font:fontValue, label:sb.getString(), id:sb.id, fillx:1 }:{}
]});
if (sa) sa.on('changed', e=>layout[e.id].label = e.getString());
if (sb) sb.on('changed', e=>layout[e.id].label = e.getString());
}
// At the bottom put time/GPS state/etc
lc.push({ type:"h", filly:1, c:[
{type:"txt", font:fontHeading, label:"GPS", id:"gps", fillx:1, bgCol:"#f00" },
{type:"txt", font:fontHeading, label:"00:00", id:"clock", fillx:1, bgCol:g.theme.fg, col:g.theme.bg },
{type:"txt", font:fontHeading, label:"STOP", id:"status", fillx:1 }
]});
// Now calculate the layout
let layout = new Layout( {
type:"v", c: lc
2023-02-20 20:00:13 +00:00
},{lazy:true, btns:[{ label:"START", cb: ()=>{if (karvonnenActive) {stopKarvonnenUI();run();} onStartStop();}, id:"button"}]});
delete lc;
2022-01-12 15:46:38 +00:00
layout.render();
2022-03-05 08:59:13 +00:00
function configureNotification(stat) {
stat.on('notify', (e)=>{
2022-03-05 09:42:07 +00:00
settings.notify[e.id].notifications.reduce(function (promise, buzzPattern) {
return promise.then(function () {
return Bangle.buzz(buzzPattern[0], buzzPattern[1]);
});
2022-03-05 20:58:34 +00:00
}, Promise.resolve());
2022-03-05 08:59:13 +00:00
});
}
Object.keys(settings.notify).forEach((statType) => {
if (settings.notify[statType].increment > 0 && exs.stats[statType]) {
configureNotification(exs.stats[statType]);
}
});
2022-03-05 08:59:13 +00:00
// Handle GPS state change for icon
2022-01-12 15:46:38 +00:00
Bangle.on("GPS", function(fix) {
layout.gps.bgCol = fix.fix ? "#0f0" : "#f00";
if (!fix.fix) return; // only process actual fixes
2022-03-01 05:54:27 +00:00
if (fixCount++ === 0) {
2022-01-22 00:14:10 +00:00
Bangle.buzz(); // first fix, does not need to respect quiet mode
2022-01-12 15:46:38 +00:00
}
});
// run() function used to switch between traditional run UI and karvonnen UI
function run() {
wu.show();
layout.lazy = false;
layout.render();
layout.lazy = true;
// We always call ourselves once a second to update
if (!runInterval){
2023-02-19 09:26:04 +00:00
runInterval = setInterval(function() {
layout.clock.label = locale.time(new Date(),1);
if (!isMenuDisplayed && !karvonnenActive) layout.render();
}, 1000);
}
}
run();
///////////////////////////////////////////////
// Karvonnen
///////////////////////////////////////////////
function stopRunUI() {
// stop updating and drawing the traditional run app UI
clearInterval(runInterval);
runInterval = undefined;
karvonnenActive = true;
}
function stopKarvonnenUI() {
g.reset().clear();
clearInterval(karvonnenInterval);
karvonnenInterval = undefined;
karvonnenActive = false;
}
let karvonnenInterval;
// Define the function to go back and foth between the different UI's
function swipeHandler(LR,_) {
if (LR==-1 && karvonnenActive && !isMenuDisplayed) {stopKarvonnenUI(); run();}
if (LR==1 && !karvonnenActive && !isMenuDisplayed) {stopRunUI(); karvonnenInterval = require("run_karvonnen").show(settings.HRM, exs.stats.bpm);}
}
// Listen for swipes with the swipeHandler
Bangle.on("swipe", swipeHandler);