mirror of https://github.com/espruino/BangleApps
Merge branch 'espruino:master' into master
commit
9b344eb1ec
14
apps.json
14
apps.json
|
@ -94,7 +94,7 @@
|
|||
"name": "Notifications (default)",
|
||||
"shortName":"Notifications",
|
||||
"icon": "notify.png",
|
||||
"version":"0.09",
|
||||
"version":"0.10",
|
||||
"description": "A handler for displaying notifications that displays them in a bar at the top of the screen",
|
||||
"tags": "widget",
|
||||
"type": "notify",
|
||||
|
@ -107,9 +107,9 @@
|
|||
"name": "Fullscreen Notifications",
|
||||
"shortName":"Notifications",
|
||||
"icon": "notify.png",
|
||||
"version":"0.10",
|
||||
"version":"0.11",
|
||||
"description": "A handler for displaying notifications that displays them fullscreen. This may not fully restore the screen after on some apps. See `Notifications (default)` for more information about the notifications library.",
|
||||
"tags": "widget",
|
||||
"tags": "widget,b2",
|
||||
"type": "notify",
|
||||
"storage": [
|
||||
{"name":"notify","url":"notify.js"}
|
||||
|
@ -155,7 +155,7 @@
|
|||
"icon": "app.png",
|
||||
"version":"0.24",
|
||||
"description": "The default notification handler for Gadgetbridge notifications from Android",
|
||||
"tags": "tool,system,android,widget",
|
||||
"tags": "tool,system,android,widget,b2",
|
||||
"readme": "README.md",
|
||||
"type":"widget",
|
||||
"dependencies": { "notify":"type" },
|
||||
|
@ -202,7 +202,7 @@
|
|||
"name": "Default Alarm",
|
||||
"shortName":"Alarms",
|
||||
"icon": "app.png",
|
||||
"version":"0.11",
|
||||
"version":"0.12",
|
||||
"description": "Set and respond to alarms",
|
||||
"tags": "tool,alarm,widget,b2",
|
||||
"storage": [
|
||||
|
@ -571,7 +571,7 @@
|
|||
{ "id": "weather",
|
||||
"name": "Weather",
|
||||
"icon": "icon.png",
|
||||
"version":"0.07",
|
||||
"version":"0.08",
|
||||
"description": "Show Gadgetbridge weather report",
|
||||
"readme": "readme.md",
|
||||
"tags": "widget,outdoors",
|
||||
|
@ -1184,7 +1184,7 @@
|
|||
{ "id": "widpedom",
|
||||
"name": "Pedometer widget",
|
||||
"icon": "widget.png",
|
||||
"version":"0.17",
|
||||
"version":"0.19",
|
||||
"description": "Daily pedometer widget",
|
||||
"tags": "widget,b2",
|
||||
"type":"widget",
|
||||
|
|
|
@ -97,7 +97,7 @@ function startRecord(force) {
|
|||
{type:"txt", id:"samples", font:"6x8:2", label:" - ", pad:5},
|
||||
{type:"txt", font:"6x8", label:"Time", pad:2},
|
||||
{type:"txt", id:"time", font:"6x8:2", label:" - ", pad:5},
|
||||
{type:"txt", font:"6x8:2", label:"RECORDING", bgCol:"#f00", pad:5, fillx:true},
|
||||
{type:"txt", font:"6x8:2", label:"RECORDING", bgCol:"#f00", pad:5, fillx:1},
|
||||
]
|
||||
},[ // Buttons...
|
||||
{label:"STOP", cb:()=>{
|
||||
|
|
|
@ -9,3 +9,4 @@
|
|||
0.09: Add per alarm auto-snooze option
|
||||
0.10: Fix auto-snooze option (this stopped new alarms being added) (fix #506)
|
||||
0.11: Respect Quiet Mode
|
||||
0.12: Fix widget for bangle 2, now uses theme
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
delete alarms;
|
||||
// add the widget
|
||||
WIDGETS["alarm"]={area:"tl",width:24,draw:function() {
|
||||
g.setColor(-1);
|
||||
g.setColor(g.theme.fg);
|
||||
g.drawImage(atob("GBgBAAAAAAAAABgADhhwDDwwGP8YGf+YMf+MM//MM//MA//AA//AA//AA//AA//AA//AB//gD//wD//wAAAAADwAABgAAAAAAAAA"),this.x,this.y);
|
||||
}};
|
||||
})()
|
||||
|
|
|
@ -6,3 +6,4 @@
|
|||
0.07: Auto-calculate height, and pad text down even when there's no title (so it stays on-screen)
|
||||
0.08: Don't turn on screen during Quiet Mode
|
||||
0.09: Add onHide callback
|
||||
0.10: Improvements to help notifications work with themes
|
||||
|
|
|
@ -5,6 +5,10 @@ A handler for displaying notifications that displays them in a bar at the top of
|
|||
This is not an app, but instead it is a library that can be used by
|
||||
other applications or widgets to display messages.
|
||||
|
||||
**Note:** There are other implementations of this library available such
|
||||
as `notifyfs` (Fullscreen Notifications). These can be used in the exact
|
||||
same way from code, but they look different to the user.
|
||||
|
||||
## Usage
|
||||
|
||||
```JS
|
||||
|
|
|
@ -96,15 +96,17 @@ exports.show = function(options) {
|
|||
b = y+h-1, r = x+w-1; // bottom,right
|
||||
g.setClipRect(x,y, r,b);
|
||||
// clear area
|
||||
g.setColor(options.bgColor||0).fillRect(x,y, r,b);
|
||||
g.reset();
|
||||
if (options.bgColor!==undefined) g.setColor(options.bgColor);
|
||||
g.clearRect(x,y, r,b);
|
||||
// bottom border
|
||||
g.setColor(0x39C7).fillRect(0,b-1, r,b);
|
||||
g.setColor("#333").fillRect(0,b-1, r,b);
|
||||
b -= 2;h -= 2;
|
||||
// title bar
|
||||
if (options.title || options.src) {
|
||||
g.setColor(options.titleBgColor||0x39C7).fillRect(x,y, r,y+20);
|
||||
const title = options.title||options.src;
|
||||
g.setColor(-1).setFontAlign(-1, -1, 0).setFont("6x8", 2);
|
||||
g.setColor(g.theme.fg).setFontAlign(-1, -1, 0).setFont("6x8", 2);
|
||||
g.drawString(title.trim().substring(0, 13), x+25,y+3);
|
||||
if (options.title && options.src) {
|
||||
g.setFont("6x8", 1).setFontAlign(1, 1, 0);
|
||||
|
@ -122,7 +124,7 @@ exports.show = function(options) {
|
|||
}
|
||||
// body text
|
||||
if (options.body) {
|
||||
g.setColor(-1).setFont("6x8", 1).setFontAlign(-1, -1, 0).drawString(text, x+6,y+4);
|
||||
g.setColor(g.theme.fg).setFont("6x8", 1).setFontAlign(-1, -1, 0).drawString(text, x+6,y+4);
|
||||
}
|
||||
|
||||
if (options.render) {
|
||||
|
|
|
@ -8,3 +8,4 @@
|
|||
0.08: Don't turn on screen during Quiet Mode
|
||||
0.09: Add onHide callback
|
||||
0.10: Ensure dismissing a notification dismissal doesn't enter launcher if in clock mode
|
||||
0.11: Improvements to help notifications work with themes, Bangle.js 2 support
|
||||
|
|
|
@ -50,22 +50,24 @@ exports.show = function(options) {
|
|||
if (options.on===undefined) options.on=true;
|
||||
id = ("id" in options)?options.id:null;
|
||||
let size = options.size||120;
|
||||
if (size>120) {size=120}
|
||||
Bangle.setLCDMode("direct");
|
||||
if (size>120) size=120;
|
||||
try { Bangle.setLCDMode("direct"); } catch(e) {} // not supported/needed on Bangle.js 2
|
||||
let x = 0,
|
||||
y = 40,
|
||||
w = 240,
|
||||
w = g.getWidth(),
|
||||
h = size;
|
||||
// clear screen
|
||||
g.setColor(options.bgColor||0).fillRect(0,0,g.getWidth(),g.getHeight());
|
||||
g.reset();
|
||||
if (options.bgColor!==undefined) g.setColor(options.bgColor);
|
||||
g.clearRect(0,0,g.getWidth(),g.getHeight());
|
||||
// top bar
|
||||
if (options.title||options.src) {
|
||||
const title = options.title || options.src
|
||||
g.setColor(options.titleBgColor||0x39C7).fillRect(x, y, x+w-1, y+30);
|
||||
g.setColor(-1).setFontAlign(-1, -1, 0).setFont("6x8", 3);
|
||||
const title = options.title || options.src;
|
||||
g.setColor(options.titleBgColor||"#333").fillRect(x, y, x+w-1, y+30);
|
||||
g.setColor(g.theme.fg).setFontAlign(-1, -1, 0).setFont("6x8", 3);
|
||||
g.drawString(title.trim().substring(0, 13), x+5, y+3);
|
||||
if (options.title && options.src) {
|
||||
g.setColor(-1).setFontAlign(1, 1, 0).setFont("6x8", 2);
|
||||
g.setColor(g.theme.fg).setFontAlign(1, 1, 0).setFont("6x8", 2);
|
||||
// above drawing area, but we are fullscreen
|
||||
g.drawString(options.src.substring(0, 10), w-16, y-4);
|
||||
}
|
||||
|
@ -73,8 +75,8 @@ exports.show = function(options) {
|
|||
}
|
||||
if (options.icon) {
|
||||
let i = options.icon, iw,ih;
|
||||
if ("string"==typeof i) {iw=i.charCodeAt(0); ih=i.charCodeAt(1)}
|
||||
else {iw=i[0]; ih=i[1]}
|
||||
if ("string"==typeof i) {iw=i.charCodeAt(0); ih=i.charCodeAt(1);}
|
||||
else {iw=i[0]; ih=i[1];}
|
||||
const iy=y ? (y+4) : (h-ih)/2; // show below title bar if present, otherwise center vertically
|
||||
g.drawImage(i, x+4,iy);
|
||||
x += iw+4;w -= iw+4;
|
||||
|
@ -84,16 +86,13 @@ exports.show = function(options) {
|
|||
const maxRows = Math.floor((h-4)/16), // font=2*(6x8)
|
||||
maxChars = Math.floor((w-4)/12),
|
||||
text=fitWords(options.body, maxRows, maxChars);
|
||||
g.setColor(-1).setFont("6x8", 2).setFontAlign(-1, -1, 0).drawString(text, x+4, y+4);
|
||||
g.setColor(g.theme.fg).setFont("6x8", 2).setFontAlign(-1, -1, 0).drawString(text, x+4, y+4);
|
||||
}
|
||||
|
||||
if (options.render) {
|
||||
const area={x:x, y:y, w:w, h:h}
|
||||
options.render(area);
|
||||
}
|
||||
if (options.on && !(require('Storage').readJSON('setting.json',1)||{}).quiet) {
|
||||
if (options.render)
|
||||
options.render({x:x, y:y, w:w, h:h});
|
||||
if (options.on && !(require('Storage').readJSON('setting.json',1)||{}).quiet)
|
||||
Bangle.setLCDPower(1); // light up
|
||||
}
|
||||
Bangle.on("touch", exports.hide);
|
||||
if (options.onHide)
|
||||
hideCallback = options.onHide;
|
||||
|
|
|
@ -3,4 +3,5 @@
|
|||
0.04: Adjust "weather unknown" message according to Bluetooth connection.
|
||||
0.05: Add wind direction.
|
||||
0.06: Use setUI for launcher.
|
||||
0.07: Add theme support and unknown icon.
|
||||
0.07: Add theme support and unknown icon.
|
||||
0.08: Refactor and reduce widget ram usage.
|
|
@ -1,5 +1,6 @@
|
|||
(() => {
|
||||
const weather = require('weather');
|
||||
let current = weather.get();
|
||||
|
||||
function formatDuration(millis) {
|
||||
let pluralize = (n, w) => n + " " + w + (n == 1 ? "" : "s");
|
||||
|
@ -10,16 +11,15 @@
|
|||
}
|
||||
|
||||
function draw() {
|
||||
let w = weather.current;
|
||||
g.reset();
|
||||
g.clearRect(0, 24, 239, 239);
|
||||
|
||||
weather.drawIcon(w.txt, 65, 90, 55);
|
||||
weather.drawIcon(current.txt, 65, 90, 55);
|
||||
const locale = require("locale");
|
||||
|
||||
g.reset();
|
||||
|
||||
const temp = locale.temp(w.temp-273.15).match(/^(\D*\d*)(.*)$/);
|
||||
const temp = locale.temp(current.temp-273.15).match(/^(\D*\d*)(.*)$/);
|
||||
let width = g.setFont("Vector", 40).stringWidth(temp[1]);
|
||||
width += g.setFont("Vector", 20).stringWidth(temp[2]);
|
||||
g.setFont("Vector", 40).setFontAlign(-1, -1, 0);
|
||||
|
@ -31,19 +31,19 @@
|
|||
g.setFontAlign(-1, 0, 0);
|
||||
g.drawString("Humidity", 135, 130);
|
||||
g.setFontAlign(1, 0, 0);
|
||||
g.drawString(w.hum+"%", 225, 130);
|
||||
if ('wind' in w) {
|
||||
g.drawString(current.hum+"%", 225, 130);
|
||||
if ('wind' in current) {
|
||||
g.setFontAlign(-1, 0, 0);
|
||||
g.drawString("Wind", 135, 142);
|
||||
g.setFontAlign(1, 0, 0);
|
||||
g.drawString(locale.speed(w.wind)+' '+w.wrose.toUpperCase(), 225, 142);
|
||||
g.drawString(locale.speed(current.wind)+' '+current.wrose.toUpperCase(), 225, 142);
|
||||
}
|
||||
|
||||
g.setFont("6x8", 2).setFontAlign(0, 0, 0);
|
||||
g.drawString(w.loc, 120, 170);
|
||||
g.drawString(current.loc, 120, 170);
|
||||
|
||||
g.setFont("6x8", 1).setFontAlign(0, 0, 0);
|
||||
g.drawString(w.txt.charAt(0).toUpperCase()+w.txt.slice(1), 120, 190);
|
||||
g.drawString(current.txt.charAt(0).toUpperCase()+current.txt.slice(1), 120, 190);
|
||||
|
||||
drawUpdateTime();
|
||||
|
||||
|
@ -51,8 +51,8 @@
|
|||
}
|
||||
|
||||
function drawUpdateTime() {
|
||||
if (!weather.current || !weather.current.time) return;
|
||||
let text = `Last update received ${formatDuration(Date.now() - weather.current.time)} ago`;
|
||||
if (!current || !current.time) return;
|
||||
let text = `Last update received ${formatDuration(Date.now() - current.time)} ago`;
|
||||
g.reset();
|
||||
g.clearRect(0, 202, 239, 210);
|
||||
g.setFont("6x8", 1).setFontAlign(0, 0, 0);
|
||||
|
@ -60,8 +60,9 @@
|
|||
}
|
||||
|
||||
function update() {
|
||||
current = weather.get();
|
||||
NRF.removeListener("connect", update);
|
||||
if (weather.current) {
|
||||
if (current) {
|
||||
draw();
|
||||
} else if (NRF.getSecurityStatus().connected) {
|
||||
E.showMessage("Weather unknown\n\nIs Gadgetbridge\nweather reporting\nset up on your\nphone?");
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
const storage = require('Storage');
|
||||
|
||||
let expiryTimeout = undefined;
|
||||
let expiryTimeout;
|
||||
function scheduleExpiry(json) {
|
||||
if (expiryTimeout) {
|
||||
clearTimeout(expiryTimeout);
|
||||
|
@ -9,53 +9,35 @@ function scheduleExpiry(json) {
|
|||
let expiry = "expiry" in json ? json.expiry : 2*3600000;
|
||||
if (json.weather && json.weather.time && expiry) {
|
||||
let t = json.weather.time + expiry - Date.now();
|
||||
expiryTimeout = setTimeout(() => {
|
||||
expiryTimeout = undefined;
|
||||
|
||||
let json = storage.readJSON('weather.json')||{};
|
||||
delete json.weather;
|
||||
storage.write('weather.json', json);
|
||||
|
||||
exports.current = undefined;
|
||||
exports.emit("update");
|
||||
}, t);
|
||||
expiryTimeout = setTimeout(update, t);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert numeric direction into human-readable label
|
||||
*
|
||||
* @param {number} deg - Direction in degrees
|
||||
* @return {string|null} - Nearest compass point
|
||||
*/
|
||||
function compassRose(deg) {
|
||||
if (typeof deg === 'undefined') return null;
|
||||
while (deg<0 || deg>360) {
|
||||
deg = (deg+360)%360;
|
||||
}
|
||||
return ['n','ne','e','se','s','sw','w','nw','n'][Math.floor((deg+22.5)/45)];
|
||||
}
|
||||
|
||||
function setCurrentWeather(json) {
|
||||
scheduleExpiry(json);
|
||||
exports.current = json.weather;
|
||||
}
|
||||
|
||||
function update(weatherEvent) {
|
||||
let weather = Object.assign({}, weatherEvent);
|
||||
weather.time = Date.now();
|
||||
if ('wdir' in weather) {
|
||||
weather.wrose = compassRose(weather.wdir);
|
||||
}
|
||||
delete weather.t;
|
||||
|
||||
let json = storage.readJSON('weather.json')||{};
|
||||
json.weather = weather;
|
||||
|
||||
if (weatherEvent) {
|
||||
let weather = weatherEvent.clone();
|
||||
delete weather.t;
|
||||
weather.time = Date.now();
|
||||
if (weather.wdir != null) {
|
||||
// Convert numeric direction into human-readable label
|
||||
let deg = weather.wdir;
|
||||
while (deg<0 || deg>360) {
|
||||
deg = (deg+360)%360;
|
||||
}
|
||||
weather.wrose = ['n','ne','e','se','s','sw','w','nw','n'][Math.floor((deg+22.5)/45)];
|
||||
}
|
||||
|
||||
json.weather = weather;
|
||||
}
|
||||
else {
|
||||
delete json.weather;
|
||||
}
|
||||
|
||||
storage.write('weather.json', json);
|
||||
|
||||
setCurrentWeather(json);
|
||||
|
||||
exports.emit("update");
|
||||
scheduleExpiry(json);
|
||||
exports.emit("update", json.weather);
|
||||
}
|
||||
|
||||
const _GB = global.GB;
|
||||
|
@ -64,7 +46,11 @@ global.GB = (event) => {
|
|||
if (_GB) setTimeout(_GB, 0, event);
|
||||
};
|
||||
|
||||
setCurrentWeather(storage.readJSON('weather.json')||{});
|
||||
exports.get = function() {
|
||||
return storage.readJSON('weather.json').weather;
|
||||
}
|
||||
|
||||
scheduleExpiry(storage.readJSON('weather.json')||{});
|
||||
|
||||
exports.drawIcon = function(cond, x, y, r) {
|
||||
function drawSun(x, y, r) {
|
||||
|
|
|
@ -1,45 +1,23 @@
|
|||
(() => {
|
||||
const weather = require('weather');
|
||||
|
||||
function draw() {
|
||||
const w = weather.current;
|
||||
if (!w) return;
|
||||
g.reset();
|
||||
g.clearRect(this.x, this.y, this.x+this.width-1, this.y+23);
|
||||
if (w.txt) {
|
||||
weather.drawIcon(w.txt, this.x+10, this.y+8, 7.5);
|
||||
}
|
||||
if (w.temp) {
|
||||
let t = require('locale').temp(w.temp-273.15); // applies conversion
|
||||
t = t.match(/[\d\-]*/)[0]; // but we have no room for units
|
||||
g.reset();
|
||||
g.setFontAlign(0, 1); // center horizontally at bottom of widget
|
||||
g.setFont('6x8', 1);
|
||||
g.drawString(t, this.x+10, this.y+24);
|
||||
}
|
||||
}
|
||||
|
||||
var dirty = false;
|
||||
|
||||
function update() {
|
||||
if (!WIDGETS["weather"].width) {
|
||||
WIDGETS["weather"].width = 20;
|
||||
Bangle.drawWidgets();
|
||||
} else if (Bangle.isLCDOn()) {
|
||||
WIDGETS["weather"].draw();
|
||||
} else {
|
||||
dirty = true;
|
||||
weather.on("update", w => {
|
||||
if (w) {
|
||||
if (!WIDGETS["weather"].width) {
|
||||
WIDGETS["weather"].width = 20;
|
||||
Bangle.drawWidgets();
|
||||
} else if (Bangle.isLCDOn()) {
|
||||
WIDGETS["weather"].draw();
|
||||
} else {
|
||||
dirty = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
WIDGETS["weather"].width = 0;
|
||||
Bangle.drawWidgets();
|
||||
}
|
||||
}
|
||||
|
||||
function hide() {
|
||||
WIDGETS["weather"].width = 0;
|
||||
Bangle.drawWidgets();
|
||||
}
|
||||
|
||||
weather.on("update", () => {
|
||||
if (weather.current) update();
|
||||
else hide();
|
||||
});
|
||||
|
||||
Bangle.on('lcdPower', on => {
|
||||
|
@ -51,7 +29,23 @@
|
|||
|
||||
WIDGETS["weather"] = {
|
||||
area: "tl",
|
||||
width: weather.current ? 20 : 0,
|
||||
draw: draw,
|
||||
width: weather.get() ? 20 : 0,
|
||||
draw: function() {
|
||||
const w = weather.get();
|
||||
if (!w) return;
|
||||
g.reset();
|
||||
g.clearRect(this.x, this.y, this.x+this.width-1, this.y+23);
|
||||
if (w.txt) {
|
||||
weather.drawIcon(w.txt, this.x+10, this.y+8, 7.5);
|
||||
}
|
||||
if (w.temp) {
|
||||
let t = require('locale').temp(w.temp-273.15); // applies conversion
|
||||
t = t.match(/[\d\-]*/)[0]; // but we have no room for units
|
||||
g.reset();
|
||||
g.setFontAlign(0, 1); // center horizontally at bottom of widget
|
||||
g.setFont('6x8', 1);
|
||||
g.drawString(t, this.x+10, this.y+24);
|
||||
}
|
||||
},
|
||||
};
|
||||
})();
|
||||
|
|
|
@ -14,3 +14,8 @@
|
|||
0.15: Settings option to hide the widget icon
|
||||
0.16: Settings option to show large digits in widget area
|
||||
0.17: Cope with 2v10+ firmware sometimes reporting >1 step
|
||||
0.18: Adjust widget width when displaying large text
|
||||
0.19: Allow goal in large font mode
|
||||
Stop goal drawing outside widget area
|
||||
Fix issue with widget overwrite in large font mode
|
||||
Memory usage enhancements
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
onchange: (g) => {
|
||||
s.goal = g
|
||||
s.progress = !!g
|
||||
save()
|
||||
save();
|
||||
},
|
||||
},
|
||||
'Show Progress': {
|
||||
|
@ -40,7 +40,7 @@
|
|||
format: () => (s.progress ? 'Yes' : 'No'),
|
||||
onchange: () => {
|
||||
s.progress = !s.progress
|
||||
save()
|
||||
save();
|
||||
},
|
||||
},
|
||||
'Large Digits': {
|
||||
|
@ -48,7 +48,7 @@
|
|||
format: () => (s.large ? 'Yes' : 'No'),
|
||||
onchange: () => {
|
||||
s.large = !s.large
|
||||
save()
|
||||
save();
|
||||
},
|
||||
},
|
||||
'Hide Widget': {
|
||||
|
@ -56,7 +56,7 @@
|
|||
format: () => (s.hide ? 'Yes' : 'No'),
|
||||
onchange: () => {
|
||||
s.hide = !s.hide
|
||||
save()
|
||||
save();
|
||||
},
|
||||
},
|
||||
'< Back': back,
|
||||
|
|
|
@ -23,78 +23,6 @@
|
|||
return (key in settings) ? settings[key] : DEFAULTS[key];
|
||||
}
|
||||
|
||||
function drawProgress(stps) {
|
||||
if (setting('hide')) return;
|
||||
const width = 24, half = width/2;
|
||||
const goal = setting('goal'), left = Math.max(goal-stps,0);
|
||||
const c = left ? "#00f" : "#090"; // blue or dark green
|
||||
g.setColor(c).fillCircle(this.x + half, this.y + half, half);
|
||||
const TAU = Math.PI*2;
|
||||
if (left) {
|
||||
const f = left/goal; // fraction to blank out
|
||||
let p = [];
|
||||
p.push(half,half);
|
||||
p.push(half,0);
|
||||
if(f>1/8) p.push(0,0);
|
||||
if(f>2/8) p.push(0,half);
|
||||
if(f>3/8) p.push(0,width);
|
||||
if(f>4/8) p.push(half,width);
|
||||
if(f>5/8) p.push(width,width);
|
||||
if(f>6/8) p.push(width,half);
|
||||
if(f>7/8) p.push(width,0);
|
||||
p.push(half - Math.sin(f * TAU) * half);
|
||||
p.push(half - Math.cos(f * TAU) * half);
|
||||
for (let i = p.length; i; i -= 2) {
|
||||
p[i - 2] += this.x;
|
||||
p[i - 1] += this.y;
|
||||
}
|
||||
g.setColor(g.theme.bg).fillPoly(p);
|
||||
}
|
||||
}
|
||||
|
||||
// show the step count in the widget area in a readable sized font
|
||||
function draw_large(st) {
|
||||
var width = 12 * st.length;
|
||||
g.reset();
|
||||
g.clearRect(this.x, this.y, this.x + width, this.y + 16); // erase background
|
||||
g.setColor(g.theme.fg);
|
||||
g.setFont("6x8",2);
|
||||
g.setFontAlign(-1, -1);
|
||||
g.drawString(st, this.x + 4, this.y + 2);
|
||||
}
|
||||
|
||||
// draw your widget
|
||||
function draw() {
|
||||
if (setting('hide')) return;
|
||||
var width = 24;
|
||||
if (stp_today > 99999){
|
||||
stp_today = stp_today % 100000; // cap to five digits + comma = 6 characters
|
||||
}
|
||||
let stps = stp_today.toString();
|
||||
if (setting('large')) {
|
||||
draw_large.call(this, stps);
|
||||
return;
|
||||
}
|
||||
g.reset().clearRect(this.x, this.y, this.x + width, this.y + 23); // erase background
|
||||
if (setting('progress')){ drawProgress.call(this, stps); }
|
||||
g.setColor(g.theme.fg);
|
||||
if (stps.length > 3){
|
||||
stps = stps.slice(0,-3) + "," + stps.slice(-3);
|
||||
g.setFont("4x6", 1); // if big, shrink text to fix
|
||||
} else {
|
||||
g.setFont("6x8", 1);
|
||||
}
|
||||
g.setFontAlign(0, 0); // align to x: center, y: center
|
||||
g.drawString(stps, this.x+width/2, this.y+19);
|
||||
// on low bpp screens, draw 1 bit. Currently there is no getBPP so we just do it based on resolution
|
||||
g.drawImage(atob("CgoCLguH9f2/7+v6/79f56CtAAAD9fw/n8Hx9A=="),this.x+(width-10)/2,this.y+2);
|
||||
}
|
||||
|
||||
function reload() {
|
||||
loadSettings()
|
||||
draw()
|
||||
}
|
||||
|
||||
Bangle.on('step', stepCount => {
|
||||
var steps = stepCount-lastStepCount;
|
||||
if (lastStepCount===undefined || steps<0) steps=1;
|
||||
|
@ -115,11 +43,11 @@
|
|||
}
|
||||
lastUpdate = date
|
||||
//console.log("up: " + up + " stp: " + stp_today + " " + date.toString());
|
||||
if (Bangle.isLCDOn()) WIDGETS["wpedom"].draw();
|
||||
WIDGETS["wpedom"].redraw();
|
||||
});
|
||||
// redraw when the LCD turns on
|
||||
Bangle.on('lcdPower', function(on) {
|
||||
if (on) WIDGETS["wpedom"].draw();
|
||||
if (on) WIDGETS["wpedom"].redraw();
|
||||
});
|
||||
// When unloading, save state
|
||||
E.on('kill', () => {
|
||||
|
@ -134,10 +62,80 @@
|
|||
|
||||
// add your widget
|
||||
WIDGETS["wpedom"]={area:"tl",width:26,
|
||||
draw:draw,
|
||||
reload:reload,
|
||||
getSteps:()=>stp_today
|
||||
};
|
||||
redraw:function() { // work out the width, and queue a full redraw if needed
|
||||
let stps = stp_today.toString();
|
||||
let newWidth = 24;
|
||||
if (setting('hide'))
|
||||
newWidth = 0;
|
||||
else {
|
||||
if (setting('large')) {
|
||||
newWidth = 12 * stps.length + 3;
|
||||
if (setting('progress'))
|
||||
newWidth += 24;
|
||||
}
|
||||
}
|
||||
if (newWidth!=this.width) {
|
||||
// width has changed, re-layout all widgets
|
||||
this.width = newWidth;
|
||||
Bangle.drawWidgets();
|
||||
} else {
|
||||
// width not changed - just redraw
|
||||
WIDGETS["wpedom"].draw();
|
||||
}
|
||||
},
|
||||
draw:function() {
|
||||
if (setting('hide')) return;
|
||||
if (stp_today > 99999)
|
||||
stp_today = stp_today % 100000; // cap to five digits + comma = 6 characters
|
||||
let stps = stp_today.toString();
|
||||
g.reset().clearRect(this.x, this.y, this.x + this.width, this.y + 23); // erase background
|
||||
if (setting('progress')) {
|
||||
const width = 23, half = 11;
|
||||
const goal = setting('goal'), left = Math.max(goal-stps,0);
|
||||
// blue or dark green
|
||||
g.setColor(left ? "#08f" : "#080").fillCircle(this.x + half, this.y + half, half);
|
||||
if (left) {
|
||||
const TAU = Math.PI*2;
|
||||
const f = left/goal; // fraction to blank out
|
||||
let p = [];
|
||||
p.push(half,half);
|
||||
p.push(half,0);
|
||||
if(f>1/8) p.push(0,0);
|
||||
if(f>2/8) p.push(0,half);
|
||||
if(f>3/8) p.push(0,width);
|
||||
if(f>4/8) p.push(half,width);
|
||||
if(f>5/8) p.push(width,width);
|
||||
if(f>6/8) p.push(width,half);
|
||||
if(f>7/8) p.push(width,0);
|
||||
p.push(half - Math.sin(f * TAU) * half);
|
||||
p.push(half - Math.cos(f * TAU) * half);
|
||||
g.setColor(g.theme.bg).fillPoly(g.transformVertices(p,{x:this.x,y:this.y}));
|
||||
}
|
||||
g.reset();
|
||||
}
|
||||
if (setting('large')) {
|
||||
g.setFont("6x8",2);
|
||||
g.setFontAlign(-1, 0);
|
||||
g.drawString(stps, this.x + (setting('progress')?28:4), this.y + 12);
|
||||
} else {
|
||||
let w = 24;
|
||||
if (stps.length > 3){
|
||||
stps = stps.slice(0,-3) + "," + stps.slice(-3);
|
||||
g.setFont("4x6", 1); // if big, shrink text to fix
|
||||
} else {
|
||||
g.setFont("6x8", 1);
|
||||
}
|
||||
g.setFontAlign(0, 0); // align to x: center, y: center
|
||||
g.drawString(stps, this.x+w/2, this.y+19);
|
||||
g.drawImage(atob("CgoCLguH9f2/7+v6/79f56CtAAAD9fw/n8Hx9A=="),this.x+(w-10)/2,this.y+2);
|
||||
}
|
||||
},
|
||||
reload:function() {
|
||||
loadSettings();
|
||||
WIDGETS["wpedom"].redraw();
|
||||
},
|
||||
getSteps:()=>stp_today
|
||||
};
|
||||
// Load data at startup
|
||||
let pedomData = require("Storage").readJSON(PEDOMFILE,1);
|
||||
if (pedomData) {
|
||||
|
|
2
core
2
core
|
@ -1 +1 @@
|
|||
Subproject commit 2aac601e38d659876eb7db5aebc7a12dd3c39da7
|
||||
Subproject commit 0fd608f085deff9b39f2db3559ecc88edb232aba
|
Loading…
Reference in New Issue