diff --git a/apps/alarm/alarm.js b/apps/alarm/alarm.js index a655dad1e..9a9e172cc 100644 --- a/apps/alarm/alarm.js +++ b/apps/alarm/alarm.js @@ -1,20 +1,38 @@ // Chances are boot0.js got run already and scheduled *another* // 'load(alarm.js)' - so let's remove it first! -clearInterval(); - -function formatTime(t) { - var hrs = 0|t; - var mins = Math.round((t-hrs)*60); - return hrs+":"+("0"+mins).substr(-2); +if (Bangle.ALARM) { + clearInterval(Bangle.ALARM); + delete Bangle.ALARM; } -function getCurrentHr() { +// 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) }; +} + +// time in { hrs, mins } -> ms +function encodeTime(o) { + return o.hrs*3600000 + o.mins*60000; +} + +function formatTime(t) { + var o = decodeTime(t); + return o.hrs+":"+("0"+o.mins).substr(-2); +} + +function getCurrentTime() { var time = new Date(); - return time.getHours()+(time.getMinutes()/60)+(time.getSeconds()/3600); + return ( + time.getHours() * 3600000 + + time.getMinutes() * 60000 + + time.getSeconds() * 1000 + ); } function showAlarm(alarm) { - var msg = formatTime(alarm.hr); + var msg = alarm.timer ? formatTime(alarm.timer) : formatTime(alarm.t); var buzzCount = 10; if (alarm.msg) msg += "\n"+alarm.msg; @@ -26,13 +44,13 @@ function showAlarm(alarm) { }).then(function(sleep) { buzzCount = 0; if (sleep) { - if(alarm.ohr===undefined) alarm.ohr = alarm.hr; - alarm.hr += 10/60; // 10 minutes + if(alarm.ot===undefined) alarm.ot = alarm.t; + alarm.t += 10*60*1000; // 10 minutes } else { alarm.last = (new Date()).getDate(); - if (alarm.ohr!==undefined) { - alarm.hr = alarm.ohr; - delete alarm.ohr; + if (alarm.ot!==undefined) { + alarm.t = alarm.ot; + delete alarm.ot; } if (!alarm.rp) alarm.on = false; } @@ -59,12 +77,12 @@ function showAlarm(alarm) { // Check for alarms var day = (new Date()).getDate(); -var hr = getCurrentHr()+10000; // get current time - 10s in future to ensure we alarm if we've started the app a tad early +var currentTime = getCurrentTime()+10000; // get current time - 10s in future to ensure we alarm if we've started the app a tad early var alarms = require("Storage").readJSON("alarm.json",1)||[]; -var active = alarms.filter(a=>a.on&&(a.hra.on&&(a.ta.hr-b.hr); + active = active.sort((a,b)=>a.t-b.t); showAlarm(active[0]); } else { // otherwise just go back to default app diff --git a/apps/alarm/app.js b/apps/alarm/app.js index 56184edf1..7419f0d5d 100644 --- a/apps/alarm/app.js +++ b/apps/alarm/app.js @@ -4,33 +4,49 @@ Bangle.drawWidgets(); var alarms = require("Storage").readJSON("alarm.json",1)||[]; /*alarms = [ { on : true, - hr : 6.5, // hours + minutes/60 + 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 - timer : 5, // OPTIONAL - if set, this is a timer and it's the time in minutes + timer : 5*60*1000, // OPTIONAL - if set, this is a timer and it's the time in ms } ];*/ +// 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) }; +} + +// time in { hrs, mins } -> ms +function encodeTime(o) { + return o.hrs*3600000 + o.mins*60000; +} + function formatTime(t) { - var hrs = 0|t; - var mins = Math.round((t-hrs)*60); - return hrs+":"+("0"+mins).substr(-2); + var o = decodeTime(t); + return o.hrs+":"+("0"+o.mins).substr(-2); } -function formatMins(t) { - mins = (0|t)%60; - hrs = 0|(t/60); - return hrs+":"+("0"+mins).substr(-2); -} - -function getCurrentHr() { +function getCurrentTime() { var time = new Date(); - return time.getHours()+(time.getMinutes()/60)+(time.getSeconds()/3600); + return ( + time.getHours() * 3600000 + + time.getMinutes() * 60000 + + time.getSeconds() * 1000 + ); +} + +function saveAndReload() { + require("Storage").write("alarm.json",JSON.stringify(alarms)); + eval(require("Storage").read("alarm.boot.js")); } 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' }, /*LANG*/'< Back' : ()=>{load();}, @@ -38,140 +54,147 @@ function showMainMenu() { /*LANG*/'New Timer': ()=>editTimer(-1) }; alarms.forEach((alarm,idx)=>{ - if (alarm.timer) { - txt = /*LANG*/"TIMER "+(alarm.on?/*LANG*/"on ":/*LANG*/"off ")+formatMins(alarm.timer); - } else { - txt = /*LANG*/"ALARM "+(alarm.on?/*LANG*/"on ":/*LANG*/"off ")+formatTime(alarm.hr); - if (alarm.rp) txt += /*LANG*/" (repeat)"; - } - menu[txt] = function() { - if (alarm.timer) editTimer(idx); - else editAlarm(idx); + var txt; // a leading space is currently required (JS error in Espruino 2v12) + if (alarm.timer) + txt = /*LANG*/"Timer"+" "+formatTime(alarm.timer); + else + txt = /*LANG*/"Alarm"+" "+formatTime(alarm.t); + if (alarm.rp) txt += "\0"+atob("FBaBAAABgAAcAAHn//////wAHsABzAAYwAAMAADAAAAAAwAAMAADGAAzgAN4AD//////54AAOAABgAA="); + menu[txt] = { + value : "\0"+atob(alarm.on?"EhKBAH//v/////////////5//x//j//H+eP+Mf/A//h//z//////////3//g":"EhKBAH//v//8AA8AA8AA8AA8AA8AA8AA8AA8AA8AA8AA8AA8AA8AA///3//g"), + onchange : function() { + if (alarm.timer) editTimer(idx, alarm); + else editAlarm(idx, alarm); + } }; }); - if (WIDGETS["alarm"]) WIDGETS["alarm"].reload(); return E.showMenu(menu); } -function editAlarm(alarmIndex) { +function editDOW(dow, onchange) { + const menu = { + '': { 'title': /*LANG*/'Days of Week' }, + '< Back' : () => onchange(dow) + }; + for (var i = 0; i < 7; i++) (i => { + var dayOfWeek = require("locale").dow({ getDay: () => i }); + menu[dayOfWeek] = { + value: !!(dow&(1< v ? "Yes" : "No", + onchange: v => v ? dow |= 1< showMainMenu(), /*LANG*/'Hours': { - value: hrs, min : 0, max : 23, wrap : true, - onchange: v => hrs=v + value: t.hrs, min : 0, max : 23, wrap : true, + onchange: v => t.hrs=v }, /*LANG*/'Minutes': { - value: mins, min : 0, max : 59, wrap : true, - onchange: v => mins=v + value: t.mins, min : 0, max : 59, wrap : true, + onchange: v => t.mins=v }, /*LANG*/'Enabled': { - value: en, + value: a.on, format: v=>v?"On":"Off", - onchange: v=>en=v + onchange: v=>a.on=v }, /*LANG*/'Repeat': { - value: en, + value: a.rp, format: v=>v?"Yes":"No", - onchange: v=>repeat=v + 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*/'Auto snooze': { - value: as, + value: a.as, format: v=>v?"Yes":"No", - onchange: v=>as=v + onchange: v=>a.as=v } }; - function getAlarm() { - var hr = hrs+(mins/60); - var day = 0; - // If alarm is for tomorrow not today (eg, in the past), set day - if (hr < getCurrentHr()) - day = (new Date()).getDate(); - // Save alarm - return { - on : en, hr : hr, - last : day, rp : repeat, as: as - }; - } - menu[/*LANG*/"> Save"] = function() { - if (newAlarm) alarms.push(getAlarm()); - else alarms[alarmIndex] = getAlarm(); - require("Storage").write("alarm.json",JSON.stringify(alarms)); + menu[/*LANG*/"Save"] = function() { + a.t = encodeTime(t); + if (a.t < getCurrentTime()) + a.day = (new Date()).getDate(); + if (newAlarm) alarms.push(a); + else alarms[alarmIndex] = a; + saveAndReload(); showMainMenu(); }; if (!newAlarm) { - menu[/*LANG*/"> Delete"] = function() { + menu[/*LANG*/"Delete"] = function() { alarms.splice(alarmIndex,1); - require("Storage").write("alarm.json",JSON.stringify(alarms)); + saveAndReload(); showMainMenu(); }; } return E.showMenu(menu); } -function editTimer(alarmIndex) { +function editTimer(alarmIndex, alarm) { var newAlarm = alarmIndex<0; - var hrs = 0; - var mins = 5; - var en = true; - if (!newAlarm) { - var a = alarms[alarmIndex]; - mins = (0|a.timer)%60; - hrs = 0|(a.timer/60); - en = a.on; + var a = { + timer : 5*60*1000, // 5 minutes + on : true, + rp : false, + as : false, + dow : 0b1111111, + last : 0 } + if (!newAlarm) Object.assign(a, alarms[alarmIndex]); + if (alarm) Object.assign(a,alarm); + var t = decodeTime(a.timer); + const menu = { '': { 'title': /*LANG*/'Timer' }, + '< Back' : () => showMainMenu(), /*LANG*/'Hours': { - value: hrs, min : 0, max : 23, wrap : true, - onchange: v => hrs=v + value: t.hrs, min : 0, max : 23, wrap : true, + onchange: v => t.hrs=v }, /*LANG*/'Minutes': { - value: mins, min : 0, max : 59, wrap : true, - onchange: v => mins=v + value: t.mins, min : 0, max : 59, wrap : true, + onchange: v => t.mins=v }, /*LANG*/'Enabled': { - value: en, - format: v=>v?/*LANG*/"On":/*LANG*/"Off", - onchange: v=>en=v + value: a.on, + format: v=>v?"On":"Off", + onchange: v=>a.on=v } }; - function getTimer() { - var d = new Date(Date.now() + ((hrs*60)+mins)*60000); - var hr = d.getHours() + (d.getMinutes()/60) + (d.getSeconds()/3600); - // Save alarm - return { - on : en, - timer : (hrs*60)+mins, - hr : hr, - rp : false, as: false - }; - } - menu["> Save"] = function() { - if (newAlarm) alarms.push(getTimer()); - else alarms[alarmIndex] = getTimer(); - require("Storage").write("alarm.json",JSON.stringify(alarms)); + menu[/*LANG*/"Save"] = function() { + a.timer = encodeTime(t); + a.hr = getCurrentTime() + a.timer; + if (newAlarm) alarms.push(a); + else alarms[alarmIndex] = a; + saveAndReload(); showMainMenu(); }; if (!newAlarm) { - menu["> Delete"] = function() { + menu[/*LANG*/"Delete"] = function() { alarms.splice(alarmIndex,1); - require("Storage").write("alarm.json",JSON.stringify(alarms)); + saveAndReload(); showMainMenu(); }; } diff --git a/apps/alarm/boot.js b/apps/alarm/boot.js index 47dae5361..a7fdd3658 100644 --- a/apps/alarm/boot.js +++ b/apps/alarm/boot.js @@ -1,25 +1,33 @@ // check for alarms (function() { + if (Bangle.ALARM) { + clearTimeout(Bangle.ALARM); + delete Bangle.ALARM; + } var alarms = require('Storage').readJSON('alarm.json',1)||[]; var time = new Date(); - var active = alarms.filter(a=>a.on); + var active = alarms.filter(a=>a.on && (a.dow>>time.getDay())&1); if (active.length) { - active = active.sort((a,b)=>(a.hr-b.hr)+(a.last-b.last)*24); - var hr = time.getHours()+(time.getMinutes()/60)+(time.getSeconds()/3600); + active = active.sort((a,b)=>(a.t-b.t)+(a.last-b.last)*86400000); + var currentTime = (time.getHours()*3600000)+(time.getMinutes()*60000)+(time.getSeconds()*1000); if (!require('Storage').read("alarm.js")) { console.log("No alarm app!"); require('Storage').write('alarm.json',"[]"); } else { - var t = 3600000*(active[0].hr-hr); - if (active[0].last == time.getDate() || t < 0) t += 86400000; - if (t<1000) t=1000; + var t = active[0].t-currentTime; + if (active[0].last == time.getDate() || t < -60000) t += 86400000; + if (t<1000) t=1000; // start alarm min 1 sec from now /* 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. */ - setTimeout(function() { + Bangle.ALARM = setTimeout(function() { load("alarm.js"); },t); } + } else { // check for new alarms at midnight (so day of week works) + Bangle.ALARM = setTimeout(() => { + eval(require("Storage").read("alarm.boot.js")); + }, 86400000 - (Date.now()%86400000)); } })();