Refactor settings menu & make colors of circles configurable

master
Marco Heiming 2022-01-29 21:51:44 +01:00
parent 40ee16c873
commit 7de40d9c8c
4 changed files with 233 additions and 172 deletions

View File

@ -15,3 +15,5 @@
0.08: Allow configuration of up to 4 circles in a row 0.08: Allow configuration of up to 4 circles in a row
0.09: Support to show temperature, air pressure or altitude from internal pressure sensor 0.09: Support to show temperature, air pressure or altitude from internal pressure sensor
Fix sunprogress calculation during night Fix sunprogress calculation during night
Refactor settings menu
Colors of circles can be configured

View File

@ -23,7 +23,6 @@ It can show the following information (this can be configured):
![Screenshot light theme with four circles](screenshot-light-4.png) ![Screenshot light theme with four circles](screenshot-light-4.png)
## Ideas ## Ideas
* Make colors configurable
* Show compass heading * Show compass heading
## Creator ## Creator

View File

@ -1,28 +1,24 @@
const locale = require("locale"); const locale = require("locale");
const heatshrink = require("heatshrink");
const storage = require("Storage"); const storage = require("Storage");
const SunCalc = require("https://raw.githubusercontent.com/mourner/suncalc/master/suncalc.js"); const SunCalc = require("https://raw.githubusercontent.com/mourner/suncalc/master/suncalc.js");
const shoesIcon = heatshrink.decompress(atob("h0OwYJGgmAAgUBkgECgVJB4cSoAUDyEBkARDpADBhMAyQRBgVAkgmDhIUDAAuQAgY1DAAYA=")); const shoesIcon = atob("EBCBAAAACAAcAB4AHgAeABwwADgGeAZ4AHgAMAAAAHAAIAAA");
const shoesIconGreen = heatshrink.decompress(atob("h0OwYJGhIEDgVIAgUEyQKDkmACgcggVACIeQAYMSgIRCgmApIbDiQUDAAkBkAFDGoYAD")); const heartIcon = atob("EBCBAAAAAAAeeD/8P/x//n/+P/w//B/4D/AH4APAAYAAAAAA");
const heartIcon = heatshrink.decompress(atob("h0OwYOLkmQhMkgACByVJgESpIFBpEEBAIFBCgIFCCgsABwcAgQOCAAMSpAwDyBNM")); const powerIcon = atob("FBSBAAAAAAAAAfgAP8AH/gB/4Af+AH/gB/4Af+AH/gB/4Af+AH/gB/4Af+AH/gB/4AAAAAAA");
const powerIcon = heatshrink.decompress(atob("h0OwYQNsAED7AEDmwEDtu2AgUbtuABwXbBIUN23AAoYOCgEDFIgODABI")); const temperatureIcon = atob("EBCBAAAAAYADwAJAAkADwAPAA8ADwAfgB+AH4AfgA8ABgAAA");
const powerIconGreen = heatshrink.decompress(atob("h0OwYQNkAEDpAEDiQEDkmSAgUJkmABwVJBIUEyVAAoYOCgEBFIgODABI"));
const powerIconRed = heatshrink.decompress(atob("h0OwYQNoAEDyAEDkgEDpIFDiVJBweSAgUJkmAAoYZDgQpEBwYAJA"));
const themperatureIcon = heatshrink.decompress(atob("h0OwIFChkAvEBkEHwEeAwXgh+An8A/gGBgYWCA=="));
const weatherCloudy = heatshrink.decompress(atob("iEQwYWTgP//+AAoMPAoPwAoN/AocfAgP//0AAgQAB/AFEABgdDAAMDDohMRA")); const weatherCloudy = atob("EBCBAAAAAAAAAAfgD/Af8H/4//7///////9//z/+AAAAAAAA");
const weatherSunny = heatshrink.decompress(atob("iEQwYLIg3AAgVgAQMMAo8Am3YAgUB23bAoUNAoIUBjYFCsOwBYoFDDpFgHYI1JI4gFGAAYA=")); const weatherSunny = atob("EBCBAAAAAYAQCBAIA8AH4A/wb/YP8A/gB+ARiBAIAYABgAAA");
const weatherMoon = heatshrink.decompress(atob("iEQwIFCgOAh/wj/4n/8AId//wBBBIoRBCoIZBDoI")); const weatherMoon = atob("EBCBAAAAAYAP8B/4P/w//D/8f/5//j/8P/w//B/4D/ABgAAA");
const weatherPartlyCloudy = heatshrink.decompress(atob("iEQwYQNv0AjgGDn4EDh///gFChwREC4MfxwIBv0//+AC4X4j4FCv/AgfwgED/wIBuAaBBwgFDgP4gf/AAXABwIEBDQQAEA==")); const weatherPartlyCloudy = atob("EBCBAAAAAAAYQAMAD8AIQBhoW+AOYBwwOBBgHGAGP/wf+AAA");
const weatherRainy = heatshrink.decompress(atob("iEQwYLIg/gAgUB///wAFBh/AgfwgED/wIBuEAj4OCv0AjgaCh/4AocAnAFBFIU4EAM//gRBEAIOBhw1C/AmDAosAC4JNIAAg")); const weatherRainy = atob("EBCBAAAAAYAH4AwwOBBgGEAOQAJBgjPOEkgGYAZgA8ABgAAA");
const weatherPartlyRainy = heatshrink.decompress(atob("h0OwYJGjkAnAFCj+AAgU//4FCuEA8EAg8ch/4gEB4////AAoIIBCIMD/wgCg4bBg/8BwMD+AgBh4ZBDQf/FIIABh4IBgAA==")); const weatherPartlyRainy = atob("EBCBAAAAEEAQAAeADMAYaFvoTmAMMDgQIBxhhiGGG9wDwAGA");
const weatherSnowy = heatshrink.decompress(atob("iEQwYROn/8AocH8AECuAFBh0Agf+CIN/4EDx/4j/x4EAgIIBwAXBAogRFDoopFGoxBGABIA=")); const weatherSnowy = atob("EBCBAAAAAAADwAGAEYg73C50BCAEIC50O9wRiAGAA8AAAAAA");
const weatherFoggy = heatshrink.decompress(atob("iEQwYROn/8AgUB/EfwAFBh/AgfwgED/wIBuEABwd/4EcDQgFDgE4Fosf///8f//A/Lj/xCQIRNA=")); const weatherFoggy = atob("EBCBAAAAAAADwAZgDDA4EGAcQAZAAgAAf74AAAAAd/4AAAAA");
const weatherStormy = heatshrink.decompress(atob("iEQwYLIg/gAgUB///wAFBh/AgfwgED/wIBuEAj4OCv0AjgaCh/4AoX8gE4AoQpBnAdBF4IRBDQMH/kOHgY7DAo4AOA==")); const weatherStormy = atob("EBCBAAAAAYAH4AwwOBBgGEAOQMJAgjmOGcgAgACAAAAAAAAA");
const sunSetDown = heatshrink.decompress(atob("iEQwIHEgOAAocT5EGtEEkF//wLDg1ggfACoo")); const sunSetDown = atob("EBCBAAAAAAABgAAAAAATyAZoBCB//gAAAAAGYAPAAYAAAAAA");
const sunSetUp = heatshrink.decompress(atob("iEQwIHEgOAAocT5EGtEEkF//wRFgfAg1gBIY")); const sunSetUp = atob("EBCBAAAAAAABgAAAAAATyAZoBCB//gAAAAABgAPABmAAAAAA");
let settings = storage.readJSON("circlesclock.json", 1) || { let settings = storage.readJSON("circlesclock.json", 1) || {
'minHR': 40, 'minHR': 40,
@ -42,7 +38,7 @@ let settings = storage.readJSON("circlesclock.json", 1) || {
}; };
// Load step goal from pedometer widget as fallback // Load step goal from pedometer widget as fallback
if (settings.stepGoal == undefined) { if (settings.stepGoal == undefined) {
const d = require('Storage').readJSON("wpedom.json", 1) || {}; const d = storage.readJSON("wpedom.json", 1) || {};
settings.stepGoal = d != undefined && d.settings != undefined ? d.settings.goal : 10000; settings.stepGoal = d != undefined && d.settings != undefined ? d.settings.goal : 10000;
} }
@ -150,7 +146,7 @@ function draw() {
function drawCircle(index) { function drawCircle(index) {
let type = settings['circle' + index]; let type = settings['circle' + index];
if (!type) type = defaultCircleTypes[index - 1]; if (!type) type = defaultCircleTypes[index - 1];
const w = getCirclePosition(type); const w = getCircleXPosition(type);
switch (type) { switch (type) {
case "steps": case "steps":
@ -199,133 +195,164 @@ let circlePositionsCache = [];
*/ */
function getCirclePosition(type) { function getCirclePosition(type) {
if (circlePositionsCache[type] >= 0) { if (circlePositionsCache[type] >= 0) {
return circlePosX[circlePositionsCache[type]]; return circlePositionsCache[type];
} }
for (let i = 1; i <= circleCount; i++) { for (let i = 1; i <= circleCount; i++) {
const setting = settings['circle' + i]; const setting = settings['circle' + i];
if (setting == type) { if (setting == type) {
circlePositionsCache[type] = i - 1; circlePositionsCache[type] = i - 1;
return circlePosX[i - 1]; return i - 1;
} }
} }
for (let i = 0; i < defaultCircleTypes.length; i++) { for (let i = 0; i < defaultCircleTypes.length; i++) {
if (type == defaultCircleTypes[i] && (!settings || settings['circle' + (i + 1)] == undefined)) { if (type == defaultCircleTypes[i] && (!settings || settings['circle' + (i + 1)] == undefined)) {
circlePositionsCache[type] = i; circlePositionsCache[type] = i;
return circlePosX[i]; return i;
} }
} }
return undefined; return undefined;
} }
function getCircleXPosition(type) {
const circlePos = getCirclePosition(type);
if (circlePos != undefined) {
return circlePosX[circlePos];
}
return undefined;
}
function isCircleEnabled(type) { function isCircleEnabled(type) {
return getCirclePosition(type) != undefined; return getCirclePosition(type) != undefined;
} }
function getCircleColor(type) {
const pos = getCirclePosition(type);
const color = settings["circle" + (pos + 1) + "color"];
if (color && color != "") return color;
}
function getImage(graphic, color) {
return {
width: 16,
height: 16,
bpp: 1,
transparent: 0,
buffer: E.toArrayBuffer(graphic),
palette: new Uint16Array([colorBg, g.toColor(color)])
};
}
function drawSteps(w) { function drawSteps(w) {
if (!w) w = getCirclePosition("steps"); if (!w) w = getCircleXPosition("steps");
const steps = getSteps(); const steps = getSteps();
drawCircleBackground(w); drawCircleBackground(w);
const color = getCircleColor("steps") || colorBlue;
const stepGoal = settings.stepGoal || 10000; const stepGoal = settings.stepGoal || 10000;
if (stepGoal > 0) { if (stepGoal > 0) {
let percent = steps / stepGoal; let percent = steps / stepGoal;
if (stepGoal < steps) percent = 1; if (stepGoal < steps) percent = 1;
drawGauge(w, h3, percent, colorBlue); drawGauge(w, h3, percent, color);
} }
drawInnerCircleAndTriangle(w); drawInnerCircleAndTriangle(w);
writeCircleText(w, shortValue(steps)); writeCircleText(w, shortValue(steps));
g.drawImage(shoesIcon, w - iconOffset, h3 + radiusOuter - iconOffset); g.drawImage(getImage(shoesIcon, color), w - iconOffset, h3 + radiusOuter - iconOffset);
} }
function drawStepsDistance(w) { function drawStepsDistance(w) {
if (!w) w = getCirclePosition("steps"); if (!w) w = getCircleXPosition("stepsDistance");
const steps = getSteps(); const steps = getSteps();
const stepDistance = settings.stepLength || 0.8; const stepDistance = settings.stepLength || 0.8;
const stepsDistance = Math.round(steps * stepDistance); const stepsDistance = Math.round(steps * stepDistance);
drawCircleBackground(w); drawCircleBackground(w);
const color = getCircleColor("stepsDistance") || colorGreen;
const stepDistanceGoal = settings.stepDistanceGoal || 8000; const stepDistanceGoal = settings.stepDistanceGoal || 8000;
if (stepDistanceGoal > 0) { if (stepDistanceGoal > 0) {
let percent = stepsDistance / stepDistanceGoal; let percent = stepsDistance / stepDistanceGoal;
if (stepDistanceGoal < stepsDistance) percent = 1; if (stepDistanceGoal < stepsDistance) percent = 1;
drawGauge(w, h3, percent, colorGreen); drawGauge(w, h3, percent, color);
} }
drawInnerCircleAndTriangle(w); drawInnerCircleAndTriangle(w);
writeCircleText(w, shortValue(stepsDistance)); writeCircleText(w, shortValue(stepsDistance));
g.drawImage(shoesIconGreen, w - iconOffset, h3 + radiusOuter - iconOffset); g.drawImage(getImage(shoesIcon, color), w - iconOffset, h3 + radiusOuter - iconOffset);
} }
function drawHeartRate(w) { function drawHeartRate(w) {
if (!w) w = getCirclePosition("hr"); if (!w) w = getCircleXPosition("hr");
drawCircleBackground(w); drawCircleBackground(w);
const color = getCircleColor("hr") || colorRed;
if (hrtValue != undefined) { if (hrtValue != undefined) {
const minHR = settings.minHR || 40; const minHR = settings.minHR || 40;
const maxHR = settings.maxHR || 200; const maxHR = settings.maxHR || 200;
const percent = (hrtValue - minHR) / (maxHR - minHR); const percent = (hrtValue - minHR) / (maxHR - minHR);
drawGauge(w, h3, percent, colorRed); drawGauge(w, h3, percent, color);
} }
drawInnerCircleAndTriangle(w); drawInnerCircleAndTriangle(w);
writeCircleText(w, hrtValue != undefined ? hrtValue : "-"); writeCircleText(w, hrtValue != undefined ? hrtValue : "-");
g.drawImage(heartIcon, w - iconOffset, h3 + radiusOuter - iconOffset); g.drawImage(getImage(heartIcon, color), w - iconOffset, h3 + radiusOuter - iconOffset);
} }
function drawBattery(w) { function drawBattery(w) {
if (!w) w = getCirclePosition("battery"); if (!w) w = getCircleXPosition("battery");
const battery = E.getBattery(); const battery = E.getBattery();
drawCircleBackground(w); drawCircleBackground(w);
let color = getCircleColor("battery") || colorYellow;
if (battery > 0) { if (battery > 0) {
const percent = battery / 100; const percent = battery / 100;
drawGauge(w, h3, percent, colorYellow); drawGauge(w, h3, percent, color);
} }
drawInnerCircleAndTriangle(w); drawInnerCircleAndTriangle(w);
let icon = powerIcon;
let color = colorFg;
if (Bangle.isCharging()) { if (Bangle.isCharging()) {
color = colorGreen; color = colorGreen;
icon = powerIconGreen;
} else { } else {
if (settings.batteryWarn != undefined && battery <= settings.batteryWarn) { if (settings.batteryWarn != undefined && battery <= settings.batteryWarn) {
color = colorRed; color = colorRed;
icon = powerIconRed;
} }
} }
writeCircleText(w, battery + '%'); writeCircleText(w, battery + '%');
g.drawImage(icon, w - iconOffset, h3 + radiusOuter - iconOffset); g.drawImage(getImage(powerIcon, color), w - iconOffset, h3 + radiusOuter - iconOffset);
} }
function drawWeather(w) { function drawWeather(w) {
if (!w) w = getCirclePosition("weather"); if (!w) w = getCircleXPosition("weather");
const weather = getWeather(); const weather = getWeather();
const tempString = weather ? locale.temp(weather.temp - 273.15) : undefined; const tempString = weather ? locale.temp(weather.temp - 273.15) : undefined;
const code = weather ? weather.code : -1; const code = weather ? weather.code : -1;
drawCircleBackground(w); drawCircleBackground(w);
const color = getCircleColor("weather") || colorYellow;
const data = settings.weatherCircleData || "humidity"; const data = settings.weatherCircleData || "humidity";
switch (data) { switch (data) {
case "humidity": case "humidity":
const humidity = weather ? weather.hum : undefined; const humidity = weather ? weather.hum : undefined;
if (humidity >= 0) { if (humidity >= 0) {
drawGauge(w, h3, humidity / 100, colorYellow); drawGauge(w, h3, humidity / 100, color);
} }
break; break;
case "wind": case "wind":
@ -336,7 +363,7 @@ function drawWeather(w) {
wind[1] = windAsBeaufort(wind[1]); wind[1] = windAsBeaufort(wind[1]);
} }
// wind goes from 0 to 12 (see https://en.wikipedia.org/wiki/Beaufort_scale) // wind goes from 0 to 12 (see https://en.wikipedia.org/wiki/Beaufort_scale)
drawGauge(w, h3, wind[1] / 12, colorYellow); drawGauge(w, h3, wind[1] / 12, color);
} }
} }
break; break;
@ -350,7 +377,7 @@ function drawWeather(w) {
if (code > 0) { if (code > 0) {
const icon = getWeatherIconByCode(code); const icon = getWeatherIconByCode(code);
if (icon) g.drawImage(icon, w - iconOffset, h3 + radiusOuter - iconOffset); if (icon) g.drawImage(getImage(icon, color), w - iconOffset, h3 + radiusOuter - iconOffset);
} else { } else {
g.drawString("?", w, h3 + radiusOuter); g.drawString("?", w, h3 + radiusOuter);
} }
@ -358,27 +385,25 @@ function drawWeather(w) {
function drawSunProgress(w) { function drawSunProgress(w) {
if (!w) w = getCirclePosition("sunprogress"); if (!w) w = getCircleXPosition("sunprogress");
const percent = getSunProgress(); const percent = getSunProgress();
drawCircleBackground(w); drawCircleBackground(w);
drawGauge(w, h3, percent, colorYellow); const color = getCircleColor("sunpgrogress") || colorYellow;
drawGauge(w, h3, percent, color);
drawInnerCircleAndTriangle(w); drawInnerCircleAndTriangle(w);
let icon = powerIcon; let icon = sunSetDown;
let color = colorFg;
if (isDay()) { if (isDay()) {
// day // day
color = colorFg;
icon = sunSetDown; icon = sunSetDown;
} else { } else {
// night // night
color = colorGrey;
icon = sunSetUp; icon = sunSetUp;
} }
g.setColor(color);
let text = "?"; let text = "?";
const times = getSunData(); const times = getSunData();
@ -402,28 +427,30 @@ function drawSunProgress(w) {
writeCircleText(w, text); writeCircleText(w, text);
g.drawImage(icon, w - iconOffset, h3 + radiusOuter - iconOffset); g.drawImage(getImage(icon, color), w - iconOffset, h3 + radiusOuter - iconOffset);
} }
function drawTemperature(w) { function drawTemperature(w) {
if (!w) w = getCirclePosition("temperature"); if (!w) w = getCircleXPosition("temperature");
getPressureValue("temperature").then((temperature) => { getPressureValue("temperature").then((temperature) => {
drawCircleBackground(w); drawCircleBackground(w);
const color = getCircleColor("temperature") || colorGreen;
drawInnerCircleAndTriangle(w); drawInnerCircleAndTriangle(w);
if (temperature) { if (temperature) {
const min = -40; // TODO: find good min, max for temperature const min = -40;
const max = 85; const max = 85;
const percent = (temperature - min) / (max - min); const percent = (temperature - min) / (max - min);
drawGauge(w, h3, percent, colorGreen); drawGauge(w, h3, percent, color);
} }
if (temperature) if (temperature)
writeCircleText(w, locale.temp(temperature)); writeCircleText(w, locale.temp(temperature));
g.drawImage(themperatureIcon, w - iconOffset, h3 + radiusOuter - iconOffset); g.drawImage(getImage(temperatureIcon, color), w - iconOffset, h3 + radiusOuter - iconOffset);
}).catch(() => { }).catch(() => {
setTimeout(() => { setTimeout(() => {
@ -433,24 +460,26 @@ function drawTemperature(w) {
} }
function drawPressure(w) { function drawPressure(w) {
if (!w) w = getCirclePosition("pressure"); if (!w) w = getCircleXPosition("pressure");
getPressureValue("pressure").then((pressure) => { getPressureValue("pressure").then((pressure) => {
drawCircleBackground(w); drawCircleBackground(w);
const color = getCircleColor("pressure") || colorGreen;
drawInnerCircleAndTriangle(w); drawInnerCircleAndTriangle(w);
if (pressure && pressure > 0) { if (pressure && pressure > 0) {
const minPressure = 950; const minPressure = 950;
const maxPressure = 1050; const maxPressure = 1050;
const percent = (pressure - minPressure) / (maxPressure - minPressure); const percent = (pressure - minPressure) / (maxPressure - minPressure);
drawGauge(w, h3, percent, colorGreen); drawGauge(w, h3, percent, color);
} }
if (pressure) if (pressure)
writeCircleText(w, Math.round(pressure)); writeCircleText(w, Math.round(pressure));
g.drawImage(themperatureIcon, w - iconOffset, h3 + radiusOuter - iconOffset); g.drawImage(getImage(temperatureIcon), w - iconOffset, h3 + radiusOuter - iconOffset);
}).catch(() => { }).catch(() => {
setTimeout(() => { setTimeout(() => {
@ -460,24 +489,26 @@ function drawPressure(w) {
} }
function drawAltitude(w) { function drawAltitude(w) {
if (!w) w = getCirclePosition("altitude"); if (!w) w = getCircleXPosition("altitude");
getPressureValue("altitude").then((altitude) => { getPressureValue("altitude").then((altitude) => {
drawCircleBackground(w); drawCircleBackground(w);
const color = getCircleColor("altitude") || colorGreen;
drawInnerCircleAndTriangle(w); drawInnerCircleAndTriangle(w);
if (altitude) { if (altitude) {
const min = 0; const min = 0;
const max = 10000; const max = 10000;
const percent = (altitude - min) / (max - min); const percent = (altitude - min) / (max - min);
drawGauge(w, h3, percent, colorGreen); drawGauge(w, h3, percent, color);
} }
if (altitude) if (altitude)
writeCircleText(w, locale.distance(Math.round(altitude))); writeCircleText(w, locale.distance(Math.round(altitude)));
g.drawImage(themperatureIcon, w - iconOffset, h3 + radiusOuter - iconOffset); g.drawImage(getImage(temperatureIcon, color), w - iconOffset, h3 + radiusOuter - iconOffset);
}).catch(() => { }).catch(() => {
setTimeout(() => { setTimeout(() => {

View File

@ -10,122 +10,151 @@
const valuesCircleTypes = ["steps", "stepsDist", "hr", "battery", "weather", "sunprogress", "empty", "temperature", "pressure", "altitude"]; const valuesCircleTypes = ["steps", "stepsDist", "hr", "battery", "weather", "sunprogress", "empty", "temperature", "pressure", "altitude"];
const namesCircleTypes = ["steps", "distance", "heart", "battery", "weather", "sun progress", "empty", "temperature", "pressure", "altitude"]; const namesCircleTypes = ["steps", "distance", "heart", "battery", "weather", "sun progress", "empty", "temperature", "pressure", "altitude"];
const valuesColors = ["", "#ff0000", "#00ff00", "#0000ff", "#ffff00", "#ff00ff", "#00ffff", "#fff", "#000"];
const namesColors = ["default", "red", "green", "blue", "yellow", "magenta", "cyan", "white", "black"];
const weatherData = ["humidity", "wind", "empty"]; const weatherData = ["humidity", "wind", "empty"];
E.showMenu({ function showMainMenu() {
'': { 'title': 'circlesclock' }, let menu ={
'< Back': back, '': { 'title': 'Circles clock' },
'min heartrate': { /*LANG*/'< Back': back,
value: "minHR" in settings ? settings.minHR : 40, /*LANG*/'circle count': {
min: 0, value: "circleCount" in settings ? settings.circleCount : 3,
max : 250, min: 3,
step: 5, max : 4,
format: x => { step: 1,
return x; onchange: x => save('circleCount', x),
}, },
onchange: x => save('minHR', x), /*LANG*/'circle 1': ()=>showCircleMenu(1),
}, /*LANG*/'circle 2': ()=>showCircleMenu(2),
'max heartrate': { /*LANG*/'circle 3': ()=>showCircleMenu(3),
value: "maxHR" in settings ? settings.maxHR : 200, /*LANG*/'circle 4': ()=>showCircleMenu(4),
min: 20, /*LANG*/'heartrate': ()=>showHRMenu(),
max : 250, /*LANG*/'steps': ()=>showStepMenu(),
step: 5, /*LANG*/'battery warn': {
format: x => { value: "batteryWarn" in settings ? settings.batteryWarn : 30,
return x; min: 10,
max : 100,
step: 10,
format: x => {
return x + '%';
},
onchange: x => save('batteryWarn', x),
}, },
onchange: x => save('maxHR', x), /*LANG*/'show widgets': {
}, value: "showWidgets" in settings ? settings.showWidgets : false,
'hr confidence': { format: () => (settings.showWidgets ? 'Yes' : 'No'),
value: "confidence" in settings ? settings.confidence : 0, onchange: x => save('showWidgets', x),
min: 0,
max : 100,
step: 10,
format: x => {
return x;
}, },
onchange: x => save('confidence', x), /*LANG*/'weather circle': {
}, value: settings.weatherCircleData ? weatherData.indexOf(settings.weatherCircleData) : 0,
'step goal': { min: 0, max: 2,
value: "stepGoal" in settings ? settings.stepGoal : 10000, format: v => weatherData[v],
min: 2000, onchange: x => save('weatherCircleData', weatherData[x]),
max : 50000, }
step: 2000, };
format: x => { E.showMenu(menu);
return x; }
function showHRMenu() {
let menu = {
'': { 'title': /*LANG*/'Heartrate' },
/*LANG*/'< Back': ()=>showMainMenu(),
/*LANG*/'minimum bpm': {
value: "minHR" in settings ? settings.minHR : 40,
min: 0,
max : 250,
step: 5,
format: x => {
return x;
},
onchange: x => save('minHR', x),
}, },
onchange: x => save('stepGoal', x), /*LANG*/'maximum bpm': {
}, value: "maxHR" in settings ? settings.maxHR : 200,
'step length': { min: 20,
value: "stepLength" in settings ? settings.stepLength : 0.8, max : 250,
min: 0.1, step: 5,
max : 1.5, format: x => {
step: 0.01, return x;
format: x => { },
return x; onchange: x => save('maxHR', x),
}, },
onchange: x => save('stepLength', x), /*LANG*/'min. confidence': {
}, value: "confidence" in settings ? settings.confidence : 0,
'step dist goal': { min: 0,
value: "stepDistanceGoal" in settings ? settings.stepDistanceGoal : 8000, max : 100,
min: 2000, step: 10,
max : 30000, format: x => {
step: 1000, return x;
format: x => { },
return x; onchange: x => save('confidence', x),
}, },
onchange: x => save('stepDistanceGoal', x), };
}, E.showMenu(menu);
'battery warn': { }
value: "batteryWarn" in settings ? settings.batteryWarn : 30,
min: 10, function showStepMenu() {
max : 100, let menu = {
step: 10, '': { 'title': /*LANG*/'Steps' },
format: x => { /*LANG*/'< Back': ()=>showMainMenu(),
return x + '%'; /*LANG*/'goal': {
value: "stepGoal" in settings ? settings.stepGoal : 10000,
min: 2000,
max : 50000,
step: 2000,
format: x => {
return x;
},
onchange: x => save('stepGoal', x),
}, },
onchange: x => save('batteryWarn', x), /*LANG*/'distance goal': {
}, value: "stepDistanceGoal" in settings ? settings.stepDistanceGoal : 8000,
'show widgets': { min: 2000,
value: "showWidgets" in settings ? settings.showWidgets : false, max : 30000,
format: () => (settings.showWidgets ? 'Yes' : 'No'), step: 1000,
onchange: x => save('showWidgets', x), format: x => {
}, return x;
'weather circle': { },
value: settings.weatherCircleData ? weatherData.indexOf(settings.weatherCircleData) : 0, onchange: x => save('stepDistanceGoal', x),
min: 0, max: 2, },
format: v => weatherData[v], /*LANG*/'step length': {
onchange: x => save('weatherCircleData', weatherData[x]), value: "stepLength" in settings ? settings.stepLength : 0.8,
}, min: 0.1,
'circle count': { max : 1.5,
value: "circleCount" in settings ? settings.circleCount : 3, step: 0.01,
min: 3, format: x => {
max : 4, return x;
step: 1, },
onchange: x => save('circleCount', x), onchange: x => save('stepLength', x),
}, }
'circle1': { };
value: settings.circle1 ? valuesCircleTypes.indexOf(settings.circle1) : 0, E.showMenu(menu);
min: 0, max: valuesCircleTypes.length, }
format: v => namesCircleTypes[v],
onchange: x => save('circle1', valuesCircleTypes[x]), function showCircleMenu(circleId) {
}, String circleName = "circle" + circleId;
'circle2': { String colorKey = circleName + "color";
value: settings.circle2 ? valuesCircleTypes.indexOf(settings.circle2) : 2, let menu = {
min: 0, max: valuesCircleTypes.length, '': { 'title': /*LANG*/'Circle ' + circleId },
format: v => namesCircleTypes[v], /*LANG*/'< Back': ()=>showMainMenu(),
onchange: x => save('circle2', valuesCircleTypes[x]), /*LANG*/'data': {
}, value: settings[circleName] ? valuesCircleTypes.indexOf(settings[circleName]) : 0,
'circle3': { min: 0, max: valuesCircleTypes.length,
value: settings.circle3 ? valuesCircleTypes.indexOf(settings.circle3) : 3, format: v => namesCircleTypes[v],
min: 0, max: valuesCircleTypes.length, onchange: x => save(circleName, valuesCircleTypes[x]),
format: v => namesCircleTypes[v], },
onchange: x => save('circle3', valuesCircleTypes[x]), /*LANG*/'color': {
}, value: settings[colorKey] ? valuesColors.indexOf(settings[colorKey]) : 0,
'circle4': { min: 0, max: valuesColors.length,
value: settings.circle4 ? valuesCircleTypes.indexOf(settings.circle4) : 4, format: v => namesColors[v],
min: 0, max: valuesCircleTypes.length, onchange: x => save(colorKey, valuesColors[x]),
format: v => namesCircleTypes[v], },
onchange: x => save('circle4', valuesCircleTypes[x]), };
} E.showMenu(menu);
}); }
showMainMenu();
}); });