mirror of https://github.com/espruino/BangleApps
health: calculate distance from steps
- multiplies step counts with stride length - distance menu under step counting is only available if stride length is setpull/3120/head
parent
4f38e475a8
commit
dbf8995b14
|
@ -29,3 +29,4 @@
|
|||
0.26: Implement API for activity fetching
|
||||
0.27: Fix typo in daily summary graph code causing graph not to load
|
||||
Fix daily summaries for 31st of the month
|
||||
0.28: Calculate distance from steps if new stride length setting is set
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
let settings;
|
||||
|
||||
function menuMain() {
|
||||
E.showMenu({
|
||||
"": { title: /*LANG*/"Health Tracking" },
|
||||
|
@ -5,16 +7,30 @@ function menuMain() {
|
|||
/*LANG*/"Step Counting": () => menuStepCount(),
|
||||
/*LANG*/"Movement": () => menuMovement(),
|
||||
/*LANG*/"Heart Rate": () => menuHRM(),
|
||||
/*LANG*/"Settings": () => eval(require("Storage").read("health.settings.js"))(()=>menuMain())
|
||||
/*LANG*/"Settings": () => eval(require("Storage").read("health.settings.js"))(()=>{loadSettings();menuMain();})
|
||||
});
|
||||
}
|
||||
|
||||
function menuStepCount() {
|
||||
E.showMenu({
|
||||
const menu = {
|
||||
"": { title:/*LANG*/"Steps" },
|
||||
/*LANG*/"< Back": () => menuMain(),
|
||||
/*LANG*/"per hour": () => stepsPerHour(),
|
||||
/*LANG*/"per day": () => stepsPerDay()
|
||||
/*LANG*/"per hour": () => stepsPerHour(menuStepCount),
|
||||
/*LANG*/"per day": () => stepsPerDay(menuStepCount)
|
||||
};
|
||||
if (settings.strideLength) {
|
||||
menu[/*LANG*/"distance"] = () => menuDistance();
|
||||
}
|
||||
|
||||
E.showMenu(menu);
|
||||
}
|
||||
|
||||
function menuDistance() {
|
||||
E.showMenu({
|
||||
"": { title:/*LANG*/"Distance" },
|
||||
/*LANG*/"< Back": () => menuStepCount(),
|
||||
/*LANG*/"per hour": () => stepsPerHour(menuDistance, settings.strideLength),
|
||||
/*LANG*/"per day": () => stepsPerDay(menuDistance, settings.strideLength)
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -36,23 +52,23 @@ function menuHRM() {
|
|||
});
|
||||
}
|
||||
|
||||
function stepsPerHour() {
|
||||
function stepsPerHour(back, mult) {
|
||||
E.showMessage(/*LANG*/"Loading...");
|
||||
current_selection = "stepsPerHour";
|
||||
var data = new Uint16Array(24);
|
||||
require("health").readDay(new Date(), h=>data[h.hr]+=h.steps);
|
||||
setButton(menuStepCount);
|
||||
barChart(/*LANG*/"HOUR", data);
|
||||
setButton(back, mult);
|
||||
barChart(/*LANG*/"HOUR", data, mult);
|
||||
}
|
||||
|
||||
function stepsPerDay() {
|
||||
function stepsPerDay(back, mult) {
|
||||
E.showMessage(/*LANG*/"Loading...");
|
||||
current_selection = "stepsPerDay";
|
||||
var data = new Uint16Array(32);
|
||||
require("health").readDailySummaries(new Date(), h=>data[h.day]+=h.steps);
|
||||
setButton(menuStepCount);
|
||||
barChart(/*LANG*/"DAY", data);
|
||||
drawHorizontalLine(settings.stepGoal);
|
||||
setButton(back, mult);
|
||||
barChart(/*LANG*/"DAY", data, mult);
|
||||
drawHorizontalLine(settings.stepGoal * (mult || 1));
|
||||
}
|
||||
|
||||
function hrmPerHour() {
|
||||
|
@ -139,7 +155,11 @@ function get_data_length(arr) {
|
|||
return nlen;
|
||||
}
|
||||
|
||||
function barChart(label, dt) {
|
||||
function barChart(label, dt, mult) {
|
||||
if (mult !== undefined) {
|
||||
// Calculate distance from steps
|
||||
dt.forEach((val, i) => dt[i] = val*mult);
|
||||
}
|
||||
data_len = get_data_length(dt);
|
||||
chart_index = Math.max(data_len - 5, -5); // choose initial index that puts the last day on the end
|
||||
chart_max_datum = max(dt); // find highest bar, for scaling
|
||||
|
@ -180,7 +200,7 @@ function drawHorizontalLine(value) {
|
|||
g.setColor(g.theme.fg).drawLine(0, top ,g.getWidth(), top);
|
||||
}
|
||||
|
||||
function setButton(fn) {
|
||||
function setButton(fn, mult) {
|
||||
Bangle.setUI({mode:"custom",
|
||||
back:fn,
|
||||
swipe:(lr,ud) => {
|
||||
|
@ -194,12 +214,16 @@ function setButton(fn) {
|
|||
}
|
||||
drawBarChart();
|
||||
if (current_selection == "stepsPerDay") {
|
||||
drawHorizontalLine(settings.stepGoal);
|
||||
drawHorizontalLine(settings.stepGoal * (mult || 1));
|
||||
}
|
||||
}});
|
||||
}
|
||||
|
||||
function loadSettings() {
|
||||
settings = require("Storage").readJSON("health.json",1)||{};
|
||||
}
|
||||
|
||||
Bangle.loadWidgets();
|
||||
Bangle.drawWidgets();
|
||||
var settings = require("Storage").readJSON("health.json",1)||{};
|
||||
loadSettings();
|
||||
menuMain();
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
"id": "health",
|
||||
"name": "Health Tracking",
|
||||
"shortName": "Health",
|
||||
"version": "0.27",
|
||||
"version": "0.28",
|
||||
"description": "Logs health data and provides an app to view it",
|
||||
"icon": "app.png",
|
||||
"tags": "tool,system,health",
|
||||
|
|
|
@ -8,44 +8,85 @@
|
|||
function setSettings() {
|
||||
require("Storage").writeJSON("health.json", settings);
|
||||
}
|
||||
E.showMenu({
|
||||
"": { title: /*LANG*/"Health Tracking" },
|
||||
|
||||
/*LANG*/"< Back": () => back(),
|
||||
function settingsMenu() {
|
||||
E.showMenu({
|
||||
"": { title: /*LANG*/"Health Tracking" },
|
||||
|
||||
/*LANG*/"HRM Interval": {
|
||||
value: settings.hrm,
|
||||
min: 0,
|
||||
max: 3,
|
||||
format: v => [
|
||||
/*LANG*/"Off",
|
||||
/*LANG*/"3 min",
|
||||
/*LANG*/"10 min",
|
||||
/*LANG*/"Always"
|
||||
][v],
|
||||
onchange: v => {
|
||||
settings.hrm = v;
|
||||
setSettings();
|
||||
}
|
||||
},
|
||||
/*LANG*/"< Back": () => back(),
|
||||
|
||||
/*LANG*/"Daily Step Goal": {
|
||||
value: settings.stepGoal,
|
||||
min: 0,
|
||||
max: 20000,
|
||||
step: 250,
|
||||
onchange: v => {
|
||||
settings.stepGoal = v;
|
||||
/*LANG*/"HRM Interval": {
|
||||
value: settings.hrm,
|
||||
min: 0,
|
||||
max: 3,
|
||||
format: v => [
|
||||
/*LANG*/"Off",
|
||||
/*LANG*/"3 min",
|
||||
/*LANG*/"10 min",
|
||||
/*LANG*/"Always"
|
||||
][v],
|
||||
onchange: v => {
|
||||
settings.hrm = v;
|
||||
setSettings();
|
||||
}
|
||||
},
|
||||
|
||||
/*LANG*/"Daily Step Goal": {
|
||||
value: settings.stepGoal,
|
||||
min: 0,
|
||||
max: 20000,
|
||||
step: 250,
|
||||
onchange: v => {
|
||||
settings.stepGoal = v;
|
||||
setSettings();
|
||||
}
|
||||
},
|
||||
|
||||
/*LANG*/"Step Goal Notification": {
|
||||
value: "stepGoalNotification" in settings ? settings.stepGoalNotification : false,
|
||||
format: () => (settings.stepGoalNotification ? 'Yes' : 'No'),
|
||||
onchange: () => {
|
||||
settings.stepGoalNotification = !settings.stepGoalNotification;
|
||||
setSettings();
|
||||
}
|
||||
},
|
||||
|
||||
/*LANG*/"Stride length": () => strideLengthMenu()
|
||||
});
|
||||
}
|
||||
|
||||
function strideLengthMenu() {
|
||||
const menu = {
|
||||
"" : { title : /*LANG*/"Stride length" },
|
||||
|
||||
"< Back" : () => {
|
||||
setSettings();
|
||||
}
|
||||
},
|
||||
/*LANG*/"Step Goal Notification": {
|
||||
value: "stepGoalNotification" in settings ? settings.stepGoalNotification : false,
|
||||
format: () => (settings.stepGoalNotification ? 'Yes' : 'No'),
|
||||
onchange: () => {
|
||||
settings.stepGoalNotification = !settings.stepGoalNotification;
|
||||
setSettings();
|
||||
}
|
||||
}
|
||||
});
|
||||
settingsMenu();
|
||||
},
|
||||
|
||||
"x 0.01" : {
|
||||
value : settings.strideLength === undefined ? 0 : settings.strideLength,
|
||||
min:0,
|
||||
step:0.01,
|
||||
format: v => require("locale").distance(v, 2),
|
||||
onchange : v => {
|
||||
settings.strideLength=v;
|
||||
menu["x 0.1"].value = v;
|
||||
},
|
||||
},
|
||||
"x 0.1" : {
|
||||
value : settings.strideLength === undefined ? 0 : settings.strideLength,
|
||||
min:0,
|
||||
step:0.1,
|
||||
format: v => require("locale").distance(v, 2),
|
||||
onchange : v => {
|
||||
settings.strideLength=v;
|
||||
menu["x 0.01"].value = v;
|
||||
},
|
||||
},
|
||||
};
|
||||
E.showMenu(menu);
|
||||
}
|
||||
|
||||
settingsMenu();
|
||||
})
|
||||
|
|
Loading…
Reference in New Issue