diff --git a/apps/setting/settings.js b/apps/setting/settings.js index cf82aedd7..56549227f 100644 --- a/apps/setting/settings.js +++ b/apps/setting/settings.js @@ -5,12 +5,38 @@ Bangle.drawWidgets(); const BANGLEJS2 = process.env.HWVERSION==2; const storage = require('Storage'); let settings; +const scrolls = []; +let menuScroller; function updateSettings() { //storage.erase('setting.json'); // - not needed, just causes extra writes if settings were the same storage.write('setting.json', settings); } +function pushMenu(menu) { + if(menuScroller) scrolls.push(menuScroller.scroll); + + // if !menu, we're just pushing and something else takes + // care of E.showMenu() + if(menu) { + const m = E.showMenu(menu); + menuScroller = m.scroller; + return m; + } +} + +function restoreMenu(menu) { + if(!menu[""]) menu[""] = {}; + menu[""].scroll = scrolls[scrolls.length - 1] | 0; + menuScroller = E.showMenu(menu).scroller; +} + +function popMenu(menu) { + if(!menu[""]) menu[""] = {}; + menu[""].scroll = scrolls.pop() | 0; + menuScroller = E.showMenu(menu).scroller; +} + function updateOptions() { var o = settings.options; // Check to make sure nobody disabled all wakeups and locked themselves out! @@ -65,38 +91,38 @@ if (("object" != typeof settings) || ("object" != typeof settings.options)) resetSettings(); -function showMainMenu() { +function mainMenu() { const mainmenu = { '': { 'title': /*LANG*/'Settings' }, '< Back': ()=>load(), - /*LANG*/'Apps': ()=>showAppSettingsMenu(), - /*LANG*/'System': ()=>showSystemMenu(), - /*LANG*/'Bluetooth': ()=>showBLEMenu(), - /*LANG*/'Alerts': ()=>showAlertsMenu(), - /*LANG*/'Utils': ()=>showUtilMenu() + /*LANG*/'Apps': ()=>pushMenu(appSettingsMenu()), + /*LANG*/'System': ()=>pushMenu(systemMenu()), + /*LANG*/'Bluetooth': ()=>pushMenu(BLEMenu()), + /*LANG*/'Alerts': ()=>pushMenu(alertsMenu()), + /*LANG*/'Utils': ()=>pushMenu(utilMenu()) }; - return E.showMenu(mainmenu); + return mainmenu; } -function showSystemMenu() { +function systemMenu() { const mainmenu = { '': { 'title': /*LANG*/'System' }, - '< Back': ()=>showMainMenu(), - /*LANG*/'Theme': ()=>showThemeMenu(), - /*LANG*/'LCD': ()=>showLCDMenu(), - /*LANG*/'Locale': ()=>showLocaleMenu(), - /*LANG*/'Clock': ()=>showClockMenu(), - /*LANG*/'Launcher': ()=>showLauncherMenu(), - /*LANG*/'Date & Time': ()=>showSetTimeMenu() + '< Back': ()=>popMenu(mainMenu()), + /*LANG*/'Theme': ()=>pushMenu(themeMenu()), + /*LANG*/'LCD': ()=>pushMenu(LCDMenu()), + /*LANG*/'Locale': ()=>pushMenu(localeMenu()), + /*LANG*/'Clock': ()=>pushMenu(clockMenu()), + /*LANG*/'Launcher': ()=>pushMenu(launcherMenu()), + /*LANG*/'Date & Time': ()=>pushMenu(setTimeMenu()) }; - return E.showMenu(mainmenu); + return mainmenu; } -function showAlertsMenu() { +function alertsMenu() { var beepMenuItem; if (BANGLEJS2) { beepMenuItem = { @@ -128,7 +154,7 @@ function showAlertsMenu() { const mainmenu = { '': { 'title': /*LANG*/'Alerts' }, - '< Back': ()=>showMainMenu(), + '< Back': ()=>popMenu(mainMenu()), /*LANG*/'Beep': beepMenuItem, /*LANG*/'Vibration': { value: settings.vibrate, @@ -153,18 +179,18 @@ function showAlertsMenu() { } }; - return E.showMenu(mainmenu); + return mainmenu; } -function showBLEMenu() { +function BLEMenu() { var hidV = [false, "kbmedia", "kb", "com", "joy"]; var hidN = [/*LANG*/"Off", /*LANG*/"Kbrd & Media", /*LANG*/"Kbrd", /*LANG*/"Kbrd & Mouse", /*LANG*/"Joystick"]; var privacy = [/*LANG*/"Off", /*LANG*/"Show name", /*LANG*/"Hide name"]; - E.showMenu({ + return { '': { 'title': /*LANG*/'Bluetooth' }, - '< Back': ()=>showMainMenu(), + '< Back': ()=>popMenu(mainMenu()), /*LANG*/'Make Connectable': ()=>makeConnectable(), /*LANG*/'BLE': { value: settings.ble, @@ -217,7 +243,7 @@ function showBLEMenu() { }, /*LANG*/'Passkey': { value: settings.passkey?settings.passkey:/*LANG*/"none", - onchange: () => setTimeout(showPasskeyMenu) // graphical_menu redraws after the call + onchange: () => setTimeout(() => pushMenu(passkeyMenu())) // graphical_menu redraws after the call }, /*LANG*/'Whitelist': { value: @@ -228,12 +254,12 @@ function showBLEMenu() { ? " (" + settings.whitelist.length + ")" : "" ), - onchange: () => setTimeout(showWhitelistMenu) // graphical_menu redraws after the call + onchange: () => setTimeout(() => pushMenu(whitelistMenu())) // graphical_menu redraws after the call } - }); + }; } -function showThemeMenu() { +function themeMenu() { function cl(x) { return g.setColor(x).getColor(); } function upd(th) { g.theme = th; @@ -250,7 +276,7 @@ function showThemeMenu() { var themesMenu = { '':{title:/*LANG*/'Theme'}, - '< Back': ()=>showSystemMenu(), + '< Back': ()=>popMenu(systemMenu()), /*LANG*/'Dark BW': ()=>{ upd({ fg:cl("#fff"), bg:cl("#000"), @@ -283,11 +309,11 @@ function showThemeMenu() { } ); - themesMenu[/*LANG*/'Customize'] = () => showCustomThemeMenu(); + themesMenu[/*LANG*/'Customize'] = () => pushMenu(customThemeMenu()); - var m = E.showMenu(themesMenu); + var m = pushMenu(themesMenu); - function showCustomThemeMenu() { + function customThemeMenu() { function setT(t, v) { let th = g.theme; th[t] = v; @@ -318,7 +344,7 @@ function showThemeMenu() { } let menu = { '':{title:/*LANG*/'Custom Theme'}, - "< Back": () => showThemeMenu() + "< Back": () => popMenu(themeMenu()) }; const labels = { fg: /*LANG*/'Foreground', bg: /*LANG*/'Background', @@ -341,17 +367,17 @@ function showThemeMenu() { }, }; }); - m = E.showMenu(menu); + m = pushMenu(menu); } } -function showPasskeyMenu() { +function passkeyMenu() { var menu = { - "< Back" : ()=>showBLEMenu(), + "< Back" : ()=>popMenu(BLEMenu()), /*LANG*/"Disable" : () => { settings.passkey = undefined; updateSettings(); - showBLEMenu(); + popMenu(BLEMenu()); } }; if (!settings.passkey || settings.passkey.length!=6) { @@ -370,24 +396,24 @@ function showPasskeyMenu() { } }; })(i); - E.showMenu(menu); + return menu; } -function showWhitelistMenu() { +function whitelistMenu() { var menu = { - "< Back" : ()=>showBLEMenu(), + "< Back" : ()=>popMenu(BLEMenu()), }; if (settings.whitelist_disabled) { menu[/*LANG*/"Enable"] = () => { delete settings.whitelist_disabled; updateSettings(); - showBLEMenu(); + popMenu(BLEMenu()); }; } else { menu[/*LANG*/"Disable"] = () => { settings.whitelist_disabled = true; updateSettings(); - showBLEMenu(); + popMenu(BLEMenu()); }; } @@ -398,14 +424,14 @@ function showWhitelistMenu() { settings.whitelist.splice(settings.whitelist.indexOf(d),1); updateSettings(); } - setTimeout(showWhitelistMenu, 50); + setTimeout(() => pushMenu(whitelistMenu()), 50); }); } }); menu[/*LANG*/'Add Device']=function() { E.showAlert(/*LANG*/"Connect device\nto add to\nwhitelist",/*LANG*/"Whitelist").then(function() { NRF.removeAllListeners('connect'); - showWhitelistMenu(); + pushMenu(whitelistMenu()); }); NRF.removeAllListeners('connect'); NRF.on('connect', function(addr) { @@ -420,13 +446,13 @@ function showWhitelistMenu() { settings.whitelist.push(addr); updateSettings(); NRF.removeAllListeners('connect'); - showWhitelistMenu(); + pushMenu(whitelistMenu()); }); }; - E.showMenu(menu); + return menu; } -function showLCDMenu() { +function LCDMenu() { // converts g to Espruino internal unit function gToInternal(g) { return g * 8192; } // converts Espruino internal unit to g @@ -436,7 +462,7 @@ function showLCDMenu() { const lcdMenu = { '': { 'title': 'LCD' }, - '< Back': ()=>showSystemMenu(), + '< Back': ()=>popMenu(systemMenu()), }; if (BANGLEJS2) Object.assign(lcdMenu, { @@ -583,13 +609,13 @@ function showLCDMenu() { } }); - return E.showMenu(lcdMenu) + return lcdMenu } -function showLocaleMenu() { +function localeMenu() { const localemenu = { '': { 'title': /*LANG*/'Locale' }, - '< Back': ()=>showSystemMenu(), + '< Back': ()=>popMenu(systemMenu()), /*LANG*/'Time Zone': { value: settings.timezone, format: v => (v > 0 ? "+" : "") + v, @@ -620,13 +646,13 @@ function showLocaleMenu() { }, } }; - return E.showMenu(localemenu); + return localemenu; } -function showUtilMenu() { +function utilMenu() { var menu = { '': { 'title': /*LANG*/'Utilities' }, - '< Back': ()=>showMainMenu(), + '< Back': ()=>popMenu(mainMenu()), /*LANG*/'Debug': { value: E.clip(0|settings.log,0,3), min: 0, @@ -640,7 +666,7 @@ function showUtilMenu() { /*LANG*/'Compact Storage': () => { E.showMessage(/*LANG*/"Compacting...\nTakes approx\n1 minute",{title:/*LANG*/"Storage"}); storage.compact(); - showUtilMenu(); + restoreMenu(utilMenu()); }, /*LANG*/'Rewrite Settings': () => { storage.write(".boot0","eval(require('Storage').read('bootupdate.js'));"); @@ -660,9 +686,13 @@ function showUtilMenu() { }, 1); } }; + const back = () => { + restoreMenu(utilMenu()); + }; + if (BANGLEJS2) menu[/*LANG*/'Calibrate Battery'] = () => { - E.showPrompt(/*LANG*/"Is the battery fully charged?",{title:/*LANG*/"Calibrate",back:showUtilMenu}).then(ok => { + E.showPrompt(/*LANG*/"Is the battery fully charged?",{title:/*LANG*/"Calibrate",back}).then(ok => { if (ok) { var s=storage.readJSON("setting.json"); s.batFullVoltage = (analogRead(D3)+analogRead(D3)+analogRead(D3)+analogRead(D3))/4; @@ -674,17 +704,17 @@ function showUtilMenu() { }); }; menu[/*LANG*/'Reset Settings'] = () => { - E.showPrompt(/*LANG*/'Reset to Defaults?',{title:/*LANG*/"Settings",back:showUtilMenu}).then((v) => { + E.showPrompt(/*LANG*/'Reset to Defaults?',{title:/*LANG*/"Settings",back}).then((v) => { if (v) { E.showMessage(/*LANG*/'Resetting'); resetSettings(); - setTimeout(showMainMenu, 50); - } else showUtilMenu(); + setTimeout(() => popMenu(mainMenu), 50); + } else restoreMenu(utilMenu()); }); }; menu[/*LANG*/"Turn Off"] = () => { E.showPrompt(/*LANG*/"Are you sure? Alarms and timers won't fire", { - title:/*LANG*/"Turn Off",back:showUtilMenu + title:/*LANG*/"Turn Off",back }).then((confirmed) => { if (confirmed) { E.showMessage(/*LANG*/"See you\nlater!", /*LANG*/"Goodbye"); @@ -697,34 +727,34 @@ function showUtilMenu() { Bangle.softOff ? Bangle.softOff() : Bangle.off(); }, 2500); } else { - showUtilMenu(); + restoreMenu(utilMenu()); } }); }; if (Bangle.factoryReset) { menu[/*LANG*/'Factory Reset'] = ()=>{ - E.showPrompt(/*LANG*/'This will remove everything!',{title:/*LANG*/"Factory Reset",back:showUtilMenu}).then((v) => { + E.showPrompt(/*LANG*/'This will remove everything!',{title:/*LANG*/"Factory Reset",back}).then((v) => { if (v) { var n = ((Math.random()*4)&3) + 1; E.showPrompt(/*LANG*/"To confirm, please press "+n,{ title:/*LANG*/"Factory Reset", buttons : {"1":1,"2":2,"3":3,"4":4}, - back:showUtilMenu + back }).then(function(v) { if (v==n) { E.showMessage(); Terminal.setConsole(); Bangle.factoryReset(); } else { - showUtilMenu(); + back(); } }); - } else showUtilMenu(); + } else back(); }); } } - return E.showMenu(menu); + return menu; } function makeConnectable() { @@ -739,19 +769,20 @@ function makeConnectable() { } if (!r) try { NRF.sleep(); } catch (e) { } delete NRF.ignoreWhitelist; - showMainMenu(); + popMenu(mainMenu()); }); } -function showClockMenu() { +function clockMenu() { var clockApps = storage.list(/\.info$/) .map(app => {var a=storage.readJSON(app, 1);return (a&&a.type == "clock")?a:undefined}) .filter(app => app) // filter out any undefined apps .sort((a, b) => a.sortorder - b.sortorder); + const back = ()=>popMenu(systemMenu()); const clockMenu = { '': { 'title': /*LANG*/'Select Clock', }, - '< Back': ()=>showSystemMenu(), + '< Back': back, }; clockApps.forEach((app, index) => { var label = app.name; @@ -762,24 +793,25 @@ function showClockMenu() { settings.clock = app.src; settings.clockHasWidgets = storage.read(app.src).includes("Bangle.loadWidgets"); updateSettings(); - showMainMenu(); + back(); }; }); if (clockApps.length === 0) { clockMenu[/*LANG*/"No Clocks Found"] = () => { }; } - return E.showMenu(clockMenu); + return clockMenu; } -function showLauncherMenu() { +function launcherMenu() { var launcherApps = storage.list(/\.info$/) .map(app => {var a=storage.readJSON(app, 1);return (a&&a.type == "launch")?a:undefined}) .filter(app => app) // filter out any undefined apps .sort((a, b) => a.sortorder - b.sortorder); + const back = ()=>popMenu(systemMenu()); const launcherMenu = { '': { 'title': /*LANG*/'Select Launcher', }, - '< Back': ()=>showSystemMenu(), + '< Back': back, }; launcherApps.forEach((app, index) => { var label = app.name; @@ -789,22 +821,22 @@ function showLauncherMenu() { launcherMenu[label] = () => { settings.launcher = app.src; updateSettings(); - showMainMenu(); + back(); }; }); if (launcherApps.length === 0) { launcherMenu[/*LANG*/"No Launchers Found"] = () => { }; } - return E.showMenu(launcherMenu); + return launcherMenu; } -function showSetTimeMenu() { +function setTimeMenu() { let d = new Date(); const timemenu = { '': { 'title': /*LANG*/'Date & Time' }, '< Back': function () { setTime(d.getTime() / 1000); - showSystemMenu(); + popMenu(systemMenu()); }, /*LANG*/'Day': { value: d.getDate(), @@ -851,13 +883,13 @@ function showSetTimeMenu() { } } }; - return E.showMenu(timemenu); + return timemenu; } -function showAppSettingsMenu() { +function appSettingsMenu() { let appmenu = { '': { 'title': /*LANG*/'App Settings' }, - '< Back': ()=>showMainMenu(), + '< Back': ()=>popMenu(mainMenu()), } const apps = storage.list(/\.settings\.js$/) .map(s => s.substr(0, s.length-12)) @@ -878,12 +910,13 @@ function showAppSettingsMenu() { apps.forEach(function (app) { appmenu[app.name] = () => { showAppSettings(app) }; }) - E.showMenu(appmenu) + return appmenu; } function showAppSettings(app) { + const back = () => popMenu(appSettingsMenu()); const showError = msg => { E.showMessage(`${app.name}:\n${msg}!\n\nBTN1 to go back`); - setWatch(showAppSettingsMenu, BTN1, { repeat: false }); + setWatch(back, BTN1, { repeat: false }); } let appSettings = storage.read(app.id+'.settings.js'); try { @@ -896,8 +929,9 @@ function showAppSettings(app) { return showError(/*LANG*/'Invalid settings'); } try { - // pass showAppSettingsMenu as "back" argument - appSettings(()=>showAppSettingsMenu()); + // pass appSettingsMenu as "back" argument + pushMenu(); + appSettings(back); } catch (e) { console.log(`${app.name} settings error:`, e); return showError(/*LANG*/'Error in settings'); @@ -961,7 +995,7 @@ function showTouchscreenCalibration() { g.setFont("6x8:2").setFontAlign(0,0).drawString(/*LANG*/"Calibrated!", g.getWidth()/2, g.getHeight()/2); } // now load the main menu again - setTimeout(showLCDMenu, 500); + setTimeout(() => restoreMenu(LCDMenu), 500); } function touchHandler(_,e) { @@ -993,5 +1027,5 @@ function showTouchscreenCalibration() { showTapSpot(); } -showMainMenu(); +pushMenu(mainMenu()); }