From f314eabe20d8e334e59e98abe29cf566d64b8cc5 Mon Sep 17 00:00:00 2001 From: jla-42 <66872002+jla-42@users.noreply.github.com> Date: Wed, 13 Mar 2024 22:32:13 +0100 Subject: [PATCH] Add files via upload --- apps/thmswtch/ChangeLog | 2 +- apps/thmswtch/README.md | 35 ++++++ apps/thmswtch/app-icon.js | 1 + apps/thmswtch/app.js | 217 ++++++++++++++++++++++++++++++++++++ apps/thmswtch/app.png | Bin 0 -> 879 bytes apps/thmswtch/boot.js | 115 +++++++++++++++++++ apps/thmswtch/metadata.json | 15 +++ 7 files changed, 384 insertions(+), 1 deletion(-) create mode 100644 apps/thmswtch/README.md create mode 100644 apps/thmswtch/app-icon.js create mode 100644 apps/thmswtch/app.js create mode 100644 apps/thmswtch/app.png create mode 100644 apps/thmswtch/boot.js create mode 100644 apps/thmswtch/metadata.json diff --git a/apps/thmswtch/ChangeLog b/apps/thmswtch/ChangeLog index 8b1378917..5560f00bc 100644 --- a/apps/thmswtch/ChangeLog +++ b/apps/thmswtch/ChangeLog @@ -1 +1 @@ - +0.01: New App! diff --git a/apps/thmswtch/README.md b/apps/thmswtch/README.md new file mode 100644 index 000000000..31e6aabe9 --- /dev/null +++ b/apps/thmswtch/README.md @@ -0,0 +1,35 @@ +# Theme Switcher + +Switch Dark/Light theme based on time or on sunrise/sunset + +## Usage + +When activated, switches automaticaly the theme based on time or on sunrise/sunset. + +## Controls + +In the app you can: + +-activate / deactivate the general functionality + +-manualy switch dark/light theme + +-define times for light / dark switch (at the moment 1 --> dark and 1 --> light switch time) + +-set automatic witching based on sunrise/sunset times privided by the [suncalc](https://github.com/jla-42/BangleApps/blob/master/modules/suncalc.js) module + +## Creator + +[jla-42](https://github.com/jla-42) + +## Note +The app functionality is inspired by the [Quiet Mode Schedule and Widget](https://github.com/espruino/BangleApps/tree/master/apps/qmsched) app, where i missed the sunrise/sunset functionality, and wanted an indipendent switch of the theme and notifications. + +## ToDos +-further code clean up + +-optimization of code (and check if needed) + +-transfer of configuration into settings, so app can be used as a shortcut to switch theme. + +-feedback is always welcome diff --git a/apps/thmswtch/app-icon.js b/apps/thmswtch/app-icon.js new file mode 100644 index 000000000..bc47207e5 --- /dev/null +++ b/apps/thmswtch/app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwgIWTj/4Aof//4ECgYFB4AFBh4FB+AWCAoIYCn///18AoN/BYMeEQf/h8AgIFCg+AFAX/gfAAocB4EHAofgAocA8A6CAoPwAolwAopGC/wFGnAFI/gFKMgIFDOAIFJ8AFERAJBDOoIFCGgIFDRoXwMoIcBMoJ/BAgJxBgYFDQYKwCAYINBAoIVCWwShBgF4AQKtCnwCBXIUfwEBG4UPSQIaCborpFCQT/HABY=")) diff --git a/apps/thmswtch/app.js b/apps/thmswtch/app.js new file mode 100644 index 000000000..e4312a44d --- /dev/null +++ b/apps/thmswtch/app.js @@ -0,0 +1,217 @@ +const SETTINGS_FILE = "themeSwitch.json"; +const storage = require("Storage"); +var sunrise, sunset, date; +var SunCalc = require("suncalc"); // from modules folder +const locale = require("locale"); +let settings = storage.readJSON('setting.json', 1); +let saved = storage.readJSON(SETTINGS_FILE, 1) || {}; +if (settings.theme.fg >0) { + saved.darkModeActive = 1 +}else { + saved.darkModeActive = 0 +} + if (require("Storage").readJSON("themeSwitch.json",1) !== undefined){ + dmH = parseInt(saved.darkModeAt.split(":")[0]| 0); + dmM = parseInt(saved.darkModeAt.split(":")[1] |0); + lmH = parseInt(saved.lightModeAt.split(":")[0] |0); + lmM = parseInt(saved.lightModeAt.split(":")[1] |0); + }else{ + dmH = 0; + dmM = 0; + lmH = 0; + lmM = 0; + } +// Main menu + + var mainmenu = { + "" : { + "title" : "Theme Switch" + }, + "< Back" : function() {load();}, + "Automatic Dark Mode" : { + value : saved.darkMode | false, + format : v => v?"On":"Off", + min:0,max:1,step:1, + onchange :v=>{ + saved.darkMode = v; + storage.writeJSON(SETTINGS_FILE,saved); + } + }, + "Dark Mode Active" : { + value : saved.darkModeActive | false, + format : v => v?"On":"Off", + min:0,max:1,step:1, + onchange :v=>{ + saved.darkModeActive = v; + storage.writeJSON(SETTINGS_FILE,saved); + if (v!==0) { + setDarkTheme(); + Bangle.drawWidgets(); + delete m.lastIdx; + }else { + setLightTheme(); + Bangle.drawWidgets(); + delete m.lastIdx;} + } + }, + "Dark Mode by Sun" : { + value : saved.darkModeBySun | false, + format : v => v?"On":"Off", + min:0,max:1,step:1, + onchange : v =>{ + saved.darkModeBySun =v; + if (v!==0) { + //print("calculating sun times"); + calculateSunTimes(); + saved.lightModeAt = sunrise; + saved.darkModeAt = sunset; + //print("sunrise" +sunrise); + //print("sunset" +sunset); + + + + } + storage.writeJSON(SETTINGS_FILE,saved); + }, + }, + "light mode at" : { + value : saved.lightModeAt, + format: v => saved.lightModeAt, + onchange :function(){ + if(saved.darkModeBySun===0){ + E.showMenu(lightModeAtMenu); + } + else{ + E.showAlert("Deactivate dark mode first!", "Action Blocked").then( + function() {E.showMenu(mainmenu);}); + } + } + }, + "dark mode at" : { + value : saved.darkModeAt , + format: v => saved.darkModeAt, + onchange :function(){ + if(saved.darkModeBySun===0){ + E.showMenu(darkModeAtMenu); + } + else{ + E.showAlert("Deactivate dark mode first!", "Action Blocked").then( function() {E.showMenu(mainmenu);}); + } + } + }, + "Exit" : function() {load();}, + +}; + +var lightModeAtMenu = { + "" : { + "title" : "light mode at" + }, + "Hour" : { + value : lmH, + min:0,max:23,step:1, + onchange : v => { lmH=v; }}, + "Minute" : { + value : lmM, + min:0,max:59,step:1, + onchange : v => { lmM=v; }}, + "< Back" : function() { saved.lightModeAt = fixTime(lmH,lmM); + storage.writeJSON(SETTINGS_FILE,saved); + E.showMenu(mainmenu); }, + }; + + var darkModeAtMenu = { + "" : { + "title" : "dark mode at" + }, + "Hour" : { + value : dmH, + min:0,max:23,step:1, + onchange : v => { dmH=v; }}, + "Minute" : { + value : dmM, + min:0,max:59,step:1, + onchange : v => { dmM=v; }}, + "< Back" : function() {saved.darkModeAt = fixTime(dmH,dmM); + storage.writeJSON(SETTINGS_FILE,saved); + E.showMenu(mainmenu); }, + }; + +// Actually display the menu +E.showMenu(mainmenu); + +// Function to fix time format +function fixTime(h, m) { + if (h.toString().length <2) { + h = "0" + h.toString(); + } + if (m.toString().length <2) { + m = "0" + m.toString(); + } + return h.toString() +":" + m.toString(); +} + +function calculateSunTimes() { + var location = require("Storage").readJSON("mylocation.json",1)||{}; + location.lat = location.lat||51.5072; + location.lon = location.lon||0.1276; // London + date = new Date(Date.now()); + var times = SunCalc.getTimes(date, location.lat, location.lon); + sunrise = fixTime(times.sunrise.getHours() , times.sunrise.getMinutes()); + sunset = fixTime(times.sunset.getHours() ,times.sunset.getMinutes()); + /* do we want to re-calculate this every day? Or we just assume + that 'show' will get called once a day? */ + } + +function cl(x) { return g.setColor(x).getColor(); } + +function upd(th) { + g.theme = th; + settings.theme = th; + storage.write('setting.json', settings); + delete g.reset; + g._reset = g.reset; + g.reset = function(n) { return g._reset().setColor(th.fg).setBgColor(th.bg); }; + g.clear = function(n) { if (n) g.reset(); return g.clearRect(0,0,g.getWidth(),g.getHeight()); }; + g.clear(1); +} + +function flipTheme() { + if (!g.theme.dark) { + upd({ + fg:cl("#fff"), bg:cl("#000"), + fg2:cl("#fff"), bg2:cl("#004"), + fgH:cl("#fff"), bgH:cl("#00f"), + dark:true + }); + } else { + upd({ + fg:cl("#000"), bg:cl("#fff"), + fg2:cl("#000"), bg2:cl("#cff"), + fgH:cl("#000"), bgH:cl("#0ff"), + dark:false + }); + } +} + +function setDarkTheme() { + if (!g.theme.dark) { + upd({ + fg:cl("#fff"), bg:cl("#000"), + fg2:cl("#fff"), bg2:cl("#004"), + fgH:cl("#fff"), bgH:cl("#00f"), + dark:true + }); + } +} + +function setLightTheme() { + if (g.theme.dark) { + upd({ + fg:cl("#000"), bg:cl("#fff"), + fg2:cl("#000"), bg2:cl("#cff"), + fgH:cl("#000"), bgH:cl("#0ff"), + dark:false + }); + } +} diff --git a/apps/thmswtch/app.png b/apps/thmswtch/app.png new file mode 100644 index 0000000000000000000000000000000000000000..44ad1483d97e53187b3df19e83b7d68eb55a3fc7 GIT binary patch literal 879 zcmV-#1CacQP)rK7_^Hdg`HSLLJUf*Gzx-3P!Tn)f=$%Bh=OP$-pRmQ7{=S(+1c5N#eMML z*nKnez1cVKy?F;sH1S`c1oQ(#z!WeKECS2GlKg%r?}kKIjahMY0^`6}pq^2bQDZVk zaC87OK+S=;DK+3eP!2(S4R9U!?SZ%{YR-`&U28k=$}{P=4Zh+_pv^b=J;3JzcKxEv zJ!?Gw1oZeM|Gfb6N*>D^Ex>t+SkXJRX15QwDPrd%`31CU>+Lrpn)(vkT*;TjAL|9n z7Gqr%R=;TPUju7h47e76d_BfZdL;=)I#*rdd=a6tksOWTa8}b<&YCA?0+FvL7@+V( z)4OL&zSC2NwUq-2T)KciqE{2oNX2+S^7RIX*u;dUd&4I3xD;lt@&j0v!s(EvUp2z+ zKR6h8_aCP1s2KQO8`GDhJQUb~3)tbNHs(^2;@!Xo?65T8v^HikNpU_P`KS)EL6=d% z#-bX~fWsLK*sP6HWkxLYYOqLA<#QISGYY^JH9)P=p3#7ktpSw)2Am-~Hrl#S(TDh! zTwb!G+x8Go6-fR;S{6;ffNdBpDv{mJLEfy-)IB;D{ho=dI{uua+eA=fKiHNMCFz*? zApg|1{7pfhHm3?QtJ4OI_05wP1+sGK$CUhqj?cPIT!M6vmf9PqUEh`Hm+6(<_xm^mMA6Ni#C zTJ^?jBp)S lt && at < dt) { + return "darkT"; + }else if (at >lt && at > dt) { + return "lightN";} + } + function setDarkTheme() { + if (!g.theme.dark) { + upd({ + fg:cl("#fff"), bg:cl("#000"), + fg2:cl("#fff"), bg2:cl("#004"), + fgH:cl("#fff"), bgH:cl("#00f"), + dark:true + }); + } + } + + function setLightTheme() { + if (g.theme.dark) { + upd({ + fg:cl("#000"), bg:cl("#fff"), + fg2:cl("#000"), bg2:cl("#cff"), + fgH:cl("#000"), bgH:cl("#0ff"), + dark:false + }); + } + } + function fixTime(h, m) { + if (h.toString().length <2) { + h = "0" + h.toString(); + } + if (m.toString().length <2) { + m = "0" + m.toString(); + } + return h.toString() +":" + m.toString(); + } + function calculateSunTimes() { + var location = require("Storage").readJSON("mylocation.json",1)||{}; + location.lat = location.lat||51.5072; + location.lon = location.lon||0.1276; // London + date = new Date(Date.now()); + var times = SunCalc.getTimes(date, location.lat, location.lon); + sunrise = fixTime(times.sunrise.getHours() , times.sunrise.getMinutes()); + sunset = fixTime(times.sunset.getHours() ,times.sunset.getMinutes()); + /* do we want to re-calculate this every day? Or we just assume + that 'show' will get called once a day? */ + } + function cl(x) { return g.setColor(x).getColor(); } + function upd(th) { + g.theme = th; + settings = storage.readJSON('setting.json',1) + settings.theme = th; + storage.write('setting.json', settings); + delete g.reset; + g._reset = g.reset; + g.reset = function(n) { return g._reset().setColor(th.fg).setBgColor(th.bg); }; + g.clear = function(n) { if (n) g.reset(); return g.clearRect(0,0,g.getWidth(),g.getHeight()); }; + g.clear(1); + } + try { + if (Bangle.dmTimeout) clearTimeout(Bangle.dmTimeout); // so the app can eval() this file to apply changes right away + delete Bangle.dmTimeout; + } catch (e) { + print("Bangle.dmTimeout does not exist"); + } + const SETTINGS_FILE = "themeSwitch.json"; + const storage = require("Storage"); + var sunrise, sunset, date; + var SunCalc = require("suncalc"); // from modules folder + const locale = require("locale"); + let bSettings = storage.readJSON(SETTINGS_FILE,true)||{}; + const now = new Date(); + hr = now.getHours()+(now.getMinutes()/60)+(now.getSeconds()/3600); // current (decimal) hour + dmH = parseFloat(bSettings.darkModeAt.split(":")[0]); + dmM = parseFloat(bSettings.darkModeAt.split(":")[1]); + lmH = parseFloat(bSettings.lightModeAt.split(":")[0]); + lmM = parseFloat(bSettings.lightModeAt.split(":")[1]); + print("reading switch timeslots....."); + let dmDec = parseFloat(dmH)+parseFloat(dmM)/parseFloat(60); + let lmDec = parseFloat(lmH)+parseFloat(lmM)/parseFloat(60); + targetMode = selectRightMode(parseFloat(lmDec),parseFloat(dmDec),parseFloat(hr)); + if (targetMode === "lightT" || targetMode === "lightN" ){ + nextH = lmH; + nextM = lmM; + } else { + nextH = dmH; + nextM = dmM; + } + nextDecH = parseFloat(nextH) + parseFloat(nextM)/parseFloat(60); + let t = 3600000*(nextDecH-hr); // timeout in milliseconds + if (t<0) {t += 86400000;} // scheduled for tomorrow: add a day + /* update theme mode at the correct time. */ + Bangle.dmTimeout=setTimeout(() => { + if (bSettings.darkMode !==0){ + if (targetMode === "lightT" || targetMode === "lightN" ){ + setLightTheme(); + }else { + setDarkTheme(); + } + Bangle.loadWidgets(); + Bangle.drawWidgets(); + setTimeout(load, 20); + if (bSettings.darkModeBySun !==0){ + calculateSunTimes(); + bSettings.lightModeAt = sunrise; + bSettings.darkModeAt = sunset; + storage.writeJSON(SETTINGS_FILE, bSettings); + } + dm(); // schedule next update + } + }, t); +})(); diff --git a/apps/thmswtch/metadata.json b/apps/thmswtch/metadata.json new file mode 100644 index 000000000..e2826acdd --- /dev/null +++ b/apps/thmswtch/metadata.json @@ -0,0 +1,15 @@ +{ "id": "thmswtch", + "name": "Theme Switcher", + "shortName":"Theme Switcher", + "version":"0.01", + "description": "change theme based on time or sunset/sunrise", + "icon": "app.png", + "tags": "tool", + "supports" : ["BANGLEJS2"], + "readme": "README.md", + "storage": [ + {"name":"thmswtch.app.js","url":"app.js"}, + {"name":"thmswtch.boot.js","url":"boot.js"}, + {"name":"thmswtch.img","url":"app-icon.js","evaluate":true} + ] +}