diff --git a/apps/alarm/ChangeLog b/apps/alarm/ChangeLog index fcafc386f..3f56f4c20 100644 --- a/apps/alarm/ChangeLog +++ b/apps/alarm/ChangeLog @@ -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 diff --git a/apps/alarm/app.js b/apps/alarm/app.js index b9404358e..1fc32ecb9 100644 --- a/apps/alarm/app.js +++ b/apps/alarm/app.js @@ -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< v ? "Yes" : "No", + format: v => v ? /*LANG*/"Yes" : /*LANG*/"No", onchange: v => v ? dow |= 1< 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< 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 ), }; diff --git a/apps/alarm/metadata.json b/apps/alarm/metadata.json index 9636257ca..db36b3ca9 100644 --- a/apps/alarm/metadata.json +++ b/apps/alarm/metadata.json @@ -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", diff --git a/apps/sched/ChangeLog b/apps/sched/ChangeLog index a2d6c370f..0f935caf8 100644 --- a/apps/sched/ChangeLog +++ b/apps/sched/ChangeLog @@ -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 diff --git a/apps/sched/README.md b/apps/sched/README.md index ed08139eb..47507fc14 100644 --- a/apps/sched/README.md +++ b/apps/sched/README.md @@ -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 diff --git a/apps/sched/lib.js b/apps/sched/lib.js index 48094c86f..bfad1ac2d 100644 --- a/apps/sched/lib.js +++ b/apps/sched/lib.js @@ -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); +}; \ No newline at end of file diff --git a/apps/sched/metadata.json b/apps/sched/metadata.json index ffa346a44..3454d2397 100644 --- a/apps/sched/metadata.json +++ b/apps/sched/metadata.json @@ -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"}] } diff --git a/apps/sched/sched.js b/apps/sched/sched.js index 9096fe4bf..83f03ac01 100644 --- a/apps/sched/sched.js +++ b/apps/sched/sched.js @@ -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); +} diff --git a/apps/sched/settings.js b/apps/sched/settings.js new file mode 100644 index 000000000..642e43b43 --- /dev/null +++ b/apps/sched/settings.js @@ -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); + }) + }); +});