Merge branch 'master' of github.com:espruino/BangleApps

master
Gordon Williams 2022-04-21 10:27:51 +01:00
commit 17eb42403e
42 changed files with 490 additions and 174 deletions

View File

@ -18,3 +18,4 @@
0.17: Moving alarm internals to 'sched' library
0.18: Cope with >1 identical alarm at once (#1667)
0.19: Ensure rescheduled alarms that already fired have 'last' reset
0.20: Use the new 'sched' factories to initialize new alarms/timers

View File

@ -1,28 +1,28 @@
Bangle.loadWidgets();
Bangle.drawWidgets();
var alarms = require("sched").getAlarms();
// An array of alarm objects (see sched/README.md)
let alarms = require("sched").getAlarms();
// time in ms -> { hrs, mins }
function decodeTime(t) {
t = 0|t; // sanitise
var hrs = 0|(t/3600000);
return { hrs : hrs, mins : Math.round((t-hrs*3600000)/60000) };
t = 0 | t; // sanitise
let hrs = 0 | (t / 3600000);
return { hrs: hrs, mins: Math.round((t - hrs * 3600000) / 60000) };
}
// time in { hrs, mins } -> ms
function encodeTime(o) {
return o.hrs*3600000 + o.mins*60000;
return o.hrs * 3600000 + o.mins * 60000;
}
function formatTime(t) {
var o = decodeTime(t);
return o.hrs+":"+("0"+o.mins).substr(-2);
let o = decodeTime(t);
return o.hrs + ":" + ("0" + o.mins).substr(-2);
}
function getCurrentTime() {
var time = new Date();
let time = new Date();
return (
time.getHours() * 3600000 +
time.getMinutes() * 60000 +
@ -39,7 +39,7 @@ function showMainMenu() {
// Timer img "\0"+atob("DhKBAP////MDDAwwMGGBzgPwB4AeAPwHOBhgwMMzDez////w")
// Alarm img "\0"+atob("FBSBAABgA4YcMPDGP8Zn/mx/48//PP/zD/8A//AP/wD/8A//AP/wH/+D//w//8AAAADwAAYA")
const menu = {
'': { 'title': 'Alarm/Timer' },
'': { 'title': /*LANG*/'Alarms&Timers' },
/*LANG*/'< Back' : ()=>{load();},
/*LANG*/'New Alarm': ()=>editAlarm(-1),
/*LANG*/'New Timer': ()=>editTimer(-1)
@ -76,13 +76,13 @@ function showMainMenu() {
function editDOW(dow, onchange) {
const menu = {
'': { 'title': /*LANG*/'Days of Week' },
'< Back' : () => onchange(dow)
/*LANG*/'< Back' : () => onchange(dow)
};
for (var i = 0; i < 7; i++) (i => {
var dayOfWeek = require("locale").dow({ getDay: () => i });
for (let i = 0; i < 7; i++) (i => {
let dayOfWeek = require("locale").dow({ getDay: () => i });
menu[dayOfWeek] = {
value: !!(dow&(1<<i)),
format: v => v ? "Yes" : "No",
format: v => v ? /*LANG*/"Yes" : /*LANG*/"No",
onchange: v => v ? dow |= 1<<i : dow &= ~(1<<i),
};
})(i);
@ -90,23 +90,15 @@ function editDOW(dow, onchange) {
}
function editAlarm(alarmIndex, alarm) {
var newAlarm = alarmIndex<0;
var a = {
t : 12*3600000, // 12 o clock default
on : true,
rp : false, // repeat not the default
as : false,
dow : 0b1111111,
last : 0,
vibrate : ".."
}
let newAlarm = alarmIndex < 0;
let a = require("sched").newDefaultAlarm();
if (!newAlarm) Object.assign(a, alarms[alarmIndex]);
if (alarm) Object.assign(a,alarm);
var t = decodeTime(a.t);
let t = decodeTime(a.t);
const menu = {
'': { 'title': /*LANG*/'Alarm' },
'< Back' : () => showMainMenu(),
/*LANG*/'< Back' : () => showMainMenu(),
/*LANG*/'Hours': {
value: t.hrs, min : 0, max : 23, wrap : true,
onchange: v => t.hrs=v
@ -117,23 +109,23 @@ function editAlarm(alarmIndex, alarm) {
},
/*LANG*/'Enabled': {
value: a.on,
format: v=>v?"On":"Off",
format: v => v ? /*LANG*/"On" : /*LANG*/"Off",
onchange: v=>a.on=v
},
/*LANG*/'Repeat': {
value: a.rp,
format: v=>v?"Yes":"No",
onchange: v=>a.rp=v
format: v => v ? /*LANG*/"Yes" : /*LANG*/"No",
onchange: v => a.rp = v
},
/*LANG*/'Days': {
value: "SMTWTFS".split("").map((d,n)=>a.dow&(1<<n)?d:".").join(""),
onchange: () => editDOW(a.dow, d=>{a.dow=d;editAlarm(alarmIndex,a)})
},
/*LANG*/'Vibrate': require("buzz_menu").pattern(a.vibrate, v => a.vibrate=v ),
/*LANG*/'Auto snooze': {
/*LANG*/'Auto Snooze': {
value: a.as,
format: v=>v?"Yes":"No",
onchange: v=>a.as=v
format: v => v ? /*LANG*/"Yes" : /*LANG*/"No",
onchange: v => a.as = v
}
};
menu[/*LANG*/"Save"] = function() {
@ -155,23 +147,15 @@ function editAlarm(alarmIndex, alarm) {
}
function editTimer(alarmIndex, alarm) {
var newAlarm = alarmIndex<0;
var a = {
timer : 5*60*1000, // 5 minutes
on : true,
rp : false,
as : false,
dow : 0b1111111,
last : 0,
vibrate : ".."
}
let newAlarm = alarmIndex < 0;
let a = require("sched").newDefaultTimer();
if (!newAlarm) Object.assign(a, alarms[alarmIndex]);
if (alarm) Object.assign(a,alarm);
var t = decodeTime(a.timer);
let t = decodeTime(a.timer);
const menu = {
'': { 'title': /*LANG*/'Timer' },
'< Back' : () => showMainMenu(),
/*LANG*/'< Back' : () => showMainMenu(),
/*LANG*/'Hours': {
value: t.hrs, min : 0, max : 23, wrap : true,
onchange: v => t.hrs=v
@ -182,8 +166,8 @@ function editTimer(alarmIndex, alarm) {
},
/*LANG*/'Enabled': {
value: a.on,
format: v=>v?"On":"Off",
onchange: v=>a.on=v
format: v => v ? /*LANG*/"On" : /*LANG*/"Off",
onchange: v => a.on = v
},
/*LANG*/'Vibrate': require("buzz_menu").pattern(a.vibrate, v => a.vibrate=v ),
};

View File

@ -1,8 +1,8 @@
{
"id": "alarm",
"name": "Alarm & Timer",
"name": "Alarms & Timers",
"shortName": "Alarms",
"version": "0.19",
"version": "0.20",
"description": "Set alarms and timers on your Bangle",
"icon": "app.png",
"tags": "tool,alarm,widget",

View File

@ -1,2 +1,3 @@
0.01: New App!
0.02: Support Bangle.js 2
0.03: Fix bug for Bangle.js 2 where g.flip was not being called.

View File

@ -1,6 +1,3 @@
//g.setTheme({fg : 0xFFFF, fg2 : 0xFFFF,bg2 : 0x0007,fgH : 0xFFFF,bgH : 0x02F7,dark : true});
/* Choozi - Choose people or things at random using Bangle.js.
* Inspired by the "Chwazi" Android app
*
@ -77,7 +74,7 @@ function arc(minR, maxR, minAngle, maxAngle) {
inside.push(centreY+s*minR);
outside.unshift(centreY+s*maxR);
outside.unshift(centreX+c*maxR);
var vertices = inside.concat(outside);
g.fillPoly(vertices, true);
}
@ -133,6 +130,7 @@ function animateChoice(target) {
g.fillCircle(x, y, ballSize);
oldx=x;
oldy=y;
g.flip();
}
}
@ -154,7 +152,7 @@ function choose() {
// draw the current value of N in the middle of the screen, with
// up/down arrows
function drawN() {
g.setColor('#000000');
g.setColor(g.theme.fg);
g.setFont("Vector",fontSize);
g.drawString(N,centreX-g.stringWidth(N)/2+4,centreY-fontSize/2);
if (N < maxN)

View File

@ -1,7 +1,7 @@
{
"id": "choozi",
"name": "Choozi",
"version": "0.02",
"version": "0.03",
"description": "Choose people or things at random using Bangle.js.",
"icon": "app.png",
"tags": "tool",

View File

@ -10,3 +10,4 @@
0.09: Fix file naming so months are 1-based (not 0) (fix #1119)
0.10: Adds additional 3 minute setting for HRM
0.11: Pre-minified boot&lib - folds constants and saves RAM
0.12: Add setting for Daily Step Goal

View File

@ -24,6 +24,7 @@ Stores:
* **Off** - Don't turn HRM on, but record heart rate if the HRM was turned on by another app/widget
* **10 Min** - Turn HRM on every 10 minutes (for each heath entry) and turn it off after 2 minutes, or when a good reading is found
* **Always** - Keep HRM on all the time (more accurate recording, but reduces battery life to ~36 hours)
* **Daily Step Goal** - Default 10000, daily step goal for pedometer apps to use
## Technical Info

View File

@ -2,8 +2,8 @@ function getSettings() {
return require("Storage").readJSON("health.json",1)||{};
}
function setSettings(s) {
require("Storage").writeJSON("health.json",s);
function setSettings(healthSettings) {
require("Storage").writeJSON("health.json",healthSettings);
}
function menuMain() {
@ -22,15 +22,21 @@ function menuMain() {
function menuSettings() {
swipe_enabled = false;
clearButton();
var s=getSettings();
var healthSettings=getSettings();
//print(healthSettings);
E.showMenu({
"":{title:"Health Tracking"},
"< Back":()=>menuMain(),
"Heart Rt":{
value : 0|s.hrm,
value : 0|healthSettings.hrm,
min : 0, max : 3,
format : v=>["Off","3 mins","10 mins","Always"][v],
onchange : v => { s.hrm=v;setSettings(s); }
onchange : v => { healthSettings.hrm=v;setSettings(healthSettings); }
},
"Daily Step Goal":{
value : (healthSettings.stepGoal ? healthSettings.stepGoal : 10000),
min : 0, max : 20000, step : 100,
onchange : v => { healthSettings.stepGoal=v;setSettings(healthSettings); }
}
});
}
@ -199,7 +205,7 @@ function drawBarChart() {
for (bar = 1; bar < 10; bar++) {
if (bar == 5) {
g.setFont('6x8', 2);
g.setFontAlign(0,-1)
g.setFontAlign(0,-1);
g.setColor(g.theme.fg);
g.drawString(chart_label + " " + (chart_index + bar -1) + " " + chart_data[chart_index + bar - 1], g.getWidth()/2, 150);
g.setColor("#00f");

View File

@ -1,7 +1,7 @@
{
"id": "health",
"name": "Health Tracking",
"version": "0.11",
"version": "0.12",
"description": "Logs health data and provides an app to view it",
"icon": "app.png",
"tags": "tool,system,health",

View File

@ -12,3 +12,4 @@
0.11: Merge Bangle.js 1 and 2 launchers, again
0.12: Add an option to hide clocks from the app list (fix #1015)
Add /*LANG*/ tags for internationalisation
0.13: Add fullscreen mode

View File

@ -2,7 +2,10 @@ var s = require("Storage");
var scaleval = 1;
var vectorval = 20;
var font = g.getFonts().includes("12x20") ? "12x20" : "6x8:2";
let settings = Object.assign({ showClocks: true }, s.readJSON("launch.json", true) || {});
let settings = Object.assign({
showClocks: true,
fullscreen: false
}, s.readJSON("launch.json", true) || {});
if ("vectorsize" in settings) {
vectorval = parseInt(settings.vectorsize);
@ -44,8 +47,11 @@ function drawApp(i, r) {
}
g.clear();
Bangle.loadWidgets();
Bangle.drawWidgets();
if (!settings.fullscreen) {
Bangle.loadWidgets();
Bangle.drawWidgets();
}
E.showScroller({
h : 64*scaleval, c : apps.length,

View File

@ -2,7 +2,7 @@
"id": "launch",
"name": "Launcher",
"shortName": "Launcher",
"version": "0.12",
"version": "0.13",
"description": "This is needed to display a menu allowing you to choose your own applications. You can replace this with a customised launcher.",
"icon": "app.png",
"type": "launch",

View File

@ -1,6 +1,9 @@
// make sure to enclose the function in parentheses
(function(back) {
let settings = Object.assign({ showClocks: true }, require("Storage").readJSON("launch.json", true) || {});
let settings = Object.assign({
showClocks: true,
fullscreen: false
}, require("Storage").readJSON("launch.json", true) || {});
let fonts = g.getFonts();
function save(key, value) {
@ -8,7 +11,7 @@
require("Storage").write("launch.json",settings);
}
const appMenu = {
"": {"title": /*LANG*/"Launcher Settings"},
"": { "title": /*LANG*/"Launcher" },
/*LANG*/"< Back": back,
/*LANG*/"Font": {
value: fonts.includes(settings.font)? fonts.indexOf(settings.font) : fonts.indexOf("12x20"),
@ -16,15 +19,20 @@
onchange: (m) => {save("font", fonts[m])},
format: v => fonts[v]
},
/*LANG*/"Vector font size": {
/*LANG*/"Vector Font Size": {
value: settings.vectorsize || 10,
min:10, max: 20,step:1,wrap:true,
onchange: (m) => {save("vectorsize", m)}
},
/*LANG*/"Show clocks": {
/*LANG*/"Show Clocks": {
value: settings.showClocks == true,
format: v => v ? /*LANG*/"Yes" : /*LANG*/"No",
onchange: (m) => {save("showClocks", m)}
onchange: (m) => { save("showClocks", m) }
},
/*LANG*/"Fullscreen": {
value: settings.fullscreen == true,
format: v => v ? /*LANG*/"Yes" : /*LANG*/"No",
onchange: (m) => { save("fullscreen", m) }
}
};
E.showMenu(appMenu);

View File

@ -17,4 +17,6 @@
0.17: Settings for mph/kph and other minor improvements.
0.18: Fullscreen mode can now be enabled or disabled in the settings.
0.19: Alarms can not go bigger than 100.
0.20: Use alarm for alarm functionality instead of own implementation.
0.20: Use alarm for alarm functionality instead of own implementation.
0.21: Add custom theming.
0.22: Fix alarm and add build in function for step counting.

View File

@ -1,8 +1,7 @@
# LCARS clock
A simple LCARS inspired clock.
Note: To display the steps, the wpedom app is required. To show weather data
such as temperature, humidity or window you BangleJS must be connected
To show weather data such as temperature, humidity or window you BangleJS must be connected
with Gadgetbride and the weather app must be installed. To use the timer
the "sched" app must be installed on your device.
@ -19,6 +18,7 @@ the "sched" app must be installed on your device.
* Tap on top/bottom of screen 1 to activate an alarm. Depends on widtmr.
* The lower orange line indicates the battery level.
* Display graphs (day or month) for steps + hrm on the second screen.
* Customizable theming colors in the settings menu of the app.
## Data that can be configured
* Steps - Steps loaded via the wpedom app.
@ -43,3 +43,4 @@ Access different screens via tap on the left/ right side of the screen
## Contributors
- [Adam Schmalhofer](https://github.com/adamschmalhofer)
- [Jon Warrington](https://github.com/BartokW)
- [Ronin Stegner](https://github.com/Ronin0000)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 795 B

After

Width:  |  Height:  |  Size: 789 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 772 B

After

Width:  |  Height:  |  Size: 760 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 791 B

After

Width:  |  Height:  |  Size: 771 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 769 B

After

Width:  |  Height:  |  Size: 742 B

View File

@ -1,14 +1,17 @@
const TIMER_IDX = "lcars";
const SETTINGS_FILE = "lcars.setting.json";
const locale = require('locale');
const storage = require('Storage');
const storage = require('Storage')
let settings = {
alarm: -1,
dataRow1: "Steps",
dataRow2: "Temp",
dataRow2: "HRM",
dataRow3: "Battery",
speed: "kph",
fullscreen: false,
themeColor1BG: "#FF9900",
themeColor2BG: "#FF00DC",
themeColor3BG: "#0094FF",
};
let saved_settings = storage.readJSON(SETTINGS_FILE, 1) || settings;
for (const key in saved_settings) {
@ -18,9 +21,9 @@ for (const key in saved_settings) {
/*
* Colors to use
*/
let cBlue = "#0094FF";
let cOrange = "#FF9900";
let cPurple = "#FF00DC";
let color1 = settings.themeColor3BG;
let color2 = settings.themeColor1BG;
let color3 = settings.themeColor2BG;
let cWhite = "#FFFFFF";
let cBlack = "#000000";
let cGrey = "#424242";
@ -33,33 +36,77 @@ let lcarsViewPos = 0;
var plotMonth = false;
/*
* Requirements and globals
*/
function convert24to16(input)
{
let RGB888 = parseInt(input.replace(/^#/, ''), 16);
let r = (RGB888 & 0xFF0000) >> 16;
let g = (RGB888 & 0xFF00) >> 8;
let b = RGB888 & 0xFF;
r = (r * 249 + 1014) >> 11;
g = (g * 253 + 505) >> 10;
b = (b * 249 + 1014) >> 11;
let RGB565 = 0;
RGB565 = RGB565 | (r << 11);
RGB565 = RGB565 | (g << 5);
RGB565 = RGB565 | b;
return "0x"+RGB565.toString(16);
}
var color1C = convert24to16(color1);
var color2C = convert24to16(color2);
var color3C = convert24to16(color3);
/*
* Requirements and globals
*/
var colorPalette = new Uint16Array([
0x0000, // not used
color2C, // second
color3C, // third
0x0000, // not used
color1C, // first
0x0000, // not used
0x0000, // not used
0x0000, // not used
0x0000, // not used
0x0000, // not used
0x0000, // not used
0x0000, // not used
0x0000, // not used
0x0000, // not used
0x0000, // not used
0x0000 // not used
],0,1);
var bgLeftFullscreen = {
width : 27, height : 176, bpp : 3,
transparent : 0,
buffer : require("heatshrink").decompress(atob("AAUM2XLlgCCwAJBBAuy4EAmQIF5cggAIGlmwgYIG2XIF42wF4ImGF4ImHJoQmGJoQdJhZNHNY47CgRNGBIJZHHgRiGBIRQ/KH5QCAFCh/eX5Q/KAwdCAGVbtu27YCCoAJBkuWrNlAQRGCiwRDAQPQBIMJCIYCBsAJBgomEtu0WoQmEy1YBIMBHYttIwQ7FyxQ/KHFlFAQ7F2weCHYplKChRTCCg5TCHw5TMAD0GzVp0wCCBBGaBIMaBAtpwECBA2mwEJBAugDgMmCIwJBF5EABAtoeQQvGCYQdPJoI7LMQzTCLJKAGzAJBO4xQ/KGQA8UP7y/KH5QnAHih/eX5Q/GQ4JCGRJlKCgxTDBAwgCCg5TCHwxTCNA4A=="))
buffer : require("heatshrink").decompress((atob("/4AB+VJkmSAQV///+BAtJn//5IIFkmf/4IGyVP/gIGpMnF41PHIImGF4ImHJoQmGJoIdK8hNHNY47C/JNGBIJZGyYJBQA5GCKH5Q/KAQAoUP7y/KH5QGDoQAy0hGF34JB6RGFr4JB9JkFl4JB+gdFy4JB/QdFpYJB/odFkqrCS4xGCWoyDCKH5Q1GShlJChQLCCg5TCHw5TMAD35FAoIIkgJB8hGGv/8Mg8/+QIFp4cB5IRGBIIvI/4IFybyCF4wTCDp5NBHZZiGz4JBLJKAGk4JBO4xQ/KGQA8UP7y/KH5QnAHih/eX5Q/GQ4JCGRJlKCgxTDBAwgCCg5TCHwxTCNA4"))),
palette: colorPalette
};
var bgLeftNotFullscreen = {
width : 27, height : 152, bpp : 3,
transparent : 0,
buffer : require("heatshrink").decompress(atob("AAUM2XLlgCCwAJBBAuy4EAmQIF5cggAIGlmwgYIG2XIF42wF4ImGF4ImHJoQmGJoQdJhZNHNY47CgRNGBIJZHHgRiGBIRQ/KH5QCAGVbtu27YCCoAJBkuWrNlAQRkCiwRDAQPQBIMJCIYCBsAJBgomEtu0WoQmEy1YBIMBHYttIwQ7FyxQ/KHFlFAQ7F2weCHYplKChRTCCg5TCHw5TMAD0GzVp0wCCBBGaBIMaBAtpwECBA2mwEJBAugDgMmCIwJBF5EABAtoeQQvGCYQdPJoI7LMQzTCLJKAGzAJBO4xQ/KGQA8UP7y/KH5QnAHih/eX5Q/GQ4JCGRJlKCgxTDBAwgCCg5TCHwxTCNA4A="))
buffer : require("heatshrink").decompress((atob("/4AB+VJkmSAQV///+BAtJn//5IIFkmf/4IGyVP/gIGpMnF41PHIImGF4ImHJoQmGJoIdK8hNHNY47C/JNGBIJZGyYJBQA5GCKH5Q/KAQAy0hGF34JB6RGFr4JB9JkFl4JB+gdFy4JB/QdFpYJB/odFkqrCS4xGCWoyhCKH5Q1GShlJChQLCCg5TCHw5TMAD35FAoIIkgJB8hGGv/8Mg8/+QIFp4cB5IRGBIIvI/4IFybyCF4wTCDp5NBHZZiGz4JBLJKAGk4JBO4xQ/KGQA8UP7y/KH5QnAHih/eX5Q/GQ4JCGRJlKCgxTDBAwgCCg5TCHwxTCNA4A=="))),
palette: colorPalette
};
var bgRightFullscreen = {
width : 27, height : 176, bpp : 3,
transparent : 0,
buffer : require("heatshrink").decompress(atob("lmy5YCDBIUyBAmy5AJBhYUG2EAhgIFAQMAgQIGCgQABCg4ABEAwUNFI2AKZHAKZEgGRZTGOIUDQxJxGKH5Q/agwAnUP7y/KH4yGeVYAJrdt23bAQVABIMly1ZsoCCMgUWCIYCB6AJBhIRDAQNgBIMFEwlt2i1CEwmWrAJBgI7FtpGCHYuWKH5QxEwpQDlo7F0A7IqBZBEwo7BCIwCBJo53CJoxiCJpIAdgOmzVpAQR/CgAIEAQJ2CBAoCBBIMmCg1oD4QLGFQUCCjQ+CKYw+CKY4JCKYwoCGRMaGREJDoroCgwdFzBlLKH5QvAHih/eX5Q/KE4A8UP7y/KH5QGDpg7HJoxZCCIx3CJowmCF4yACJox/CgAA="))
buffer : require("heatshrink").decompress((atob("yVJkgCCyf/AAPJBAYCBk4JB8gUFyVP//yBAoCB//5BAwUCAAIUHAAIgGChopGv5TIn5TIz4yLKYxxC/iGI/xxGKH5Q/agwAnUP7y/KH4yGeVYAJ0hGF34JB6RGFr4JB9JkFl4JB+gdFy4JB/QdFpYJB/odFkp4CS4xGCWoyhCKH5QuDoxQCDpI7GDoJZGHYIRGLIQvGO4QvGMQRNJADv+GIqTC/5PGz4JBJ41JBIPJCg2TD4QLGn4JB/gUaHwRTGHwRTHBIRTGNAQyJ8gyI+QdFp4JB/IdFk5lLKH5QvAHih/eX5Q/KE4A8UP7y/KH5QGDpg7HJoxZCCIx3CJowmCF4yACJoyJC/4A=="))),
palette: colorPalette
};
var bgRightNotFullscreen = {
width : 27, height : 152, bpp : 3,
transparent : 0,
buffer : require("heatshrink").decompress(atob("lmy5YCDBIUyBAmy5AJBhYUG2EAhgIFAQMAgQIGCgQABCg4ABEAwUNFI2AKZHAKZEgGRZTGOIUDQxJxGKH5Q/agwAxrdt23bAQVABIMly1ZsoCCMgUWCIYCB6AJBhIRDAQNgBIMFEwlt2i1CEwmWrAJBgI7FtpGCHYuWKH5QxEwpQDlo7F0A7IqBZBEwo7BCIwCBJo53CJoxiCJpIAdgOmzVpAQR/CgAIEAQJ2CBAoCBBIMmCg1oD4QLGFQUCCjQ+CKYw+CKY4JCKYwoCGRMaGREJDoroCgwdFzBlLKH5QvAHih/eX5Q/KE4A8UP7y/KH5QGDpg7HJoxZCCIx3CJowmCF4yACJox/CgA="))
buffer : require("heatshrink").decompress((atob("yVJkgCCyf/AAPJBAYCBk4JB8gUFyVP//yBAoCB//5BAwUCAAIUHAAIgGChopGv5TIn5TIz4yLKYxxC/iGI/xxGKH5Q/agwAx0hGF34JB6RGFr4JB9JkFl4JB+gdFy4JB/QdFpYJB/odFkqrCS4xGCWoyhCKH5QuDoxQCDpI7GDoJZGHYIRGLIQvGO4QvGMQRNJADv+GIqTC/5PGz4JBJ41JBIPJCg2TD4QLGn4JB/gUaHwRTGHwRTHBIRTGNAQyJ8gyI+QdFp4JB/IdFk5lLKH5QvAHih/eX5Q/KE4A8UP7y/KH5QGDpg7HJoxZCCIx3CJowmCF4yACJoyJC/4A="))),
palette: colorPalette
};
var bgLeft = settings.fullscreen ? bgLeftFullscreen : bgLeftNotFullscreen;
@ -191,7 +238,7 @@ function _drawData(key, y, c){
value = E.getAnalogVRef().toFixed(2) + "V";
} else if(key == "HRM"){
value = Math.round(Bangle.getHealthStatus("day").bpm);
value = Math.round(Bangle.getHealthStatus("last").bpm);
} else if (key == "TEMP"){
var weather = getWeather();
@ -244,9 +291,11 @@ function drawInfo(){
return;
}
// Draw Infor is called from different sources so
// we have to ensure that the alignment is always the same.
g.setFontAlign(-1, -1, 0);
g.setFontAntonioMedium();
g.setColor(cOrange);
g.setColor(color2);
g.clearRect(120, 10, g.getWidth(), 75);
g.drawString("LCARS", 128, 13);
@ -256,7 +305,7 @@ function drawInfo(){
g.drawString("NOCON", 128, 33);
}
if(Bangle.isLocked()){
g.setColor(cPurple);
g.setColor(color3);
g.drawString("LOCK", 128, 53);
}
}
@ -287,7 +336,7 @@ function drawState(){
g.drawString("STATUS", 23+26, 108);
} else {
// Alarm within symbol
g.setColor(cOrange);
g.setColor(color2);
g.drawString("ALARM", 23+26, 108);
g.setColor(cWhite);
g.setFontAntonioLarge();
@ -302,19 +351,19 @@ function drawPosition0(){
// Draw background image
var offset = settings.fullscreen ? 0 : 24;
g.drawImage(bgLeft, 0, offset);
drawHorizontalBgLine(cBlue, 25, 120, offset, 4);
drawHorizontalBgLine(cBlue, 130, 176, offset, 4);
drawHorizontalBgLine(cPurple, 20, 70, 80, 4);
drawHorizontalBgLine(cPurple, 80, 176, 80, 4);
drawHorizontalBgLine(cOrange, 35, 110, 87, 4);
drawHorizontalBgLine(cOrange, 120, 176, 87, 4);
drawHorizontalBgLine(color1, 25, 120, offset, 4);
drawHorizontalBgLine(color1, 130, 176, offset, 4);
drawHorizontalBgLine(color3, 20, 70, 80, 4);
drawHorizontalBgLine(color3, 80, 176, 80, 4);
drawHorizontalBgLine(color2, 35, 110, 87, 4);
drawHorizontalBgLine(color2, 120, 176, 87, 4);
// The last line is a battery indicator too
var bat = E.getBattery() / 100.0;
var batStart = 19;
var batWidth = 172 - batStart;
var batX2 = parseInt(batWidth * bat + batStart);
drawHorizontalBgLine(cOrange, batStart, batX2, 171, 5);
drawHorizontalBgLine(color2, batStart, batX2, 171, 5);
drawHorizontalBgLine(cGrey, batX2, 172, 171, 5);
for(var i=0; i+batStart<=172; i+=parseInt(batWidth/4)){
drawHorizontalBgLine(cBlack, batStart+i, batStart+i+3, 168, 8)
@ -353,9 +402,9 @@ function drawPosition0(){
// Draw data
g.setFontAlign(-1, -1, 0);
g.setColor(cWhite);
drawData(settings.dataRow1, 97, cOrange);
drawData(settings.dataRow2, 122, cPurple);
drawData(settings.dataRow3, 147, cBlue);
drawData(settings.dataRow1, 97, color2);
drawData(settings.dataRow2, 122, color3);
drawData(settings.dataRow3, 147, color1);
// Draw state
drawState();
@ -366,13 +415,13 @@ function drawPosition1(){
var offset = settings.fullscreen ? 0 : 24;
g.drawImage(bgRight, 149, offset);
if(settings.fullscreen){
drawHorizontalBgLine(cBlue, 0, 140, offset, 4);
drawHorizontalBgLine(color1, 0, 140, offset, 4);
}
drawHorizontalBgLine(cPurple, 0, 80, 80, 4);
drawHorizontalBgLine(cPurple, 90, 150, 80, 4);
drawHorizontalBgLine(cOrange, 0, 50, 87, 4);
drawHorizontalBgLine(cOrange, 60, 140, 87, 4);
drawHorizontalBgLine(cOrange, 0, 150, 171, 5);
drawHorizontalBgLine(color3, 0, 80, 80, 4);
drawHorizontalBgLine(color3, 90, 150, 80, 4);
drawHorizontalBgLine(color2, 0, 50, 87, 4);
drawHorizontalBgLine(color2, 60, 140, 87, 4);
drawHorizontalBgLine(color2, 0, 150, 171, 5);
// Draw steps bars
g.setColor(cWhite);
@ -511,17 +560,20 @@ function draw(){
* Step counter via widget
*/
function getSteps() {
var steps = 0;
try{
if (WIDGETS.wpedom !== undefined) {
return WIDGETS.wpedom.getSteps();
steps = WIDGETS.wpedom.getSteps();
} else if (WIDGETS.activepedom !== undefined) {
return WIDGETS.activepedom.getSteps();
steps = WIDGETS.activepedom.getSteps();
} else {
steps = Bangle.getHealthStatus("day").steps;
}
} catch(ex) {
// In case we failed, we can only show 0 steps.
}
return 0;
return steps;
}
@ -530,38 +582,35 @@ function getWeather(){
try {
weatherJson = storage.readJSON('weather.json');
var weather = weatherJson.weather;
// Temperature
weather.temp = locale.temp(weather.temp-273.15);
// Humidity
weather.hum = weather.hum + "%";
// Wind
const wind = locale.speed(weather.wind).match(/^(\D*\d*)(.*)$/);
var speedFactor = settings.speed == "kph" ? 1.0 : 1.0 / 1.60934;
weather.wind = Math.round(wind[1] * speedFactor);
return weather
} catch(ex) {
// Return default
}
if(weatherJson === undefined){
return {
temp: "-",
hum: "-",
txt: "-",
wind: "-",
wdir: "-",
wrose: "-"
};
}
var weather = weatherJson.weather;
// Temperature
weather.temp = locale.temp(weather.temp-273.15);
// Humidity
weather.hum = weather.hum + "%";
// Wind
const wind = locale.speed(weather.wind).match(/^(\D*\d*)(.*)$/);
var speedFactor = settings.speed == "kph" ? 1.0 : 1.0 / 1.60934;
weather.wind = Math.round(wind[1] * speedFactor);
return weather
return {
temp: " ? ",
hum: " ? ",
txt: " ? ",
wind: " ? ",
wdir: " ? ",
wrose: " ? "
};
}
/*
* Handle alarm
*/
@ -594,7 +643,7 @@ function increaseAlarm(){
var minutes = isAlarmEnabled() ? getAlarmMinutes() : 0;
var alarm = require('sched')
alarm.setAlarm(TIMER_IDX, {
timer : (minutes+5)*60*1000,
timer : (minutes+5)*60*1000,
});
alarm.reload();
} catch(ex){ }
@ -609,9 +658,9 @@ function decreaseAlarm(){
alarm.setAlarm(TIMER_IDX, undefined);
if(minutes > 0){
alarm.setAlarm(TIMER_IDX, {
timer : minutes*60*1000,
});
alarm.setAlarm(TIMER_IDX, {
timer : minutes*60*1000,
});
}
alarm.reload();
@ -642,7 +691,6 @@ Bangle.on('charging',function(charging) {
drawState();
});
function feedback(){
Bangle.buzz(40, 0.3);
}

View File

@ -5,11 +5,14 @@
const storage = require('Storage')
let settings = {
alarm: -1,
dataRow1: "Battery",
dataRow2: "Steps",
dataRow3: "Temp",
dataRow1: "Steps",
dataRow2: "HRM",
dataRow3: "Battery",
speed: "kph",
fullscreen: false,
themeColor1BG: "#FF9900",
themeColor2BG: "#FF00DC",
themeColor3BG: "#0094FF",
};
let saved_settings = storage.readJSON(SETTINGS_FILE, 1) || settings;
for (const key in saved_settings) {
@ -20,8 +23,11 @@
storage.write(SETTINGS_FILE, settings)
}
var dataOptions = ["Steps", "Battery", "VREF", "HRM", "Temp", "Humidity", "Wind", "Altitude", "CoreT"];
var speedOptions = ["kph", "mph"];
var color_options = ['Green','Orange','Cyan','Purple','Red','Blue','Yellow','White'];
var bg_code = ['#00ff00','#FF9900','#0094FF','#FF00DC','#ff0000','#0000ff','#ffef00','#FFFFFF'];
E.showMenu({
'': { 'title': 'LCARS Clock' },
@ -69,6 +75,33 @@
settings.speed = speedOptions[v];
save();
},
},
'Theme Color 1': {
value: 0 | bg_code.indexOf(settings.themeColor1BG),
min: 0, max: 7,
format: v => color_options[v],
onchange: v => {
settings.themeColor1BG = bg_code[v];
save();
},
},
'Theme Color 2': {
value: 0 | bg_code.indexOf(settings.themeColor2BG),
min: 0, max: 7,
format: v => color_options[v],
onchange: v => {
settings.themeColor2BG = bg_code[v];
save();
},
},
'Theme Color 3': {
value: 0 | bg_code.indexOf(settings.themeColor3BG),
min: 0, max: 7,
format: v => color_options[v],
onchange: v => {
settings.themeColor3BG = bg_code[v];
save();
},
}
});
})

View File

@ -3,7 +3,7 @@
"name": "LCARS Clock",
"shortName":"LCARS",
"icon": "lcars.png",
"version":"0.20",
"version":"0.22",
"readme": "README.md",
"supports": ["BANGLEJS2"],
"description": "Library Computer Access Retrieval System (LCARS) clock.",

View File

@ -44,3 +44,5 @@
0.29: Fix message list overwrites on Bangle.js 1 (fix #1642)
0.30: Add new Icons (Youtube, Twitch, MS TODO, Teams, Snapchat, Signal, Post & DHL, Nina, Lieferando, Kalender, Discord, Corona Warn, Bibel)
0.31: Option to disable icon flashing
0.32: Added an option to allow quiet mode to override message auto-open
0.33: Timeout from the message list screen if the message being displayed is removed and there is a timer going

View File

@ -470,8 +470,6 @@ function checkMessages(options) {
// no new messages - go to clock?
if (options.clockIfAllRead && newMessages.length==0)
return load();
// we don't have to time out of this screen...
cancelReloadTimeout();
active = "main";
// Otherwise show a menu
E.showScroller({

View File

@ -56,9 +56,16 @@ exports.pushMessage = function(event) {
}
// otherwise load messages/show widget
var loadMessages = Bangle.CLOCK || event.important;
// first, buzz
var quiet = (require('Storage').readJSON('setting.json',1)||{}).quiet;
var unlockWatch = (require('Storage').readJSON('messages.settings.json',1)||{}).unlockWatch;
var appSettings = require('Storage').readJSON('messages.settings.json',1)||{};
var unlockWatch = appSettings.unlockWatch;
var quietNoAutOpn = appSettings.quietNoAutOpn;
delete appSettings;
// don't auto-open messages in quiet mode if quietNoAutOpn is true
if(quiet && quietNoAutOpn) {
loadMessages = false;
}
// first, buzz
if (!quiet && loadMessages && global.WIDGETS && WIDGETS.messages){
WIDGETS.messages.buzz();
if(unlockWatch != false){

View File

@ -1,7 +1,7 @@
{
"id": "messages",
"name": "Messages",
"version": "0.31",
"version": "0.33",
"description": "App to display notifications from iOS and Gadgetbridge/Android",
"icon": "app.png",
"type": "app",

View File

@ -53,6 +53,11 @@
format: v => v?/*LANG*/'Yes':/*LANG*/'No',
onchange: v => updateSetting("flash", v)
},
/*LANG*/'Quiet mode disables auto-open': {
value: !!settings().quietNoAutOpn,
format: v => v?/*LANG*/'Yes':/*LANG*/'No',
onchange: v => updateSetting("quietNoAutOpn", v)
},
};
E.showMenu(mainmenu);
})

View File

@ -2,3 +2,4 @@
0.02: Fix scheduling of other alarms if there is a pending alarm from the past (fix #1667)
0.03: Fix `getTimeToAlarm` for a timer already used at same day, don't set `last` for timers.
0.04: Fix `getTimeToAlarm` to check for next dow if alarm.t lower currentTime.
0.05: Export new functions (`newDefaultAlarm/Timer`), add Settings page

View File

@ -8,8 +8,17 @@ Other apps can use this to provide alarm functionality.
App
---
The Alarm app allows you to add/modify any running timers.
The **Alarms & Timers** app allows you to add/modify any running alarms and timers.
Global Settings
---------------
- `Unlock at Buzz` - If `Yes` the alarm/timer will unlock the watch
- `Default Auto Snooze` - Default _Auto Snooze_ value for newly created alarms (_Alarms_ only)
- `Default Snooze` - Default _Snooze_ value for newly created alarms/timers
- `Buzz Count` - The number of buzzes before the watch goes silent
- `Buzz Interval` - The interval between one buzz and the next
- `Default Alarm/Timer Pattern` - Default vibration pattern for newly created alarms/timers
Internals / Library
-------------------
@ -53,21 +62,27 @@ use too much RAM.
It can be used as follows:
```
// add/update an existing alarm
// Get a new alarm with default values
let alarm = require("sched").newDefaultAlarm();
// Get a new timer with default values
let timer = require("sched").newDefaultTimer();
// Add/update an existing alarm
require("sched").setAlarm("mytimer", {
msg : "Wake up",
timer : 10*60*1000, // 10 Minutes
timer : 10 * 60 * 1000 // 10 minutes
});
// Ensure the widget and alarm timer updates to schedule the new alarm properly
require("sched").reload();
// Get the time to the next alarm for us
var timeToNext = require("sched").getTimeToAlarm(require("sched").getAlarm("mytimer"));
// timeToNext===undefined if no alarm or alarm disabled
let timeToNext = require("sched").getTimeToAlarm(require("sched").getAlarm("mytimer"));
// timeToNext === undefined if no alarm or alarm disabled
// delete an alarm
// Delete an alarm
require("sched").setAlarm("mytimer", undefined);
// reload after deleting...
// Reload after deleting
require("sched").reload();
// Or add an alarm that runs your own code - in this case
@ -76,12 +91,15 @@ require("sched").reload();
require("sched").setAlarm("customrunner", {
appid : "myapp",
js : "load('setting.app.js')",
timer : 1*60*1000, // 1 Minute
timer : 1 * 60 * 1000 // 1 minute
});
// If you have been specifying `appid` you can also find any alarms that
// your app has created with the following:
require("sched").getAlarms().filter(a=>a.appid=="myapp");
require("sched").getAlarms().filter(a => a.appid == "myapp");
// Get the scheduler settings
let settings = require("sched").getSettings();
```
If your app requires alarms, you can specify that the alarms app needs to

View File

@ -52,3 +52,58 @@ exports.reload = function() {
Bangle.drawWidgets();
}
};
// Factory that creates a new alarm with default values
exports.newDefaultAlarm = function () {
const settings = exports.getSettings();
let alarm = {
t: 12 * 3600000, // Default to 12:00
on: true,
rp: false, // repeat not the default
as: settings.defaultAutoSnooze || false,
dow: 0b1111111,
last: 0,
vibrate: settings.defaultAlarmPattern,
};
delete settings;
return alarm;
}
// Factory that creates a new timer with default values
exports.newDefaultTimer = function () {
const settings = exports.getSettings();
let timer = {
timer: 5 * 60 * 1000, // 5 minutes
on: true,
rp: false,
as: false,
dow: 0b1111111,
last: 0,
vibrate: settings.defaultTimerPattern
}
delete settings;
return timer;
};
// Return the scheduler settings
exports.getSettings = function () {
return Object.assign(
{
unlockAtBuzz: false,
defaultSnoozeMillis: 600000, // 10 minutes
defaultAutoSnooze: false,
buzzCount: 10,
buzzIntervalMillis: 3000, // 3 seconds
defaultAlarmPattern: "..",
defaultTimerPattern: ".."
},
require("Storage").readJSON("sched.settings.json", true) || {}
);
}
// Write the updated settings back to storage
exports.setSettings = function(settings) {
require("Storage").writeJSON("sched.settings.json", settings);
};

View File

@ -1,7 +1,7 @@
{
"id": "sched",
"name": "Scheduler",
"version": "0.04",
"version": "0.05",
"description": "Scheduling library for alarms and timers",
"icon": "app.png",
"type": "scheduler",
@ -12,7 +12,8 @@
{"name":"sched.boot.js","url":"boot.js"},
{"name":"sched.js","url":"sched.js"},
{"name":"sched.img","url":"app-icon.js","evaluate":true},
{"name":"sched","url":"lib.js"}
{"name":"sched","url":"lib.js"},
{"name":"sched.settings.js","url":"settings.js"}
],
"data": [{"name":"sched.json"}]
"data": [{"name":"sched.json"}, {"name":"sched.settings.json"}]
}

View File

@ -18,7 +18,9 @@ function formatTime(t) {
}
function showAlarm(alarm) {
var msg = "";
const settings = require("sched").getSettings();
let msg = "";
msg += alarm.timer ? formatTime(alarm.timer) : formatTime(alarm.t);
if (alarm.msg) {
msg += "\n"+alarm.msg;
@ -28,9 +30,12 @@ function showAlarm(alarm) {
else
msg = atob("AC0swgF97///RcEpMlVVVVVVf9VVVVVVVVX/9VVf9VVf/1VVV///1Vf9VX///VVX///VWqqlV///1Vf//9aqqqqpf//9V///2qqqqqqn///V///6qqqqqqr///X//+qqoAAKqqv//3//6qoAAAAKqr//3//qqAAAAAAqq//3/+qoAADwAAKqv/3/+qgAADwAACqv/3/aqAAADwAAAqp/19qoAAADwAAAKqfV1qgAAADwAAACqXVWqgAAADwAAACqlVWqAAAADwAAAAqlVWqAAAADwAAAAqlVWqAAAADwAAAAqlVaoAAAADwAAAAKpVaoAAAADwAAAAKpVaoAAAADwAAAAKpVaoAAAAOsAAAAKpVaoAAAAOsAAAAKpVaoAAAAL/AAAAKpVaoAAAAgPwAAAKpVaoAAACAD8AAAKpVWqAAAIAA/AAAqlVWqAAAgAAPwAAqlVWqAACAAADwAAqlVWqgAIAAAAAACqlVVqgAgAAAAAACqVVVqoAAAAAAAAKqVVVaqAAAAAAAAqpVVVWqgAAAAAACqlVVVWqoAAAAAAKqlVVVVqqAAAAAAqqVVVVVaqoAAAAKqpVVVVVeqqoAAKqqtVVVVV/6qqqqqqr/VVVVX/2qqqqqqn/1VVVf/VaqqqqpV/9VVVf9VVWqqlVVf9VVVf1VVVVVVVVX9VQ==")+" "+msg;
}
Bangle.loadWidgets();
Bangle.drawWidgets();
var buzzCount = 10;
let buzzCount = settings.buzzCount;
E.showPrompt(msg,{
title:alarm.timer ? /*LANG*/"TIMER!" : /*LANG*/"ALARM!",
buttons : {/*LANG*/"Snooze":true,/*LANG*/"Ok":false} // default is sleep so it'll come back in 10 mins
@ -38,7 +43,7 @@ function showAlarm(alarm) {
buzzCount = 0;
if (sleep) {
if(alarm.ot===undefined) alarm.ot = alarm.t;
alarm.t += 10*60*1000; // 10 minutes
alarm.t += settings.defaultSnoozeMillis;
} else {
if (!alarm.timer) alarm.last = (new Date()).getDate();
if (alarm.ot!==undefined) {
@ -51,24 +56,35 @@ function showAlarm(alarm) {
require("sched").setAlarms(alarms);
load();
});
function buzz() {
require("buzz").pattern(alarm.vibrate===undefined?"..":alarm.vibrate).then(function() {
if (buzzCount--)
setTimeout(buzz, 3000);
else if(alarm.as) { // auto-snooze
buzzCount = 10;
setTimeout(buzz, 600000);
if (settings.unlockAtBuzz) {
Bangle.setLocked(false);
}
require("buzz").pattern(alarm.vibrate === undefined ? ".." : alarm.vibrate).then(() => {
if (buzzCount--) {
setTimeout(buzz, settings.buzzIntervalMillis);
} else if (alarm.as) { // auto-snooze
buzzCount = settings.buzzCount;
setTimeout(buzz, settings.defaultSnoozeMillis);
}
});
}
if ((require('Storage').readJSON('setting.json',1)||{}).quiet>1) return;
if ((require("Storage").readJSON("setting.json", 1) || {}).quiet > 1)
return;
buzz();
}
// Check for alarms
var alarms = require("sched").getAlarms();
var active = require("sched").getActiveAlarms(alarms);
if (active.length) // if there's an alarm, show it
let alarms = require("sched").getAlarms();
let active = require("sched").getActiveAlarms(alarms);
if (active.length) {
// if there's an alarm, show it
showAlarm(active[0]);
else // otherwise just go back to default app
} else {
// otherwise just go back to default app
setTimeout(load, 100);
}

72
apps/sched/settings.js Normal file
View File

@ -0,0 +1,72 @@
(function (back) {
let settings = require("sched").getSettings();
E.showMenu({
"": { "title": /*LANG*/"Scheduler" },
/*LANG*/"< Back": () => back(),
/*LANG*/"Unlock at Buzz": {
value: settings.unlockAtBuzz,
format: v => v ? /*LANG*/"Yes" : /*LANG*/"No",
onchange: v => {
settings.unlockAtBuzz = v;
require("sched").setSettings(settings);
}
},
/*LANG*/"Default Auto Snooze": {
value: settings.defaultAutoSnooze,
format: v => v ? /*LANG*/"Yes" : /*LANG*/"No",
onchange: v => {
settings.defaultAutoSnooze = v;
require("sched").setSettings(settings);
}
},
/*LANG*/"Default Snooze": {
value: settings.defaultSnoozeMillis / 60000,
min: 5,
max: 30,
step: 5,
format: v => v + /*LANG*/" min",
onchange: v => {
settings.defaultSnoozeMillis = v * 60000;
require("sched").setSettings(settings);
}
},
/*LANG*/"Buzz Count": {
value: settings.buzzCount,
min: 5,
max: 15,
step: 1,
onchange: v => {
settings.buzzCount = v;
require("sched").setSettings(settings);
}
},
/*LANG*/"Buzz Interval": {
value: settings.buzzIntervalMillis / 1000,
min: 1,
max: 5,
step: 1,
format: v => v + /*LANG*/"s",
onchange: v => {
settings.buzzIntervalMillis = v * 1000;
require("sched").setSettings(settings);
}
},
/*LANG*/"Default Alarm Pattern": require("buzz_menu").pattern(settings.defaultAlarmPattern, v => {
settings.defaultAlarmPattern = v;
require("sched").setSettings(settings);
}),
/*LANG*/"Default Timer Pattern": require("buzz_menu").pattern(settings.defaultTimerPattern, v => {
settings.defaultTimerPattern = v;
require("sched").setSettings(settings);
})
});
});

1
apps/widstep/ChangeLog Normal file
View File

@ -0,0 +1 @@
0.01: New widget

9
apps/widstep/README.md Normal file
View File

@ -0,0 +1,9 @@
# Step counter widget
This is my step counter. There are many like it, but this one is mine.
A pedometer widget designed to be as narrow as possible, but still easy to read, by sacrificing accuracy and only showing to the nearest 100 steps (0.1k).
Shows a subtle fill colour in the background for progress to the goal. The goal is picked up from the health tracker settings.
![](widstep-light.png)
![](widstep-dark.png)

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -0,0 +1,17 @@
{
"id": "widstep",
"name": "Step counter widget",
"version": "0.01",
"description": "Step counter widget, narrow but clearly readable",
"readme": "README.md",
"icon": "icons8-winter-boots-48.png",
"screenshots": [{"url":"widstep-light.png"},{"url":"widstep-dark.png"}],
"type": "widget",
"tags": "widget,health",
"supports": ["BANGLEJS","BANGLEJS2"],
"dependencies" : {"health":"app"},
"allow_emulator":false,
"storage": [
{"name":"widstep.wid.js","url":"widstep.wid.js"}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

View File

@ -0,0 +1,23 @@
let wsSettingsGoal = (require('Storage').readJSON("health.json", 1) || {}).stepGoal || 10000;
Bangle.on('step', function(s) { WIDGETS["widstep"].draw(); });
Bangle.on('lcdPower', function(on) {
if (on) WIDGETS["widstep"].draw();
});
WIDGETS["widstep"]={area:"tl", sortorder:-1, width:28,
draw:function() {
if (!Bangle.isLCDOn()) return; // dont redraw if LCD is off
var steps = Bangle.getHealthStatus("day").steps;
g.reset();
g.setColor(g.theme.bg);
g.fillRect(this.x, this.y, this.x + this.width, this.y + 23);
g.setColor(g.theme.dark ? '#00f' : '#0ff');
var progress = this.width * Math.min(steps/wsSettingsGoal, 1);
g.fillRect(this.x+1, this.y+1, this.x + progress -1, this.y + 23);
g.setColor(g.theme.fg);
g.setFontAlign(0, -1);
var steps_k = (steps/1000).toFixed(1) + 'k';
g.setFont('6x15').drawString(steps_k, this.x+this.width/2, this.y + 10);
g.setFont('4x6').drawString('steps', this.x+this.width/2, this.y + 2);
}
};

View File

@ -81,7 +81,7 @@ a.btn.btn-link.dropdown-toggle {
min-height: 8em;
}
.tile-content { position: relative; word-break: break-all; }
.tile-content { position: relative; }
.link-github {
position:absolute;
top: 36px;