Fixes, README and alarm lib

pull/1661/head
Gordon Williams 2022-03-31 15:32:26 +01:00
parent 0feebdb318
commit 9055cd7990
7 changed files with 135 additions and 14 deletions

View File

@ -14,3 +14,4 @@
0.13: Alarm widget state now updates when setting/resetting an alarm
0.14: Order of 'back' menu item
0.15: Fix hour/minute wrapping code for new menu system
0.16: Adding alarm library

70
apps/alarm/README.md Normal file
View File

@ -0,0 +1,70 @@
Default Alarm & Timer
======================
This provides an app, widget, library and tools for alarms and timers.
Other apps can use this to provide alarm functionality.
App
---
The Alarm app allows you to add/modify any running timers.
Internals / Library
-------------------
Alarms are stored in an array in `alarm.json`, and take the form:
```
{
id : "mytimer", // optional ID for this alarm/timer, so apps can easily find *their* timers
on : true, // is the alarm enabled?
t : 23400000, // Time of day since midnight in ms
msg : "Eat chocolate", // message to display
last : 0, // last day of the month we alarmed on - so we don't alarm twice in one day!
rp : true, // repeat
as : false, // auto snooze
timer : 5*60*1000, // OPTIONAL - if set, this is a timer and it's the time in ms
js : "load('myapp.js')" // OPTIONAL - a JS command to execute when the alarm activates (*instead* of loading 'alarm.js')
// when this code is run, you're responsible for setting alarm.on=false (or removing the alarm)
}
```
The [`alarm` library](https://github.com/espruino/BangleApps/blob/master/apps/alarm/lib.js) contains
a few helpful functions for getting/setting alarms, but is intentionally sparse so as not to
use too much RAM.
It can be used as follows:
```
// add/update an existing alarm
require("alarm").setAlarm("mytimer", {
msg : "Wake up",
timer : 10*60*1000, // 10 Minutes
});
// Ensure the widget and alarm timer updates to schedule the new alarm properly
require("alarm").reload();
// Get the time to the next alarm for us
var timeToNext = require("alarm").getTimeToAlarm(require("alarm").getAlarm("mytimer"));
// timeToNext===undefined if no alarm or alarm disabled
// delete an alarm
require("alarm").setAlarm("mytimer", undefined);
// reload after deleting...
require("alarm").reload();
// Or add an alarm that runs your own code - in this case
// loading the settings app. The alarm will not be removed/stopped
// automatically.
require("alarm").setAlarm("customrunner", {
js : "load('setting.app.js')",
timer : 1*60*1000, // 1 Minute
});
```
If your app requires alarms, you can specify that the alarms app needs to
be installed by adding `"dependencies": {"alarm":"app"},` to your metadata.

View File

@ -3,13 +3,16 @@ Bangle.drawWidgets();
var alarms = require("Storage").readJSON("alarm.json",1)||[];
/*alarms = [
{ on : true,
t : 23400000, // Time of day since midnight in ms
msg : "Eat chocolate",
last : 0, // last day of the month we alarmed on - so we don't alarm twice in one day!
rp : true, // repeat
as : false, // auto snooze
{
id : "mytimer", // optional ID for this alarm/timer, so apps can easily find *their* timers
on : true, // is the alarm enabled?
t : 23400000, // Time of day since midnight in ms
msg : "Eat chocolate", // message to display
last : 0, // last day of the month we alarmed on - so we don't alarm twice in one day!
rp : true, // repeat
as : false, // auto snooze
timer : 5*60*1000, // OPTIONAL - if set, this is a timer and it's the time in ms
js : "load('myapp.js')" // OPTIONAL - a JS command to execute when the alarm activates (*instead* of loading 'alarm.js')
}
];*/
@ -41,7 +44,7 @@ function getCurrentTime() {
function saveAndReload() {
require("Storage").write("alarm.json",JSON.stringify(alarms));
eval(require("Storage").read("alarm.boot.js"));
require("alarm").reload();
}
function showMainMenu() {
@ -185,7 +188,7 @@ function editTimer(alarmIndex, alarm) {
};
menu[/*LANG*/"Save"] = function() {
a.timer = encodeTime(t);
a.hr = getCurrentTime() + a.timer;
a.t = getCurrentTime() + a.timer;
if (newAlarm) alarms.push(a);
else alarms[alarmIndex] = a;
saveAndReload();

View File

@ -20,10 +20,9 @@
/* execute alarm at the correct time. We avoid execing immediately
since this code will get called AGAIN when alarm.js is loaded. alarm.js
will then clearInterval() to get rid of this call so it can proceed
normally. */
Bangle.ALARM = setTimeout(function() {
load("alarm.js");
},t);
normally.
If active[0].js is defined, just run that code as-is and not alarm.js */
Bangle.ALARM = setTimeout(active[0].js||'load("alarm.js")',t);
}
} else { // check for new alarms at midnight (so day of week works)
Bangle.ALARM = setTimeout(() => {

45
apps/alarm/lib.js Normal file
View File

@ -0,0 +1,45 @@
// Return an array of all alarms
exports.getAlarms = function() {
return require("Storage").readJSON("alarm.json",1)||[];
};
// Return an alarm object based on ID
exports.getAlarm = function(id) {
var alarms = require("Storage").readJSON("alarm.json",1)||[];
return alarms.find(a=>a.id==id);
};
// Set an alarm object based on ID. Leave 'alarm' undefined to remove it
exports.setAlarm = function(id, alarm) {
var alarms = require("Storage").readJSON("alarm.json",1)||[];
alarms = alarms.filter(a=>a.id!=id);
if (alarm !== undefined) {
alarm.id = id;
if (alarm.dow===undefined) alarm.dow = 0b1111111;
if (alarm.on!==false) alarm.on=true;
if (alarm.timer) { // if it's a timer, set the start time as a time from *now*
var time = new Date();
var currentTime = (time.getHours()*3600000)+(time.getMinutes()*60000)+(time.getSeconds()*1000);
alarm.t = currentTime + alarm.timer;
}
}
alarms.push(alarm);
require("Storage").writeJSON("alarm.json", alarms);
};
/// Get time until the given alarm (object). Return undefined if alarm not enabled, or if 86400000 or more, alarm could me *more* than a day in the future
exports.getTimeToAlarm = function(alarm, time) {
if (!alarm) return undefined;
if (!time) time = new Date();
var active = alarm.on && (alarm.dow>>time.getDay())&1;
if (!active) return undefined;
var currentTime = (time.getHours()*3600000)+(time.getMinutes()*60000)+(time.getSeconds()*1000);
var t = alarm.t-currentTime;
if (alarm.last == time.getDate() || t < -60000) t += 86400000;
return t;
};
/// Force a reload of the current alarms and widget
exports.reload = function() {
eval(require("Storage").read("alarm.boot.js"));
if (WIDGETS["alarm"]) {
WIDGETS["alarm"].reload();
Bangle.drawWidgets();
}
};

View File

@ -2,17 +2,19 @@
"id": "alarm",
"name": "Default Alarm & Timer",
"shortName": "Alarms",
"version": "0.15",
"version": "0.16",
"description": "Set and respond to alarms and timers",
"icon": "app.png",
"tags": "tool,alarm,widget",
"supports": ["BANGLEJS","BANGLEJS2"],
"readme": "README.md",
"storage": [
{"name":"alarm.app.js","url":"app.js"},
{"name":"alarm.boot.js","url":"boot.js"},
{"name":"alarm.js","url":"alarm.js"},
{"name":"alarm.img","url":"app-icon.js","evaluate":true},
{"name":"alarm.wid.js","url":"widget.js"}
{"name":"alarm.wid.js","url":"widget.js"},
{"name":"alarm","url":"lib.js"}
],
"data": [{"name":"alarm.json"}]
}

View File

@ -1,6 +1,7 @@
WIDGETS["alarm"]={area:"tl",width:0,draw:function() {
if (this.width) g.reset().drawImage(atob("GBgBAAAAAAAAABgADhhwDDwwGP8YGf+YMf+MM//MM//MA//AA//AA//AA//AA//AA//AB//gD//wD//wAAAAADwAABgAAAAAAAAA"),this.x,this.y);
},reload:function() {
// don't include library here as we're trying to use as little RAM as possible
WIDGETS["alarm"].width = (require('Storage').readJSON('alarm.json',1)||[]).some(alarm=>alarm.on) ? 24 : 0;
}
};