BangleApps/apps/qmsched/app.js

290 lines
8.0 KiB
JavaScript
Raw Normal View History

2021-03-25 22:25:04 +00:00
Bangle.loadWidgets();
Bangle.drawWidgets();
const modeNames = [/*LANG*/"Off", /*LANG*/"Alarms", /*LANG*/"Silent"];
const B2 = process.env.HWVERSION===2;
2022-01-12 18:08:19 +00:00
// load global settings
const STORAGE = require('Storage');
let bSettings = STORAGE.readJSON('setting.json',true)||{};
let current = 0|bSettings.quiet;
delete bSettings; // we don't need any other global settings
/**
* Save settings to qmsched.json
*/
function save() {
STORAGE.writeJSON('qmsched.json', settings);
eval(STORAGE.read('qmsched.boot.js')); // apply new schedules right away
2021-03-25 22:25:04 +00:00
}
function get(key, def) {
return (key in settings) ? settings[key] : def;
}
function set(key, val) {
settings[key] = val; save();
scheds = settings.scheds; options = settings.options; // update references
}
function unset(key) {
delete settings[key]; save();
}
let settings,
scheds, options; // references for convenience
/**
* Load settings file, check if we need to migrate old setting formats to new
*/
function loadSettings() {
settings = STORAGE.readJSON("qmsched.json", true) || {};
if (Array.isArray(settings)) {
// migrate old file (plain array of schedules, qmOptions stored in global settings file)
STORAGE.erase("qmsched.json"); // need to erase old file, or Things Break, somehow...
let bOptions = STORAGE.readJSON('setting.json',true)||{};
settings = {
options: bOptions.qmOptions || {},
scheds: settings,
};
// store new format
save();
// and clean up qmOptions from global settings file
delete bOptions.qmOptions;
STORAGE.writeJSON('setting.json',bOptions);
}
// apply defaults
settings = Object.assign({
options: {}, // Bangle options to override during quiet mode, default = none
scheds: [
// default schedule:
{"hr": 8, "mode": 0},
{"hr": 22, "mode": 1},
],
}, settings);
scheds = settings.scheds; options = settings.options;
if (scheds.length && scheds.some(s => "last" in s)) {
// cleanup: remove "last" values (used by older versions)
set('scheds', scheds.map(s => {
delete s.last;
return s;
}));
}
}
2021-03-25 22:25:04 +00:00
function formatTime(t) {
const hrs = 0|t;
const mins = Math.round((t-hrs)*60);
return (" "+hrs).substr(-2)+":"+("0"+mins).substr(-2);
}
2022-01-12 18:08:19 +00:00
/**
* Apply theme
*/
function applyTheme() {
const theme = (STORAGE.readJSON("setting.json", 1) || {}).theme;
2022-01-12 18:08:19 +00:00
g.theme = theme;
delete g.reset;
g._reset = g.reset;
g.reset = function(n) { return g._reset().setColor(g.theme.fg).setBgColor(g.theme.bg); };
g.clear = function(n) { if (n) g.reset(); return g.clearRect(0,0,g.getWidth(),g.getHeight()); };
g.clear(1);
Bangle.drawWidgets();
delete m.lastIdx; // force redraw
m.draw();
}
2021-03-25 22:25:04 +00:00
/**
* This creates menu entries for setting themes. This code is lifted from the setting app.
* @returns
*/
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': ()=>{
unset(option);
back();
}
};
STORAGE.list(/^.*\.theme$/).forEach(
n => {
let newTheme = STORAGE.readJSON(n);
themesMenu[newTheme.name ? newTheme.name : n] = () => {
set(option, n);
back();
};
}
);
E.showMenu(themesMenu);
}
2022-01-12 18:08:19 +00:00
/**
* Library uses this to make the app update itself
* @param {int} mode New Quite Mode
*/
function setAppQuietMode(mode) {
2022-01-12 18:08:19 +00:00
if (mode === current) return;
current = mode;
delete m.lastIdx; // force redraw
applyTheme();
if (m.lastIdx===undefined) m.draw(); // applyTheme didn't redraw menu, but we need to show updated mode
}
let m;
2021-03-25 22:25:04 +00:00
function showMainMenu() {
let menu = {"": {"title": /*LANG*/"Quiet Mode"}};
menu[B2 ? "< Back" : /*LANG*/"< Exit"] = () => {load();};
menu[/*LANG*/"Current Mode"] = {
value: current,
2022-01-12 18:08:19 +00:00
min:0, max:2, wrap: true,
format: v => modeNames[v],
2022-01-12 18:08:19 +00:00
onchange: require("qmsched").setMode, // library calls setAppMode(), which updates `current`
2021-03-25 22:25:04 +00:00
};
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 :-(
2021-03-25 22:25:04 +00:00
});
menu[/*LANG*/"Add Schedule"] = () => showEditMenu(-1);
menu[/*LANG*/"Switch Theme"] = {
2022-01-12 18:08:19 +00:00
value: !!get("switchTheme"),
onchange: v => v ? set("switchTheme", v) : unset("switchTheme"),
};
menu[/*LANG*/"Options"] = () => showOptionsMenu();
2022-01-12 18:08:19 +00:00
m = E.showMenu(menu);
2021-03-25 22:25:04 +00:00
}
function showEditMenu(index) {
const isNew = index<0;
let hrs = 12, mins = 0;
let mode = 1;
if (!isNew) {
const s = scheds[index];
hrs = 0|s.hr;
mins = Math.round((s.hr-hrs)*60);
mode = s.mode;
}
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;},
2021-03-25 22:25:04 +00:00
};
function getSched() {
return {
hr: hrs+(mins/60),
2021-03-25 22:25:04 +00:00
mode: mode,
};
}
menu[B2 ? /*LANG*/"Save" : /*LANG*/"> Save"] = function() {
2021-03-25 22:25:04 +00:00
if (isNew) {
scheds.push(getSched());
} else {
scheds[index] = getSched();
}
save();
2021-03-25 22:25:04 +00:00
showMainMenu();
};
if (!isNew) {
menu[B2 ? /*LANG*/"Delete" : /*LANG*/"> Delete"] = function() {
2021-03-25 22:25:04 +00:00
scheds.splice(index, 1);
save();
2021-03-25 22:25:04 +00:00
showMainMenu();
};
}
2022-01-12 18:08:19 +00:00
m = E.showMenu(menu);
2021-03-25 22:25:04 +00:00
}
function showOptionsMenu() {
const disabledFormat = v => v ? /*LANG*/"Off" : "-";
function toggle(option) {
// we disable wakeOn* events by setting them to `false` in options
// not disabled = not present in options at all
if (option in options) {
delete options[option];
} else {
options[option] = false;
}
save();
}
let resetTimeout;
const oMenu = {
"": {"title": /*LANG*/"LCD Settings"},
"< Back": () => showMainMenu(),
/*LANG*/"LCD Brightness": {
value: get("brightness", 0),
min: 0, // 0 = use default
max: 1,
step: 0.1,
format: v => (v>0.05) ? v : "-",
onchange: v => {
if (v>0.05) { // prevent v=0.000000000000001 bugs
set("brightness", v);
Bangle.setLCDBrightness(v); // show result, even if not quiet right now
// restore brightness after half a second
if (resetTimeout) clearTimeout(resetTimeout);
resetTimeout = setTimeout(() => {
resetTimeout = undefined;
require("qmsched").setMode(current);
}, 500);
} else {
unset("brightness");
require("qmsched").setMode(current);
}
},
},
/*LANG*/"LCD Timeout": {
value: get("timeout", 0),
min: 0, // 0 = use default (no constant on for quiet mode)
max: 60,
step: 5,
format: v => v>1 ? v : "-",
onchange: v => {
if (v>1) set("timeout", v);
else unset("timeout");
},
},
// we disable wakeOn* events by overwriting them as false in options
// not disabled = not present in options at all
/*LANG*/"Wake on FaceUp": {
value: "wakeOnFaceUp" in options,
format: disabledFormat,
onchange: () => {toggle("wakeOnFaceUp");},
},
/*LANG*/"Wake on Touch": {
value: "wakeOnTouch" in options,
format: disabledFormat,
onchange: () => {toggle("wakeOnTouch");},
},
/*LANG*/"Wake on Twist": {
value: "wakeOnTwist" in options,
format: disabledFormat,
onchange: () => {toggle("wakeOnTwist");},
},
};
oMenu[/*LANG*/"Normal Theme"] = () => showThemeMenu(showOptionsMenu, false);
oMenu[/*LANG*/"Quiet Theme"] = () => showThemeMenu(showOptionsMenu, true);
2022-01-12 18:08:19 +00:00
m = E.showMenu(oMenu);
}
loadSettings();
2021-03-25 22:25:04 +00:00
showMainMenu();