diff --git a/apps/qmsched/ChangeLog b/apps/qmsched/ChangeLog index 897d06c260f..f605c89fad6 100644 --- a/apps/qmsched/ChangeLog +++ b/apps/qmsched/ChangeLog @@ -9,3 +9,6 @@ 0.08: Support new Bangle.js 2 menu 0.09: Use default Bangle formatter for booleans 0.10: Allow using theme files +0.11: Add day-specific scheduling + Added clock info for fast switching + Consolidated getMode into lib.js diff --git a/apps/qmsched/app.js b/apps/qmsched/app.js index 023c247ee58..9df87805455 100644 --- a/apps/qmsched/app.js +++ b/apps/qmsched/app.js @@ -9,6 +9,15 @@ let bSettings = STORAGE.readJSON('setting.json',true)||{}; let current = 0|bSettings.quiet; delete bSettings; // we don't need any other global settings +const allDays = 0b1111111; // bits 0–6 = Sun, Mon, Tue, Wed, Thu, Fri, Sat +const dayNames = ["Su","Mo","Tu","We","Th","Fr","Sa"]; + +function formatDays(mask) { + if (!mask || mask === allDays) return "Every day"; + if (mask === 0b0111110) return "Mon-Fri"; + if (mask === 0b1000001) return "Weekends"; + return dayNames.filter((_, i) => mask & (1 << i)).join(","); +} @@ -49,6 +58,7 @@ function loadSettings() { scheds: settings, }; // store new format + save(); // and clean up qmOptions from global settings file delete bOptions.qmOptions; @@ -101,7 +111,6 @@ function applyTheme() { */ function showThemeMenu(back, quiet){ const option = quiet ? "quietTheme" : "normalTheme"; - function cl(x) { return g.setColor(x).getColor(); } var themesMenu = { '':{title:/*LANG*/'Theme', back: back}, /*LANG*/'Default': ()=>{ @@ -126,6 +135,7 @@ function showThemeMenu(back, quiet){ * Library uses this to make the app update itself * @param {int} mode New Quite Mode */ +//eslint-disable-next-line no-unused-vars function setAppQuietMode(mode) { if (mode === current) return; current = mode; @@ -146,8 +156,8 @@ function showMainMenu() { }; scheds.sort((a, b) => (a.hr-b.hr)); scheds.forEach((sched, idx) => { - menu[formatTime(sched.hr)] = () => { showEditMenu(idx); }; - menu[formatTime(sched.hr)].format = () => modeNames[sched.mode]+' >'; // this does nothing :-( + const label = formatTime(sched.hr) + " " + formatDays(sched.days ?? allDays); + menu[label] = () => { showEditMenu(idx); }; }); menu[/*LANG*/"Add Schedule"] = () => showEditMenu(-1); menu[/*LANG*/"Switch Theme"] = { @@ -155,60 +165,71 @@ function showMainMenu() { onchange: v => v ? set("switchTheme", v) : unset("switchTheme"), }; menu[/*LANG*/"Options"] = () => showOptionsMenu(); + m = E.showMenu(menu); -} +} +function showDaysMenu(mask, onDone) { + let cur = mask; + let menu = {"": {title: "Active Days"}}; + menu["< Back"] = () => onDone(cur); + dayNames.forEach((name, i) => { + menu[name] = { + value: !!(cur & (1 << i)), + onchange: v => { + if (v) cur |= (1 << i); + else cur &= ~(1 << i); + }, + }; + }); + E.showMenu(menu); +} function showEditMenu(index) { const isNew = index<0; let hrs = 12, mins = 0; let mode = 1; + let days = allDays; if (!isNew) { const s = scheds[index]; hrs = 0|s.hr; mins = Math.round((s.hr-hrs)*60); mode = s.mode; + days = ("days" in s) ? s.days : allDays; } - let menu = {"": {"title": (isNew ? /*LANG*/"Add Schedule" : /*LANG*/"Edit Schedule")}}; - menu[B2 ? "< Back" : /*LANG*/"< Cancel"] = () => showMainMenu(); - menu[/*LANG*/"Hours"] = { - value: hrs, - min:0, max:23, wrap:true, - onchange: v => {hrs = v;}, - }; - menu[/*LANG*/"Minutes"] = { - value: mins, - min:0, max:55, step:5, wrap:true, - onchange: v => {mins = v;}, - }; - menu[/*LANG*/"Switch to"] = { - value: mode, - min:0, max:2, wrap:true, - format: v => modeNames[v], - onchange: v => {mode = v;}, - }; - function getSched() { - return { - hr: hrs+(mins/60), - mode: mode, + + function show() { + let menu = {"": {"title": (isNew ? "Add Schedule" : "Edit Schedule")}}; + menu[B2 ? "< Back" : "< Cancel"] = () => showMainMenu(); + menu[/*LANG*/"Hours"] = { value: hrs, min:0, max:23, wrap:true, onchange: v => {hrs = v;} }; + menu[/*LANG*/"Minutes"] = { value: mins, min:0, max:55, step:5, wrap:true, onchange: v => {mins = v;} }; + menu[/*LANG*/"Days: "+formatDays(days)] = () => { + showDaysMenu(days, newDays => { + days = newDays || allDays; + show(); // rebuild with updated days key + }); }; - } - menu[B2 ? /*LANG*/"Save" : /*LANG*/"> Save"] = function() { - if (isNew) { - scheds.push(getSched()); - } else { - scheds[index] = getSched(); + menu[/*LANG*/"Switch to"] = { value: mode, min:0, max:2, wrap:true, format: v => modeNames[v], onchange: v => {mode = v;} }; + + function getSched() { + return { hr: hrs+(mins/60), mode: mode, days: days }; } - save(); - showMainMenu(); - }; - if (!isNew) { - menu[B2 ? /*LANG*/"Delete" : /*LANG*/"> Delete"] = function() { - scheds.splice(index, 1); + menu[B2 ? /*LANG*/"Save" : /*LANG*/"> Save"] = function() { + if (isNew) scheds.push(getSched()); + else scheds[index] = getSched(); save(); showMainMenu(); }; + if (!isNew) { + menu[B2 ? /*LANG*/"Delete" : /*LANG*/"> Delete"] = function() { + scheds.splice(index, 1); + save(); + showMainMenu(); + }; + } + m = E.showMenu(menu); } - m = E.showMenu(menu); + + show(); } function showOptionsMenu() { diff --git a/apps/qmsched/boot.js b/apps/qmsched/boot.js index c4610ce3e75..16b8146a004 100644 --- a/apps/qmsched/boot.js +++ b/apps/qmsched/boot.js @@ -1,27 +1,33 @@ -// apply Quiet Mode schedules (function qm() { - if (Bangle.qmTimeout) clearTimeout(Bangle.qmTimeout); // so the app can eval() this file to apply changes right away + if (Bangle.qmTimeout) clearTimeout(Bangle.qmTimeout); delete Bangle.qmTimeout; let bSettings = require('Storage').readJSON('setting.json',true)||{}; const curr = 0|bSettings.quiet; delete bSettings; - if (curr) require("qmsched").applyOptions(curr); // no need to re-apply default options - + if (curr) require("qmsched").applyOptions(curr); let settings = require('Storage').readJSON('qmsched.json',true)||{}; let scheds = settings.scheds||[]; if (!scheds.length) {return;} - const now = new Date(), - hr = now.getHours()+(now.getMinutes()/60)+(now.getSeconds()/3600); // current (decimal) hour + const days = 0b1111111; + const now = new Date(); + const hr = now.getHours()+(now.getMinutes()/60)+(now.getSeconds()/3600); scheds.sort((a, b) => a.hr-b.hr); - const tday = scheds.filter(s => s.hr>hr), // scheduled for today - tmor = scheds.filter(s => s.hr<=hr); // scheduled for tomorrow - const next = tday.length ? tday[0] : tmor[0], - mode = next.mode; - let t = 3600000*(next.hr-hr); // timeout in milliseconds - if (t<0) {t += 86400000;} // scheduled for tomorrow: add a day - /* update quiet mode at the correct time. */ + let best = null, bestT = Infinity; + for (let i = 0; i < scheds.length; i++) { + const s = scheds[i]; + const mask = s.days !== undefined ? s.days : days; + for (let d = 0; d < 7; d++) { + const dayBit = 1 << ((now.getDay() + d) % 7); + if (!(mask & dayBit)) continue; + let t = 3600000 * (s.hr - hr) + d * 86400000; + if (t <= 0) continue; + if (t < bestT) { bestT = t; best = s; } + break; + } + } + if (!best) {return;} Bangle.qmTimeout=setTimeout(() => { - require("qmsched").setMode(mode); - qm(); // schedule next update - }, t); + require("qmsched").setMode(best.mode); + qm(); + }, bestT); })(); diff --git a/apps/qmsched/clkinfo.js b/apps/qmsched/clkinfo.js new file mode 100644 index 00000000000..6ce492b5d07 --- /dev/null +++ b/apps/qmsched/clkinfo.js @@ -0,0 +1,34 @@ +(function() { + return { + name: "qmsched", + items: [ + { name : "Quiet Mode Toggle", + get : function() { + const mode = require("qmsched").getMode() + let txt="Off"; + let img=atob("GBgBAAAAAAAAAAAAABwAABwAAH8AAP+AAf/AA//gA//gA//gB//wA//gA//gA//gA//gA//gA//gABwAAD4AABwAAAgAAAAAAAAA"); + if(mode==1){ + txt="Alarms"; + img=atob("GBgBAAAAAAAAAAgAAP+AA//gB//wD//4D//4H//8H//8AAAAAAAAIADiAADgAADgH/nwH/nwD/P4D/P4B/hAA/zgAPnwAAjgAABA") + } + if(mode==2){ + txt="Silent" + img=atob("GBgBAAAAAAAAAAgAAP+AA//gB//wD//4D//4H//8H//8GAAMGAAMOAAOGAAMH//8H//8H//8D//4D//4B//wA//gAP+AAAgAAAAA"); + } + + return { + text : txt, + img : img}}, + show : function() {}, + hide : function() {}, + run : function() { + let mode=require("qmsched").getMode(); + mode = (mode + 1) % 3; + require("qmsched").setMode(mode); + this.emit("redraw"); + } + + } + ] + }; +}) diff --git a/apps/qmsched/lib.js b/apps/qmsched/lib.js index 1d636f263b4..3c1be28018b 100644 --- a/apps/qmsched/lib.js +++ b/apps/qmsched/lib.js @@ -91,5 +91,13 @@ exports.setMode = function(mode) { )); exports.applyOptions(mode); if (typeof WIDGETS === "object" && "qmsched" in WIDGETS) WIDGETS["qmsched"].draw(); + //eslint-disable-next-line no-undef if (global.setAppQuietMode) setAppQuietMode(mode); // current app knows how to update itself }; +/** + * Get the active quiet mode + * Returns: (int) active quiet mode + */ +exports.getMode = function(){ + return (require("Storage").readJSON("setting.json", 1) || {}).quiet|0; +}; diff --git a/apps/qmsched/metadata.json b/apps/qmsched/metadata.json index 26019b6ba8e..2b76e4b6b16 100644 --- a/apps/qmsched/metadata.json +++ b/apps/qmsched/metadata.json @@ -2,12 +2,12 @@ "id": "qmsched", "name": "Quiet Mode Schedule and Widget", "shortName": "Quiet Mode", - "version": "0.10", - "description": "Automatically turn Quiet Mode on or off at set times, change theme and LCD options while Quiet Mode is active.", + "version": "0.11", + "description": "Schedule quiet modes and options to activate at certain times, and provides a clockinfo and widget for changing/viewing modes.", "icon": "app.png", "screenshots": [{"url":"screenshot_b1_main.png"},{"url":"screenshot_b1_edit.png"},{"url":"screenshot_b1_lcd.png"}, {"url":"screenshot_b2_main.png"},{"url":"screenshot_b2_edit.png"},{"url":"screenshot_b2_lcd.png"}], - "tags": "tool,widget", + "tags": "tool,widget,clkinfo", "supports": ["BANGLEJS","BANGLEJS2"], "readme": "README.md", "storage": [ @@ -15,7 +15,8 @@ {"name":"qmsched.app.js","url":"app.js"}, {"name":"qmsched.boot.js","url":"boot.js"}, {"name":"qmsched.img","url":"icon.js","evaluate":true}, - {"name":"qmsched.wid.js","url":"widget.js"} + {"name":"qmsched.wid.js","url":"widget.js"}, + {"name":"qmsched.clkinfo.js","url":"clkinfo.js"} ], "data": [{"name":"qmsched.json"}] } diff --git a/apps/qmsched/widget.js b/apps/qmsched/widget.js index daa11ac71c5..89f5e49174f 100644 --- a/apps/qmsched/widget.js +++ b/apps/qmsched/widget.js @@ -3,7 +3,7 @@ area: "tl", width: ((require("Storage").readJSON("setting.json", 1) || {}).quiet|0) ? 24 : 0, draw: function() { - const mode = (require("Storage").readJSON("setting.json", 1) || {}).quiet|0; + const mode = require("qmsched").getMode(); if (mode===0) { // Off if (this.width!==0) { this.width = 0; @@ -33,4 +33,4 @@ .drawLine(x+5, y-3, x+3, y-5).drawLine(x-5, y-3, x-3, y-5); // wriggles }, }; -})(); \ No newline at end of file +})();