forked from FOSS/BangleApps
commit
e28117a2c3
|
@ -1717,17 +1717,18 @@
|
||||||
{
|
{
|
||||||
"id": "wohrm",
|
"id": "wohrm",
|
||||||
"name": "Workout HRM",
|
"name": "Workout HRM",
|
||||||
"version": "0.08",
|
"version": "0.09",
|
||||||
"description": "Workout heart rate monitor notifies you with a buzz if your heart rate goes above or below the set limits.",
|
"description": "Workout heart rate monitor notifies you with a buzz if your heart rate goes above or below the set limits.",
|
||||||
"icon": "app.png",
|
"icon": "app.png",
|
||||||
"type": "app",
|
"type": "app",
|
||||||
"tags": "hrm,workout",
|
"tags": "hrm,workout",
|
||||||
"supports": ["BANGLEJS"],
|
"supports": ["BANGLEJS", "BANGLEJS2"],
|
||||||
"readme": "README.md",
|
"readme": "README.md",
|
||||||
"allow_emulator": true,
|
"allow_emulator": true,
|
||||||
"screenshots": [{"url":"bangle1-workout-HRM-screenshot.png"}],
|
"screenshots": [{"url":"bangle1-workout-HRM-screenshot.png"}],
|
||||||
"storage": [
|
"storage": [
|
||||||
{"name":"wohrm.app.js","url":"app.js"},
|
{"name":"wohrm.app.js","url":"app.js"},
|
||||||
|
{"name":"wohrm.settings.js","url":"settings.js"},
|
||||||
{"name":"wohrm.img","url":"app-icon.js","evaluate":true}
|
{"name":"wohrm.img","url":"app-icon.js","evaluate":true}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
|
@ -5,4 +5,7 @@
|
||||||
0.05: Improved buzz timing and rendering
|
0.05: Improved buzz timing and rendering
|
||||||
0.06: Removed debug outputs, fixed rendering for upper limit, improved rendering for +/- icons, changelog version order fixed
|
0.06: Removed debug outputs, fixed rendering for upper limit, improved rendering for +/- icons, changelog version order fixed
|
||||||
0.07: Home button fixed and README added
|
0.07: Home button fixed and README added
|
||||||
0.08: tag HRM power requests to allow this ot work alongside other widgets/apps (fix #799)
|
0.08: tag HRM power requests to allow this to work alongside other widgets/apps (fix #799)
|
||||||
|
0.09: Ported to Bangle.js2
|
||||||
|
Home returns to clock, instead of menu
|
||||||
|
Add settings
|
||||||
|
|
|
@ -8,6 +8,9 @@ and will notify you with a buzz whenever your heart rate falls below or jumps ab
|
||||||
[Try it out](https://www.espruino.com/ide/emulator.html?codeurl=https://raw.githubusercontent.com/msdeibel/BangleApps/master/apps/wohrm/app.js&upload) using the [online Espruino emulator](https://www.espruino.com/ide/emulator.html).
|
[Try it out](https://www.espruino.com/ide/emulator.html?codeurl=https://raw.githubusercontent.com/msdeibel/BangleApps/master/apps/wohrm/app.js&upload) using the [online Espruino emulator](https://www.espruino.com/ide/emulator.html).
|
||||||
|
|
||||||
## Setting the limits
|
## Setting the limits
|
||||||
|
|
||||||
|
Use the settings menu to set the limits. On the Bangle.js1 these can in addition be set with the buttons:
|
||||||
|
|
||||||
For setting the lower limit press button 4 (left part of the watch's touch screen).
|
For setting the lower limit press button 4 (left part of the watch's touch screen).
|
||||||
Then adjust the value with the buttons 1 (top) and 3 (bottom) of the watch.
|
Then adjust the value with the buttons 1 (top) and 3 (bottom) of the watch.
|
||||||
|
|
||||||
|
@ -22,7 +25,7 @@ the received value: For 85% and above the bars are green, between 84% and 50% th
|
||||||
and below 50% they turn red.
|
and below 50% they turn red.
|
||||||
|
|
||||||
## Closing the app
|
## Closing the app
|
||||||
Pressing button 2 (middle) will switch off the HRM of the watch and return you to the launcher.
|
Pressing middle button will switch off the HRM of the watch and return you to the launcher.
|
||||||
|
|
||||||
# HRM usage
|
# HRM usage
|
||||||
The HRM is switched on when the app is started. It stays switch on while the app is running, even
|
The HRM is switched on when the app is started. It stays switch on while the app is running, even
|
||||||
|
|
|
@ -1,327 +1,400 @@
|
||||||
/* eslint-disable no-undef */
|
/* eslint-disable no-undef */
|
||||||
const Setter = {
|
const Setter = {
|
||||||
NONE: "none",
|
NONE: "none",
|
||||||
UPPER: 'upper',
|
UPPER: 'upper',
|
||||||
LOWER: 'lower'
|
LOWER: 'lower'
|
||||||
};
|
};
|
||||||
|
const SETTINGS_FILE = "wohrm.setting.json";
|
||||||
const shortBuzzTimeInMs = 80;
|
var settings = require('Storage').readJSON(SETTINGS_FILE, 1) || {
|
||||||
const longBuzzTimeInMs = 400;
|
upperLimit: 130,
|
||||||
|
lowerLimit: 100
|
||||||
let upperLimit = 130;
|
};
|
||||||
let upperLimitChanged = true;
|
|
||||||
|
const shortBuzzTimeInMs = 80;
|
||||||
let lowerLimit = 100;
|
const longBuzzTimeInMs = 400;
|
||||||
let lowerLimitChanged = true;
|
|
||||||
|
let upperLimitChanged = true;
|
||||||
let limitSetter = Setter.NONE;
|
let lowerLimitChanged = true;
|
||||||
|
|
||||||
let currentHeartRate = 0;
|
let limitSetter = Setter.NONE;
|
||||||
let hrConfidence = -1;
|
|
||||||
let hrChanged = true;
|
let currentHeartRate = 0;
|
||||||
let confidenceChanged = true;
|
let hrConfidence = -1;
|
||||||
|
let hrChanged = true;
|
||||||
let setterHighlightTimeout;
|
let confidenceChanged = true;
|
||||||
|
|
||||||
function renderUpperLimitBackground() {
|
let setterHighlightTimeout;
|
||||||
g.setColor(1,0,0);
|
|
||||||
g.fillRect(125,40, 210, 70);
|
const isB1 = process.env.HWVERSION==1;
|
||||||
g.fillRect(180,70, 210, 200);
|
const upperLshape = isB1 ? {
|
||||||
|
right: 125,
|
||||||
//Round top left corner
|
left: 210,
|
||||||
g.fillEllipse(115,40,135,70);
|
bottom: 40,
|
||||||
|
top: 210,
|
||||||
//Round top right corner
|
rectWidth: 30,
|
||||||
g.setColor(0,0,0);
|
cornerRoundness: 5,
|
||||||
g.fillRect(205,40, 210, 45);
|
orientation: -1,
|
||||||
g.setColor(1,0,0);
|
color: '#f00'
|
||||||
g.fillEllipse(190,40,210,50);
|
} : {
|
||||||
|
right: Bangle.appRect.x2-100,
|
||||||
//Round inner corner
|
left: Bangle.appRect.x2,
|
||||||
g.fillRect(174,71, 179, 76);
|
bottom: 24,
|
||||||
g.setColor(0,0,0);
|
top: Bangle.appRect.y2,
|
||||||
g.fillEllipse(160,71,179,82);
|
rectWidth: 26,
|
||||||
|
cornerRoundness: 4,
|
||||||
//Round bottom
|
orientation: -1, // rotated 180°
|
||||||
g.setColor(1,0,0);
|
color: '#f00'
|
||||||
g.fillEllipse(180,190, 210, 210);
|
};
|
||||||
}
|
|
||||||
|
const lowerLshape = {
|
||||||
function renderLowerLimitBackground() {
|
left: isB1 ? 10 : Bangle.appRect.x,
|
||||||
g.setColor(0,0,1);
|
right: 100,
|
||||||
g.fillRect(10, 180, 100, 210);
|
bottom: upperLshape.top,
|
||||||
g.fillRect(10, 50, 40, 180);
|
top: upperLshape.bottom,
|
||||||
|
rectWidth: upperLshape.rectWidth,
|
||||||
//Rounded top
|
cornerRoundness: upperLshape.cornerRoundness,
|
||||||
g.setColor(0,0,1);
|
orientation: 1,
|
||||||
g.fillEllipse(10,40, 40, 60);
|
color: '#00f'
|
||||||
|
};
|
||||||
//Round bottom right corner
|
|
||||||
g.setColor(0,0,1);
|
const centerBar = {
|
||||||
g.fillEllipse(90,180,110,210);
|
minY: (upperLshape.bottom + upperLshape.top - upperLshape.rectWidth)/2,
|
||||||
|
maxY: (upperLshape.bottom + upperLshape.top + upperLshape.rectWidth)/2,
|
||||||
//Round inner corner
|
confidenceWidth: isB1 ? 10 : 8,
|
||||||
g.setColor(0,0,1);
|
minX: isB1 ? 55 : upperLshape.rectWidth + 14,
|
||||||
g.fillRect(40,175,45,180);
|
maxX: isB1 ? 165 : Bangle.appRect.x2 - upperLshape.rectWidth - 14
|
||||||
g.setColor(0,0,0);
|
};
|
||||||
g.fillEllipse(41,170,60,179);
|
|
||||||
|
const fontSizes = isB1 ? {
|
||||||
//Round bottom left corner
|
limits: 13,
|
||||||
g.setColor(0,0,0);
|
heartRate: 24
|
||||||
g.fillRect(10,205, 15, 210);
|
} : {
|
||||||
g.setColor(0,0,1);
|
limits: 12,
|
||||||
g.fillEllipse(10,200,30,210);
|
heartRate: 20
|
||||||
}
|
};
|
||||||
|
|
||||||
function drawTrainingHeartRate() {
|
function fillEllipse(x, y, x2, y2) {
|
||||||
//Only redraw if the display is on
|
g.fillEllipse(Math.min(x, x2),
|
||||||
if (Bangle.isLCDOn()) {
|
Math.min(y, y2),
|
||||||
renderUpperLimit();
|
Math.max(x, x2),
|
||||||
|
Math.max(y, y2));
|
||||||
renderCurrentHeartRate();
|
}
|
||||||
|
|
||||||
renderLowerLimit();
|
/**
|
||||||
|
* @param p.left: the X coordinate of the left side of the L in its orientation
|
||||||
renderConfidenceBars();
|
* @param p.right: the X coordinate of the right side of the L in its orientation
|
||||||
}
|
* @param p.top: the Y coordinate of the top side of the L in its orientation
|
||||||
|
* @param p.bottom: the Y coordinate of the bottom side of the L in its orientation
|
||||||
buzz();
|
* @param p.strokeWidth: how thick we draw the letter.
|
||||||
}
|
* @param p.cornerRoundness: how much the corners should be rounded
|
||||||
|
* @param p.orientation: 1 == turned 0°; -1 == turned 180°
|
||||||
function renderUpperLimit() {
|
* @param p.color: the color to draw the shape
|
||||||
if(!upperLimitChanged) { return; }
|
*/
|
||||||
|
function renderLshape(p) {
|
||||||
g.setColor(1,0,0);
|
g.setColor(p.color);
|
||||||
g.fillRect(125,40, 210, 70);
|
|
||||||
|
g.fillRect(p.right, p.bottom, p.left, p.bottom-p.orientation*p.rectWidth);
|
||||||
if(limitSetter === Setter.UPPER){
|
g.fillRect(p.left+p.orientation*p.rectWidth,
|
||||||
g.setColor(255,255, 0);
|
p.bottom-p.orientation*p.rectWidth,
|
||||||
} else {
|
p.left,
|
||||||
g.setColor(255,255,255);
|
p.top+p.orientation*p.cornerRoundness*2);
|
||||||
}
|
|
||||||
g.setFontVector(13);
|
//Round end of small line
|
||||||
g.drawString("Upper: " + upperLimit, 125, 50);
|
fillEllipse(p.right+p.orientation*p.cornerRoundness*2,
|
||||||
|
p.bottom,
|
||||||
upperLimitChanged = false;
|
p.right-p.orientation*p.cornerRoundness*2,
|
||||||
}
|
p.bottom-p.orientation*p.rectWidth);
|
||||||
|
|
||||||
function renderCurrentHeartRate() {
|
//Round outer corner
|
||||||
if(!hrChanged) { return; }
|
g.setColor(g.theme.bg);
|
||||||
|
g.fillRect(p.left+p.orientation*p.cornerRoundness,
|
||||||
g.setColor(255,255,255);
|
p.bottom,
|
||||||
g.fillRect(55, 110, 165, 150);
|
p.left,
|
||||||
|
p.bottom-p.orientation*p.cornerRoundness);
|
||||||
g.setColor(0,0,0);
|
g.setColor(p.color);
|
||||||
g.setFontVector(24);
|
fillEllipse(p.left+p.orientation*p.cornerRoundness*4,
|
||||||
g.setFontAlign(1, -1, 0);
|
p.bottom,
|
||||||
g.drawString(currentHeartRate, 130, 117);
|
p.left,
|
||||||
|
p.bottom-p.orientation*p.cornerRoundness*2);
|
||||||
//Reset alignment to defaults
|
|
||||||
g.setFontAlign(-1, -1, 0);
|
//Round inner corner
|
||||||
|
g.fillRect(p.left+p.orientation*(p.rectWidth+p.cornerRoundness+1),
|
||||||
hrChanged = false;
|
p.bottom-p.orientation*(p.rectWidth+1),
|
||||||
}
|
p.left+p.orientation*(p.rectWidth+1),
|
||||||
|
p.bottom-p.orientation*(p.rectWidth+p.cornerRoundness-1));
|
||||||
function renderLowerLimit() {
|
g.setColor(g.theme.bg);
|
||||||
if(!lowerLimitChanged) { return; }
|
fillEllipse(p.left+p.orientation*(p.rectWidth+p.cornerRoundness*4),
|
||||||
|
p.bottom-p.orientation*(p.rectWidth+1),
|
||||||
g.setColor(0,0,1);
|
p.left+p.orientation*(p.rectWidth+1),
|
||||||
g.fillRect(10, 180, 100, 210);
|
p.bottom-p.orientation*(p.rectWidth+p.cornerRoundness*3-1));
|
||||||
|
|
||||||
if(limitSetter === Setter.LOWER){
|
//Round end of long line
|
||||||
g.setColor(255,255, 0);
|
g.setColor(p.color);
|
||||||
} else {
|
fillEllipse(p.left+p.orientation*p.rectWidth,
|
||||||
g.setColor(255,255,255);
|
p.top+p.orientation*p.cornerRoundness*4,
|
||||||
}
|
p.left,
|
||||||
g.setFontVector(13);
|
p.top);
|
||||||
g.drawString("Lower: " + lowerLimit, 20,190);
|
}
|
||||||
|
|
||||||
lowerLimitChanged = false;
|
function drawTrainingHeartRate() {
|
||||||
}
|
//Only redraw if the display is on
|
||||||
|
if (Bangle.isLCDOn()) {
|
||||||
function renderConfidenceBars(){
|
renderUpperLimit();
|
||||||
if(!confidenceChanged) { return; }
|
|
||||||
|
renderCurrentHeartRate();
|
||||||
if(hrConfidence >= 85){
|
|
||||||
g.setColor(0, 255, 0);
|
renderLowerLimit();
|
||||||
} else if (hrConfidence >= 50) {
|
|
||||||
g.setColor(255, 255, 0);
|
renderConfidenceBars();
|
||||||
} else if(hrConfidence >= 0){
|
}
|
||||||
g.setColor(255, 0, 0);
|
|
||||||
} else {
|
buzz();
|
||||||
g.setColor(255, 255, 255);
|
}
|
||||||
}
|
|
||||||
|
function renderUpperLimit() {
|
||||||
g.fillRect(45, 110, 55, 150);
|
if(!upperLimitChanged) { return; }
|
||||||
g.fillRect(165, 110, 175, 150);
|
|
||||||
|
renderLshape(upperLshape);
|
||||||
confidenceChanged = false;
|
|
||||||
}
|
if(limitSetter === Setter.UPPER){
|
||||||
|
g.setColor(1,1,0);
|
||||||
function renderPlusMinusIcons() {
|
} else {
|
||||||
if (limitSetter === Setter.NONE) {
|
g.setColor(g.theme.fg);
|
||||||
g.setColor(0, 0, 0);
|
}
|
||||||
} else {
|
g.setFontVector(fontSizes.limits).setFontAlign(-1, 0, 0);
|
||||||
g.setColor(1, 1, 1);
|
g.drawString("Upper: " + settings.upperLimit,
|
||||||
}
|
upperLshape.right,
|
||||||
|
upperLshape.bottom+upperLshape.rectWidth/2);
|
||||||
g.setFontVector(14);
|
|
||||||
|
upperLimitChanged = false;
|
||||||
//+ for Btn1
|
}
|
||||||
g.drawString("+", 222, 50);
|
|
||||||
|
function renderCurrentHeartRate() {
|
||||||
//- for Btn3
|
if(!hrChanged) { return; }
|
||||||
g.drawString("-", 222,165);
|
|
||||||
|
g.setColor(g.theme.fg);
|
||||||
return;
|
g.fillRect(centerBar.minX, centerBar.minY,
|
||||||
}
|
centerBar.maxX, centerBar.maxY);
|
||||||
|
|
||||||
function renderHomeIcon() {
|
g.setColor(g.theme.bg);
|
||||||
//Home for Btn2
|
g.setFontVector(fontSizes.heartRate);
|
||||||
g.setColor(1, 1, 1);
|
g.setFontAlign(1, 0, 0);
|
||||||
g.drawLine(220, 118, 227, 110);
|
g.drawString(currentHeartRate,
|
||||||
g.drawLine(227, 110, 234, 118);
|
Math.max(upperLshape.right+upperLshape.cornerRoundness,
|
||||||
|
lowerLshape.right-lowerLshape.cornerRoundness),
|
||||||
g.drawPoly([222,117,222,125,232,125,232,117], false);
|
(centerBar.minY+centerBar.maxY)/2);
|
||||||
g.drawRect(226,120,229,125);
|
|
||||||
}
|
//Reset alignment to defaults
|
||||||
|
g.setFontAlign(-1, -1, 0);
|
||||||
function buzz() {
|
|
||||||
// Do not buzz if not confident
|
hrChanged = false;
|
||||||
if(hrConfidence < 85) { return; }
|
}
|
||||||
|
|
||||||
if(currentHeartRate > upperLimit)
|
function renderLowerLimit() {
|
||||||
{
|
if(!lowerLimitChanged) { return; }
|
||||||
Bangle.buzz(shortBuzzTimeInMs);
|
|
||||||
setTimeout(() => { Bangle.buzz(shortBuzzTimeInMs); }, shortBuzzTimeInMs * 2);
|
renderLshape(lowerLshape);
|
||||||
}
|
|
||||||
|
if(limitSetter === Setter.LOWER){
|
||||||
if(currentHeartRate < lowerLimit)
|
g.setColor(1,1,0);
|
||||||
{
|
} else {
|
||||||
Bangle.buzz(longBuzzTimeInMs);
|
g.setColor(g.theme.fg);
|
||||||
}
|
}
|
||||||
}
|
g.setFontVector(fontSizes.limits).setFontAlign(-1, 0, 0);
|
||||||
|
g.drawString("Lower: " + settings.lowerLimit,
|
||||||
function onHrm(hrm){
|
lowerLshape.left + lowerLshape.rectWidth/2,
|
||||||
if(currentHeartRate !== hrm.bpm){
|
lowerLshape.bottom - lowerLshape.rectWidth/2);
|
||||||
currentHeartRate = hrm.bpm;
|
|
||||||
hrChanged = true;
|
lowerLimitChanged = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(hrConfidence !== hrm.confidence) {
|
function renderConfidenceBars(){
|
||||||
hrConfidence = hrm.confidence;
|
if(!confidenceChanged) { return; }
|
||||||
confidenceChanged = true;
|
|
||||||
}
|
if(hrConfidence >= 85){
|
||||||
}
|
g.setColor(0, 1, 0);
|
||||||
|
} else if (hrConfidence >= 50) {
|
||||||
function setLimitSetterToLower() {
|
g.setColor(1, 1, 0);
|
||||||
resetHighlightTimeout();
|
} else if(hrConfidence >= 0){
|
||||||
|
g.setColor(1, 0, 0);
|
||||||
limitSetter = Setter.LOWER;
|
} else {
|
||||||
|
g.setColor(g.theme.fg);
|
||||||
upperLimitChanged = true;
|
}
|
||||||
lowerLimitChanged = true;
|
|
||||||
|
g.fillRect(centerBar.minX-centerBar.confidenceWidth, centerBar.minY, centerBar.minX, centerBar.maxY);
|
||||||
renderUpperLimit();
|
g.fillRect(centerBar.maxX, centerBar.minY, centerBar.maxX+centerBar.confidenceWidth, centerBar.maxY);
|
||||||
renderLowerLimit();
|
|
||||||
renderPlusMinusIcons();
|
confidenceChanged = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
function setLimitSetterToUpper() {
|
function renderPlusMinusIcons() {
|
||||||
resetHighlightTimeout();
|
if (limitSetter === Setter.NONE) {
|
||||||
|
g.setColor(g.theme.bg);
|
||||||
limitSetter = Setter.UPPER;
|
} else {
|
||||||
|
g.setColor(g.theme.fg);
|
||||||
upperLimitChanged = true;
|
}
|
||||||
lowerLimitChanged = true;
|
|
||||||
|
g.setFontVector(14);
|
||||||
renderLowerLimit();
|
|
||||||
renderUpperLimit();
|
//+ for Btn1
|
||||||
renderPlusMinusIcons();
|
g.drawString("+", 222, 50);
|
||||||
}
|
|
||||||
|
//- for Btn3
|
||||||
function setLimitSetterToNone() {
|
g.drawString("-", 222,165);
|
||||||
limitSetter = Setter.NONE;
|
|
||||||
|
return;
|
||||||
upperLimitChanged = true;
|
}
|
||||||
lowerLimitChanged = true;
|
|
||||||
|
function renderHomeIcon() {
|
||||||
renderLowerLimit();
|
//Home for Btn2
|
||||||
renderUpperLimit();
|
g.setColor(1, 1, 1);
|
||||||
renderPlusMinusIcons();
|
g.drawLine(220, 118, 227, 110);
|
||||||
}
|
g.drawLine(227, 110, 234, 118);
|
||||||
|
|
||||||
function incrementLimit() {
|
g.drawPoly([222,117,222,125,232,125,232,117], false);
|
||||||
resetHighlightTimeout();
|
g.drawRect(226,120,229,125);
|
||||||
|
}
|
||||||
if (limitSetter === Setter.UPPER) {
|
|
||||||
upperLimit++;
|
function buzz() {
|
||||||
renderUpperLimit();
|
// Do not buzz if not confident
|
||||||
upperLimitChanged = true;
|
if(hrConfidence < 85) { return; }
|
||||||
} else if(limitSetter === Setter.LOWER) {
|
|
||||||
lowerLimit++;
|
if(currentHeartRate > settings.upperLimit)
|
||||||
renderLowerLimit();
|
{
|
||||||
lowerLimitChanged = true;
|
Bangle.buzz(shortBuzzTimeInMs);
|
||||||
}
|
setTimeout(() => { Bangle.buzz(shortBuzzTimeInMs); }, shortBuzzTimeInMs * 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
function decrementLimit(){
|
if(currentHeartRate < settings.lowerLimit)
|
||||||
resetHighlightTimeout();
|
{
|
||||||
|
Bangle.buzz(longBuzzTimeInMs);
|
||||||
if (limitSetter === Setter.UPPER) {
|
}
|
||||||
upperLimit--;
|
}
|
||||||
renderUpperLimit();
|
|
||||||
upperLimitChanged = true;
|
function onHrm(hrm){
|
||||||
} else if(limitSetter === Setter.LOWER) {
|
if(currentHeartRate !== hrm.bpm){
|
||||||
lowerLimit--;
|
currentHeartRate = hrm.bpm;
|
||||||
renderLowerLimit();
|
hrChanged = true;
|
||||||
lowerLimitChanged = true;
|
}
|
||||||
}
|
|
||||||
}
|
if(hrConfidence !== hrm.confidence) {
|
||||||
|
hrConfidence = hrm.confidence;
|
||||||
function resetHighlightTimeout() {
|
confidenceChanged = true;
|
||||||
if (setterHighlightTimeout) {
|
}
|
||||||
clearTimeout(setterHighlightTimeout);
|
}
|
||||||
}
|
|
||||||
|
function setLimitSetterToLower() {
|
||||||
setterHighlightTimeout = setTimeout(setLimitSetterToNone, 2000);
|
resetHighlightTimeout();
|
||||||
}
|
|
||||||
|
limitSetter = Setter.LOWER;
|
||||||
function switchOffApp(){
|
|
||||||
Bangle.setHRMPower(0,"wohrm");
|
upperLimitChanged = true;
|
||||||
Bangle.showLauncher();
|
lowerLimitChanged = true;
|
||||||
}
|
|
||||||
|
renderUpperLimit();
|
||||||
Bangle.on('lcdPower', (on) => {
|
renderLowerLimit();
|
||||||
g.clear();
|
renderPlusMinusIcons();
|
||||||
if (on) {
|
}
|
||||||
Bangle.drawWidgets();
|
|
||||||
|
function setLimitSetterToUpper() {
|
||||||
renderHomeIcon();
|
resetHighlightTimeout();
|
||||||
renderLowerLimitBackground();
|
|
||||||
renderUpperLimitBackground();
|
limitSetter = Setter.UPPER;
|
||||||
lowerLimitChanged = true;
|
|
||||||
upperLimitChanged = true;
|
upperLimitChanged = true;
|
||||||
drawTrainingHeartRate();
|
lowerLimitChanged = true;
|
||||||
}
|
|
||||||
});
|
renderLowerLimit();
|
||||||
|
renderUpperLimit();
|
||||||
Bangle.setHRMPower(1,"wohrm");
|
renderPlusMinusIcons();
|
||||||
Bangle.on('HRM', onHrm);
|
}
|
||||||
|
|
||||||
setWatch(incrementLimit, BTN1, {edge:"rising", debounce:50, repeat:true});
|
function setLimitSetterToNone() {
|
||||||
setWatch(decrementLimit, BTN3, {edge:"rising", debounce:50, repeat:true});
|
limitSetter = Setter.NONE;
|
||||||
setWatch(setLimitSetterToLower, BTN4, {edge:"rising", debounce:50, repeat:true});
|
|
||||||
setWatch(setLimitSetterToUpper, BTN5, { edge: "rising", debounce: 50, repeat: true });
|
upperLimitChanged = true;
|
||||||
|
lowerLimitChanged = true;
|
||||||
setWatch(switchOffApp, BTN2, {edge:"falling", debounce:50, repeat:true});
|
|
||||||
|
renderLowerLimit();
|
||||||
g.clear();
|
renderUpperLimit();
|
||||||
Bangle.loadWidgets();
|
renderPlusMinusIcons();
|
||||||
Bangle.drawWidgets();
|
}
|
||||||
|
|
||||||
renderHomeIcon();
|
function incrementLimit() {
|
||||||
renderLowerLimitBackground();
|
resetHighlightTimeout();
|
||||||
renderUpperLimitBackground();
|
|
||||||
|
if (limitSetter === Setter.UPPER) {
|
||||||
setInterval(drawTrainingHeartRate, 1000);
|
settings.upperLimit++;
|
||||||
|
renderUpperLimit();
|
||||||
|
upperLimitChanged = true;
|
||||||
|
} else if(limitSetter === Setter.LOWER) {
|
||||||
|
settings.lowerLimit++;
|
||||||
|
renderLowerLimit();
|
||||||
|
lowerLimitChanged = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function decrementLimit(){
|
||||||
|
resetHighlightTimeout();
|
||||||
|
|
||||||
|
if (limitSetter === Setter.UPPER) {
|
||||||
|
settings.upperLimit--;
|
||||||
|
renderUpperLimit();
|
||||||
|
upperLimitChanged = true;
|
||||||
|
} else if(limitSetter === Setter.LOWER) {
|
||||||
|
settings.lowerLimit--;
|
||||||
|
renderLowerLimit();
|
||||||
|
lowerLimitChanged = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function resetHighlightTimeout() {
|
||||||
|
if (setterHighlightTimeout) {
|
||||||
|
clearTimeout(setterHighlightTimeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
setterHighlightTimeout = setTimeout(setLimitSetterToNone, 2000);
|
||||||
|
}
|
||||||
|
|
||||||
|
function switchOffApp(){
|
||||||
|
Bangle.setHRMPower(0,"wohrm");
|
||||||
|
load();
|
||||||
|
}
|
||||||
|
|
||||||
|
Bangle.on('lcdPower', (on) => {
|
||||||
|
if (on) {
|
||||||
|
Bangle.drawWidgets();
|
||||||
|
|
||||||
|
if (typeof(BTN5) !== typeof(undefined)) {
|
||||||
|
renderHomeIcon();
|
||||||
|
}
|
||||||
|
renderLshape(lowerLshape);
|
||||||
|
renderLshape(upperLshape);
|
||||||
|
lowerLimitChanged = true;
|
||||||
|
upperLimitChanged = true;
|
||||||
|
drawTrainingHeartRate();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Bangle.setHRMPower(1,"wohrm");
|
||||||
|
Bangle.on('HRM', onHrm);
|
||||||
|
|
||||||
|
g.setTheme({bg:"#000",fg:"#fff",dark:true});
|
||||||
|
g.reset();
|
||||||
|
g.clear();
|
||||||
|
Bangle.loadWidgets();
|
||||||
|
Bangle.drawWidgets();
|
||||||
|
|
||||||
|
if (typeof(BTN5) !== typeof(undefined)) {
|
||||||
|
renderHomeIcon();
|
||||||
|
setWatch(incrementLimit, BTN1, {edge:"rising", debounce:50, repeat:true});
|
||||||
|
setWatch(decrementLimit, BTN3, {edge:"rising", debounce:50, repeat:true});
|
||||||
|
setWatch(setLimitSetterToLower, BTN4, {edge:"rising", debounce:50, repeat:true});
|
||||||
|
setWatch(setLimitSetterToUpper, BTN5, { edge: "rising", debounce: 50, repeat: true });
|
||||||
|
|
||||||
|
setWatch(switchOffApp, BTN2, {edge:"falling", debounce:50, repeat:true});
|
||||||
|
} else {
|
||||||
|
setWatch(switchOffApp, BTN1, {edge:"falling", debounce:50, repeat:true});
|
||||||
|
}
|
||||||
|
|
||||||
|
setInterval(drawTrainingHeartRate, 1000);
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
(function menu(back) {
|
||||||
|
const SETTINGS_FILE = "wohrm.setting.json";
|
||||||
|
|
||||||
|
// initialize with default settings...
|
||||||
|
const storage = require('Storage');
|
||||||
|
var settings = storage.readJSON(SETTINGS_FILE, 1) || {
|
||||||
|
upperLimit: 130,
|
||||||
|
lowerLimit: 100
|
||||||
|
};
|
||||||
|
|
||||||
|
function save() {
|
||||||
|
storage.write(SETTINGS_FILE, settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
E.showMenu({
|
||||||
|
'': { 'title': 'Workout HRM' },
|
||||||
|
'< Back': back,
|
||||||
|
'Upper limit': {
|
||||||
|
value: settings.upperLimit,
|
||||||
|
min: 100, max: 200,
|
||||||
|
onchange: v => {
|
||||||
|
settings.upperLimit = v;
|
||||||
|
save();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'Lower limit': {
|
||||||
|
value: settings.lowerLimit,
|
||||||
|
min: 50, max: 150,
|
||||||
|
onchange: v => {
|
||||||
|
settings.lowerLimit = v;
|
||||||
|
save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})
|
Loading…
Reference in New Issue