2023-12-03 19:45:28 +00:00
|
|
|
let settings;
|
2023-12-10 08:18:21 +00:00
|
|
|
const myprofile = require("Storage").readJSON("myprofile.json",1)||{};
|
2023-12-03 19:45:28 +00:00
|
|
|
|
2021-10-14 16:14:10 +00:00
|
|
|
function menuMain() {
|
|
|
|
E.showMenu({
|
2022-04-22 20:09:47 +00:00
|
|
|
"": { title: /*LANG*/"Health Tracking" },
|
|
|
|
/*LANG*/"< Back": () => load(),
|
|
|
|
/*LANG*/"Step Counting": () => menuStepCount(),
|
|
|
|
/*LANG*/"Movement": () => menuMovement(),
|
2022-04-25 14:11:01 +00:00
|
|
|
/*LANG*/"Heart Rate": () => menuHRM(),
|
2023-12-03 19:45:28 +00:00
|
|
|
/*LANG*/"Settings": () => eval(require("Storage").read("health.settings.js"))(()=>{loadSettings();menuMain();})
|
2021-10-14 16:14:10 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2022-04-20 11:39:41 +00:00
|
|
|
function menuStepCount() {
|
2023-12-03 19:45:28 +00:00
|
|
|
const menu = {
|
2022-04-22 20:09:47 +00:00
|
|
|
"": { title:/*LANG*/"Steps" },
|
|
|
|
/*LANG*/"< Back": () => menuMain(),
|
2023-12-03 19:45:28 +00:00
|
|
|
/*LANG*/"per hour": () => stepsPerHour(menuStepCount),
|
|
|
|
/*LANG*/"per day": () => stepsPerDay(menuStepCount)
|
|
|
|
};
|
2023-12-10 08:18:21 +00:00
|
|
|
if (myprofile.strideLength) {
|
2023-12-03 19:45:28 +00:00
|
|
|
menu[/*LANG*/"distance"] = () => menuDistance();
|
|
|
|
}
|
|
|
|
|
|
|
|
E.showMenu(menu);
|
|
|
|
}
|
|
|
|
|
|
|
|
function menuDistance() {
|
2023-12-10 08:18:21 +00:00
|
|
|
const distMult = 1*require("locale").distance(myprofile.strideLength, 2); // hackish: this removes the distance suffix, e.g. 'm'
|
2023-12-03 19:45:28 +00:00
|
|
|
E.showMenu({
|
|
|
|
"": { title:/*LANG*/"Distance" },
|
|
|
|
/*LANG*/"< Back": () => menuStepCount(),
|
2023-12-05 20:03:32 +00:00
|
|
|
/*LANG*/"per hour": () => stepsPerHour(menuDistance, distMult),
|
|
|
|
/*LANG*/"per day": () => stepsPerDay(menuDistance, distMult)
|
2022-04-20 11:39:41 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2021-10-14 16:14:10 +00:00
|
|
|
function menuMovement() {
|
|
|
|
E.showMenu({
|
2022-04-22 20:09:47 +00:00
|
|
|
"": { title:/*LANG*/"Movement" },
|
|
|
|
/*LANG*/"< Back": () => menuMain(),
|
|
|
|
/*LANG*/"per hour": () => movementPerHour(),
|
|
|
|
/*LANG*/"per day": () => movementPerDay(),
|
2021-10-14 16:14:10 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2021-11-01 09:54:28 +00:00
|
|
|
function menuHRM() {
|
|
|
|
E.showMenu({
|
2022-04-22 20:09:47 +00:00
|
|
|
"": { title:/*LANG*/"Heart Rate" },
|
|
|
|
/*LANG*/"< Back": () => menuMain(),
|
|
|
|
/*LANG*/"per hour": () => hrmPerHour(),
|
|
|
|
/*LANG*/"per day": () => hrmPerDay(),
|
2021-11-01 09:54:28 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2023-12-03 19:45:28 +00:00
|
|
|
function stepsPerHour(back, mult) {
|
2022-04-10 19:35:46 +00:00
|
|
|
E.showMessage(/*LANG*/"Loading...");
|
2023-01-03 07:15:37 +00:00
|
|
|
current_selection = "stepsPerHour";
|
2022-05-17 21:18:44 +00:00
|
|
|
var data = new Uint16Array(24);
|
2021-10-14 16:14:10 +00:00
|
|
|
require("health").readDay(new Date(), h=>data[h.hr]+=h.steps);
|
2023-12-05 20:03:32 +00:00
|
|
|
if (mult !== undefined) {
|
|
|
|
// Calculate distance from steps
|
|
|
|
data.forEach((d, i) => data[i] = d*mult+0.5);
|
|
|
|
}
|
2023-12-03 19:45:28 +00:00
|
|
|
setButton(back, mult);
|
|
|
|
barChart(/*LANG*/"HOUR", data, mult);
|
2021-10-14 16:14:10 +00:00
|
|
|
}
|
|
|
|
|
2023-12-03 19:45:28 +00:00
|
|
|
function stepsPerDay(back, mult) {
|
2022-04-10 19:35:46 +00:00
|
|
|
E.showMessage(/*LANG*/"Loading...");
|
2023-01-03 07:15:37 +00:00
|
|
|
current_selection = "stepsPerDay";
|
2023-08-29 16:04:37 +00:00
|
|
|
var data = new Uint16Array(32);
|
2021-10-29 09:34:14 +00:00
|
|
|
require("health").readDailySummaries(new Date(), h=>data[h.day]+=h.steps);
|
2023-12-11 06:32:58 +00:00
|
|
|
// Include data for today
|
|
|
|
if (data[(new Date()).getDate()] === 0) {
|
|
|
|
data[(new Date()).getDate()] = Bangle.getHealthStatus("day").steps;
|
|
|
|
}
|
2023-12-05 20:03:32 +00:00
|
|
|
if (mult !== undefined) {
|
|
|
|
// Calculate distance from steps
|
|
|
|
data.forEach((d, i) => data[i] = d*mult+0.5);
|
|
|
|
}
|
2023-12-03 19:45:28 +00:00
|
|
|
setButton(back, mult);
|
|
|
|
barChart(/*LANG*/"DAY", data, mult);
|
|
|
|
drawHorizontalLine(settings.stepGoal * (mult || 1));
|
2021-10-29 09:34:14 +00:00
|
|
|
}
|
|
|
|
|
2021-11-01 09:54:28 +00:00
|
|
|
function hrmPerHour() {
|
2022-04-10 19:35:46 +00:00
|
|
|
E.showMessage(/*LANG*/"Loading...");
|
2023-01-03 07:15:37 +00:00
|
|
|
current_selection = "hrmPerHour";
|
2022-05-17 21:18:44 +00:00
|
|
|
var data = new Uint16Array(24);
|
2023-08-04 08:36:18 +00:00
|
|
|
var cnt = new Uint8Array(24);
|
2021-11-01 09:54:28 +00:00
|
|
|
require("health").readDay(new Date(), h=>{
|
|
|
|
data[h.hr]+=h.bpm;
|
|
|
|
if (h.bpm) cnt[h.hr]++;
|
|
|
|
});
|
2023-12-05 20:03:32 +00:00
|
|
|
data.forEach((d,i)=>data[i] = d/cnt[i]+0.5);
|
2021-11-15 21:19:02 +00:00
|
|
|
setButton(menuHRM);
|
2022-12-01 20:03:15 +00:00
|
|
|
barChart(/*LANG*/"HOUR", data);
|
2021-11-01 09:54:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
function hrmPerDay() {
|
2022-04-10 19:35:46 +00:00
|
|
|
E.showMessage(/*LANG*/"Loading...");
|
2023-01-03 07:15:37 +00:00
|
|
|
current_selection = "hrmPerDay";
|
2023-08-29 16:04:37 +00:00
|
|
|
var data = new Uint16Array(32);
|
|
|
|
var cnt = new Uint8Array(32);
|
2021-11-01 09:54:28 +00:00
|
|
|
require("health").readDailySummaries(new Date(), h=>{
|
|
|
|
data[h.day]+=h.bpm;
|
|
|
|
if (h.bpm) cnt[h.day]++;
|
|
|
|
});
|
2023-12-05 20:03:32 +00:00
|
|
|
data.forEach((d,i)=>data[i] = d/cnt[i]+0.5);
|
2021-11-15 21:19:02 +00:00
|
|
|
setButton(menuHRM);
|
2022-12-01 20:03:15 +00:00
|
|
|
barChart(/*LANG*/"DAY", data);
|
2021-11-01 09:54:28 +00:00
|
|
|
}
|
|
|
|
|
2021-10-14 16:14:10 +00:00
|
|
|
function movementPerHour() {
|
2022-04-10 19:35:46 +00:00
|
|
|
E.showMessage(/*LANG*/"Loading...");
|
2023-01-03 07:15:37 +00:00
|
|
|
current_selection = "movementPerHour";
|
2022-05-17 21:18:44 +00:00
|
|
|
var data = new Uint16Array(24);
|
2023-08-04 08:36:18 +00:00
|
|
|
var cnt = new Uint8Array(24);
|
|
|
|
require("health").readDay(new Date(), h=>{
|
2023-08-22 21:38:06 +00:00
|
|
|
data[h.hr]+=h.movement;
|
2023-08-04 08:36:18 +00:00
|
|
|
cnt[h.hr]++;
|
|
|
|
});
|
2023-12-05 20:03:32 +00:00
|
|
|
data.forEach((d,i)=>data[i] = d/cnt[i]+0.5);
|
2021-11-15 21:19:02 +00:00
|
|
|
setButton(menuMovement);
|
2022-12-01 20:03:15 +00:00
|
|
|
barChart(/*LANG*/"HOUR", data);
|
2021-10-14 16:14:10 +00:00
|
|
|
}
|
|
|
|
|
2021-10-29 09:34:14 +00:00
|
|
|
function movementPerDay() {
|
2022-04-10 19:35:46 +00:00
|
|
|
E.showMessage(/*LANG*/"Loading...");
|
2023-01-03 07:15:37 +00:00
|
|
|
current_selection = "movementPerDay";
|
2023-08-29 16:04:37 +00:00
|
|
|
var data = new Uint16Array(32);
|
|
|
|
var cnt = new Uint8Array(32);
|
2023-08-04 08:36:18 +00:00
|
|
|
require("health").readDailySummaries(new Date(), h=>{
|
2023-08-22 21:38:06 +00:00
|
|
|
data[h.day]+=h.movement;
|
2023-08-22 21:00:50 +00:00
|
|
|
cnt[h.day]++;
|
2023-08-04 08:36:18 +00:00
|
|
|
});
|
2023-12-05 20:03:32 +00:00
|
|
|
data.forEach((d,i)=>data[i] = d/cnt[i]+0.5);
|
2021-11-15 21:19:02 +00:00
|
|
|
setButton(menuMovement);
|
2022-12-01 20:03:15 +00:00
|
|
|
barChart(/*LANG*/"DAY", data);
|
2021-11-15 21:19:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Bar Chart Code
|
|
|
|
const w = g.getWidth();
|
|
|
|
const h = g.getHeight();
|
2023-01-03 07:15:37 +00:00
|
|
|
const bar_bot = 140;
|
2021-11-15 21:19:02 +00:00
|
|
|
|
|
|
|
var data_len;
|
|
|
|
var chart_index;
|
|
|
|
var chart_max_datum;
|
|
|
|
var chart_label;
|
|
|
|
var chart_data;
|
2023-01-03 07:15:37 +00:00
|
|
|
var current_selection;
|
2021-11-15 21:19:02 +00:00
|
|
|
|
2022-04-25 14:11:01 +00:00
|
|
|
// find the max value in the array, using a loop due to array size
|
2021-11-15 21:19:02 +00:00
|
|
|
function max(arr) {
|
|
|
|
var m = -Infinity;
|
|
|
|
for(var i=0; i< arr.length; i++)
|
|
|
|
if(arr[i] > m) m = arr[i];
|
|
|
|
return m;
|
|
|
|
}
|
|
|
|
|
|
|
|
// find the end of the data, the array might be for 31 days but only have 2 days of data in it
|
|
|
|
function get_data_length(arr) {
|
|
|
|
var nlen = arr.length;
|
|
|
|
for(var i = arr.length - 1; i > 0 && arr[i] == 0; i--)
|
|
|
|
nlen--;
|
|
|
|
return nlen;
|
|
|
|
}
|
|
|
|
|
2023-12-05 20:03:32 +00:00
|
|
|
function barChart(label, dt) {
|
2021-11-15 21:19:02 +00:00
|
|
|
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
|
|
|
|
chart_label = label;
|
|
|
|
chart_data = dt;
|
|
|
|
drawBarChart();
|
|
|
|
swipe_enabled = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
function drawBarChart() {
|
|
|
|
const bar_width = (w - 2) / 9; // we want 9 bars, bar 5 in the centre
|
|
|
|
var bar_top;
|
|
|
|
var bar;
|
2022-12-01 10:32:49 +00:00
|
|
|
g.reset().clearRect(0,24,w,h);
|
2022-04-25 14:11:01 +00:00
|
|
|
|
2021-11-15 21:19:02 +00:00
|
|
|
for (bar = 1; bar < 10; bar++) {
|
|
|
|
if (bar == 5) {
|
2022-12-01 10:32:49 +00:00
|
|
|
g.setFont('6x8', 2).setFontAlign(0,-1).setColor(g.theme.fg);
|
2021-11-15 21:19:02 +00:00
|
|
|
g.drawString(chart_label + " " + (chart_index + bar -1) + " " + chart_data[chart_index + bar - 1], g.getWidth()/2, 150);
|
|
|
|
g.setColor("#00f");
|
|
|
|
} else {
|
|
|
|
g.setColor("#0ff");
|
|
|
|
}
|
|
|
|
|
|
|
|
// draw a fake 0 height bar if chart_index is outside the bounds of the array
|
2022-05-17 21:19:42 +00:00
|
|
|
if ((chart_index + bar - 1) >= 0 && (chart_index + bar - 1) < data_len && chart_max_datum > 0)
|
2021-11-15 21:19:02 +00:00
|
|
|
bar_top = bar_bot - 100 * (chart_data[chart_index + bar - 1]) / chart_max_datum;
|
|
|
|
else
|
|
|
|
bar_top = bar_bot;
|
|
|
|
|
|
|
|
g.fillRect( 1 + (bar - 1)* bar_width, bar_bot, 1 + bar*bar_width, bar_top);
|
2022-12-01 10:32:49 +00:00
|
|
|
g.setColor(g.theme.fg).drawRect( 1 + (bar - 1)* bar_width, bar_bot, 1 + bar*bar_width, bar_top);
|
2021-11-15 21:19:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-01-03 07:15:37 +00:00
|
|
|
function drawHorizontalLine(value) {
|
|
|
|
const top = bar_bot - 100 * value / chart_max_datum;
|
|
|
|
g.setColor(g.theme.fg).drawLine(0, top ,g.getWidth(), top);
|
|
|
|
}
|
|
|
|
|
2023-12-03 19:45:28 +00:00
|
|
|
function setButton(fn, mult) {
|
2022-12-01 10:32:49 +00:00
|
|
|
Bangle.setUI({mode:"custom",
|
|
|
|
back:fn,
|
|
|
|
swipe:(lr,ud) => {
|
|
|
|
if (lr == 1) {
|
|
|
|
// HOUR data starts at index 0, DAY data starts at index 1
|
2022-12-01 20:03:15 +00:00
|
|
|
chart_index = Math.max((chart_label == /*LANG*/"DAY") ? -3 : -4, chart_index - 1);
|
2022-12-01 10:32:49 +00:00
|
|
|
} else if (lr<0) {
|
|
|
|
chart_index = Math.min(data_len - 5, chart_index + 1);
|
|
|
|
} else {
|
|
|
|
return fn();
|
|
|
|
}
|
|
|
|
drawBarChart();
|
2023-01-03 07:15:37 +00:00
|
|
|
if (current_selection == "stepsPerDay") {
|
2023-12-03 19:45:28 +00:00
|
|
|
drawHorizontalLine(settings.stepGoal * (mult || 1));
|
2023-01-03 07:15:37 +00:00
|
|
|
}
|
2022-12-01 10:32:49 +00:00
|
|
|
}});
|
2021-10-29 09:34:14 +00:00
|
|
|
}
|
|
|
|
|
2023-12-03 19:45:28 +00:00
|
|
|
function loadSettings() {
|
|
|
|
settings = require("Storage").readJSON("health.json",1)||{};
|
|
|
|
}
|
|
|
|
|
2021-10-14 16:14:10 +00:00
|
|
|
Bangle.loadWidgets();
|
|
|
|
Bangle.drawWidgets();
|
2023-12-03 19:45:28 +00:00
|
|
|
loadSettings();
|
2021-10-14 16:14:10 +00:00
|
|
|
menuMain();
|