1
0
Fork 0
Danny 2022-02-04 00:55:04 +01:00
commit afd46a389a
32 changed files with 538 additions and 197 deletions

View File

@ -5,3 +5,4 @@
0.04: Android icon now goes to settings page with 'find phone'
0.05: Fix handling of message actions
0.06: Option to keep messages after a disconnect (default false) (fix #1186)
0.07: Include charging state in battery updates to phone

View File

@ -50,8 +50,9 @@
};
// Battery monitor
function sendBattery() { gbSend({ t: "status", bat: E.getBattery() }); }
function sendBattery() { gbSend({ t: "status", bat: E.getBattery(), chg: Bangle.isCharging()?1:0 }); }
NRF.on("connect", () => setTimeout(sendBattery, 2000));
Bangle.on("charging", sendBattery);
if (!settings.keep)
NRF.on("disconnect", () => require("messages").clearAll()); // remove all messages on disconnect
setInterval(sendBattery, 10*60*1000);

View File

@ -2,7 +2,7 @@
"id": "android",
"name": "Android Integration",
"shortName": "Android",
"version": "0.06",
"version": "0.07",
"description": "Display notifications/music/etc sent from the Gadgetbridge app on Android. This replaces the old 'Gadgetbridge' Bangle.js widget.",
"icon": "app.png",
"tags": "tool,system,messages,notifications,gadgetbridge",

View File

@ -26,3 +26,4 @@
0.24: tag HRM power requests to allow this to work alongside other widgets/apps (fix #799)
0.25: workaround call notification
Fix inflated step number
0.26: Include charging status in battery updates to phone

View File

@ -11,11 +11,12 @@ t can be one of "info", "warn", "error"
## report battery level
```
{ "t": "status", "bat": 30, "volt": 30 }
{ "t": "status", "bat": 30, "volt": 30, "chg": 0 }
```
* bat is in range 0 to 100
* volt is optional and should be greater than 0
* chg is optional and should be either 0 or 1 to indicate the watch is charging
## find phone

View File

@ -1,7 +1,7 @@
{
"id": "gbridge",
"name": "Gadgetbridge",
"version": "0.25",
"version": "0.26",
"description": "(NOT RECOMMENDED) Displays Gadgetbridge notifications from Android. Please use the 'Android' Bangle.js app instead.",
"icon": "app.png",
"type": "widget",

View File

@ -256,7 +256,7 @@
}
function sendBattery() {
gbSend({ t: "status", bat: E.getBattery() });
gbSend({ t: "status", bat: E.getBattery(), chg: Bangle.isCharging()?1:0 });
}
// Send a summary of activity to Gadgetbridge
@ -268,6 +268,7 @@
// Battery monitor
NRF.on("connect", () => setTimeout(sendBattery, 2000));
Bangle.on("charging", sendBattery);
setInterval(sendBattery, 10*60*1000);
sendBattery();
// Activity monitor

View File

@ -9,3 +9,4 @@
0.08: Suppress bleed through of E.showMenu's when displaying bar charts
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

View File

@ -34,6 +34,11 @@ writes data to a binary file (one per month).
A library (that can be used with `require("health").readXYZ` can then be used
to grab historical health info.
`boot.js` and `lib.js` include some constants that don't get inlined by the simple
minifier used in the App Loader, so we use the closure compiler to pre-minify them.
The easiest way to use it is to install `https://github.com/espruino/EspruinoDocs`
and run `EspruinoDocs/bin/minify.js lib.js lib.min.js`
## TODO
* `interface` page for desktop to allow data to be viewed and exported in common formats

4
apps/health/boot.min.js vendored Normal file
View File

@ -0,0 +1,4 @@
(function(){var a=0|(require("Storage").readJSON("health.json",1)||{}).hrm;if(1==a||2==a){function f(){Bangle.setHRMPower(1,"health");setTimeout(()=>Bangle.setHRMPower(0,"health"),6E4*a);if(1==a)for(var b=1;2>=b;b++)setTimeout(()=>{Bangle.setHRMPower(1,"health");setTimeout(()=>{Bangle.setHRMPower(0,"health")},2E5*b+6E4)},2E5*b)}Bangle.on("health",f);Bangle.on("HRM",b=>{80<b.confidence&&Bangle.setHRMPower(0,"health")});Bangle.getHealthStatus().bpmConfidence||f()}else Bangle.setHRMPower(0!=
a,"health")})();Bangle.on("health",a=>{function f(c){return String.fromCharCode(c.steps>>8,c.steps&255,c.bpm,Math.min(c.movement/8,255))}var b=new Date(Date.now()-59E4),e=function(c){return 145*(c.getDate()-1)+6*c.getHours()+(0|6*c.getMinutes()/60)}(b);b=function(c){return"health-"+c.getFullYear()+"-"+(c.getMonth()+1)+".raw"}(b);var g=require("Storage").read(b);if(g){var d=g.substr(8+4*e,4);if("\u00ff\u00ff\u00ff\u00ff"!=d){print("HEALTH ERR: Already written!");return}}else require("Storage").write(b,
"HEALTH1\x00",0,17988);var h=8+4*e;require("Storage").write(b,f(a),h,17988);if(143==e%145)if(e=h+4,"\u00ff\u00ff\u00ff\u00ff"!=g.substr(e,4))print("HEALTH ERR: Daily summary already written!");else{a={steps:0,bpm:0,movement:0,movCnt:0,bpmCnt:0};for(var k=0;144>k;k++)d=g.substr(h,4),"\u00ff\u00ff\u00ff\u00ff"!=d&&(a.steps+=(d.charCodeAt(0)<<8)+d.charCodeAt(1),a.movement+=d.charCodeAt(2),a.movCnt++,d=d.charCodeAt(2),a.bpm+=d,d&&a.bpmCnt++),h-=4;a.bpmCnt&&(a.bpm/=a.bpmCnt);a.movCnt&&(a.movement/=a.movCnt);
require("Storage").write(b,f(a),e,17988)}})

3
apps/health/lib.min.js vendored Normal file
View File

@ -0,0 +1,3 @@
function h(a){return"health-"+a.getFullYear()+"-"+(a.getMonth()+1)+".raw"}function k(a){return 145*(a.getDate()-1)+6*a.getHours()+(0|6*a.getMinutes()/60)}exports.readAllRecords=function(a,f){a=h(a);a=require("Storage").read(a);if(void 0!==a)for(var c=8,d=0;31>d;d++){for(var b=0;24>b;b++)for(var e=0;6>e;e++){var g=a.substr(c,4);"\u00ff\u00ff\u00ff\u00ff"!=g&&f({day:d+1,hr:b,min:10*e,steps:g.charCodeAt(0)<<8|g.charCodeAt(1),bpm:g.charCodeAt(2),movement:g.charCodeAt(3)});c+=
4}c+=4}};exports.readDailySummaries=function(a,f){k(a);a=h(a);a=require("Storage").read(a);if(void 0!==a)for(var c=584,d=0;31>d;d++){var b=a.substr(c,4);"\u00ff\u00ff\u00ff\u00ff"!=b&&f({day:d+1,steps:b.charCodeAt(0)<<8|b.charCodeAt(1),bpm:b.charCodeAt(2),movement:b.charCodeAt(3)});c+=580}};exports.readDay=function(a,f){k(a);var c=h(a);c=require("Storage").read(c);if(void 0!==c){a=8+580*(a.getDate()-1);for(var d=0;24>d;d++)for(var b=0;6>b;b++){var e=c.substr(a,4);"\u00ff\u00ff\u00ff\u00ff"!=e&&f({hr:d,
min:10*b,steps:e.charCodeAt(0)<<8|e.charCodeAt(1),bpm:e.charCodeAt(2),movement:e.charCodeAt(3)});a+=4}}}

View File

@ -1,7 +1,7 @@
{
"id": "health",
"name": "Health Tracking",
"version": "0.10",
"version": "0.11",
"description": "Logs health data and provides an app to view it (requires firmware 2v10.100 or later)",
"icon": "app.png",
"tags": "tool,system,health",
@ -11,7 +11,7 @@
"storage": [
{"name":"health.app.js","url":"app.js"},
{"name":"health.img","url":"app-icon.js","evaluate":true},
{"name":"health.boot.js","url":"boot.js"},
{"name":"health","url":"lib.js"}
{"name":"health.boot.js","url":"boot.min.js"},
{"name":"health","url":"lib.min.js"}
]
}

View File

@ -6,3 +6,4 @@
0.06: Fix (not) popupping up old messages
0.07: Added more details from music (instead of Undefined), added more app identifiers
0.08: Added more app identifiers, added 'cannot display' in case a message goes empty because of replacements
0.09: Enable 'ams' on new firmwares (ams/ancs can now be enabled individually) (fix #1365)

View File

@ -1,4 +1,5 @@
bleServiceOptions.ancs = true;
if (NRF.amsIsActive) bleServiceOptions.ams = true; // amsIsActive was added at the same time as the "am" option
Bangle.ancsMessageQueue = [];
/* Handle ANCS events coming in, and fire off 'notify' events

View File

@ -1,7 +1,7 @@
{
"id": "ios",
"name": "iOS Integration",
"version": "0.08",
"version": "0.09",
"description": "Display notifications/music/etc from iOS devices",
"icon": "app.png",
"tags": "tool,system,ios,apple,messages,notifications",

1
apps/lazybones/ChangeLog Normal file
View File

@ -0,0 +1 @@
0.01: first release

45
apps/lazybones/README.md Normal file
View File

@ -0,0 +1,45 @@
# Lazybones
'Warns when you have been sat still for too long.'
![](screenshot_lazybones2.png)
![](screenshot_lazybones.png)
- Spending too much time sat down is destructive to our health and fitness.
- Lazy bones checks the step count every minute and if this
has not changed after 26 minutes the buzzer will sound and a pop up
screen will show.
- It gives 3 warnings before giving up
- Standing up and walking around until the step counting threshold is reached will automatically dismiss the warning.
- When the warning is not displaying the apps is a simple clock
- The timer only goes off between the hours 9am to 9pm.
- The app is a basic proof of concept that can be used in other clocks
- A settings menu may be added in a future release
## Dedication
This is app is dedicated in memory of my friend, Huw Evans 1960-2019,
poet, writer, actor, archiologist, technical author, husband, father,
friend.
In May 2017, Huw Evans received a terminal cancer diagnosis. [Not
Long Now](https://www.youtube.com/watch?v=HD_Xysb6ZEA) is his
response to that diagnosis and the drastic shortening of his life
expectancy. Not Long Now is a one-man show, which uses poetry,
story-telling, puppetry and video to address one basic question:
given we are all going to die, how then shall we live?
## Why the Skull ?
![](lazybones.png)
The Skull is a [Memento
mori](https://en.wikipedia.org/wiki/Memento_mori) (Latin for
'remember that you [have to] die') is an artistic or symbolic trope
acting as a reminder of the inevitability of death.
Let us choose not to die from sitting too long.
Written by: [Hugh Barney](https://github.com/hughbarney) For support and discussion please post in the [Bangle JS Forum](http://forum.espruino.com/microcosms/1424/)

View File

@ -0,0 +1,204 @@
Graphics.prototype.setFontRoboto = function(scale) {
// Actual height 21 (20 - 0)
this.setFontCustom(atob("AAAAAAAAAAAAAAAAAAAAAAAAH/zA/+YAAAAAAAHwAAwAAHwAA+AAAAAAAAAAAQACDAAYbADP4B/8A/zAGYZADH4A/+A/7AHYYADCAAAAAAAQAeHgH4eBzgwMMHnhw88GGBw4wHj+AcPgAAAAAAAAAAB4AA/gAGMAAwhwGMcAfuABzgABzgAc+AOMYBhBAAMYAB/AAHwAAAAAHwD5+A/8YGPDAw8YGPzA/HYD4fAADwAB/AAOYAABAAAAHwAA4AAAAAAAAAAH/gD//B8A+cAA7AADAAAAAAAYAAbwAHHgHwf/4A/8AAAAEAABiAAGwAA8AA/AAH+AAGwAByAAEAAAAAAAMAABgAAMAABgAH/wA/+AAMAABgAAMAABgAAAAAAAIAAfAADwAAAABgAAMAABgAAMAABgAAAAAAAAAAAAADAAAYAAAAAAAAADgAB8AB+AA+AA+AA/AAHAAAgAAAAAAB8AB/8Af/wHAHAwAYGADAwAYHAHAf/wB/8AAAAAAAAAAABgAAcAADAAAYAAH//A//4AAAAAAAAAAAAAAAAAAAAABwDAeA4HAPAwHYGBzAwcYHHDAfwYB8DAAAYAAAAAAABgOAcBwHADAwwYGGDAwwYHPHAf/wB58AAAAAAAAADAAB4AAfAAPYAHjAB4YA8DAH//A//4AAYAADAAAAAAAAAEMA/xwH+HAxgYGMDAxgYGODAw/4GD+AAHAAAAAAAAAf8AP/wD2HA5wYGMDAxgYGOHAA/wAD8AAAAAAAAAAAGAAAwAAGADAwB4GB+Aw+AGfAA/gAHwAAwAAAAAAADAB5+Af/wHPDAwwYGGDAwwYHPHAfvwB58AAAAAAAAAAAB+AAf4AHDjAwMYGBjAwM4HDOAf/gB/4AAAAAAAAAAAAYDADAYAAAAAAAAAAYDAfAYHwAAAABAAAcAADgAA+AAGwAB3AAMYABjgAYMAAAAAAAAAAAAAAABmAAMwABmAAMwABmAAMwABmAAMwAAiAAAAAAAAAYMADjgAMYAB3AAGwAA2AADgAAcAABAAAAAAAAAMAADgAA4AAGBzAweYGHAA/wAD8AAEAAAAwAB/4A/PwOAGDgAYYPxmH/Mw4ZmMDMxgZmM+Mx/5mHDAYAIDgDAPBwAf8AAMAAAAAAAYAAfAAPwAP4AH+AH4wA8GAH4wAP2AAPwAAfwAAfAAAYAAAAAAAAAAA//4H//AwwYGGDAwwYGGDAwwYH/HAf/wB58AAAAADAAH/AD/+AcBwHADAwAYGADAwAYGADA4A4DweAODgAAAAAAAAAAAAAAH//A//4GADAwAYGADAwAYGADAYAwD4+AP/gAfwAAAAAAAAAAAH//A//4GDDAwYYGDDAwYYGDDAwYYGCDAgAYAAAAAAAH//A//4GDAAwYAGDAAwYAGDAAwYAGAAAAAAAAAAH/AD/8AcBwHAHAwAYGADAwYYGDDA4YYDz/AOfwAAAAAAAAAAA//4H//A//4ADAAAYAADAAAYAADAAAYAADAA//4H//AAAAAAAAAAAAAAA//4H//AAAAAAAAABAAAeAAB4AADAAAYAADAAAYAAHA//wH/8AAAAAAAAAAAAAAA//4H//AAcAAPAAD4AA/wAOPADg8A4B4GAHAgAYAAAAAAAH//A//4AADAAAYAADAAAYAADAAAYAADAAAAAAAA//4H//A+AAB+AAD8AAD8AAH4AAPAAH4AH4AD8AD8AA+AAH//A//4AAAAAAAH//A//4H//AeAAB8AADwAAPgAAeAAA8AADwH//A//4AAAAAAAAAAAH/AB/8AeDwHAHAwAYGADAwAYGADA4A4DweAP/gA/4AAAAAAAAAAAH//A//4GBgAwMAGBgAwMAGBgAwcAH/AAfwAA8AAAAAA/4AP/gDgOA4A4GADAwAYGADAwAYHAHgeD+B/8wD+GAAAAAAAAAAA//4H//AwYAGDAAwYAGDgAweAHH8Afz4B8HAAAIAAYAPDwD8OA5w4GGDAwwYGHDAwYYHDnAePwBw8AAAAGAAAwAAGAAAwAAGAAA//4H//AwAAGAAAwAAGAAAwAAAAAAAAAH/4A//wAAPAAAYAADAAAYAADAAAYAAPA//wH/8AAAAAAAAgAAHAAA/AAB/AAD+AAD+AAD4AAfAAfwAfwAfwAH4AA4AAEAAA+AAH/AAH/gAD/AAD4AD+AH+AH8AA+AAH+AAD+AAD/AAD4AH/AP/AH+AA8AAAAAAAAAGADA4A4HweAPPgA/wAB8AAfwAPvgDweA8B4GADAAAIGAAA4AAHwAAPgAAfAAA/4AH/AD4AB8AA+AAHgAAwAAAAAAAAAGADAwB4GAfAwPYGDzAx4YGeDA/AYHwDA4AYGADAAAAAAAA///3//+wAA2AAGAAAGAAA+AAD8AAD8AAD4AAH4AAHgAAMAAAAwAA2AAG///3//+AAAAAAAAAAAOAAHwAD4AA8AAD8AADwAAGAAAAAAABgAAMAABgAAMAABgAAMAABgAAMAABgAAAEAAAwAADAAAIAAAAAAAAAAEeABn4Ad3ADMYAZjADMYAZmAB/4AP/AAAAAAAA//4H//ABgwAYDADAYAYDADg4AP+AA/gABwAAAAAAAAA/gAP+ADg4AYDADAYAYDADAYAOOABxwAAAAAEAAH8AB/wAcHADAYAYDADAYAcDA//4H//AAAAAAAAAAAAH8AB/wAdnADMYAZjADMYAZjAB84AHmAAMAAMAABgAB//gf/8HMAAxgAGIAAAAAAH8IB/zAcHMDAZgYDMDAZgcHcD//Af/wAAAAAAAAAAH//A//4AMAADAAAYAADAAAcAAD/4AP/AAAAAAAAAAAGf/Az/4AAAAAAAAAAMz//mf/4AAAAAAAAAAH//A//4ABwAAeAAH4ABzwAcPACAYAABAAAAAAAA//4H//AAAAAAAAAAAAf/AD/4AMAADAAAYAADAAAcAAD/4AP/ABgAAYAADAAAYAADgAAP/AA/4AAAAAAAAf/AD/4AMAADAAAYAADAAAcAAD/4AP/AAAAAAAAAAAAH8AB/wAcHADAYAYDADAYAYDADx4AP+AA/gAAAAAAAAf/8D//gYDADAYAYDADAYAcHAB/wAH8AAEAAAAAAEAAH8AB/wAcHADAYAYDADAYAYDAD//gf/8AAAAAAAAAAAf/AD/4AcAADAAAYAACAAAAEAB5wAfnADMYAZjADGYAYzADn4AOeAAAAAAAADAAAYAAf/wD//ADAYAYDAAAAAAAAD/gAf/AAA4AADAAAYAADAAAwAf/AD/4AAAAAAAAYAAD4AAP4AAP4AAPAAH4AH4AD8AAcAAAAAAQAADwAAf4AAf4AAPAAP4AP4ADwAAfgAA/gAA/AAD4AH+AD+AAeAAAAAAAAACAYAcHADzwAH8AAfAAH8ADx4AcHACAIAcAMD4BgP4MAP/AAPwAP4AP4AD4AAcAAAAAAAAADAYAYHADD4AY7ADOYAfjADwYAcDADAYAAAAADAAA4AH//B/v8cABzAACAAAH//w//+AAAAAAACAACcAAx/n+H//AA4AAHAAAAAAAAAAAAAOAADgAAYAADAAAcAABgAAGAAAwAAGAADwAAcAAAAA"), 32, atob("BQUHDQwPDQQHBwkMBAYGCQwMDAwMDAwMDAwFBAsMCwoTDg0ODgwMDg8GDA0LEg8ODQ4NDA0ODRMNDQ0GCQYJCQYLDAsMCwcMDAUFCwUSDAwMDAcLBwwKEAoKCgcFBw4A"), 21+(scale<<8)+(1<<16));
return this;
}
function setSmallFont() {
g.setFontRoboto();
}
const h = g.getHeight();
const w = g.getWidth();
function draw() {
if (!idle)
drawClock();
else
drawIdle();
queueDraw();
}
function drawClock() {
var date = new Date();
var timeStr = require("locale").time(date,1);
g.reset();
g.setColor(g.theme.bg);
g.fillRect(Bangle.appRect);
g.setFont('Vector', w/3);
g.setFontAlign(0, 0);
g.setColor(g.theme.fg);
g.drawString(timeStr, w/2, h/2);
setSmallFont();
g.drawString('Last Step ' + lastStepTime, w/2, 3*h/4);
}
///////////////// IDLE TIMER /////////////////////////////////////
function log_debug(o) {
//print(o);
}
// variable for controlling idle alert
let lastStep = getTime();
let lastStepTime = '??';
let warned = 0;
let idle = false;
let IDLE_MINUTES = 26;
function drawIdle() {
let mins = Math.round((getTime() - lastStep) / 60);
g.reset();
g.setColor(g.theme.bg);
g.fillRect(Bangle.appRect);
g.setColor(g.theme.fg);
setSmallFont();
g.setFontAlign(0, 0);
g.drawString('Last step was', w/2, (h/3));
g.drawString(mins + ' minutes ago', w/2, 20+(h/3));
dismissBtn.draw();
}
/////////////// BUTTON CLASS ///////////////////////////////////////////
// simple on screen button class
function BUTTON(name,x,y,w,h,c,f,tx) {
this.name = name;
this.x = x;
this.y = y;
this.w = w;
this.h = h;
this.color = c;
this.callback = f;
this.text = tx;
}
// if pressed the callback
BUTTON.prototype.check = function(x,y) {
//console.log(this.name + ":check() x=" + x + " y=" + y +"\n");
if (x>= this.x && x<= (this.x + this.w) && y>= this.y && y<= (this.y + this.h)) {
log_debug(this.name + ":callback\n");
this.callback();
return true;
}
return false;
};
BUTTON.prototype.draw = function() {
g.setColor(this.color);
g.fillRect(this.x, this.y, this.x + this.w, this.y + this.h);
g.setColor("#000"); // the icons and boxes are drawn black
setSmallFont();
g.setFontAlign(0, 0);
g.drawString(this.text, (this.x + this.w/2), (this.y + this.h/2));
g.drawRect(this.x, this.y, (this.x + this.w), (this.y + this.h));
};
function dismissPrompt() {
idle = false;
warned = false;
lastStep = getTime();
Bangle.buzz(100);
draw();
}
var dismissBtn = new BUTTON("big",0, 3*h/4 ,w, h/4, "#0ff", dismissPrompt, "Dismiss");
Bangle.on('touch', function(button, xy) {
if (idle && dismissBtn.check(xy.x, xy.y)) return;
});
// if we get a step then we are not idle
Bangle.on('step', s => {
setLastStepTime();
lastStep = getTime();
// redraw if we had been idle
if (idle == true) {
dismissPrompt();
}
idle = false;
warned = 0;
});
function setLastStepTime() {
var date = new Date();
lastStepTime = require("locale").time(date,1);
}
function checkIdle() {
let hour = (new Date()).getHours();
let active = (hour >= 9 && hour < 21);
//let active = true;
let dur = getTime() - lastStep;
if (active && dur > IDLE_MINUTES * 60) {
drawIdle();
if (warned++ < 3) {
buzzer(warned);
log_debug("checkIdle: warned=" + warned);
Bangle.setLocked(false);
}
idle = true;
} else {
idle = false;
warned = 0;
}
}
setLastStepTime();
// timeout for multi-buzzer
var buzzTimeout;
// n buzzes
function buzzer(n) {
log_debug("buzzer n=" + n);
if (n-- < 1) return;
Bangle.buzz(250);
if (buzzTimeout) clearTimeout(buzzTimeout);
buzzTimeout = setTimeout(function() {
buzzTimeout = undefined;
buzzer(n);
}, 500);
}
///////////////////////////////////////////////////////////////////////////////
// timeout used to update every minute
var drawTimeout;
const DRAW_PERIOD = 60000;
// schedule a draw for the next minute
function queueDraw() {
if (drawTimeout) clearTimeout(drawTimeout);
drawTimeout = setTimeout(function() {
drawTimeout = undefined;
checkIdle();
draw();
}, DRAW_PERIOD - (Date.now() % DRAW_PERIOD));
}
// Stop updates when LCD is off, restart when on
Bangle.on('lcdPower',on=>{
if (on) {
draw(); // draw immediately, queue redraw
} else { // stop draw timer
if (drawTimeout) clearTimeout(drawTimeout);
drawTimeout = undefined;
}
});
g.clear();
// Show launcher when middle button pressed
Bangle.setUI("clock");
Bangle.loadWidgets();
Bangle.drawWidgets();
draw();

View File

@ -0,0 +1 @@
require("heatshrink").decompress(atob("mEwgIEBn/8BIUD///4AFBh/AgfwAoM8AQlwAQMOgEB8AFBg+AgeAAoMBDQIxD4EGAodghg9EAosYAocYApcwAocMAshgBLwIFBg/4j/ghkxh0cnFwxkZxgOBmOYjcYg1gjHYAosPAofwhwFDuEGAodgAoIjBAoYvBAoUP/Of+AFBg/j4/gAoLGBYgNgU4IjBU4MBwEOuADBgHwhuwh5nBvEP+EeAoMcg/gnBzCWQQCBggCBkACBZgQqBAo0HAQLsCIAJCCAAP//6eDn/8AYI"))

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -0,0 +1,16 @@
{
"id": "lazybones",
"name": "Lazybones",
"version": "0.01",
"description": "Idleness timer, warns when you have been sat too long",
"icon": "lazybones.png",
"screenshots": [{"url":"screenshot_lazybones.png"}],
"readme": "README.md",
"type": "clock",
"tags": "clock",
"supports": ["BANGLEJS","BANGLEJS2"],
"storage": [
{"name":"lazybones.app.js","url":"lazybones.app.js"},
{"name":"lazybones.img","url":"lazybones.icon.js","evaluate":true}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

@ -11,3 +11,5 @@
0.07: Add recording for Barometer
Record all HRM events
Move recording for CoreTemp to its own app
0.08: Memory usage improvements for recorder app itself
0.09: Show correct number for log in overwrite prompt

View File

@ -95,6 +95,7 @@ function showMainMenu() {
Object.keys(recorders).forEach(id=>{
mainmenu["Log "+recorders[id]().name] = menuRecord(id);
});
delete recorders;
return E.showMenu(mainmenu);
}
@ -217,12 +218,8 @@ function viewTrack(filename, info) {
});
};
menu['< Back'] = () => { viewTracks(); };
return E.showMenu(menu);
}
function plotTrack(info) {
"ram"
function plotTrack(info) { "ram"
function distance(lat1,long1,lat2,long2) { "ram"
var x = (long1-long2) * Math.cos((lat1+lat2)*Math.PI/360);
var y = lat2 - lat1;
@ -316,8 +313,7 @@ function plotTrack(info) {
g.flip();
}
function plotGraph(info, style) {
"ram"
function plotGraph(info, style) { "ram"
E.showMenu(); // remove menu
E.showMessage("Calculating...","Track "+info.fn);
var filename = info.filename;
@ -415,4 +411,8 @@ function plotGraph(info, style) {
g.flip();
}
return E.showMenu(menu);
}
showMainMenu();

View File

@ -1,8 +1,8 @@
{
"id": "recorder",
"name": "Recorder (BETA)",
"name": "Recorder",
"shortName": "Recorder",
"version": "0.07",
"version": "0.09",
"description": "Record GPS position, heart rate and more in the background, then download to your PC.",
"icon": "app.png",
"tags": "tool,outdoors,gps,widget",

View File

@ -228,7 +228,7 @@
},setRecording:function(isOn) {
var settings = loadSettings();
if (isOn && !settings.recording && require("Storage").list(settings.file).length)
return E.showPrompt("Overwrite\nLog 0?",{title:"Recorder",buttons:{Yes:"yes",No:"no"}}).then(selection=>{
return E.showPrompt("Overwrite\nLog " + settings.file.match(/\d+/)[0] + "?",{title:"Recorder",buttons:{Yes:"yes",No:"no"}}).then(selection=>{
if (selection=="no") return false; // just cancel
if (selection=="yes") require("Storage").open(settings.file,"r").erase();
// TODO: Add 'new file' option

View File

@ -3,3 +3,5 @@
The simplest working clock, acts as a tutorial piece
![](screenshot.jpg)
Written by: [Hugh Barney](https://github.com/hughbarney) For support and discussion please post in the [Bangle JS Forum](http://forum.espruino.com/microcosms/1424/)

View File

@ -1,2 +1,3 @@
0.01: New App!
0.02: Change start sequence to BTN1/3/1/3 to avoid accidental turning on (fix #342)
0.03: Add Color Changing Settings

View File

@ -1,6 +1,16 @@
const SETTINGS_FILE = "torch.json";
let settings;
function loadSettings() {
settings = require("Storage").readJSON(SETTINGS_FILE,1)|| {'bg': '#FFFFFF', 'color': 'White'};
}
loadSettings();
Bangle.setLCDPower(1);
Bangle.setLCDTimeout(0);
g.reset();
g.setColor(settings.bg);
g.fillRect(0,0,g.getWidth(),g.getHeight());
// Any button turns off
setWatch(()=>load(), BTN1);

View File

@ -2,14 +2,15 @@
"id": "torch",
"name": "Torch",
"shortName": "Torch",
"version": "0.02",
"description": "Turns screen white to help you see in the dark. Select from the launcher or press BTN1,BTN3,BTN1,BTN3 quickly to start when in any app that shows widgets",
"version": "0.03",
"description": "Turns screen white to help you see in the dark. Select from the launcher or press BTN1,BTN3,BTN1,BTN3 quickly to start when in any app that shows widgets. You can also set the color through the apps settings menu.",
"icon": "app.png",
"tags": "tool,torch",
"supports": ["BANGLEJS"],
"storage": [
{"name":"torch.app.js","url":"app.js"},
{"name":"torch.wid.js","url":"widget.js"},
{"name":"torch.img","url":"app-icon.js","evaluate":true}
{"name":"torch.img","url":"app-icon.js","evaluate":true},
{"name":"torch.settings.js","url":"settings.js"}
]
}

38
apps/torch/settings.js Normal file
View File

@ -0,0 +1,38 @@
(function(back) {
const SETTINGS_FILE = "torch.json";
// initialize with default settings...
let s = {'bg': '#FFFFFF', 'color': 'White'}
// ...and overwrite them with any saved values
// This way saved values are preserved if a new version adds more settings
const storage = require('Storage')
let settings = storage.readJSON(SETTINGS_FILE, 1) || s;
const saved = settings || {}
for (const key in saved) {
s[key] = saved[key]
}
function save() {
settings = s
storage.write(SETTINGS_FILE, settings)
}
var color_options = ['Green','Orange','Cyan','Purple','Red','Blue','Yellow','White'];
var bg_code = ['#0f0','#FFA500','#0ff','#f0f','#f00','#00f','#ffef00','#FFFFFF'];
E.showMenu({
'': { 'title': 'Torch' },
'< Back': back,
'Colour': {
value: 0 | color_options.indexOf(s.color),
min: 0, max: 7,
format: v => color_options[v],
onchange: v => {
s.color = color_options[v];
s.bg = bg_code[v];
save();
},
}
});
})