Merge pull request #1237 from myxor/circlesclock_v0.04

Circlesclock v0.04
pull/1260/head
Gordon Williams 2022-01-10 08:48:43 +00:00 committed by GitHub
commit 84b7dd2595
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 381 additions and 116 deletions

View File

@ -5081,10 +5081,10 @@
{ "id": "circlesclock", { "id": "circlesclock",
"name": "Circles clock", "name": "Circles clock",
"shortName":"Circles clock", "shortName":"Circles clock",
"version":"0.03", "version":"0.04",
"description": "A clock with circles for different data at the bottom in a probably familiar style", "description": "A clock with circles for different data at the bottom in a probably familiar style",
"icon": "app.png", "icon": "app.png",
"screenshots": [{"url":"screenshot.png"}], "screenshots": [{"url":"screenshot-dark.png"}, {"url":"screenshot-light.png"}],
"dependencies": {"widpedom":"app"}, "dependencies": {"widpedom":"app"},
"type": "clock", "type": "clock",
"tags": "clock", "tags": "clock",

View File

@ -1,3 +1,7 @@
0.01: New clock 0.01: New clock
0.02: Fix icon & add battery warn functionality 0.02: Fix icon & add battery warn functionality
0.03: Theming support & minor fixes 0.03: Theming support & minor fixes
0.04: Make configurable what to show in each circle
Add step distance and weather
Allow switching visibility of widgets
Make circles and text slightly bigger

View File

@ -2,19 +2,22 @@
A clock with circles for different data at the bottom in a probably familiar style A clock with circles for different data at the bottom in a probably familiar style
It shows besides time, date and day of week the following information: By default the time, date and day of week is shown.
It can show the following information (this can be configured):
* Steps (requires [pedometer widget](https://banglejs.com/apps/#pedometer)) * Steps (requires [pedometer widget](https://banglejs.com/apps/#pedometer))
* Heart rate (when screen is on and unlocked) * Steps distance (depending on steps)
* Battery (including charging and battery low) * Heart rate (automatically updates when screen is on and unlocked)
* Battery (including charging status and battery low warning)
* Weather (requires [weather app](https://banglejs.com/apps/#weather))
## Screenshot ## Screenshots
![Screenshot dark theme](screenshot-dark.png)
![Screenshot light theme](screenshot-light.png)
![Screenshot](screenshot.png) # TODO
* Add sunrise and sunset
## TODO * Display moon instead of sun during night on weather circle
* Show weather information
* Configure which information to show in each circle
* Configure visibility of widgets
## Creator ## Creator
Marco ([myxor](https://github.com/myxor)) Marco ([myxor](https://github.com/myxor))

View File

@ -1,19 +1,37 @@
const locale = require("locale"); const locale = require("locale");
const heatshrink = require("heatshrink"); const heatshrink = require("heatshrink");
const storage = require("Storage");
const shoesIcon = heatshrink.decompress(atob("h0OwYJGgmAAgUBkgECgVJB4cSoAUDyEBkARDpADBhMAyQRBgVAkgmDhIUDAAuQAgY1DAAYA=")); const shoesIcon = heatshrink.decompress(atob("h0OwYJGgmAAgUBkgECgVJB4cSoAUDyEBkARDpADBhMAyQRBgVAkgmDhIUDAAuQAgY1DAAYA="));
const shoesIconGreen = heatshrink.decompress(atob("h0OwYJGhIEDgVIAgUEyQKDkmACgcggVACIeQAYMSgIRCgmApIbDiQUDAAkBkAFDGoYAD"));
const heartIcon = heatshrink.decompress(atob("h0OwYOLkmQhMkgACByVJgESpIFBpEEBAIFBCgIFCCgsABwcAgQOCAAMSpAwDyBNM")); const heartIcon = heatshrink.decompress(atob("h0OwYOLkmQhMkgACByVJgESpIFBpEEBAIFBCgIFCCgsABwcAgQOCAAMSpAwDyBNM"));
const powerIcon = heatshrink.decompress(atob("h0OwYQNsAED7AEDmwEDtu2AgUbtuABwXbBIUN23AAoYOCgEDFIgODABI")); const powerIcon = heatshrink.decompress(atob("h0OwYQNsAED7AEDmwEDtu2AgUbtuABwXbBIUN23AAoYOCgEDFIgODABI"));
const powerIconGreen = heatshrink.decompress(atob("h0OwYQNkAEDpAEDiQEDkmSAgUJkmABwVJBIUEyVAAoYOCgEBFIgODABI")); const powerIconGreen = heatshrink.decompress(atob("h0OwYQNkAEDpAEDiQEDkmSAgUJkmABwVJBIUEyVAAoYOCgEBFIgODABI"));
const powerIconRed = heatshrink.decompress(atob("h0OwYQNoAEDyAEDkgEDpIFDiVJBweSAgUJkmAAoYZDgQpEBwYAJA")); const powerIconRed = heatshrink.decompress(atob("h0OwYQNoAEDyAEDkgEDpIFDiVJBweSAgUJkmAAoYZDgQpEBwYAJA"));
const weatherCloudy = heatshrink.decompress(atob("iEQwYWTgP//+AAoMPAoPwAoN/AocfAgP//0AAgQAB/AFEABgdDAAMDDohMRA"));
const weatherSunny = heatshrink.decompress(atob("iEQwYLIg3AAgVgAQMMAo8Am3YAgUB23bAoUNAoIUBjYFCsOwBYoFDDpFgHYI1JI4gFGAAYA="));
const weatherPartlyCloudy = heatshrink.decompress(atob("iEQwYQNv0AjgGDn4EDh///gFChwREC4MfxwIBv0//+AC4X4j4FCv/AgfwgED/wIBuAaBBwgFDgP4gf/AAXABwIEBDQQAEA=="));
const weatherRainy = heatshrink.decompress(atob("iEQwYLIg/gAgUB///wAFBh/AgfwgED/wIBuEAj4OCv0AjgaCh/4AocAnAFBFIU4EAM//gRBEAIOBhw1C/AmDAosAC4JNIAAg"));
const weatherPartlyRainy = heatshrink.decompress(atob("h0OwYJGjkAnAFCj+AAgU//4FCuEA8EAg8ch/4gEB4////AAoIIBCIMD/wgCg4bBg/8BwMD+AgBh4ZBDQf/FIIABh4IBgAA=="));
const weatherSnowy = heatshrink.decompress(atob("iEQwYROn/8AocH8AECuAFBh0Agf+CIN/4EDx/4j/x4EAgIIBwAXBAogRFDoopFGoxBGABIA="));
const weatherFoggy = heatshrink.decompress(atob("iEQwYROn/8AgUB/EfwAFBh/AgfwgED/wIBuEABwd/4EcDQgFDgE4Fosf///8f//A/Lj/xCQIRNA="));
const weatherStormy = heatshrink.decompress(atob("iEQwYLIg/gAgUB///wAFBh/AgfwgED/wIBuEAj4OCv0AjgaCh/4AoX8gE4AoQpBnAdBF4IRBDQMH/kOHgY7DAo4AOA=="));
let settings; let settings;
function loadSettings() { function loadSettings() {
settings = require("Storage").readJSON("circlesclock.json", 1) || { settings = storage.readJSON("circlesclock.json", 1) || {
'minHR': 40,
'maxHR': 200, 'maxHR': 200,
'stepGoal': 10000, 'stepGoal': 10000,
'batteryWarn': 30 'stepDistanceGoal': 8000,
'stepLength': 0.8,
'batteryWarn': 30,
'showWidgets': false,
'circle1': 'hr',
'circle2': 'steps',
'circle3': 'battery'
}; };
// Load step goal from pedometer widget as fallback // Load step goal from pedometer widget as fallback
if (settings.stepGoal == undefined) { if (settings.stepGoal == undefined) {
@ -21,122 +39,227 @@ function loadSettings() {
settings.stepGoal = d != undefined && d.settings != undefined ? d.settings.goal : 10000; settings.stepGoal = d != undefined && d.settings != undefined ? d.settings.goal : 10000;
} }
} }
loadSettings();
const showWidgets = settings.showWidgets || false;
let hrtValue;
// layout values:
const colorFg = g.theme.dark ? '#fff' : '#000'; const colorFg = g.theme.dark ? '#fff' : '#000';
const colorBg = g.theme.dark ? '#000' : '#fff'; const colorBg = g.theme.dark ? '#000' : '#fff';
const colorGrey = '#808080'; const colorGrey = '#808080';
const colorRed = '#ff0000'; const colorRed = '#ff0000';
const colorGreen = '#00ff00'; const colorGreen = '#008000';
const colorBlue = '#0000ff';
let hrtValue; const colorYellow = '#ffff00';
const widgetOffset = showWidgets ? 24 : 0;
const h = g.getHeight(); const h = g.getHeight() - widgetOffset;
const w = g.getWidth(); const w = g.getWidth();
const hOffset = 30; const hOffset = 30 - widgetOffset;
const h1 = Math.round(1 * h / 5 - hOffset); const h1 = Math.round(1 * h / 5 - hOffset);
const h2 = Math.round(3 * h / 5 - hOffset); const h2 = Math.round(3 * h / 5 - hOffset);
const h3 = Math.round(8 * h / 8 - hOffset); const h3 = Math.round(8 * h / 8 - hOffset - 3); // circle y position
const w1 = Math.round(w / 6); const circlePosX = [Math.round(w / 6), Math.round(3 * w / 6), Math.round(5 * w / 6)]; // cirle x positions
const w2 = Math.round(3 * w / 6); const radiusOuter = 25;
const w3 = Math.round(5 * w / 6); const radiusInner = 20;
const radiusOuter = 22; const circleFont = "Vector:15";
const radiusInner = 16; const circleFontBig = "Vector:16";
const circleFontSmall = "Vector:13";
function draw() { function draw() {
g.reset(); g.clear(true);
if (!showWidgets) {
/*
* we are not drawing the widgets as we are taking over the whole screen
* so we will blank out the draw() functions of each widget and change the
* area to the top bar doesn't get cleared.
*/
if (WIDGETS && typeof WIDGETS === "object") {
for (let wd of WIDGETS) {
wd.draw = () => {};
wd.area = "";
}
}
} else {
Bangle.drawWidgets();
}
g.setColor(colorBg); g.setColor(colorBg);
g.fillRect(0, 0, w, h); g.fillRect(0, widgetOffset, w, h);
// time // time
g.setFont("Vector:50"); g.setFont("Vector:50");
g.setFontAlign(-1, -1); g.setFontAlign(0, -1);
g.setColor(colorFg); g.setColor(colorFg);
g.drawString(locale.time(new Date(), 1), w / 10, h1 + 8); g.drawString(locale.time(new Date(), 1), w / 2, h1 + 8);
// date & dow // date & dow
g.setFont("Vector:20"); g.setFont("Vector:21");
g.setFontAlign(-1, 0); g.setFontAlign(-1, 0);
g.drawString(locale.date(new Date()), w / 10, h2); g.drawString(locale.date(new Date()), w > 180 ? 2 * w / 10 : w / 10, h2);
g.drawString(locale.dow(new Date()), w / 10, h2 + 22); g.drawString(locale.dow(new Date()), w > 180 ? 2 * w / 10 : w / 10, h2 + 22);
// Steps circle drawCircle(1);
drawSteps(); drawCircle(2);
drawCircle(3);
// Heart circle
drawHeartRate();
// Battery circle
drawBattery();
} }
const defaultCircleTypes = ["steps", "hr", "battery"];
function drawCircle(index) {
let type = settings['circle' + index];
if (!type) type = defaultCircleTypes[index - 1];
const w = getCirclePosition(type);
switch (type) {
case "steps":
drawSteps(w);
break;
case "stepsDist":
drawStepsDistance(w);
break;
case "hr":
drawHeartRate(w);
break;
case "battery":
drawBattery(w);
break;
case "weather":
drawWeather(w);
break;
}
}
function drawSteps() { function getCirclePosition(type) {
for (let i = 1; i <= 3; i++) {
const setting = settings['circle' + i];
if (setting == type) return circlePosX[i - 1];
}
for (let i = 0; i < defaultCircleTypes.length; i++) {
if (type == defaultCircleTypes[i]) return circlePosX[i];
}
return undefined;
}
function isCircleEnabled(type) {
return getCirclePosition(type) != undefined;
}
function drawSteps(w) {
if (!w) w = getCirclePosition("steps");
const steps = getSteps(); const steps = getSteps();
const blue = '#0000ff';
// Draw rectangle background:
g.setColor(colorBg);
g.fillRect(w - radiusOuter - 3, h3 - radiusOuter - 3, w + radiusOuter + 3, h3 + radiusOuter + 3);
g.setColor(colorGrey); g.setColor(colorGrey);
g.fillCircle(w1, h3, radiusOuter); g.fillCircle(w, h3, radiusOuter);
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(w1, h3, percent, blue); drawGauge(w, h3, percent, colorBlue);
} }
g.setColor(colorBg); g.setColor(colorBg);
g.fillCircle(w1, h3, radiusInner); g.fillCircle(w, h3, radiusInner);
g.fillPoly([w1, h3, w1 - 15, h3 + radiusOuter + 5, w1 + 15, h3 + radiusOuter + 5]); g.fillPoly([w, h3, w - 15, h3 + radiusOuter + 5, w + 15, h3 + radiusOuter + 5]);
g.setFont("Vector:12"); g.setFont(circleFont);
g.setFontAlign(0, 0); g.setFontAlign(0, 0);
g.setColor(colorFg); g.setColor(colorFg);
g.drawString(shortValue(steps), w1 + 2, h3); g.drawString(shortValue(steps), w + 2, h3);
g.drawImage(shoesIcon, w1 - 6, h3 + radiusOuter - 6); g.drawImage(shoesIcon, w - 6, h3 + radiusOuter - 6);
} }
function drawHeartRate() { function drawStepsDistance(w) {
if (!w) w = getCirclePosition("steps");
const steps = getSteps();
const stepDistance = settings.stepLength || 0.8;
const stepsDistance = Math.round(steps * stepDistance);
// Draw rectangle background:
g.setColor(colorBg);
g.fillRect(w - radiusOuter - 3, h3 - radiusOuter - 3, w + radiusOuter + 3, h3 + radiusOuter + 3);
g.setColor(colorGrey); g.setColor(colorGrey);
g.fillCircle(w2, h3, radiusOuter); g.fillCircle(w, h3, radiusOuter);
const stepDistanceGoal = settings.stepDistanceGoal || 8000;
if (stepDistanceGoal > 0) {
let percent = stepsDistance / stepDistanceGoal;
if (stepDistanceGoal < stepsDistance) percent = 1;
drawGauge(w, h3, percent, colorGreen);
}
g.setColor(colorBg);
g.fillCircle(w, h3, radiusInner);
g.fillPoly([w, h3, w - 15, h3 + radiusOuter + 5, w + 15, h3 + radiusOuter + 5]);
g.setFont(circleFont);
g.setFontAlign(0, 0);
g.setColor(colorFg);
g.drawString(shortValue(stepsDistance), w + 2, h3);
g.drawImage(shoesIconGreen, w - 6, h3 + radiusOuter - 6);
}
function drawHeartRate(w) {
if (!w) w = getCirclePosition("hr");
// Draw rectangle background:
g.setColor(colorBg);
g.fillRect(w - radiusOuter - 3, h3 - radiusOuter - 3, w + radiusOuter + 3, h3 + radiusOuter + 3);
g.setColor(colorGrey);
g.fillCircle(w, h3, radiusOuter);
if (hrtValue != undefined && hrtValue > 0) { if (hrtValue != undefined && hrtValue > 0) {
const minHR = 40; const minHR = settings.minHR || 40;
const percent = (hrtValue - minHR) / (settings.maxHR - minHR); const percent = (hrtValue - minHR) / (settings.maxHR - minHR);
drawGauge(w2, h3, percent, colorRed); drawGauge(w, h3, percent, colorRed);
} }
g.setColor(colorBg); g.setColor(colorBg);
g.fillCircle(w2, h3, radiusInner); g.fillCircle(w, h3, radiusInner);
g.fillPoly([w2, h3, w2 - 15, h3 + radiusOuter + 5, w2 + 15, h3 + radiusOuter + 5]); g.fillPoly([w, h3, w - 15, h3 + radiusOuter + 5, w + 15, h3 + radiusOuter + 5]);
g.setFont("Vector:12"); g.setFont(circleFontBig);
g.setFontAlign(0, 0); g.setFontAlign(0, 0);
g.setColor(colorFg); g.setColor(colorFg);
g.drawString(hrtValue != undefined ? hrtValue : "-", w2, h3); g.drawString(hrtValue != undefined ? hrtValue : "-", w, h3);
g.drawImage(heartIcon, w2 - 6, h3 + radiusOuter - 6); g.drawImage(heartIcon, w - 6, h3 + radiusOuter - 6);
} }
function drawBattery() { function drawBattery(w) {
if (!w) w = getCirclePosition("battery");
const battery = E.getBattery(); const battery = E.getBattery();
const yellow = '#ffff00';
// Draw rectangle background:
g.setColor(colorBg);
g.fillRect(w - radiusOuter - 3, h3 - radiusOuter - 3, w + radiusOuter + 3, h3 + radiusOuter + 3);
g.setColor(colorGrey); g.setColor(colorGrey);
g.fillCircle(w3, h3, radiusOuter); g.fillCircle(w, h3, radiusOuter);
if (battery > 0) { if (battery > 0) {
const percent = battery / 100; const percent = battery / 100;
drawGauge(w3, h3, percent, yellow); drawGauge(w, h3, percent, colorYellow);
} }
g.setColor(colorBg); g.setColor(colorBg);
g.fillCircle(w3, h3, radiusInner); g.fillCircle(w, h3, radiusInner);
g.fillPoly([w3, h3, w3 - 15, h3 + radiusOuter + 5, w3 + 15, h3 + radiusOuter + 5]); g.fillPoly([w, h3, w - 15, h3 + radiusOuter + 5, w + 15, h3 + radiusOuter + 5]);
g.setFont("Vector:12"); g.setFont(circleFont);
g.setFontAlign(0, 0); g.setFontAlign(0, 0);
let icon = powerIcon; let icon = powerIcon;
@ -144,17 +267,95 @@ function drawBattery() {
if (Bangle.isCharging()) { if (Bangle.isCharging()) {
color = colorGreen; color = colorGreen;
icon = powerIconGreen; icon = powerIconGreen;
} } else {
else {
if (settings.batteryWarn != undefined && battery <= settings.batteryWarn) { if (settings.batteryWarn != undefined && battery <= settings.batteryWarn) {
color = colorRed; color = colorRed;
icon = powerIconRed; icon = powerIconRed;
} }
} }
g.setColor(color); g.setColor(color);
g.drawString(battery + '%', w3, h3); g.drawString(battery + '%', w, h3);
g.drawImage(icon, w3 - 6, h3 + radiusOuter - 6); g.drawImage(icon, w - 6, h3 + radiusOuter - 6);
}
function drawWeather(w) {
if (!w) w = getCirclePosition("weather");
const weather = getWeather();
const tempString = weather ? locale.temp(weather.temp - 273.15) : undefined;
const code = weather ? weather.code : -1;
// Draw rectangle background:
g.setColor(colorBg);
g.fillRect(w - radiusOuter - 3, h3 - radiusOuter - 3, w + radiusOuter + 3, h3 + radiusOuter + 3);
g.setColor(colorGrey);
g.fillCircle(w, h3, radiusOuter);
g.setColor(colorBg);
g.fillCircle(w, h3, radiusInner);
g.fillPoly([w, h3, w - 25, h3 + radiusOuter + 5, w + 25, h3 + radiusOuter + 5]);
const content = tempString ? tempString : "?";
g.setFont(content.length < 4 ? circleFont : circleFontSmall);
g.setFontAlign(0, 0);
g.setColor(colorFg);
g.drawString(content, w, h3);
if (code > 0) {
const icon = getWeatherIconByCode(code);
if (icon) g.drawImage(icon, w - 6, h3 + radiusOuter - 10);
}
}
/*
* Choose weather icon to display based on weather conditition code
* https://openweathermap.org/weather-conditions#Weather-Condition-Codes-2
*/
function getWeatherIconByCode(code) {
const codeGroup = Math.round(code / 100);
switch (codeGroup) {
case 2:
return weatherStormy;
case 3:
return weatherCloudy;
case 5:
switch (code) {
case 511:
return weatherSnowy;
case 520:
return weatherPartlyRainy;
case 521:
return weatherPartlyRainy;
case 522:
return weatherPartlyRainy;
case 531:
return weatherPartlyRainy;
default:
return weatherRainy;
}
break;
case 6:
return weatherSnowy;
case 7:
return weatherFoggy;
case 8:
switch (code) {
case 800:
return weatherSunny;
case 801:
return weatherPartlyCloudy;
case 802:
return weatherPartlyCloudy;
default:
return weatherCloudy;
}
break;
default:
return undefined;
}
return undefined;
} }
function radians(a) { function radians(a) {
@ -171,11 +372,11 @@ function drawGauge(cx, cy, percent, color) {
if (percent > 1) percent = 1; if (percent > 1) percent = 1;
var startrot = -offset; var startrot = -offset;
var endrot = startrot - ((end - offset) * percent) - 15; var endrot = startrot - ((end - offset) * percent) - 35;
g.setColor(color); g.setColor(color);
const size = 4; const size = radiusOuter - radiusInner - 2;
// draw gauge // draw gauge
for (i = startrot; i > endrot - size; i -= size) { for (i = startrot; i > endrot - size; i -= size) {
x = cx + r * Math.sin(radians(i)); x = cx + r * Math.sin(radians(i));
@ -198,54 +399,56 @@ function shortValue(v) {
} }
function getSteps() { function getSteps() {
if (WIDGETS.wpedom !== undefined) { if (WIDGETS && WIDGETS.wpedom !== undefined) {
return WIDGETS.wpedom.getSteps(); return WIDGETS.wpedom.getSteps();
} }
return 0; return 0;
} }
Bangle.on('lock', function(isLocked) { function getWeather() {
if (!isLocked) { const jsonWeather = storage.readJSON('weather.json');
Bangle.setHRMPower(1, "watch"); return jsonWeather && jsonWeather.weather ? jsonWeather.weather : undefined;
}
function enableHRMSensor() {
Bangle.setHRMPower(1, "circleclock");
if (hrtValue == undefined) { if (hrtValue == undefined) {
hrtValue = '...'; hrtValue = '...';
drawHeartRate(); drawHeartRate();
} }
} else {
Bangle.setHRMPower(0, "watch");
} }
drawHeartRate();
drawSteps(); Bangle.on('lock', function(isLocked) {
if (!isLocked) {
if (isCircleEnabled("hr")) {
enableHRMSensor();
}
draw();
} else {
Bangle.setHRMPower(0, "circleclock");
}
}); });
Bangle.on('HRM', function(hrm) { Bangle.on('HRM', function(hrm) {
//if(hrm.confidence > 90){ if (isCircleEnabled("hr")) {
hrtValue = hrm.bpm; hrtValue = hrm.bpm;
if (Bangle.isLCDOn()) if (Bangle.isLCDOn())
drawHeartRate(); drawHeartRate();
//} else { }
// hrtValue = undefined;
//}
}); });
Bangle.setUI("clock");
Bangle.loadWidgets();
draw();
setInterval(draw, 60000);
Bangle.on('charging', function(charging) { Bangle.on('charging', function(charging) {
drawBattery(); if (isCircleEnabled("battery")) drawBattery();
}); });
g.clear(); if (isCircleEnabled("hr")) {
Bangle.loadWidgets(); enableHRMSensor();
/*
* we are not drawing the widgets as we are taking over the whole screen
* so we will blank out the draw() functions of each widget and change the
* area to the top bar doesn't get cleared.
*/
if (typeof WIDGETS === "object") {
for (let wd of WIDGETS) {
wd.draw = () => {};
wd.area = "";
} }
}
loadSettings();
setInterval(draw, 60000);
draw();
Bangle.setUI("clock");

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

View File

@ -6,13 +6,26 @@
settings[key] = value; settings[key] = value;
storage.write(SETTINGS_FILE, settings); storage.write(SETTINGS_FILE, settings);
} }
var valuesCircleTypes = ["steps", "stepsDist", "hr", "battery", "weather"];
var namesCircleTypes = ["steps", "distance", "heart", "battery", "weather"];
E.showMenu({ E.showMenu({
'': { 'title': 'circlesclock' }, '': { 'title': 'circlesclock' },
'< Back': back,
'min heartrate': {
value: "minHR" in settings ? settings.minHR : 40,
min: 0,
max : 250,
step: 5,
format: x => {
return x;
},
onchange: x => save('minHR', x),
},
'max heartrate': { 'max heartrate': {
value: "maxHR" in settings ? settings.maxHR : 200, value: "maxHR" in settings ? settings.maxHR : 200,
min: 20, min: 20,
max : 250, max : 250,
step: 10, step: 5,
format: x => { format: x => {
return x; return x;
}, },
@ -28,7 +41,27 @@
}, },
onchange: x => save('stepGoal', x), onchange: x => save('stepGoal', x),
}, },
'battery warn lvl': { 'step length': {
value: "stepLength" in settings ? settings.stepLength : 0.8,
min: 0.1,
max : 1.5,
step: 0.01,
format: x => {
return x;
},
onchange: x => save('stepLength', x),
},
'step dist goal': {
value: "stepDistanceGoal" in settings ? settings.stepDistanceGoal : 8000,
min: 2000,
max : 30000,
step: 1000,
format: x => {
return x;
},
onchange: x => save('stepDistanceGoal', x),
},
'battery warn': {
value: "batteryWarn" in settings ? settings.batteryWarn : 30, value: "batteryWarn" in settings ? settings.batteryWarn : 30,
min: 10, min: 10,
max : 100, max : 100,
@ -38,6 +71,28 @@
}, },
onchange: x => save('batteryWarn', x), onchange: x => save('batteryWarn', x),
}, },
'< Back': back, 'show widgets': {
value: "showWidgets" in settings ? settings.showWidgets : false,
format: () => (settings.showWidgets ? 'Yes' : 'No'),
onchange: x => save('showWidgets', x),
},
'left': {
value: settings.circle1 ? valuesCircleTypes.indexOf(settings.circle1) : 0,
min: 0, max: 4,
format: v => namesCircleTypes[v],
onchange: x => save('circle1', valuesCircleTypes[x]),
},
'middle': {
value: settings.circle2 ? valuesCircleTypes.indexOf(settings.circle2) : 2,
min: 0, max: 4,
format: v => namesCircleTypes[v],
onchange: x => save('circle2', valuesCircleTypes[x]),
},
'right': {
value: settings.circle3 ? valuesCircleTypes.indexOf(settings.circle3) : 3,
min: 0, max: 4,
format: v => namesCircleTypes[v],
onchange: x => save('circle3', valuesCircleTypes[x]),
}
}); });
}); });