From 94690a81ee6fd651d078f8ee213bbe7eb4a76907 Mon Sep 17 00:00:00 2001 From: Alessandro Cocco Date: Wed, 11 May 2022 23:03:10 +0200 Subject: [PATCH 1/5] Add new time_utils module and move some functions from sched module to it --- apps/sched/ChangeLog | 1 + apps/sched/lib.js | 17 ------------ apps/sched/metadata.json | 2 +- apps/sched/sched.js | 4 +-- modules/time_utils.js | 57 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 61 insertions(+), 20 deletions(-) create mode 100644 modules/time_utils.js diff --git a/apps/sched/ChangeLog b/apps/sched/ChangeLog index 914bd7002..c68653a76 100644 --- a/apps/sched/ChangeLog +++ b/apps/sched/ChangeLog @@ -7,3 +7,4 @@ 0.07: Update settings Correct `decodeTime(t)` to return a more likely expected time 0.08: add day of week check to getActiveAlarms() +0.09: Move some functions to new time_utils module diff --git a/apps/sched/lib.js b/apps/sched/lib.js index ff35c94cb..fb1a7e4d6 100644 --- a/apps/sched/lib.js +++ b/apps/sched/lib.js @@ -113,20 +113,3 @@ exports.getSettings = function () { exports.setSettings = function(settings) { require("Storage").writeJSON("sched.settings.json", settings); }; - -// time in ms -> { hrs, mins } -exports.decodeTime = function(t) { - t = Math.ceil(t / 60000); // sanitise to full minutes - let hrs = 0 | (t / 60); - return { hrs: hrs, mins: t - hrs * 60 }; -} - -// time in { hrs, mins } -> ms -exports.encodeTime = function(o) { - return o.hrs * 3600000 + o.mins * 60000; -} - -exports.formatTime = function(t) { - let o = exports.decodeTime(t); - return o.hrs + ":" + ("0" + o.mins).substr(-2); -} diff --git a/apps/sched/metadata.json b/apps/sched/metadata.json index 089fffe31..b962326e3 100644 --- a/apps/sched/metadata.json +++ b/apps/sched/metadata.json @@ -1,7 +1,7 @@ { "id": "sched", "name": "Scheduler", - "version": "0.08", + "version": "0.09", "description": "Scheduling library for alarms and timers", "icon": "app.png", "type": "scheduler", diff --git a/apps/sched/sched.js b/apps/sched/sched.js index 7c97600d9..f4d1bc9ad 100644 --- a/apps/sched/sched.js +++ b/apps/sched/sched.js @@ -9,7 +9,7 @@ function showAlarm(alarm) { const settings = require("sched").getSettings(); let msg = ""; - msg += alarm.timer ? require("sched").formatTime(alarm.timer) : require("sched").formatTime(alarm.t); + msg += require("time_utils").formatTime(alarm.timer ? alarm.timer : alarm.t); if (alarm.msg) { msg += "\n"+alarm.msg; } else { @@ -26,7 +26,7 @@ function showAlarm(alarm) { 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 + buttons : {/*LANG*/"Snooze":true,/*LANG*/"Stop":false} // default is sleep so it'll come back in 10 mins }).then(function(sleep) { buzzCount = 0; if (sleep) { diff --git a/modules/time_utils.js b/modules/time_utils.js new file mode 100644 index 000000000..152de2fd0 --- /dev/null +++ b/modules/time_utils.js @@ -0,0 +1,57 @@ +// module "time_utils" +// +// Utility functions useful to work with time and durations. +// Functions usually receive or return a {h, m} object or a +// number of milliseconds representing a time or a duration. +// + +/** + * @param {object} time {h, m} + * @returns the milliseconds contained in the passed time object + */ +exports.encodeTime = (time) => time.h * 3600000 + time.m * 60000; + +/** + * @param {int} millis the number of milliseconds + * @returns a time object {h, m} built from the milliseconds + */ +exports.decodeTime = (millis) => { + millis = Math.ceil(millis / 60000); + var h = 0 | (millis / 60); + return { + h: h, + m: millis - h * 60 + }; +} + +/** + * @param {object|int} value {h,m} object or milliseconds + * @returns an human-readable time string like "10:25" + */ +exports.formatTime = (value) => { + var time = (value.h === undefined || value.m === undefined) ? exports.decodeTime(value) : value; + return time.h + ":" + ("0" + time.m).substr(-2); +} + +/** + * @param {object|int} value {h,m} object or milliseconds + * @returns an human-readable duration string like "1h 10m" + */ +exports.formatDuration = (value) => { + var duration; + + var time = (value.h === undefined || value.m === undefined) ? exports.decodeTime(value) : value; + + if (time.h == 0) { + duration = time.m + "m" + } else { + duration = time.h + "h" + (time.m ? (" " + time.m + "m") : "") + } + + return duration +} + +exports.getCurrentTimeMillis = () => { + var time = new Date(); + return (time.getHours() * 3600 + time.getMinutes() * 60 + time.getSeconds()) * 1000; +} From ee663ef1691f94172d3d5b60bfa54ebb4f5b38a8 Mon Sep 17 00:00:00 2001 From: Alessandro Cocco Date: Thu, 12 May 2022 22:51:41 +0200 Subject: [PATCH 2/5] [sleepphasealarm] Update to new time_utils module --- apps/sleepphasealarm/ChangeLog | 1 + apps/sleepphasealarm/app.js | 4 ++-- apps/sleepphasealarm/metadata.json | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/apps/sleepphasealarm/ChangeLog b/apps/sleepphasealarm/ChangeLog index ec3fe3a23..208058472 100644 --- a/apps/sleepphasealarm/ChangeLog +++ b/apps/sleepphasealarm/ChangeLog @@ -6,3 +6,4 @@ 0.06: Add logging use Layout library and display ETA 0.07: Add check for day of week +0.08: Update to new time_utils module diff --git a/apps/sleepphasealarm/app.js b/apps/sleepphasealarm/app.js index 8ccd43eb2..febc8a259 100644 --- a/apps/sleepphasealarm/app.js +++ b/apps/sleepphasealarm/app.js @@ -46,8 +46,8 @@ function calc_ess(acc_magn) { var nextAlarm; active.forEach(alarm => { const now = new Date(); - const t = require("sched").decodeTime(alarm.t); - var dateAlarm = new Date(now.getFullYear(), now.getMonth(), now.getDate(), t.hrs, t.mins); + const time = require("time_utils").decodeTime(alarm.t); + var dateAlarm = new Date(now.getFullYear(), now.getMonth(), now.getDate(), time.h, time.m); if (dateAlarm < now) { // dateAlarm in the past, add 24h dateAlarm.setTime(dateAlarm.getTime() + (24*60*60*1000)); } diff --git a/apps/sleepphasealarm/metadata.json b/apps/sleepphasealarm/metadata.json index d74590704..c74a617ab 100644 --- a/apps/sleepphasealarm/metadata.json +++ b/apps/sleepphasealarm/metadata.json @@ -2,7 +2,7 @@ "id": "sleepphasealarm", "name": "SleepPhaseAlarm", "shortName": "SleepPhaseAlarm", - "version": "0.07", + "version": "0.08", "description": "Uses the accelerometer to estimate sleep and wake states with the principle of Estimation of Stationary Sleep-segments (ESS, see https://ubicomp.eti.uni-siegen.de/home/datasets/ichi14/index.html.en). This app will read the next alarm from the alarm application and will wake you up to 30 minutes early at the best guessed time when you are almost already awake.", "icon": "app.png", "tags": "alarm", From f22f113687a2a3cf9943806ff73e28a8257c1777 Mon Sep 17 00:00:00 2001 From: Alessandro Cocco Date: Thu, 12 May 2022 22:59:03 +0200 Subject: [PATCH 3/5] [Alarms & Timers] Full UI rewrite --- apps/alarm/ChangeLog | 1 + apps/alarm/app.js | 488 +++++++++++++++++++++++---------------- apps/alarm/metadata.json | 2 +- apps/sched/lib.js | 6 +- 4 files changed, 288 insertions(+), 209 deletions(-) diff --git a/apps/alarm/ChangeLog b/apps/alarm/ChangeLog index ca1417b5b..b952b1dcd 100644 --- a/apps/alarm/ChangeLog +++ b/apps/alarm/ChangeLog @@ -26,3 +26,4 @@ Add "Enable All", "Disable All" and "Remove All" actions 0.25: Fix redrawing selected Alarm/Timer entry inside edit submenu 0.26: Add support for Monday as first day of the week (#1780) +0.27: New UI! diff --git a/apps/alarm/app.js b/apps/alarm/app.js index cf46823d6..0cf1f3d6f 100644 --- a/apps/alarm/app.js +++ b/apps/alarm/app.js @@ -1,20 +1,160 @@ Bangle.loadWidgets(); Bangle.drawWidgets(); +// 0 = Sunday (default), 1 = Monday +const firstDayOfWeek = (require("Storage").readJSON("setting.json", true) || {}).firstDayOfWeek || 0; +const WORKDAYS = 62 +const WEEKEND = firstDayOfWeek ? 192 : 65; +const EVERY_DAY = firstDayOfWeek ? 254 : 127; + +const iconAlarmOn = "\0" + atob("GBiBAAAAAAAAAAYAYA4AcBx+ODn/nAP/wAf/4A/n8A/n8B/n+B/n+B/n+B/n+B/h+B/4+A/+8A//8Af/4AP/wAH/gAB+AAAAAAAAAA=="); +const iconAlarmOff = "\0" + (g.theme.dark + ? atob("GBjBAP////8AAAAAAAAGAGAOAHAcfjg5/5wD/8AH/+AP5/AP5/Af5/gf5/gf5wAf5gAf4Hgf+f4P+bYP8wMH84cD84cB8wMAebYAAf4AAHg=") + : atob("GBjBAP//AAAAAAAAAAAGAGAOAHAcfjg5/5wD/8AH/+AP5/AP5/Af5/gf5/gf5wAf5gAf4Hgf+f4P+bYP8wMH84cD84cB8wMAebYAAf4AAHg=")); + +const iconTimerOn = "\0" + (g.theme.dark + ? atob("GBjBAP////8AAAAAAAAAAAAH/+AH/+ABgYABgYABgYAA/wAA/wAAfgAAPAAAPAAAfgAA5wAAwwABgYABgYABgYAH/+AH/+AAAAAAAAAAAAA=") + : atob("GBjBAP//AAAAAAAAAAAAAAAH/+AH/+ABgYABgYABgYAA/wAA/wAAfgAAPAAAPAAAfgAA5wAAwwABgYABgYABgYAH/+AH/+AAAAAAAAAAAAA=")); +const iconTimerOff = "\0" + (g.theme.dark + ? atob("GBjBAP////8AAAAAAAAAAAAH/+AH/+ABgYABgYABgYAA/wAA/wAAfgAAPAAAPAAAfgAA5HgAwf4BgbYBgwMBg4cH84cH8wMAAbYAAf4AAHg=") + : atob("GBjBAP//AAAAAAAAAAAAAAAH/+AH/+ABgYABgYABgYAA/wAA/wAAfgAAPAAAPAAAfgAA5HgAwf4BgbYBgwMBg4cH84cH8wMAAbYAAf4AAHg=")); + // An array of alarm objects (see sched/README.md) var alarms = require("sched").getAlarms(); -// 0 = Sunday -// 1 = Monday -var firstDayOfWeek = (require("Storage").readJSON("setting.json", true) || {}).firstDayOfWeek || 0; +function handleFirstDayOfWeek(dow) { + if (firstDayOfWeek == 1) { + if ((dow & 1) == 1) { + // In the scheduler API Sunday is 1. + // Here the week starts on Monday and Sunday is ON so + // when I read the dow I need to move Sunday to 128... + dow += 127; + } else if ((dow & 128) == 128) { + // ... and then when I write the dow I need to move Sunday back to 1. + dow -= 127; + } + } + return dow; +} -function getCurrentTime() { - var time = new Date(); - return ( - time.getHours() * 3600000 + - time.getMinutes() * 60000 + - time.getSeconds() * 1000 - ); +// Check the first day of week and update the dow field accordingly. +alarms.forEach(alarm => alarm.dow = handleFirstDayOfWeek(alarm.dow)); + +function showMainMenu() { + const menu = { + "": { "title": /*LANG*/"Alarms & Timers" }, + "< Back": () => load(), + /*LANG*/"New...": () => showNewMenu() + }; + + alarms.forEach((e, index) => { + var label = e.timer + ? require("time_utils").formatDuration(e.timer) + : require("time_utils").formatTime(e.t) + (e.dow > 0 ? (" " + decodeDOW(e)) : ""); + menu[label] = { + value: e.on ? (e.timer ? iconTimerOn : iconAlarmOn) : (e.timer ? iconTimerOff : iconAlarmOff), + onchange: () => setTimeout(e.timer ? showEditTimerMenu : showEditAlarmMenu, 10, e, index) + }; + }); + + menu[/*LANG*/"Advanced"] = () => showAdvancedMenu(); + + E.showMenu(menu); +} + +function showNewMenu() { + E.showMenu({ + "": { "title": /*LANG*/"New..." }, + "< Back": () => showMainMenu(), + /*LANG*/"Alarm": () => showEditAlarmMenu(undefined, undefined), + /*LANG*/"Timer": () => showEditTimerMenu(undefined, undefined) + }); +} + +function showEditAlarmMenu(selectedAlarm, alarmIndex) { + var isNew = alarmIndex === undefined; + + var alarm = require("sched").newDefaultAlarm(); + alarm.dow = handleFirstDayOfWeek(alarm.dow); + + if (selectedAlarm) { + Object.assign(alarm, selectedAlarm); + } + + var time = require("time_utils").decodeTime(alarm.t); + + const menu = { + "": { "title": isNew ? /*LANG*/"New Alarm" : /*LANG*/"Edit Alarm" }, + "< Back": () => { + saveAlarm(alarm, alarmIndex, time); + showMainMenu(); + }, + /*LANG*/"Hour": { + value: time.h, + format: v => ("0" + v).substr(-2), + min: 0, + max: 23, + wrap: true, + onchange: v => time.h = v + }, + /*LANG*/"Minute": { + value: time.m, + format: v => ("0" + v).substr(-2), + min: 0, + max: 59, + wrap: true, + onchange: v => time.m = v + }, + /*LANG*/"Enabled": { + value: alarm.on, + onchange: v => alarm.on = v + }, + /*LANG*/"Repeat": { + value: decodeDOW(alarm), + onchange: () => setTimeout(showEditRepeatMenu, 100, alarm.dow, dow => { + alarm.rp = dow > 0; + alarm.dow = dow; + alarm.t = require("time_utils").encodeTime(time); + setTimeout(showEditAlarmMenu, 10, alarm, alarmIndex); + }) + }, + /*LANG*/"Vibrate": require("buzz_menu").pattern(alarm.vibrate, v => alarm.vibrate = v), + /*LANG*/"Auto Snooze": { + value: alarm.as, + onchange: v => alarm.as = v + }, + /*LANG*/"Cancel": () => showMainMenu() + }; + + if (!isNew) { + menu[/*LANG*/"Delete"] = () => { + E.showPrompt(/*LANG*/"Are you sure?", { title: /*LANG*/"Delete Alarm" }).then((confirm) => { + if (confirm) { + alarms.splice(alarmIndex, 1); + saveAndReload(); + showMainMenu(); + } else { + alarm.t = require("time_utils").encodeTime(time); + setTimeout(showEditAlarmMenu, 10, alarm, alarmIndex); + } + }); + }; + } + + E.showMenu(menu); +} + +function saveAlarm(alarm, alarmIndex, time) { + alarm.t = require("time_utils").encodeTime(time); + alarm.last = alarm.t < require("time_utils").getCurrentTimeMillis() ? new Date().getDate() : 0; + + if (alarmIndex === undefined) { + alarms.push(alarm); + } else { + alarms[alarmIndex] = alarm; + } + + saveAndReload(); } function saveAndReload() { @@ -23,249 +163,187 @@ function saveAndReload() { require("sched").setAlarms(alarms); require("sched").reload(); + + // Fix after save + alarms.forEach(a => a.dow = handleFirstDayOfWeek(a.dow, firstDayOfWeek)); } -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': /*LANG*/'Alarms&Timers' }, - /*LANG*/'< Back': () => { load(); }, - /*LANG*/'New Alarm': () => editAlarm(-1), - /*LANG*/'New Timer': () => editTimer(-1) - }; - alarms.forEach((alarm, idx) => { - alarm.dow = handleFirstDayOfWeek(alarm.dow, firstDayOfWeek); +function decodeDOW(alarm) { + return alarm.rp + ? require("date_utils") + .dows(firstDayOfWeek, 2) + .map((day, index) => alarm.dow & (1 << (index + firstDayOfWeek)) ? day : "_") + .join("") + .toLowerCase() + : "Once" +} - var type, txt; // a leading space is currently required (JS error in Espruino 2v12) - if (alarm.timer) { - type = /*LANG*/"Timer"; - txt = " " + require("sched").formatTime(alarm.timer); - } else { - type = /*LANG*/"Alarm"; - txt = " " + require("sched").formatTime(alarm.t); +function showEditRepeatMenu(dow, dowChangeCallback) { + var originalDow = dow; + var isCustom = dow > 0 && dow != WORKDAYS && dow != WEEKEND && dow != EVERY_DAY; + + const menu = { + "": { "title": /*LANG*/"Repeat Alarm" }, + "< Back": () => dowChangeCallback(dow), + /*LANG*/"Once": { // No days set: the alarm will fire once + value: dow == 0, + onchange: () => dowChangeCallback(0) + }, + /*LANG*/"Workdays": { + value: dow == WORKDAYS, + onchange: () => dowChangeCallback(WORKDAYS) + }, + /*LANG*/"Weekends": { + value: dow == WEEKEND, + onchange: () => dowChangeCallback(WEEKEND) + }, + /*LANG*/"Every Day": { + value: dow == EVERY_DAY, + onchange: () => dowChangeCallback(EVERY_DAY) + }, + /*LANG*/"Custom": { + value: isCustom ? decodeDOW({ rp: true, dow: dow }) : false, + onchange: () => setTimeout(showCustomDaysMenu, 10, isCustom ? dow : EVERY_DAY, dowChangeCallback, originalDow) } - if (alarm.rp) txt += "\0" + atob("FBaBAAABgAAcAAHn//////wAHsABzAAYwAAMAADAAAAAAwAAMAADGAAzgAN4AD//////54AAOAABgAA="); - // rename duplicate alarms - if (menu[type + txt]) { - var n = 2; - while (menu[type + " " + n + txt]) n++; - txt = type + " " + n + txt; - } else txt = type + txt; - // add to menu - 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 () { - setTimeout(alarm.timer ? editTimer : editAlarm, 10, idx, alarm); - } - }; - }); + }; - if (alarms.some(e => !e.on)) { - menu[/*LANG*/"Enable All"] = () => enableAll(true); - } - if (alarms.some(e => e.on)) { - menu[/*LANG*/"Disable All"] = () => enableAll(false); - } - if (alarms.length > 0) { - menu[/*LANG*/"Delete All"] = () => deleteAll(); - } - - if (WIDGETS["alarm"]) WIDGETS["alarm"].reload(); - return E.showMenu(menu); + E.showMenu(menu); } -function editDOW(dow, onchange) { +function showCustomDaysMenu(dow, dowChangeCallback, originalDow) { const menu = { - '': { 'title': /*LANG*/'Days of Week' }, - /*LANG*/'< Back': () => onchange(dow) + "": { "title": /*LANG*/"Custom Days" }, + "< Back": () => dowChangeCallback(dow), }; require("date_utils").dows(firstDayOfWeek).forEach((day, i) => { menu[day] = { value: !!(dow & (1 << (i + firstDayOfWeek))), - format: v => v ? /*LANG*/"Yes" : /*LANG*/"No", onchange: v => v ? (dow |= 1 << (i + firstDayOfWeek)) : (dow &= ~(1 << (i + firstDayOfWeek))) }; }); + menu[/*LANG*/"Cancel"] = () => setTimeout(showEditRepeatMenu, 10, originalDow, dowChangeCallback) + E.showMenu(menu); } -function editAlarm(alarmIndex, alarm) { - var newAlarm = alarmIndex < 0; - var a = require("sched").newDefaultAlarm(); - a.dow = handleFirstDayOfWeek(a.dow, firstDayOfWeek); +function showEditTimerMenu(selectedTimer, timerIndex) { + var isNew = timerIndex === undefined; - if (!newAlarm) Object.assign(a, alarms[alarmIndex]); - if (alarm) Object.assign(a, alarm); - var t = require("sched").decodeTime(a.t); + var timer = require("sched").newDefaultTimer(); + + if (selectedTimer) { + Object.assign(timer, selectedTimer); + } + + var time = require("time_utils").decodeTime(timer.timer); const menu = { - '': { 'title': /*LANG*/'Alarm' }, - /*LANG*/'< Back': () => { - saveAlarm(newAlarm, alarmIndex, a, t); + "": { "title": isNew ? /*LANG*/"New Timer" : /*LANG*/"Edit Timer" }, + "< Back": () => { + saveTimer(timer, timerIndex, time); showMainMenu(); }, - /*LANG*/'Hours': { - value: t.hrs, min: 0, max: 23, wrap: true, - onchange: v => t.hrs = v + /*LANG*/"Hours": { + value: time.h, + min: 0, + max: 23, + wrap: true, + onchange: v => time.h = v }, - /*LANG*/'Minutes': { - value: t.mins, min: 0, max: 59, wrap: true, - onchange: v => t.mins = v + /*LANG*/"Minutes": { + value: time.m, + min: 0, + max: 59, + wrap: true, + onchange: v => time.m = v }, - /*LANG*/'Enabled': { - value: a.on, - format: v => v ? /*LANG*/"On" : /*LANG*/"Off", - onchange: v => a.on = v + /*LANG*/"Enabled": { + value: timer.on, + onchange: v => timer.on = v }, - /*LANG*/'Repeat': { - value: a.rp, - format: v => v ? /*LANG*/"Yes" : /*LANG*/"No", - onchange: v => a.rp = v - }, - /*LANG*/'Days': { - value: decodeDOW(a.dow), - onchange: () => setTimeout(editDOW, 100, a.dow, d => { - a.dow = d; - a.t = require("sched").encodeTime(t); - editAlarm(alarmIndex, a); - }) - }, - /*LANG*/'Vibrate': require("buzz_menu").pattern(a.vibrate, v => a.vibrate = v), - /*LANG*/'Auto Snooze': { - value: a.as, - format: v => v ? /*LANG*/"Yes" : /*LANG*/"No", - onchange: v => a.as = v - } + /*LANG*/"Vibrate": require("buzz_menu").pattern(timer.vibrate, v => timer.vibrate = v), }; - menu[/*LANG*/"Cancel"] = () => showMainMenu(); - - if (!newAlarm) { - menu[/*LANG*/"Delete"] = function () { - alarms.splice(alarmIndex, 1); - saveAndReload(); - showMainMenu(); + if (!isNew) { + menu[/*LANG*/"Delete"] = () => { + E.showPrompt(/*LANG*/"Are you sure?", { title: /*LANG*/"Delete Timer" }).then((confirm) => { + if (confirm) { + alarms.splice(timerIndex, 1); + saveAndReload(); + showMainMenu(); + } else { + timer.timer = require("time_utils").encodeTime(time); + setTimeout(showEditTimerMenu, 10, timer, timerIndex) + } + }); }; } - return E.showMenu(menu); + E.showMenu(menu); } -function saveAlarm(newAlarm, alarmIndex, a, t) { - a.t = require("sched").encodeTime(t); - a.last = (a.t < getCurrentTime()) ? (new Date()).getDate() : 0; +function saveTimer(timer, timerIndex, time) { + timer.timer = require("time_utils").encodeTime(time); + timer.t = require("time_utils").getCurrentTimeMillis() + timer.timer; + timer.last = 0; - if (newAlarm) { - alarms.push(a); + if (timerIndex === undefined) { + alarms.push(timer); } else { - alarms[alarmIndex] = a; + alarms[timerIndex] = timer; } saveAndReload(); } -function editTimer(alarmIndex, alarm) { - var newAlarm = alarmIndex < 0; - var a = require("sched").newDefaultTimer(); - if (!newAlarm) Object.assign(a, alarms[alarmIndex]); - if (alarm) Object.assign(a, alarm); - var t = require("sched").decodeTime(a.timer); - - const menu = { - '': { 'title': /*LANG*/'Timer' }, - /*LANG*/'< Back': () => { - saveTimer(newAlarm, alarmIndex, a, t); - showMainMenu(); - }, - /*LANG*/'Hours': { - value: t.hrs, min: 0, max: 23, wrap: true, - onchange: v => t.hrs = v - }, - /*LANG*/'Minutes': { - value: t.mins, min: 0, max: 59, wrap: true, - onchange: v => t.mins = v - }, - /*LANG*/'Enabled': { - value: a.on, - format: v => v ? /*LANG*/"On" : /*LANG*/"Off", - onchange: v => a.on = v - }, - /*LANG*/'Vibrate': require("buzz_menu").pattern(a.vibrate, v => a.vibrate = v), - }; - - menu[/*LANG*/"Cancel"] = () => showMainMenu(); - - if (!newAlarm) { - menu[/*LANG*/"Delete"] = function () { - alarms.splice(alarmIndex, 1); - saveAndReload(); - showMainMenu(); - }; - } - return E.showMenu(menu); -} - -function saveTimer(newAlarm, alarmIndex, a, t) { - a.timer = require("sched").encodeTime(t); - a.t = getCurrentTime() + a.timer; - a.last = 0; - - if (newAlarm) { - alarms.push(a); - } else { - alarms[alarmIndex] = a; - } - - saveAndReload(); -} - -function handleFirstDayOfWeek(dow, firstDayOfWeek) { - if (firstDayOfWeek == 1) { - if ((dow & 1) == 1) { - // By default 1 = Sunday. - // Here the week starts on Monday and Sunday is ON so move Sunday to 128. - dow += 127; - } else if ((dow & 128) == 128) { - dow -= 127; - } - } - return dow; -} - -function decodeDOW(dow) { - return require("date_utils") - .dows(firstDayOfWeek, 2) - .map((day, index) => dow & (1 << (index + firstDayOfWeek)) ? day : "_") - .join(""); +function showAdvancedMenu() { + E.showMenu({ + "": { "title": /*LANG*/"Advanced" }, + "< Back": () => showMainMenu(), + /*LANG*/"Scheduler Settings": () => eval(require("Storage").read("sched.settings.js"))(() => showAdvancedMenu()), + /*LANG*/"Enable All": () => enableAll(true), + /*LANG*/"Disable All": () => enableAll(false), + /*LANG*/"Delete All": () => deleteAll() + }); } function enableAll(on) { - E.showPrompt(/*LANG*/"Are you sure?", { - title: on ? /*LANG*/"Enable All" : /*LANG*/"Disable All" - }).then((confirm) => { - if (confirm) { - alarms.forEach(alarm => alarm.on = on); - saveAndReload(); - } - - showMainMenu(); - }); + if (alarms.filter(e => e.on == !on).length == 0) { + E.showPrompt(on ? /*LANG*/"Nothing to Enable" : /*LANG*/"Nothing to Disable", { + title: on ? /*LANG*/"Enable All" : /*LANG*/"Disable All", + buttons: { /*LANG*/"Ok": true } + }).then(() => showAdvancedMenu()); + } else { + E.showPrompt(/*LANG*/"Are you sure?", { title: on ? "/*LANG*/Enable All" : /*LANG*/"Disable All" }).then((confirm) => { + if (confirm) { + alarms.forEach(alarm => alarm.on = on); + saveAndReload(); + showMainMenu(); + } else { + showAdvancedMenu(); + } + }); + } } function deleteAll() { - E.showPrompt(/*LANG*/"Are you sure?", { - title: /*LANG*/"Delete All" - }).then((confirm) => { - if (confirm) { - alarms = []; - saveAndReload(); - } - - showMainMenu(); - }); + if (alarms.length == 0) { + E.showPrompt(/*LANG*/"Nothing to delete", { title: /*LANG*/"Delete All", buttons: { /*LANG*/"Ok": true } }).then(() => showAdvancedMenu()); + } else { + E.showPrompt(/*LANG*/"Are you sure?", { + title: /*LANG*/"Delete All" + }).then((confirm) => { + if (confirm) { + alarms = []; + saveAndReload(); + showMainMenu(); + } else { + showAdvancedMenu(); + } + }); + } } showMainMenu(); diff --git a/apps/alarm/metadata.json b/apps/alarm/metadata.json index c062b030d..d51e9fa19 100644 --- a/apps/alarm/metadata.json +++ b/apps/alarm/metadata.json @@ -2,7 +2,7 @@ "id": "alarm", "name": "Alarms & Timers", "shortName": "Alarms", - "version": "0.26", + "version": "0.27", "description": "Set alarms and timers on your Bangle", "icon": "app.png", "tags": "tool,alarm,widget", diff --git a/apps/sched/lib.js b/apps/sched/lib.js index fb1a7e4d6..063402e3d 100644 --- a/apps/sched/lib.js +++ b/apps/sched/lib.js @@ -61,12 +61,12 @@ exports.reload = function() { exports.newDefaultAlarm = function () { const settings = exports.getSettings(); - let alarm = { + var alarm = { t: 12 * 3600000, // Default to 12:00 on: true, rp: settings.defaultRepeat, as: settings.defaultAutoSnooze, - dow: 0b1111111, + dow: settings.defaultRepeat ? 0b1111111 : 0b0000000, last: 0, vibrate: settings.defaultAlarmPattern, }; @@ -79,7 +79,7 @@ exports.newDefaultAlarm = function () { exports.newDefaultTimer = function () { const settings = exports.getSettings(); - let timer = { + var timer = { timer: 5 * 60 * 1000, // 5 minutes on: true, rp: false, From dc0c8d7f0cf42bdf63026c08973dd524a4052135 Mon Sep 17 00:00:00 2001 From: Alessandro Cocco Date: Fri, 13 May 2022 12:05:23 +0200 Subject: [PATCH 4/5] [Alarms & Timers] Add screenshots --- apps/alarm/metadata.json | 23 ++++++++++++++++++----- apps/alarm/screenshot-1.png | Bin 0 -> 1752 bytes apps/alarm/screenshot-10.png | Bin 0 -> 1979 bytes apps/alarm/screenshot-11.png | Bin 0 -> 2326 bytes apps/alarm/screenshot-2.png | Bin 0 -> 1451 bytes apps/alarm/screenshot-3.png | Bin 0 -> 2402 bytes apps/alarm/screenshot-4.png | Bin 0 -> 2053 bytes apps/alarm/screenshot-5.png | Bin 0 -> 1948 bytes apps/alarm/screenshot-6.png | Bin 0 -> 2277 bytes apps/alarm/screenshot-7.png | Bin 0 -> 2144 bytes apps/alarm/screenshot-8.png | Bin 0 -> 2360 bytes apps/alarm/screenshot-9.png | Bin 0 -> 2274 bytes 12 files changed, 18 insertions(+), 5 deletions(-) create mode 100644 apps/alarm/screenshot-1.png create mode 100644 apps/alarm/screenshot-10.png create mode 100644 apps/alarm/screenshot-11.png create mode 100644 apps/alarm/screenshot-2.png create mode 100644 apps/alarm/screenshot-3.png create mode 100644 apps/alarm/screenshot-4.png create mode 100644 apps/alarm/screenshot-5.png create mode 100644 apps/alarm/screenshot-6.png create mode 100644 apps/alarm/screenshot-7.png create mode 100644 apps/alarm/screenshot-8.png create mode 100644 apps/alarm/screenshot-9.png diff --git a/apps/alarm/metadata.json b/apps/alarm/metadata.json index d51e9fa19..b9ce55756 100644 --- a/apps/alarm/metadata.json +++ b/apps/alarm/metadata.json @@ -6,12 +6,25 @@ "description": "Set alarms and timers on your Bangle", "icon": "app.png", "tags": "tool,alarm,widget", - "supports": ["BANGLEJS","BANGLEJS2"], + "supports": [ "BANGLEJS", "BANGLEJS2" ], "readme": "README.md", - "dependencies": {"scheduler":"type"}, + "dependencies": { "scheduler":"type" }, "storage": [ - {"name":"alarm.app.js","url":"app.js"}, - {"name":"alarm.img","url":"app-icon.js","evaluate":true}, - {"name":"alarm.wid.js","url":"widget.js"} + { "name": "alarm.app.js", "url": "app.js" }, + { "name": "alarm.img", "url": "app-icon.js", "evaluate": true }, + { "name": "alarm.wid.js", "url": "widget.js" } + ], + "screenshots": [ + { "url": "screenshot-1.png" }, + { "url": "screenshot-2.png" }, + { "url": "screenshot-3.png" }, + { "url": "screenshot-4.png" }, + { "url": "screenshot-5.png" }, + { "url": "screenshot-6.png" }, + { "url": "screenshot-7.png" }, + { "url": "screenshot-8.png" }, + { "url": "screenshot-9.png" }, + { "url": "screenshot-10.png" }, + { "url": "screenshot-11.png" } ] } diff --git a/apps/alarm/screenshot-1.png b/apps/alarm/screenshot-1.png new file mode 100644 index 0000000000000000000000000000000000000000..d2bd3a409955c711e18d5e3f093ab488df21a64a GIT binary patch literal 1752 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 literal 0 HcmV?d00001 diff --git a/apps/alarm/screenshot-11.png b/apps/alarm/screenshot-11.png new file mode 100644 index 0000000000000000000000000000000000000000..197c8419449afd37afa1482a31903d8975e2afd5 GIT binary patch literal 2326 zcmZvedpHw}7suV3HLTa%!fd2Ql)IS3$o=PD$#RKYD|=nCScI&Z+bEP~6w4*%-NPvZfCLKu4NFN!KI%^0NG=vJ% zGNs_hl$R*cwP!)x%uUsJb67xvxX4R2c~;sfi?6;QsCvtKUlS81sIZV=9=UHvOt}ib zMJN#V&~+U+c0O9}o6DH-$81yw%;!q{<^x&b_UMDf8*>>OFC&y=XCK*G(F9{0wZwA2 zqB4mxyTckrq^O7cMDz_}0#e#;eg?lY0acmjn4k_oT8#bptfCkmhgUNH2t^IIlEOK< zn|xfW$jQ4O7*UBBdZe~Tgho7!Rk`96BW1pzh-Tm4dF=aGGn#MnSmcES1TMf7HtS9E$Xp5%BpZF z1m{)?YQXeKFxG12CR+h;?_@Zs=;(JfVO_?aE3#o(#CWIkY2t>2O65Y`K3#uJlh2)U8=ey; zClrm+w4`z;iB06&UG_(Ci5Q$%LH!lUefIB`>sBwjK*8X~<@yZ2LZRo1@}cAAS=z11 z#wYeoD7~`#4wgfcJFfsbZ6DM!o^znrwugQtrTR5O-d=(@+=z;jJw}~|5Kwf-831G{&waAD@Lnh z&w=d~^_@|xRyoZGp*R zg;#ZqT!!8sT**+7CQ9O6>j+@fk~DUEtjLTyQoo(kd>cxcwo`A7T(!GgyukJe_DOV< zCmHNb8>oXT?VzpdFVwjm$6eH3md5zS+pyCo-q!vge^Bgq58tvuCvJuw8(dT>#pdO9 z9=yHYl~h8NX2gCU7_I#=o?t$;QnIs^wzk%(RLZSrx=?~L>+4gYcw9#=S(UC?c+Sf@ zz6E^FjqR}lElqb1VM)Bi@WxX?QqG*_)9^Y5acqZJU~|J#j#Nf2tkPoIX&9p&6(aK@ zdpFeFKtUrg0^bZovK$I0MOrO(_m!~r@_IayaV z^?jcEAwzh}8`EZvb2L%>Rk*$aXqV!e|D{e*pdi8(;Dr#$N&b^I0CvN$++Y7b7$)5P zR|-f(PaKj2aT`_L^y020kj zS)r%CZQ~8C`<8*L<5lA-8_`T|n8rFHHSYpFLzgb91*H}v#FK}Hv4>O1U}6yP)Ax!f zZ)3Imsuj`@rfd)UP-L6;!YJhVnZ~K(z&9R3Li0WYT>Gm!q)TA$IJ0myYtuVSXa&UOHv!_Zv z+wOZ){X;K@?J}7Ze|~H7)jTFL3d1NSLpjCmtq$CA5}tplrkSQKH|TNsizP{q|?Z}0n_~Q{7d}S0;J32#Ww7MUIAMI(SD1$*Z{$8RzphfUD45K56QOFRO>aR zI!%Shl*&iPhE^ox!QUWlT+QgsR2B<8_vD^WkmCG3P%EXdEy!Pe-1watPG=-QNT@}) z#zUMu_B+q~3tnM-5*{U>P@^kK7Q_oEcol&EXAe;T4(Q7+^c66@(AffRA@+X*0Kj&4 zcxTcIMehecoyreN6!1gPXzLy zZNnAi-;Okf_V)qZf@dFP6;*;|F|1ietagGt(gt^(Ngw^k<1A)$YbYqDKal7BLnk(K zZJX<_vG)Bl@SC!dgZk?-vbIN$sk}_-SnaU|*y?OP&@IyhX%O|=5BV_6vfH!FJ@|>w zYg!E5$AjUpZd90ccM~l(QgyAY!!$n$wWBkDmcux;4nX}W4mwhQK>7_9A)*BldgY&` z!2#{M`O~^on6RLrUXIn%U>HF_;VvPmH%163sQ2610k9PnyA=y_MOE)>yZ?@W{Yhu* JT9kjve*rl9J~{vZ literal 0 HcmV?d00001 diff --git a/apps/alarm/screenshot-2.png b/apps/alarm/screenshot-2.png new file mode 100644 index 0000000000000000000000000000000000000000..1cbc255a92c2d568765feb3cbf104f10a33d013b GIT binary patch literal 1451 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 L+7UxXdnWuB4r*zu literal 0 HcmV?d00001 diff --git a/apps/alarm/screenshot-4.png b/apps/alarm/screenshot-4.png new file mode 100644 index 0000000000000000000000000000000000000000..7fd7e99b65434752c2a7886124ee704c2ce3b8f1 GIT binary patch literal 2053 zcmai#dpy&N8^`4~#C)k3EtwYO(rF>HWiGR#<5EbuavQ~Q&g=Di{a)v<-yhHOyq-Uve?Fh*{XD4`Y|hC@DN6|n3CUPm znA`2vn!iIrcsHx^gC&K8KpabRQ-_G0uel?XB2@raJMd%Y7hPHP&dM}lhSwtbCGWZF z*>4i&<%)|tq$H~22*j6Jh@Gi}_-0llcOlAz zL6B*KHv(Hsm3tedr0$|W^m4ByC)-+m8z>vxT7#%-VonAz;rl79(K$j+e;EJk_~Z*L z={i<1x+^~@e>l%9=yrNtfp*!YvkL&x(s=>J#&C@U+P405(;c5^uBNM&!Q@dZgAm4e z)uGrg?On@~`UW$0)S+b`zLuj3Z^1G|3_T_JTV!?G&y}_9K_~Gu>8$FwOm6hMvfLRY zGu@+u)&~ENBu?KhFy)o>jWGSCR|Pl4)KqZ3k8@-M4^8u4fu@e}hBerRNd>lL_!OF& zZo9rXMJ=S*5J$H4Fzsf+j9a8odMy@OtqE2nr{eOpEF#mCjBo2!8nY&lX?PRVuYWlJ^=f$M^kfh*yo!0e>guHD3lBikH z`|YDC?~dZBFV?%FWbeo)j=464k9|Qb9DGNWJt$5#iN{{vgcdRg4?AvFv6_$h`xmK@ zQ*J)L*YBWUWc77^7T~ev!9-B8BgFeqHg^9b1?XhJ9ID|@6jQ?)g3X*z@(OCinmeD3 z!|=AObNAYQDbSb+g3q{fE)(X~^W%m%l3A|j zS)mPHQenF@TbDXuV}(R81?h5!o@^@zojf$Zs=E)oBrbC!54v+~Usn&ffI}pvpaa*= z6KGOOv+`GKX?DD@71hw(ky5B|Kv&5+How6EjT8+@#O5PKJ12l+;6101qG{M$(%^(i zK-K;oB9uIq_H0o`3n>cENCL~x02!?iVe4zsdn7Bc`Kh)OK*p_q%?>XDo83DRoFv!p zuI-K`-+oZ+6pW@h^))ZC6QT`MD_&@RI2T>^Wi+k=n^C#!yf6ct=)P)J&(>X?Ka*uG zk`i6Gq70tuKa<55;09B9xZ;5sVwCkW_FbJvGGLh{4~HOutv^ zwnxE4d!6qNanp)J3_OVJZ4*pP>7uI4B~Zzs6ggknk(Z+>L>ZpnifZL&s&q%ZU);xd zwNNxu!=c&yBQQ`nh+SMJbU@4mxw<{)k2jr_y`*u2Drj^RDP1h0rpsTC4x=hL7_@4?RPzgk>qty@8Ec8Or#l&jqGDE)V9uGTj*GAelG0t0ExqQe1a@k%HRgKnaUh z*afJtN1()hvXD}cRe|K+LQ;VLDRbn*H6ReYm~{=22!^f_IB$qr;NsGe2|3Fk2H8+%yy_R>N(uUJ9ogb+S^lQTlBC&vNz^og|SV4=+u_e?@h34XYPJ@DSeza z>Xxc~N+T_=3WFz6&K(E5_TCeGuJo^)_W>7(T0FQ53(>wG_xR>4bQV}T@N4G_XF*6L z<97QCSM6ehwHyLdf2|5TXz!qJEhZebU6wF!rv*Zhn);`&x|4_kdW1_>4P#4)d<-8b zkpx1SU(vaQ5~N46g|JRB$~kI+YAS3f?w3)dlAfAu_kp(8F5!s9 z5nG?{Ae}oPSrjSARJqwP$yZPp4B0w0#SZua5R%z7?H4`-aIBx=G$T)PUz{%@X?B02 zzddAszhiRWn&anmYKLE+#$C79x3LWJRdIJDGdjc{t{5Ulz9kA3X2DE$VJAvty!pq$ zPDGOW?zWpan_1*zO@#3hdI<|6S2LFULD;3g+$!_tCrse(g5t>$`v(<(x@o=HCf)_-RIz9>Z zYPtByrk8Vp-h$PoaoSmDB45k(7}Z*3@+D!>#`E!-E@?k|GS;kz$fsxx$)4Tod_C5El@{JdfbSQhP?X~$IMBqo zfi{*x#Oyt;G`0nOJ6UZHM#KkLRwo*eY#iU8WXMJqpK_~>y#w;Ws9g@7Dn^*cT-rNL zI33mN_hbmP5vC{0&$dM|?-#nU^A)BRMS zb7U6i3YSj8xb$%oYaL3kt!Rlu*Yk;V{9Mvzf_BJB*?&3qzr$zvym!}p`E8Lm?(j#w T$r{bO?_J0eXJcMvcJ20G*^k@2 literal 0 HcmV?d00001 diff --git a/apps/alarm/screenshot-5.png b/apps/alarm/screenshot-5.png new file mode 100644 index 0000000000000000000000000000000000000000..4174c5670eb9800beb19a71ca3e1acc8f58132a6 GIT binary patch literal 1948 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 literal 0 HcmV?d00001 diff --git a/apps/alarm/screenshot-7.png b/apps/alarm/screenshot-7.png new file mode 100644 index 0000000000000000000000000000000000000000..49da44710d70b2d5882b399dffade0827a9ed76e GIT binary patch literal 2144 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 Ug0Ds8;B(+HH?cy|khjAA0;8-7=l}o! literal 0 HcmV?d00001 diff --git a/apps/alarm/screenshot-8.png b/apps/alarm/screenshot-8.png new file mode 100644 index 0000000000000000000000000000000000000000..86d69cd93ca3141b1b3c47cab200e5a4bcfc129a GIT binary patch literal 2360 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 literal 0 HcmV?d00001 diff --git a/apps/alarm/screenshot-9.png b/apps/alarm/screenshot-9.png new file mode 100644 index 0000000000000000000000000000000000000000..2d8c7fc83045f4ce09531eec84c155eb314406e6 GIT binary patch literal 2274 zcmV<82p#u{P)V{QoaA4|X8|62cv=vmdgm1p_D?kk(k|oRP8C7-Ndrz{#j@qRn@R>wFG$ zjz`dR6O#@hdr^1<^U#j-j+^*tbX1!ejH7Vj`)=Y#NNaEhW^)Z`_QH4H#838UvpcW= zwoi<>i60>wIF^D=bnq!ScCNgJfk;flTJ_aU^Kthsd;EL4s1W`%JWyz^k@kt|htG6i^EZ^~5aGHALzNtc81~sL+WhQ|X-VzrTBKIrL){*2cr0T>B9>5lMCWy^p`g0;x#kx+zyf6Cu^;>k6*Y%^?ygBE+$SH z*-?A_$&Isz@}@?q6hhO~cZ?4(eGQS~yAC(;hsWhPJ4*F`Mw66W0ilL%WZe#I^;A?H zV%O*wuH7|fS6$`kTz@3I2hO?v1%Xgu&FRHfH&;xP{Zn zA;3JasGP!cpEx!wD)smoJ)5+?K1#AvmA;GYZS~QMO0MXWH-d)jnQmZ-jcWC94qcl4ATy+^0jwba0UhE94v`0Q_{P**IeDuMYY0HVlmQ6n5P*OV z0SK86VPSvFhG0<%2t*-H=&i7Obpi?j2v7)ECwbN>9%S}8!&L9h@*eJ+ z?a${uaIKJA_jIeo-w`AFsZ$95XF4d0qq9Flv3gJlj#Q_|D1`ay1lL35bLBi551LT| zg^0NCSNMGxc%Qu+7_Jz3Z7`yrCn>}b5AU;tOGLk^Qd9!Q&p3rhb{(u?cP#WC!n4wS3w<4g z`aj)9+}B5Z9A)ov!#;$NqzuMT}5e0uZoPSgH0Aze6iZLq-mEro?fpBxcMYL0Zr(EGHERg&d8#UA#^yCd z?HnnW+g693x}9L}CM=6n*)W$!$MybeJs9S9n};V_!kRdh#qkt9@n`xk6NA#P68vhR z)`PE4TOGo6%tLL&eFf&lsf@}q%nZ~PK~heQ%4#d3wv=ZvcBhg&c3SiI1Sr_cQ$E$X z>~SNWE2mbJ-du;TW)w?5)3(9+!5dTWdCI6_*i**K?EO%>yC%&RaVp!XdLsW#eoGf%&(q*nCJt@eaEG}`rXDxnZ3v*F9Fp46v|&J*g;Q}bFDDMZ>^v$1AUe1w;5lI)@C z^YCIG%_r(dg`qiDA?}M3#CIa`7!)y}ggBLX58;fM^RLMhwj%wyE2;x`HRP+bT_Mtz z=IcL7Ar{1d>W^gAJibp3RHadfRKlk#1eeD!zgK$Dv_(EwUxxz~!qvp7RK=KzQmwUV zD(As4zgKz?+LABjify;OuV zCL28?tu0%JU@0KfLGZ9wA+9T6X)E$0gz;0ehWM_}z0LN!vLEKSoZ2%_YdrMVp{;KH z_AYu^oXR`HcX&Exq-y$dxsUT_X-aAH&|inPx{XzcMR6*>K3se}>=UI(l<|H*>R&8f z@Nmbt^uH=S6kAd7Ag Date: Fri, 13 May 2022 15:04:46 +0200 Subject: [PATCH 5/5] [Alarms & Timers] Update README --- apps/alarm/README.md | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/apps/alarm/README.md b/apps/alarm/README.md index e979dbaf1..741946b0c 100644 --- a/apps/alarm/README.md +++ b/apps/alarm/README.md @@ -1,7 +1,31 @@ -Alarms & Timers -=============== +# Alarms & Timers This app allows you to add/modify any alarms and timers. -It uses the [`sched` library](https://github.com/espruino/BangleApps/blob/master/apps/sched) -to handle the alarm scheduling in an efficient way that can work alongside other apps. +It uses the [`sched` library](https://github.com/espruino/BangleApps/blob/master/apps/sched) to handle the alarm scheduling in an efficient way that can work alongside other apps. + +## Menu overview + +- `New...` + - `New Alarm` → Configure a new alarm + - `Repeat` → Select when the alarm will fire. You can select a predefined option (_Once_, _Every Day_, _Workdays_ or _Weekends_ or you can configure the days freely) + - `New Timer` → Configure a new timer +- `Advanced` + - `Scheduler settings` → Open the [Scheduler](https://github.com/espruino/BangleApps/tree/master/apps/sched) settings page, see its [README](https://github.com/espruino/BangleApps/blob/master/apps/sched/README.md) for details + - `Enable All` → Enable _all_ disabled alarms & timers + - `Disable All` → Disable _all_ enabled alarms & timers + - `Delete All` → Delete _all_ alarms & timers + +## Creator + +- [Gordon Williams](https://github.com/gfwilliams) + +## Main Contributors + +- [Alessandro Cocco](https://github.com/alessandrococco) - New UI, full rewrite, new features +- [Sabin Iacob](https://github.com/m0n5t3r) - Auto snooze support +- [storm64](https://github.com/storm64) - Fix redrawing in submenus + +## Attributions + +All icons used in this app are from [icons8](https://icons8.com).