David Peer 2023-01-09 18:12:53 +01:00
commit 6774bc113c
79 changed files with 800 additions and 222 deletions

View File

@ -1,3 +1,4 @@
0.01: Beta version for Bangle 2 (2021/11/28) 0.01: Beta version for Bangle 2 (2021/11/28)
0.02: Shows night time on the map (2022/12/28) 0.02: Shows night time on the map (2022/12/28)
0.03: Add 1 minute timer with upper taps (2023/01/05) 0.03: Add 1 minute timer with upper taps (2023/01/05)
1.00: Page to set up custom time zones (2023/01/06)

View File

@ -8,11 +8,11 @@
* Bottom Left tap: decrease by 5 minutes * Bottom Left tap: decrease by 5 minutes
* Short buzz at T-30, T-20, T-10 ; Double buzz at T * Short buzz at T-30, T-20, T-10 ; Double buzz at T
* Other time zones * Other time zones
* Currently hardcoded to Paris and Tokyo (this will be customizable in a future version) * Showing Paris and Tokyo by default, but you can customize this using the dedicated configuration page on the app store
* World Map * World Map
* The map shows day and night on Earth and the position of the Sun (yellow line) * The map shows day and night on Earth and the position of the Sun (yellow line)
![](screenshot.png) ![](screenshot-1.png) ![](screenshot.png)
## Creator ## Creator
[@alainsaas](https://github.com/alainsaas) [@alainsaas](https://github.com/alainsaas)

View File

@ -89,6 +89,7 @@ function showWelcomeMessage() {
} }
// time // time
var offsets = require("Storage").readJSON("a_clock_timer.settings.json") || [ ["PAR",1], ["TYO",9] ];
var drawTimeout; var drawTimeout;
function getGmt() { function getGmt() {
@ -119,7 +120,7 @@ function draw() {
g.setColor('#ff0').drawLine(x_sun, g.getHeight()-IMAGEHEIGHT, x_sun, g.getHeight()); g.setColor('#ff0').drawLine(x_sun, g.getHeight()-IMAGEHEIGHT, x_sun, g.getHeight());
g.reset(); g.reset();
var x_night_start = 176 - (((gmtHours-6)%24) / 24 * 176 + 4); var x_night_start = (176 - (((gmtHours-6)%24) / 24 * 176 + 4)) % 176;
var x_night_end = 176 - (((gmtHours+6)%24) / 24 * 176 + 4); var x_night_end = 176 - (((gmtHours+6)%24) / 24 * 176 + 4);
g.setColor('#000'); g.setColor('#000');
for (let x = x_night_start; x < (x_night_end < x_night_start ? 176 : x_night_end); x+=2) { for (let x = x_night_start; x < (x_night_end < x_night_start ? 176 : x_night_end); x+=2) {
@ -138,8 +139,8 @@ function draw() {
g.setFont("Michroma36").drawString(locale.time(date,1), g.getWidth()/2, 46); g.setFont("Michroma36").drawString(locale.time(date,1), g.getWidth()/2, 46);
g.setFont("6x8"); g.setFont("6x8");
g.drawString(locale.date(new Date(),1), 125, 68); g.drawString(locale.date(new Date(),1), 125, 68);
g.drawString("PAR "+locale.time(getTimeFromTimezone(1),1), 125, 80); g.drawString(offsets[0][0]+" "+locale.time(getTimeFromTimezone(offsets[0][1]),1), 125, 80);
g.drawString("TYO "+locale.time(getTimeFromTimezone(9),1), 125, 88); g.drawString(offsets[1][0]+" "+locale.time(getTimeFromTimezone(offsets[1][1]),1), 125, 88);
queueNextDraw(); queueNextDraw();
} }

View File

@ -0,0 +1,58 @@
<html>
<head>
<link rel="stylesheet" href="../../css/spectre.min.css">
</head>
<body>
<p>You can set the 2 additional timezones displayed by the clock.</p>
<table id="a_clock_timer-offsets">
<tr>
<th>Name</th>
<th>UTC Offset (Hours)</th>
</tr>
</table>
<p>Click <button id="upload" class="btn btn-primary">Upload</button></p>
<script src="../../core/lib/customize.js"></script>
<script>
var offsets=[];
try{
var stored = localStorage.getItem('a_clock_timer-offset-list')
if(stored) offsets = JSON.parse(stored);
if (!offsets || offsets.length!=2) {
throw "Offsets invalid";
}
} catch(e){
offsets=[
["PAR",1],
["TYO",9],
];
}
console.log(offsets);
var tbl=document.getElementById("a_clock_timer-offsets");
for (var i=0; i<2; i++) {
var $offset = document.createElement('tr')
$offset.innerHTML = `
<td><input type="text" size="4" maxlength="3" id="name_${i}" value="${offsets[i][0]}"></td>
<td><input type="number" id="offset_${i}" value="${offsets[i][1]}"></td>`
tbl.append($offset);
}
document.getElementById("upload").addEventListener("click", function() {
var storage_offsets=[];
var app_offsets=[];
for (var i=0; i<2; i++) {
var name=document.getElementById("name_"+i).value;
var offset=document.getElementById("offset_"+i).value;
app_offsets.push([name,offset]);
storage_offsets.push([name,offset]);
}
console.log(storage_offsets);
console.log(app_offsets);
localStorage.setItem('a_clock_timer-offset-list',JSON.stringify(storage_offsets));
sendCustomizedApp({
storage:[
{name:"a_clock_timer.settings.json", content:JSON.stringify(app_offsets)},
]
});
});
</script>
</body>
</html>

View File

@ -1,17 +1,19 @@
{ {
"id": "a_clock_timer", "id": "a_clock_timer",
"name": "A Clock with Timer", "name": "A Clock with Timer",
"version": "0.03", "version": "1.00",
"description": "A Clock with Timer, Map and Time Zones", "description": "A Clock with Timer, Map and Time Zones",
"icon": "app.png", "icon": "app.png",
"screenshots": [{"url":"screenshot.png"}], "screenshots": [{"url":"screenshot.png"},{"url":"screenshot-1.png"}],
"type": "clock", "type": "clock",
"tags": "clock", "tags": "clock",
"supports": ["BANGLEJS2"], "supports": ["BANGLEJS2"],
"allow_emulator": true, "allow_emulator": true,
"readme": "README.md", "readme": "README.md",
"custom": "custom.html",
"storage": [ "storage": [
{"name":"a_clock_timer.app.js","url":"app.js"}, {"name":"a_clock_timer.app.js","url":"app.js"},
{"name":"a_clock_timer.img","url":"app-icon.js","evaluate":true} {"name":"a_clock_timer.img","url":"app-icon.js","evaluate":true}
] ],
"data": [{"name":"a_clock_timer.settings.json"}]
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

View File

@ -14,3 +14,4 @@
0.14: Use ClockFace_menu.addItems 0.14: Use ClockFace_menu.addItems
0.15: Add Power saving option 0.15: Add Power saving option
0.16: Support Fast Loading 0.16: Support Fast Loading
0.17: Hide widgets instead of not loading them at all

View File

@ -1,7 +1,7 @@
{ {
"id": "barclock", "id": "barclock",
"name": "Bar Clock", "name": "Bar Clock",
"version": "0.16", "version": "0.17",
"description": "A simple digital clock showing seconds as a bar", "description": "A simple digital clock showing seconds as a bar",
"icon": "clock-bar.png", "icon": "clock-bar.png",
"screenshots": [{"url":"screenshot.png"},{"url":"screenshot_pm.png"}], "screenshots": [{"url":"screenshot.png"},{"url":"screenshot_pm.png"}],

View File

@ -1,5 +1,10 @@
(function(back) { (function(back) {
let s = require("Storage").readJSON("barclock.settings.json", true) || {}; let s = require("Storage").readJSON("barclock.settings.json", true) || {};
// migrate "don't load widgets" to "hide widgets"
if (!("hideWidgets" in s) && ("loadWidgets" in s) && !s.loadWidgets) {
s.hideWidgets = 1;
}
delete s.loadWidgets;
function save(key, value) { function save(key, value) {
s[key] = value; s[key] = value;
@ -19,7 +24,7 @@
}; };
let items = { let items = {
showDate: s.showDate, showDate: s.showDate,
loadWidgets: s.loadWidgets, hideWidgets: s.hideWidgets,
}; };
// Power saving for Bangle.js 1 doesn't make sense (no updates while screen is off anyway) // Power saving for Bangle.js 1 doesn't make sense (no updates while screen is off anyway)
if (process.env.HWVERSION>1) { if (process.env.HWVERSION>1) {

View File

@ -27,4 +27,5 @@
0.26: Use clkinfo.addInteractive instead of a custom implementation 0.26: Use clkinfo.addInteractive instead of a custom implementation
0.27: Clean out some leftovers in the remove function after switching to 0.27: Clean out some leftovers in the remove function after switching to
clkinfo.addInteractive that would cause ReferenceError. clkinfo.addInteractive that would cause ReferenceError.
0.28: Option to show (1) time only and (2) week of year. 0.28: Option to show (1) time only and (2) week of year.
0.29: use setItem of clockInfoMenu to change the active item

View File

@ -327,9 +327,7 @@ Bangle.on('lock', lockListenerBw);
let charging = function(charging){ let charging = function(charging){
// Jump to battery // Jump to battery
clockInfoMenu.menuA = 0; clockInfoMenu.setItem(0, 2);
clockInfoMenu.menuB = 2;
clockInfoMenu.redraw();
drawTime(); drawTime();
} }
Bangle.on('charging', charging); Bangle.on('charging', charging);

View File

@ -1,7 +1,7 @@
{ {
"id": "bwclk", "id": "bwclk",
"name": "BW Clock", "name": "BW Clock",
"version": "0.28", "version": "0.29",
"description": "A very minimalistic clock.", "description": "A very minimalistic clock.",
"readme": "README.md", "readme": "README.md",
"icon": "app.png", "icon": "app.png",

View File

@ -1,3 +1,4 @@
0.01: New clock 0.01: New clock
0.02: Use ClockFace library, add settings 0.02: Use ClockFace library, add settings
0.03: Use ClockFace_menu.addSettingsFile 0.03: Use ClockFace_menu.addSettingsFile
0.04: Hide widgets instead of not loading them at all

View File

@ -1,7 +1,7 @@
{ {
"id": "cogclock", "id": "cogclock",
"name": "Cog Clock", "name": "Cog Clock",
"version": "0.03", "version": "0.04",
"description": "A cross-shaped clock inside a cog", "description": "A cross-shaped clock inside a cog",
"icon": "icon.png", "icon": "icon.png",
"screenshots": [{"url":"screenshot.png"}], "screenshots": [{"url":"screenshot.png"}],

View File

@ -4,7 +4,7 @@
/*LANG*/"< Back": back, /*LANG*/"< Back": back,
}; };
require("ClockFace_menu").addSettingsFile(menu, "cogclock.settings.json", [ require("ClockFace_menu").addSettingsFile(menu, "cogclock.settings.json", [
"showDate", "loadWidgets" "showDate", "hideWidgets"
]); ]);
E.showMenu(menu); E.showMenu(menu);
}); });

View File

@ -25,4 +25,6 @@ facilitate 'fast switching' of apps where available.
widgets would still be loaded when they weren't supposed to. widgets would still be loaded when they weren't supposed to.
0.21: Bangle 2: Call Bangle.drawWidgets() early on so that the widget field 0.21: Bangle 2: Call Bangle.drawWidgets() early on so that the widget field
immediately follows the correct theme. immediately follows the correct theme.
0.22: Bangle 2: Change to not automatically marking the first app on a page
when moving pages. Add caching for faster startups.

View File

@ -13,20 +13,25 @@
}, require('Storage').readJSON("dtlaunch.json", true) || {}); }, require('Storage').readJSON("dtlaunch.json", true) || {});
let s = require("Storage"); let s = require("Storage");
var apps = s.list(/\.info$/).map(app=>{ // Borrowed caching from Icon Launcher, code by halemmerich.
let a=s.readJSON(app,1); let launchCache = s.readJSON("launch.cache.json", true)||{};
return a && { let launchHash = require("Storage").hash(/\.info/);
name:a.name, type:a.type, icon:a.icon, sortorder:a.sortorder, src:a.src if (launchCache.hash!=launchHash) {
};}).filter( launchCache = {
app=>app && (app.type=="app" || (app.type=="clock" && settings.showClocks) || (app.type=="launch" && settings.showLaunchers) || !app.type)); hash : launchHash,
apps : s.list(/\.info$/)
apps.sort((a,b)=>{ .map(app=>{var a=s.readJSON(app,1);return a&&{name:a.name,type:a.type,icon:a.icon,sortorder:a.sortorder,src:a.src};})
let n=(0|a.sortorder)-(0|b.sortorder); .filter(app=>app && (app.type=="app" || (app.type=="clock" && settings.showClocks) || !app.type))
if (n) return n; // do sortorder first .sort((a,b)=>{
if (a.name<b.name) return -1; var n=(0|a.sortorder)-(0|b.sortorder);
if (a.name>b.name) return 1; if (n) return n; // do sortorder first
return 0; if (a.name<b.name) return -1;
}); if (a.name>b.name) return 1;
return 0;
}) };
s.writeJSON("launch.cache.json", launchCache);
}
let apps = launchCache.apps;
apps.forEach(app=>{ apps.forEach(app=>{
if (app.icon) if (app.icon)
app.icon = s.read(app.icon); // should just be a link to a memory area app.icon = s.read(app.icon); // should just be a link to a memory area
@ -90,7 +95,7 @@
let swipeListenerDt = function(dirLeftRight, dirUpDown){ let swipeListenerDt = function(dirLeftRight, dirUpDown){
updateTimeoutToClock(); updateTimeoutToClock();
selected = 0; selected = -1;
oldselected=-1; oldselected=-1;
if(settings.swipeExit && dirLeftRight==1) Bangle.showClock(); if(settings.swipeExit && dirLeftRight==1) Bangle.showClock();
if (dirUpDown==-1||dirLeftRight==-1){ if (dirUpDown==-1||dirLeftRight==-1){
@ -154,3 +159,4 @@
updateTimeoutToClock(); updateTimeoutToClock();
} // end of app scope } // end of app scope

View File

@ -1,7 +1,7 @@
{ {
"id": "dtlaunch", "id": "dtlaunch",
"name": "Desktop Launcher", "name": "Desktop Launcher",
"version": "0.21", "version": "0.22",
"description": "Desktop style App Launcher with six (four for Bangle 2) apps per page - fast access if you have lots of apps installed.", "description": "Desktop style App Launcher with six (four for Bangle 2) apps per page - fast access if you have lots of apps installed.",
"screenshots": [{"url":"shot1.png"},{"url":"shot2.png"},{"url":"shot3.png"}], "screenshots": [{"url":"shot1.png"},{"url":"shot2.png"},{"url":"shot3.png"}],
"icon": "icon.png", "icon": "icon.png",

View File

@ -18,3 +18,5 @@
0.17: Add automatic translation of bar chart labels 0.17: Add automatic translation of bar chart labels
0.18: Show step goal in daily step chart 0.18: Show step goal in daily step chart
0.19: Can show notification when daily step goal is reached 0.19: Can show notification when daily step goal is reached
0.20: Fix the settings page, it would not update settings correctly.
0.21: Update boot.min.js.

View File

@ -105,7 +105,7 @@ function handleStepGoalNotification() {
if (!settings.stepGoalNotificationDate || settings.stepGoalNotificationDate < now) { // notification not yet shown today? if (!settings.stepGoalNotificationDate || settings.stepGoalNotificationDate < now) { // notification not yet shown today?
Bangle.buzz(200, 0.5); Bangle.buzz(200, 0.5);
require("notify").show({ require("notify").show({
title : /*LANG*/ settings.stepGoal + " steps", title : settings.stepGoal + /*LANG*/ " steps",
body : /*LANG*/ "You reached your step goal!", body : /*LANG*/ "You reached your step goal!",
icon : atob("DAyBABmD6BaBMAsA8BCBCBCBCA8AAA==") icon : atob("DAyBABmD6BaBMAsA8BCBCBCBCA8AAA==")
}); });

View File

@ -1,5 +1,5 @@
function l(){var a=require("Storage").readJSON("health.json",1)||{},d=Bangle.getHealthStatus("day").steps;a.stepGoalNotification&&0<a.stepGoal&&d>=a.stepGoal&&(d=(new Date(Date.now())).toISOString().split("T")[0],!a.stepGoalNotificationDate||a.stepGoalNotificationDate<d)&&(Bangle.buzz(200,.5),require("notify").show({title:"8000 steps",body:"You reached your step goal!",icon:atob("DAyBABmD6BaBMAsA8BCBCBCBCA8AAA==")}),a.stepGoalNotificationDate=d,require("Storage").writeJSON("health.json", function l(){var a=require("Storage").readJSON("health.json",1)||{},d=Bangle.getHealthStatus("day").steps;a.stepGoalNotification&&0<a.stepGoal&&d>=a.stepGoal&&(d=(new Date(Date.now())).toISOString().split("T")[0],!a.stepGoalNotificationDate||a.stepGoalNotificationDate<d)&&(Bangle.buzz(200,.5),require("notify").show({title:a.stepGoal+" steps",body:"You reached your step goal!",icon:atob("DAyBABmD6BaBMAsA8BCBCBCBCA8AAA==")}),a.stepGoalNotificationDate=d,require("Storage").writeJSON("health.json",
a))}(function(){var a=0|(require("Storage").readJSON("health.json",1)||{}).hrm;if(1==a||2==a){var d=function(){Bangle.setHRMPower(1,"health");setTimeout(function(){return Bangle.setHRMPower(0,"health")},6E4*a);if(1==a)for(var b=1;2>=b;b++)setTimeout(function(){Bangle.setHRMPower(1,"health");setTimeout(function(){Bangle.setHRMPower(0,"health")},2E5*b+6E4)},2E5*b)};Bangle.on("health",d);Bangle.on("HRM",function(b){80<b.confidence&&Bangle.setHRMPower(0,"health")});Bangle.getHealthStatus().bpmConfidence|| a))}(function(){var a=0|(require("Storage").readJSON("health.json",1)||{}).hrm;if(1==a||2==a){var d=function(){Bangle.setHRMPower(1,"health");setTimeout(function(){return Bangle.setHRMPower(0,"health")},6E4*a);if(1==a)for(var b=1;2>=b;b++)setTimeout(function(){Bangle.setHRMPower(1,"health");setTimeout(function(){Bangle.setHRMPower(0,"health")},2E5*b+6E4)},2E5*b)};Bangle.on("health",d);Bangle.on("HRM",function(b){80<b.confidence&&Bangle.setHRMPower(0,"health")});Bangle.getHealthStatus().bpmConfidence||
d()}else Bangle.setHRMPower(0!=a,"health")})();Bangle.on("health",function(a){function d(c){return String.fromCharCode(c.steps>>8,c.steps&255,c.bpm,Math.min(c.movement/8,255))}var b=new Date(Date.now()-59E4);a&&0<a.steps&&l();var f=function(c){return 145*(c.getDate()-1)+6*c.getHours()+(0|6*c.getMinutes()/60)}(b);b=function(c){return"health-"+c.getFullYear()+"-"+(c.getMonth()+1)+".raw"}(b);var g=require("Storage").read(b);if(g){var e=g.substr(8+4*f,4);if("\u00ff\u00ff\u00ff\u00ff"!=e){print("HEALTH ERR: Already written!"); d()}else Bangle.setHRMPower(0!=a,"health")})();Bangle.on("health",function(a){function d(c){return String.fromCharCode(c.steps>>8,c.steps&255,c.bpm,Math.min(c.movement/8,255))}var b=new Date(Date.now()-59E4);a&&0<a.steps&&l();var f=function(c){return 145*(c.getDate()-1)+6*c.getHours()+(0|6*c.getMinutes()/60)}(b);b=function(c){return"health-"+c.getFullYear()+"-"+(c.getMonth()+1)+".raw"}(b);var g=require("Storage").read(b);if(g){var e=g.substr(8+4*f,4);if("\u00ff\u00ff\u00ff\u00ff"!=e){print("HEALTH ERR: Already written!");
return}}else require("Storage").write(b,"HEALTH1\x00",0,17988);var h=8+4*f;require("Storage").write(b,d(a),h,17988);if(143==f%145)if(f=h+4,"\u00ff\u00ff\u00ff\u00ff"!=g.substr(f,4))print("HEALTH ERR: Daily summary already written!");else{a={steps:0,bpm:0,movement:0,movCnt:0,bpmCnt:0};for(var k=0;144>k;k++)e=g.substr(h,4),"\u00ff\u00ff\u00ff\u00ff"!=e&&(a.steps+=(e.charCodeAt(0)<<8)+e.charCodeAt(1),a.movement+=e.charCodeAt(2),a.movCnt++,e=e.charCodeAt(2),a.bpm+=e,e&&a.bpmCnt++),h-=4;a.bpmCnt&&(a.bpm/= return}}else require("Storage").write(b,"HEALTH1\x00",0,17988);var h=8+4*f;require("Storage").write(b,d(a),h,17988);if(143==f%145)if(f=h+4,"\u00ff\u00ff\u00ff\u00ff"!=g.substr(f,4))print("HEALTH ERR: Daily summary already written!");else{a={steps:0,bpm:0,movement:0,movCnt:0,bpmCnt:0};for(var k=0;144>k;k++)e=g.substr(h,4),"\u00ff\u00ff\u00ff\u00ff"!=e&&(a.steps+=(e.charCodeAt(0)<<8)+e.charCodeAt(1),a.movement+=e.charCodeAt(2),a.movCnt++,e=e.charCodeAt(2),a.bpm+=e,e&&a.bpmCnt++),h-=4;a.bpmCnt&&(a.bpm/=
a.bpmCnt);a.movCnt&&(a.movement/=a.movCnt);require("Storage").write(b,d(a),f,17988)}}) a.bpmCnt);a.movCnt&&(a.movement/=a.movCnt);require("Storage").write(b,d(a),f,17988)}})

View File

@ -2,7 +2,7 @@
"id": "health", "id": "health",
"name": "Health Tracking", "name": "Health Tracking",
"shortName": "Health", "shortName": "Health",
"version": "0.19", "version": "0.21",
"description": "Logs health data and provides an app to view it", "description": "Logs health data and provides an app to view it",
"icon": "app.png", "icon": "app.png",
"tags": "tool,system,health", "tags": "tool,system,health",

View File

@ -5,6 +5,9 @@
stepGoalNotification: false stepGoalNotification: false
}, require("Storage").readJSON("health.json", true) || {}); }, require("Storage").readJSON("health.json", true) || {});
function setSettings() {
require("Storage").writeJSON("health.json", settings);
}
E.showMenu({ E.showMenu({
"": { title: /*LANG*/"Health Tracking" }, "": { title: /*LANG*/"Health Tracking" },
@ -22,7 +25,7 @@
][v], ][v],
onchange: v => { onchange: v => {
settings.hrm = v; settings.hrm = v;
setSettings(settings); setSettings();
} }
}, },
@ -33,7 +36,7 @@
step: 250, step: 250,
onchange: v => { onchange: v => {
settings.stepGoal = v; settings.stepGoal = v;
setSettings(settings); setSettings();
} }
}, },
/*LANG*/"Step Goal Notification": { /*LANG*/"Step Goal Notification": {
@ -45,8 +48,4 @@
} }
} }
}); });
function setSettings(settings) {
require("Storage").writeJSON("health.json", settings);
}
}) })

View File

@ -1 +1,2 @@
0.01: New app! 0.01: New app!
0.02: Fix music updates while app is already open

View File

@ -85,9 +85,9 @@
} }
const setUI = function(options, cb) { const setUI = function(options, cb) {
delete Bangle.uiRemove; // don't clear out things when switching UI within the app
options = Object.assign({remove: () => uiRemove()}, options); options = Object.assign({remove: () => uiRemove()}, options);
Bangle.setUI(options, cb); Bangle.setUI(options, cb);
Bangle.on("message", onMessage);
}; };
const remove = function(msg) { const remove = function(msg) {
@ -1161,48 +1161,49 @@
idx = MESSAGES.findIndex(m => m.src && m.src.toLowerCase().startsWith("alarm")); idx = MESSAGES.findIndex(m => m.src && m.src.toLowerCase().startsWith("alarm"));
if (idx>=0) alarm = MESSAGES.splice(idx, 1)[0]; if (idx>=0) alarm = MESSAGES.splice(idx, 1)[0];
}; };
if (MESSAGES!==undefined) { // only if loading MESSAGES worked
g.reset().clear();
Bangle.loadWidgets();
require("messages").toggleWidget(false);
Bangle.drawWidgets();
findSpecials(); // sets global vars for special messages
// any message we asked to show?
const showIdx = MESSAGES.findIndex(m => m.show);
// any new text messages?
const newIdx = MESSAGES.findIndex(m => m.new);
// figure out why the app was loaded // Internal setUI suppresses Bangle.uiRemove between internal screens, so we
if (showIdx>=0) show(showIdx); // need to call setUI to run uiRemove from previous app when fast-loaded.
else if (call && call.new) showCall(); Bangle.setUI();
else if (alarm && alarm.new) showAlarm(); Bangle.loadWidgets();
else if (map && map.new) showMap(); require("messages").toggleWidget(false);
else if (music && music.new && settings().openMusic) { Bangle.drawWidgets();
if (settings().alwaysShowMusic===undefined) { findSpecials(); // sets global vars for special messages
// if not explicitly disabled, enable this the first time we see music // any message we asked to show?
let s = settings(); const showIdx = MESSAGES.findIndex(m => m.show);
s.alwaysShowMusic = true; // any new text messages?
require("Storage").writeJSON("messages.settings.json", s); const newIdx = MESSAGES.findIndex(m => m.new);
}
showMusic(); // figure out why the app was loaded
if (showIdx>=0) show(showIdx);
else if (call && call.new) showCall();
else if (alarm && alarm.new) showAlarm();
else if (map && map.new) showMap();
else if (music && music.new && settings().openMusic) {
if (settings().alwaysShowMusic===undefined) {
// if not explicitly disabled, enable this the first time we see music
let s = settings();
s.alwaysShowMusic = true;
require("Storage").writeJSON("messages.settings.json", s);
} }
// check for new message last: Maybe we already showed it, but timed out before showMusic();
// if that happened, and we're loading for e.g. music now, we want to show the music screen
else if (newIdx>=0) {
showMessage(newIdx);
// auto-loaded for message(s): auto-close after timeout
let unreadTimeoutSecs = settings().unreadTimeout;
if (unreadTimeoutSecs===undefined) unreadTimeoutSecs = 60;
if (unreadTimeoutSecs) {
unreadTimeout = setTimeout(load, unreadTimeoutSecs*1000);
}
} else if (MESSAGES.length) { // not autoloaded, but we have messages to show
back = "main"; // prevent "back" from loading clock
showMessage();
} else showMain();
// stop buzzing, auto-close timeout on input
["touch", "drag", "swipe"].forEach(l => Bangle.on(l, clearUnreadStuff));
(B2 ? [BTN1] : [BTN1, BTN2, BTN3]).forEach(b => watches.push(setWatch(clearUnreadStuff, b, false)));
} }
// check for new message last: Maybe we already showed it, but timed out before
// if that happened, and we're loading for e.g. music now, we want to show the music screen
else if (newIdx>=0) {
showMessage(newIdx);
// auto-loaded for message(s): auto-close after timeout
let unreadTimeoutSecs = settings().unreadTimeout;
if (unreadTimeoutSecs===undefined) unreadTimeoutSecs = 60;
if (unreadTimeoutSecs) {
unreadTimeout = setTimeout(load, unreadTimeoutSecs*1000);
}
} else if (MESSAGES.length) { // not autoloaded, but we have messages to show
back = "main"; // prevent "back" from loading clock
showMessage();
} else showMain();
// stop buzzing, auto-close timeout on input
["touch", "drag", "swipe"].forEach(l => Bangle.on(l, clearUnreadStuff));
(B2 ? [BTN1] : [BTN1, BTN2, BTN3]).forEach(b => watches.push(setWatch(clearUnreadStuff, b, false)));
} }

View File

@ -1,7 +1,7 @@
{ {
"id": "messagelist", "id": "messagelist",
"name": "Message List", "name": "Message List",
"version": "0.01", "version": "0.02",
"description": "Display notifications from iOS and Gadgetbridge/Android as a list", "description": "Display notifications from iOS and Gadgetbridge/Android as a list",
"icon": "app.png", "icon": "app.png",
"type": "app", "type": "app",

View File

@ -0,0 +1,3 @@
0.01: fork from miclock, Added compatib with b widgets, devices(dynamic x,y) and themes(dynamic colors)
0.02: Code refactored, change colors in real time
0.03: Hour point size can be modified on real time.

View File

@ -0,0 +1,58 @@
# Mix Digital & Analog Clock
A dual and simultaneous Analog and Digital Clock, also shows day, month and year.
Color are automatically set depending on the configured Theme or device, bunt also change on realtime through touching the right side.
Compatible with BangleJS1,BangleJS2,and EMSCRIPTENx emulators
## Pictures:
Bangle JS1
![](photo_mixdigan_bjs1.jpg)
Screenshot emulator BJS2
![](ss_mixdigan_ems2.png)
Screenshot emulator BJS1
![](ss_mixdigan_ems.png)
SS emulator -color change
![](ss_mixdigan_ems_2.png)
SS emulator -color change
![](ss_mixdigan_ems2_2.png)
SS emulator -color change
![](ss_mixdigan_ems2_3.png)
## Usage
Open and see
## Features
Compatibility with devices
Dynamic Colours and positions
Support for bottom widgets
## Controls
Exit : BTN2 (BJS1)
Exit/launcher : left area
Change Color : right area
Increase Hour Points : swipe right
Decrease Hour Points : swipe left
## Coming soon
A better color combination
## Support
This app is so basic that probably the easiest is to just edit the code ;)
Otherwise you can contact me [here](https://github.com/dapgo/my_espruino_smartwatch_things)

View File

@ -0,0 +1 @@
require("heatshrink").decompress(atob("mEw4X/AAN994JB8noH+cFqtVqALHr5IB+oWHKgX/DAwWCDA8BA4IvBB4NABYcH/4KBAAP/6ALDj4WCDAX0BYd/6tVq2VqtX/ouECgILCEgIwCgP9BYt/BYUHFwQLDr48CBZcfHQILEq5ICBZd/LgQLDqpUCBbYAEC4+a1WlBaYjLBZNaIwIBBEYwLNy2WC6KbBC4qnFC4oLDZYILFa4oLJfYYADfYcB/4LF/4LCKgLkCcQRSCJAX1BYdfIwQ8CEgn/HQQwDDAVfFwgABA4IAC+oKEgEFBYdQBYoYDCwwYCF4IWHAFgA="))

View File

@ -0,0 +1,17 @@
{
"id": "mixdiganclock",
"name": "Mix Dig&Anal Clock",
"version": "0.03",
"description": "A dual Analog and Digital Clock, based in Mixed Clock, but with more compatibility, change of colors, thicker clock hands... ",
"icon": "mixdiganclock.png",
"type": "clock",
"tags": "clock",
"screenshots": [{"url":"pic_mixdigan_bjs1.jpg"}],
"supports": ["BANGLEJS","BANGLEJS"],
"readme": "README.md",
"allow_emulator": true,
"storage": [
{"name":"mixdiganclock.app.js","url":"mixdiganclock.app.js"},
{"name":"mixdiganclock.img","url":"app-icon.js","evaluate":true}
]
}

View File

@ -0,0 +1,230 @@
/*fork of miclock, dynamic x,y, colors on realtime,
compatible with BJS1, BJS2 and bottom widgets
*/
var locale = require("locale");
var v_mode_debug=0; //, 0=no, 1 min, 2 prone detail
var v_model=process.env.BOARD;
var LastDrawDay; // to notice a change and repaint static texts
//RGB565 0x White , black, 'Orange',blue,red, olive,...
var a_colors= [0xFFFF,0x0000, 0xFD20, 0x001F,0xF800,0x7be0,0x780F,0x07E0]; //new Array(0xFFFF
var Radius= []; //new Array();
var TxtPosition=[];
var v_bfont_size;
var v_vfont_size;
var v_color1;
var v_color2;
var v_color3;
var v_color_erase;
var v_count_col;
var rect = Bangle.appRect;
var v_center_x;
var v_center_y;
if (v_mode_debug>0) console.log("a_colors.length "+a_colors.length);
g.clear();
//show the exit button
//Bangle.setUI();
Bangle.setUI("clock"); //implies center button for launcher
/*{
mode : "custom",
back : Bangle.showLauncher
});*/
Bangle.loadWidgets();
function setVariables() {
// different values depending on loaded widgets or not, so after load widgets
rect = Bangle.appRect;
v_center_x = g.getWidth()/2;
v_center_y = g.getHeight()/2; //vertical middle
//if (v_mode_debug>1) console.log(v_model+" center x, y "+v_center_x+" , "+v_center_y+" Max y,y2"+rect.y+" ,"+rect.y2);
TxtPosition = {
"x1": 3, "x2": g.getWidth()-3,
"y1": rect.y+17, "y2": rect.y2-6,
"x_HH": g.getWidth()/2 ,"y_mm": v_center_y+32
};
//emuls EMSCRIPTEN,EMSCRIPTEN2
v_count_col=2; //1st=0 1st compatible color (dark/light theme)
v_color_erase=g.getBgColor();
if (v_model=='BANGLEJS'||v_model=='EMSCRIPTEN') {
Radius = { "center": 7, "hour": 50, "min": 70, "dots": 88,"circleH":6,"circleM":2 };
v_bfont_size=3;
v_vfont_size=35;
v_color1=2; // orange
v_color2=4;
v_color3=0; //white , for hands PEND replace hardcoded by logic
}else{
Radius = { "center": 5, "hour": 35, "min": 50, "dots": 60, "circleH":5,"circleM":2 };
v_bfont_size=2;
v_vfont_size=22;
v_color1=3; // blue
v_color2=1;
v_color3=1; //opposite to bg, for hands PEND replace hardcoded by logic
}
if (v_mode_debug>0) console.log("set vars for: "+v_model);
}
function rotatePoint(x, y, d) {
rad = -1 * d / 180 * Math.PI;
var sin = Math.sin(rad);
var cos = Math.cos(rad);
xn = ((v_center_x + x * cos - y * sin) + 0.5) | 0;
yn = ((v_center_y + x * sin - y * cos) + 0.5) | 0;
p = [xn, yn];
return p;
}
//no need to repaint
function drawStaticRing(v_colorparam){
// draw hour and minute dots
if (v_mode_debug>0) console.log("color: "+v_colorparam);
//g.setColor(a_colors[v_color1]);
g.setColor(v_colorparam);
for (i = 0; i < 60; i++) {
// ? 2 : 4;
radius = (i % 5) ? Radius.circleM : Radius.circleH;
point = rotatePoint(0, Radius.dots, i * 6);
//if (v_mode_debug>1) console.log("point"+point);
g.fillCircle(point[0], point[1], radius);
}
}
//no need to repaint every min
function drawDailyTxt(){
var date = new Date();
var isEn = locale.name.startsWith("en");
var dateArray = date.toString().split(" ");
LastDrawDay=locale.dow(date,true);
var hour = date.getHours();
if (v_mode_debug>1) {
console.log("full date "+date.toString());
console.log("locale time "+locale.time(date,true));
console.log("LastDrawDay "+LastDrawDay);
console.log("locale new day "+(locale.dow(date,true)));
}
g.setColor(a_colors[v_color2]);
//small size then bitmap
g.setFont("4x6", v_bfont_size); //6x8
g.setFontAlign(-1, 0);
g.drawString(locale.dow(date,true) + ' ',TxtPosition.x1 , TxtPosition.y1, true);
g.drawString(isEn?(' ' + dateArray[2]):locale.month(date,true), TxtPosition.x1, TxtPosition.y2, true);
g.setFontAlign(1, 0);
g.drawString(isEn?locale.month(date,true):(' ' + dateArray[2]), TxtPosition.x2, TxtPosition.y1, true);
g.drawString(dateArray[3], TxtPosition.x2, TxtPosition.y2, true);
}
function drawMixedClock() {
var date = new Date();
var dateArray = date.toString().split(" ");
//var isEn = locale.name.startsWith("en");
var point = [];
var minute = date.getMinutes();
var hour = date.getHours();
var radius;
//Call function only after a change of day
if (LastDrawDay!=locale.dow(date,true)) drawDailyTxt();
//ERASE previous hands
// erase last MINutes hand
g.setColor(v_color_erase);
point = rotatePoint(0, Radius.min, (minute - 1) * 6);
g.drawLine(v_center_x, v_center_y, point[0], point[1]);
//to increase thicknes
g.drawLine(v_center_x+1, v_center_y, point[0]+1, point[1]);
// erase last two HOUR hands ¿2?
g.setColor(v_color_erase);
p = rotatePoint(0, Radius.hour, hour % 12 * 30 + (minute - 2) / 2 | 0);
g.drawLine(v_center_x, v_center_y, p[0], p[1]);
//to increase thicknes
g.drawLine(v_center_x+1, v_center_y, p[0]+1, p[1]);
point = rotatePoint(0, Radius.hour, hour % 12 * 30 + (minute - 1) / 2 | 0);
g.drawLine(v_center_x, v_center_y, point[0], point[1]);
//to increase thicknes
g.drawLine(v_center_x+1, v_center_y, point[0]+1, point[1]);
// here time DIGITs are draw under hands
// draw new MINute hand
point = rotatePoint(0, Radius.min, minute * 6);
g.setColor(a_colors[v_color3]);
g.drawLine(v_center_x, v_center_y, point[0], point[1]);
//to increase thicknes
g.drawLine(v_center_x+1, v_center_y, point[0]+1, point[1]);
// draw new HOUR hand
point = rotatePoint(0, Radius.hour, hour % 12 * 30 + date.getMinutes() / 2 | 0);
g.setColor(a_colors[v_color3]);
g.drawLine(v_center_x, v_center_y, point[0], point[1]);
//to increase thicknes
g.drawLine(v_center_x+1, v_center_y, point[0]+1, point[1]);
// draw DIGITs of time above hands for better UX
//g.setFont("6x8", 3); 3 bigger size
g.setFontVector(v_vfont_size);
g.setColor(a_colors[v_color2]);
g.setFontAlign(0, 0);
//by default 24H, to use format config 12H 24H read from locale
g.drawString(dateArray[4].substr(0, 5), TxtPosition.x_HH, TxtPosition.y_mm, true);
// the central point requires redrawing because hands draw over it
g.setColor(a_colors[v_color1]);
g.fillCircle(v_center_x, v_center_y, Radius.center);
}
function UserInput(){
Bangle.on('touch', function(button){
switch(button){
case 1:
Bangle.showLauncher();
break;
case 2:
//testing to improve
if (v_mode_debug>0) console.log("v_count_col/total: "+v_count_col+"/"+a_colors.length);
if (v_count_col<a_colors.length){
v_color1=v_count_col;
v_color2=v_count_col;
v_color3=v_count_col;
v_count_col++; //next color
}
else setVariables(); //v_count_col=3; //reset to 1st common color
if (v_mode_debug>0) console.log("paint on color: "+v_count_col);
drawStaticRing(a_colors[v_color1]);
drawDailyTxt();
break;
case 3:
//console.log("Touch 3 aka 1+2 not for emul");//center 1+2
break;
}
});
Bangle.on('swipe', dir => {
if(dir == 1) {
drawStaticRing(v_color_erase);
if (Radius.circleH<13) Radius.circleH++;
if (v_mode_debug>0) console.log("radio: "+Radius.circleH);
drawStaticRing(a_colors[v_color1]);
}
else {
drawStaticRing(v_color_erase);
if (Radius.circleH>1) Radius.circleH--;
if (v_mode_debug>0) console.log("radio: "+Radius.circleH);
drawStaticRing(a_colors[v_color1]);
}
});
}
Bangle.on('lcdPower', function(on) {
if (on)
drawMixedClock();
});
setVariables();
Bangle.drawWidgets();
UserInput();
setInterval(drawMixedClock, 5E3);
drawStaticRing(a_colors[v_color1]);
drawDailyTxt(); //1st time
drawMixedClock();

View File

@ -0,0 +1 @@
{"id":"mixdiganclock","name":"Mix Dig&Anal","type":"clock","src":"mixdiganclock.app.js","icon":"mixdiganclock.img","version":"0.02","tags":"clock","files":"mixdiganclock.info,mixdiganclock.app.js,mixdiganclock.img"}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

2
apps/saclock/ChangeLog Normal file
View File

@ -0,0 +1,2 @@
0.01: New App!
0.02: Hide widgets instead of not loading them at all

View File

@ -1,7 +1,7 @@
{ "id": "saclock", { "id": "saclock",
"name": "Simple analog clock", "name": "Simple analog clock",
"shortName":"Analog clock", "shortName":"Analog clock",
"version":"0.01", "version":"0.02",
"description": "A very basic analog clock", "description": "A very basic analog clock",
"screenshots": [{"url":"screenshot.png"}], "screenshots": [{"url":"screenshot.png"}],
"icon": "icon.png", "icon": "icon.png",

View File

@ -4,7 +4,7 @@
/*LANG*/"< Back": back, /*LANG*/"< Back": back,
}; };
require("ClockFace_menu").addSettingsFile(menu, "saclock.settings.json", [ require("ClockFace_menu").addSettingsFile(menu, "saclock.settings.json", [
"loadWidgets" "hideWidgets"
]); ]);
E.showMenu(menu); E.showMenu(menu);
}); });

View File

@ -19,3 +19,4 @@
0.16: Improve support for date timezone 0.16: Improve support for date timezone
0.17: Fix midnight in local timezone (alarms wouldn't always fire as expected in timezone != 0) 0.17: Fix midnight in local timezone (alarms wouldn't always fire as expected in timezone != 0)
0.18: Update clock_info to avoid a redraw 0.18: Update clock_info to avoid a redraw
0.19: Update clock_info to refresh periodically on active alarms/timers

View File

@ -49,6 +49,52 @@
return val; return val;
} }
/*
* Returns the array [interval, switchTimeout]
* `interval` is the refresh rate (hourly or per minute)
* `switchTimeout` is the time before the refresh rate should change (or expiration)
*/
function getRefreshIntervals(a) {
const minute = 60 * 1000;
const halfhour = 30 * minute;
const hour = 2 * halfhour;
let msecs = alarm.getTimeToAlarm(a);
if(typeof msecs == "undefined" || msecs == 0)
return [];
if(msecs > hour) { //refresh every half an hour
let remain = (msecs+minute) % halfhour;
if(remain < 27 * minute && remain != 0) //first align period (some tolerance)
return [ halfhour, remain ];
return [ halfhour, msecs - hour ];
} else { //refresh every minute
//alarms just need the progress bar refreshed, no need every minute
if(!a.timer) return [];
return [ minute, msecs ];
}
}
function _doInterval(interval) {
return setTimeout(()=>{
this.emit("redraw");
this.interval = setInterval(()=>{
this.emit("redraw");
}, interval);
}, interval);
}
function _doSwitchTimeout(a, switchTimeout) {
return setTimeout(()=>{
this.emit("redraw");
clearInterval(this.interval);
this.interval = undefined;
var tmp = getRefreshIntervals(a);
var interval = tmp[0];
var switchTimeout = tmp[1];
if(!interval) return;
this.interval = _doInterval.call(this, interval);
this.switchTimeout = _doSwitchTimeout.call(this, a, switchTimeout);
}, switchTimeout);
}
var img = iconAlarmOn; var img = iconAlarmOn;
//get only alarms not created by other apps //get only alarms not created by other apps
var alarmItems = { var alarmItems = {
@ -63,8 +109,20 @@
hasRange: true, hasRange: true,
get: () => ({ text: getAlarmText(a), img: getAlarmIcon(a), get: () => ({ text: getAlarmText(a), img: getAlarmIcon(a),
v: getAlarmValue(a), min:0, max:getAlarmMax(a)}), v: getAlarmValue(a), min:0, max:getAlarmMax(a)}),
show: function() {}, show: function() {
hide: function () {}, var tmp = getRefreshIntervals(a);
var interval = tmp[0];
var switchTimeout = tmp[1];
if(!interval) return;
this.interval = _doInterval.call(this, interval);
this.switchTimeout = _doSwitchTimeout.call(this, a, switchTimeout);
},
hide: function() {
clearInterval(this.interval);
clearTimeout(this.switchTimeout);
this.interval = undefined;
this.switchTimeout = undefined;
},
run: function() { } run: function() { }
})), })),
}; };

View File

@ -1,7 +1,7 @@
{ {
"id": "sched", "id": "sched",
"name": "Scheduler", "name": "Scheduler",
"version": "0.18", "version": "0.19",
"description": "Scheduling library for alarms and timers", "description": "Scheduling library for alarms and timers",
"icon": "app.png", "icon": "app.png",
"type": "scheduler", "type": "scheduler",

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

View File

@ -1 +1,2 @@
0.01: 1st version: saves values to csv 0.01: 1st version: saves values to csv
0.02: added HTML interface

View File

@ -17,6 +17,13 @@ Screenshot BJS1
![](ss_emul_bjs1.png) ![](ss_emul_bjs1.png)
Screenshot data file content
![](file_interface.png)
![](CSV_IDE_view.png)
![](CSV_excel_view.png)
## Usage ## Usage

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

View File

@ -0,0 +1,67 @@
<html>
<head>
<link rel="stylesheet" href="../../css/spectre.min.css">
</head>
<body>
<div id="data"></div>
<button class="btn btn-default" id="btnSave">Save</button>
<button class="btn btn-default" id="btnDelete">Delete</button>
<script src="../../core/lib/interface.js"></script>
<script>
var dataElement = document.getElementById("data");
var csvData = "";
function getData() {
// show loading window
Util.showModal("Loading...");
// get the data
dataElement.innerHTML = "";
Util.readStorageFile(`temphistory.csv`,data=>{
csvData = data.trim();
// remove window
Util.hideModal();
// If no data, report it and exit
if (data.length==0) {
dataElement.innerHTML = "<b>No data found</b>";
return;
}
// Otherwise parse the data and output it as a table
//<td>${(new Date(l[0]*1000)).toLocaleString()}</td>
dataElement.innerHTML = `<table>
<tr>
<th>Month</th>
<th>Day</th>
<th>Time HH:mm</th>
<th>temperature</th>
</tr>`+data.trim().split("\n").map(l=>{
l = l.split(";");
return `<tr>
<td>${l[0]}</td>
<td>${l[1]}</td>
<td>${l[2]}</td>
<td>${l[3]}</td>
</tr>`
}).join("\n")+"</table>";
});
}
// You can call a utility function to save the data
document.getElementById("btnSave").addEventListener("click", function() {
Util.saveCSV("temphistory.csv", csvData);
});
// Or you can also delete the file
document.getElementById("btnDelete").addEventListener("click", function() {
Util.showModal("Deleting...");
Util.eraseStorageFile("temphistory.csv", function() {
Util.hideModal();
getData();
});
});
// Called when app starts
function onInit() {
getData();
}
</script>
</body>
</html>

View File

@ -1,12 +1,14 @@
{ {
"id": "tempmonitor", "id": "tempmonitor",
"name": "Temperature monitor", "name": "Temperature monitor",
"version": "0.01", "version": "0.02",
"description": "Displays the current temperature and stores in a CSV file", "description": "Displays the current temperature and stores in a CSV file",
"icon": "app.png", "icon": "app.png",
"tags": "tool", "tags": "tool",
"interface": "interface.html",
"supports": ["BANGLEJS", "BANGLEJS2"], "supports": ["BANGLEJS", "BANGLEJS2"],
"screenshots": [{"url":"photo_banglejs1.jpg"}], "readme": "README.md",
"screenshots": [{"url":"ss_emul_bjs2.png"}],
"allow_emulator": true, "allow_emulator": true,
"storage": [ "storage": [
{"name":"tempmonitor.app.js","url":"tempmonitor.app.js"}, {"name":"tempmonitor.app.js","url":"tempmonitor.app.js"},

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

View File

@ -1,14 +1,14 @@
// Temperature monitor that saves a log of measures // Temperature monitor that saves a log of measures
// Version 001 standalone for developer // standalone ver for developer, to remove testing lines
// PEND // delimiter ; (excel) or , (oldscool)
//test with small savefreq {
var v_mode_debug=0; //, 0=no, 1 min, 2 prone detail var v_mode_debug=0; //, 0=no, 1 min, 2 prone detail
//var required for drawing with dynamic screen //var required for drawing with dynamic screen
var rect = Bangle.appRect; var rect = Bangle.appRect;
var history = []; var history = [];
var readFreq=5000; //ms //PEND add to settings var readFreq=5000; //ms //PEND add to settings
var saveFreq=30000; //ms var saveFreq=60000; //ms 1min
var v_saveToFile='Y'; //Y save //N var v_saveToFile= new Boolean(true); //true save //false
//with upload file º is not displayed properly //with upload file º is not displayed properly
//with upload RAM º is displayed //with upload RAM º is displayed
var v_t_symbol="";//ºC var v_t_symbol="";//ºC
@ -68,10 +68,10 @@ function saveToFile() {
var strlastSaveTime=new String(); var strlastSaveTime=new String();
strlastSaveTime=a.toISOString(); strlastSaveTime=a.toISOString();
//strlastSaveTime=strlastSaveTime.concat(a.getFullYear(),a.getMonth()+1,a.getDate(),a.getHours(),a.getMinutes());; //strlastSaveTime=strlastSaveTime.concat(a.getFullYear(),a.getMonth()+1,a.getDate(),a.getHours(),a.getMinutes());;
if (v_mode_debug==1) console.log("saving="+strlastSaveTime+","+lastMeasure); if (v_mode_debug==1) console.log("saving="+strlastSaveTime+";"+a.getHours()+":"+a.getMinutes()+";"+lastMeasure);
if (v_saveToFile==true){
if (v_saveToFile=='Y'){ //write(strlastSaveTime+";"+
require("Storage").open(filename,"a").write(strlastSaveTime+","+lastMeasure+"\n"); require("Storage").open(filename,"a").write((a.getMonth()+1)+";"+a.getDate()+";"+a.getHours()+":"+a.getMinutes()+";"+lastMeasure+"\n");
//(getTime()+","); //(getTime()+",");
v_saved_entries=v_saved_entries+1; v_saved_entries=v_saved_entries+1;
} }
@ -127,11 +127,12 @@ setInterval(function() {
drawTemperature(); drawTemperature();
}, readFreq); //ms }, readFreq); //ms
if (v_saveToFile=="Y") { if (v_saveToFile==true) {
setInterval(function() { setInterval(function() {
saveToFile(); saveToFile();
}, saveFreq); //ms }, saveFreq); //ms
} }
setTimeout(ClearScreen, 3500); setTimeout(ClearScreen, 3500);
setTimeout(drawGraph,4000); setTimeout(drawGraph,4000);
setTimeout(drawTemperature,4500); setTimeout(drawTemperature,4500);
}

View File

@ -5,3 +5,5 @@
0.05: Add altitude display (only Bangle.js 2) 0.05: Add altitude display (only Bangle.js 2)
0.06: Add power related settings to control the HR and pressure(altitude) sensor from the watchface 0.06: Add power related settings to control the HR and pressure(altitude) sensor from the watchface
0.07: Use ClockFace module and rework the settings to be able to personnalize the order of the lines 0.07: Use ClockFace module and rework the settings to be able to personnalize the order of the lines
0.08: Hide widgets instead of not loading them at all
Use Clockface_menu for widgets and power saving settings

View File

@ -32,7 +32,8 @@ const clock = new ClockFace({
this.unlock_precision = 1; this.unlock_precision = 1;
if (this.HRMinConfidence === undefined) this.HRMinConfidence = 50; if (this.HRMinConfidence === undefined) this.HRMinConfidence = 50;
if (this.PowerOnInterval === undefined) this.PowerOnInterval = 15; if (this.PowerOnInterval === undefined) this.PowerOnInterval = 15;
if (this.powerSaving===undefined) this.powerSaving = true; if (this.powerSave===undefined) this.powerSave = this.powerSaving; // migrate old setting
if (this.powerSave===undefined) this.powerSave = true;
["L2", "L3", "L4", "L5", "L6", "L7", "L8", "L9"].forEach(k => { ["L2", "L3", "L4", "L5", "L6", "L7", "L8", "L9"].forEach(k => {
if (this[k]===undefined){ if (this[k]===undefined){
if(k == "L2") this[k] = "Date"; if(k == "L2") this[k] = "Date";
@ -55,7 +56,7 @@ const clock = new ClockFace({
}); });
// set the services (HRM, pressure sensor, etc....) // set the services (HRM, pressure sensor, etc....)
if(!this.powerSaving){ if(!this.powerSave){
turnOnServices(); turnOnServices();
} else{ } else{
setInterval(turnOnServices, this.PowerOnInterval*60000); // every PowerOnInterval min setInterval(turnOnServices, this.PowerOnInterval*60000); // every PowerOnInterval min
@ -156,7 +157,7 @@ function turnOnServices(){
if(clock.showAltitude){ if(clock.showAltitude){
Bangle.setBarometerPower(true, "terminalclock"); Bangle.setBarometerPower(true, "terminalclock");
} }
if(clock.powerSaving){ if(clock.powerSave){
setTimeout(function () { setTimeout(function () {
turnOffServices(); turnOffServices();
}, 45000); }, 45000);
@ -194,7 +195,7 @@ Clock related functions but not in the ClockFace module
---------------------------------------------------- */ ---------------------------------------------------- */
function unlock(){ function unlock(){
if(clock.powerSaving){ if(clock.powerSave){
turnOnServices(); turnOnServices();
} }
clock.precision = clock.unlock_precision; clock.precision = clock.unlock_precision;

View File

@ -3,7 +3,7 @@
"name": "Terminal Clock", "name": "Terminal Clock",
"shortName":"Terminal Clock", "shortName":"Terminal Clock",
"description": "A terminal cli like clock displaying multiple sensor data", "description": "A terminal cli like clock displaying multiple sensor data",
"version":"0.07", "version":"0.08",
"icon": "app.png", "icon": "app.png",
"type": "clock", "type": "clock",
"tags": "clock", "tags": "clock",

View File

@ -2,11 +2,8 @@
var FILE = "terminalclock.json"; var FILE = "terminalclock.json";
// Load settings // Load settings
var settings = Object.assign({ var settings = Object.assign({
// ClockFace lib
loadWidgets: true,
// TerminalClock specific // TerminalClock specific
HRMinConfidence: 50, HRMinConfidence: 50,
powerSaving: true,
PowerOnInterval: 15, PowerOnInterval: 15,
L2: 'Date', L2: 'Date',
L3: 'HR', L3: 'HR',
@ -17,6 +14,18 @@
L8: 'Empty', L8: 'Empty',
L9: 'Empty', L9: 'Empty',
}, require('Storage').readJSON(FILE, true) || {}); }, require('Storage').readJSON(FILE, true) || {});
// ClockFace lib: migrate "don't load widgets" to "hide widgets"
if (!("hideWidgets" in settings)) {
if (("loadWidgets" in settings) && !settings.loadWidgets) settings.hideWidgets = 1;
else settings.hideWidgets = 0;
}
delete settings.loadWidgets;
// ClockFace lib: migrate `powerSaving` to `powerSave`
if (!("powerSave" in settings)) {
if ("powerSaving" in settings) settings.powerSave = settings.powerSaving;
else settings.powerSave = true;
}
delete settings.powerSaving;
function writeSettings() { function writeSettings() {
require('Storage').writeJSON(FILE, settings); require('Storage').writeJSON(FILE, settings);
@ -63,25 +72,16 @@
writeSettings(); writeSettings();
} }
}, },
'Show widgets': {
value: settings.loadWidgets,
onchange: v => {
settings.loadWidgets = v;
writeSettings();
}
},
'Power saving': {
value: settings.powerSaving,
onchange: v => {
settings.powerSaving = v;
writeSettings();
setTimeout(function() {
E.showMenu(getMainMenu());
},0);
}
}
}; };
if(settings.powerSaving){ const save = (key, v) => {
settings[key] = v;
writeSettings();
};
require("ClockFace_menu").addItems(mainMenu, save, {
hideWidgets: settings.hideWidgets,
powerSave: settings.powerSave,
});
if(settings.powerSave){
mainMenu['Power on interval'] = { mainMenu['Power on interval'] = {
value: settings.PowerOnInterval, value: settings.PowerOnInterval,
min: 3, max: 60, min: 3, max: 60,

View File

@ -6,7 +6,7 @@ WIDGETS["wdclk"]={area:"tl",width:Bangle.CLOCK?0:52/* g.stringWidth("00:00") */,
this.width = Bangle.CLOCK?0:52; this.width = Bangle.CLOCK?0:52;
return setTimeout(Bangle.drawWidgets,1); // widget changed size - redraw return setTimeout(Bangle.drawWidgets,1); // widget changed size - redraw
} }
if (!this.width) return; // if size not right, return if (!this.width) return; // if not visible, return
g.reset().setFontCustom(atob("AAAAAAAAAAIAAAQCAQAAAd0BgMBdwAAAAAAAdwAB0RiMRcAAAERiMRdwAcAQCAQdwAcERiMRBwAd0RiMRBwAAEAgEAdwAd0RiMRdwAcERiMRdwAFAAd0QiEQdwAdwRCIRBwAd0BgMBAAABwRCIRdwAd0RiMRAAAd0QiEQAAAAAAAAAA="), 32, atob("BgAAAAAAAAAAAAAAAAYCAAYGBgYGBgYGBgYCAAAAAAAABgYGBgYG"), 512+9); g.reset().setFontCustom(atob("AAAAAAAAAAIAAAQCAQAAAd0BgMBdwAAAAAAAdwAB0RiMRcAAAERiMRdwAcAQCAQdwAcERiMRBwAd0RiMRBwAAEAgEAdwAd0RiMRdwAcERiMRdwAFAAd0QiEQdwAdwRCIRBwAd0BgMBAAABwRCIRdwAd0RiMRAAAd0QiEQAAAAAAAAAA="), 32, atob("BgAAAAAAAAAAAAAAAAYCAAYGBgYGBgYGBgYCAAAAAAAABgYGBgYG"), 512+9);
var time = require("locale").time(new Date(),1); var time = require("locale").time(new Date(),1);
g.drawString(time, this.x, this.y+3, true); // 5 * 6*2 = 60 g.drawString(time, this.x, this.y+3, true); // 5 * 6*2 = 60

View File

@ -1,5 +1,9 @@
# Digital clock widget (bottom widget area) # Digital clock widget (bottom widget area)
This very basic widget clock allows to test the unfrequently used widget bottom area. This very basic widget clock shows time inside apps that respect the bottom widget area, also allows to test this unfrequently used area.
Note that it will not be displayed when a clock app is been shown
Compatible with BangleJS1,BangleJS2,and EMSCRIPTENx emulators
forked from forked from
https://github.com/espruino/BangleApps/tree/master/apps/widclk https://github.com/espruino/BangleApps/tree/master/apps/widclk
@ -10,14 +14,17 @@ Example of usage
![](widTextBottom_ss1.jpg) ![](widTextBottom_ss1.jpg)
Screenshot emulator bangle.js2
![](ss_bjs2.jpg)
## Usage ## Usage
Upload the widget file Upload the widget file
Open an app that supports displaying widgets Open an app (not a clock/watchface) that supports displaying widgets (included the bottom one)
@ -25,4 +32,4 @@ Open an app that supports displaying widgets
This app is so basic that probably the easiest is to just edit the code ;) This app is so basic that probably the easiest is to just edit the code ;)
Otherwise you can contact me [here](https://github.com/dapgo) Otherwise you can contact me [here](https://github.com/dapgo/my_espruino_smartwatch_things)

View File

@ -3,11 +3,12 @@
"name": "Digital clock (Bottom) widget", "name": "Digital clock (Bottom) widget",
"shortName": "Digital clock Bottom Widget", "shortName": "Digital clock Bottom Widget",
"version": "0.05", "version": "0.05",
"description": "Displays time in the bottom of the screen (may not be compatible with some apps)", "description": "Displays time HH:mm in the bottom of the screen (may not be compatible with some apps)",
"icon": "widclkbttm.png", "icon": "widclkbttm.png",
"type": "widget", "type": "widget",
"tags": "widget", "tags": "widget",
"supports": ["BANGLEJS","BANGLEJS2"], "supports": ["BANGLEJS","BANGLEJS2"],
"screenshots": [{"url":"ss_bjs1.png"}],
"readme": "README.md", "readme": "README.md",
"storage": [ "storage": [
{"name":"widclkbttm.wid.js","url":"widclkbttm.wid.js"} {"name":"widclkbttm.wid.js","url":"widclkbttm.wid.js"}

BIN
apps/widclkbttm/ss_bjs1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

BIN
apps/widclkbttm/ss_bjs2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

View File

@ -1,9 +1,9 @@
WIDGETS["wdclkbttm"]={area:"br",width:Bangle.CLOCK?0:60,draw:function() { WIDGETS["wdclkbttm"]={area:"br",width:Bangle.CLOCK?0:60,draw:function() {
if (!Bangle.CLOCK == !this.width) { // if we're the wrong size for if we have a clock or not... if (!Bangle.CLOCK == !this.width) { // if we're the wrong size for if we have a clock or not...
this.width = Bangle.CLOCK?0:60; this.width = Bangle.CLOCK?0:60;
return setTimeout(Bangle.drawWidgets,1); // widget changed size - redraw return setTimeout(Bangle.drawWidgets,1); // widget changed size - redraw
} }
if (!this.width) return; // if size not right, return if (!this.width) return; // if not visible, return
g.reset().setFont("6x8", 2).setFontAlign(-1, 0); g.reset().setFont("6x8", 2).setFontAlign(-1, 0);
var time = require("locale").time(new Date(),1); var time = require("locale").time(new Date(),1);
g.drawString(time, this.x, this.y+11, true); // 5 * 6*2 = 60 g.drawString(time, this.x, this.y+11, true); // 5 * 6*2 = 60

View File

@ -1,2 +1,3 @@
0.01: 1st ver, inspired in some code from widclkbttm (Digital clock bttom widget) 0.01: 1st ver, inspired in some code from widclkbttm (Digital clock bttom widget)
0.02: Correction, intervals, dynamic color and font size depending on device 0.02: Correction, intervals, dynamic color and font size depending on device
0.03: minor corrections, and color depending on theme

View File

@ -2,8 +2,9 @@
A basic HW/performance monitor widget that shows on real time some technical info, such as free mem, free storage, trash mem, files, FW version. Also allows to test the unfrequently used widget bottom area. A basic HW/performance monitor widget that shows on real time some technical info, such as free mem, free storage, trash mem, files, FW version. Also allows to test the unfrequently used widget bottom area.
Compatible with BangleJS1,BangleJS2,and EMSCRIPTENx emulators Compatible with BangleJS1,BangleJS2,and EMSCRIPTENx emulators
Dynamic Color dependant on Theme color bg
forked from widclkbttm (Digital clock bttom widget) forked from my widclkbttm (Digital clock bttom widget)
## Photo ## Photo
@ -13,6 +14,8 @@ Example of usage
![](widhwbttm.ss1.jpg) ![](widhwbttm.ss1.jpg)
![](widhwbttm.ss2.jpg) ![](widhwbttm.ss2.jpg)
Screenshot emulator
![](screenshot_ems2.png)

View File

@ -2,12 +2,13 @@
"id": "widhwbttm", "id": "widhwbttm",
"name": "HW stats (Bottom) widget", "name": "HW stats (Bottom) widget",
"shortName": "Digital clock Bottom Widget", "shortName": "Digital clock Bottom Widget",
"version": "0.02", "version": "0.03",
"description": "Displays technical info and mem stats in the bottom of the screen (may not be compatible with some apps)", "description": "Displays technical info, such as model, ver, temperatura or mem stats in the bottom of the screen (may not be compatible with some apps)",
"icon": "widhwbttm.png", "icon": "widhwbttm.png",
"type": "widget", "type": "widget",
"tags": "widget", "tags": "widget",
"supports": ["BANGLEJS","BANGLEJS2"], "supports": ["BANGLEJS","BANGLEJS2"],
"screenshots": [{"url":"screenshot.png"}],
"readme": "README.md", "readme": "README.md",
"storage": [ "storage": [
{"name":"widhwbttm.wid.js","url":"widhwbttm.wid.js"} {"name":"widhwbttm.wid.js","url":"widhwbttm.wid.js"}

Binary file not shown.

After

Width:  |  Height:  |  Size: 981 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 787 B

View File

@ -1,57 +1,59 @@
(function() { (function() {
let intervalRef = null; let intervalRef = null;
var v_switch; // show stats var v_count; // show stats
var v_str_hw=new String(); var v_str_hw=new String();
if (process.env.BOARD=='BANGLEJS'||process.env.BOARD=='EMSCRIPTEN') var v_font_size=16; //if (process.env.BOARD=='BANGLEJS'||process.env.BOARD=='EMSCRIPTEN') var v_bfont_size=2;
else var v_font_size=14; var v_bfont_size=2;
if (v_switch == null || v_switch == '') v_switch=0; if (g.theme.dark==true) var v_color=0xFFFF; //white
function draw(){ else var v_color=0x0000; //black
if (Bangle.CLOCK) return; if (v_count == null || v_count == '') v_count=0;
if (v_switch==0) { function draw(){
// var v_hw=process.env.VERSION; // if (Bangle.CLOCK) return; //to remove from a clock
v_str_hw="V "+process.env.VERSION.substr(0,6); if (v_count==0) {
v_switch++; v_str_hw=process.env.VERSION.substr(0,6);
} else if (v_switch==1) { v_count++;
} else if (v_count==1) {
v_str_hw=process.env.BOARD.substr(0,3)+".."+process.env.BOARD.substr(process.env.BOARD.length-3,3); v_str_hw=process.env.BOARD.substr(0,3)+".."+process.env.BOARD.substr(process.env.BOARD.length-3,3);
v_switch++; v_count++;
} } else if (v_count==2) {
else if (v_switch==2) {
v_str_hw="Bat "+E.getBattery()+"%"; v_str_hw="Bat "+E.getBattery()+"%";
v_switch++; v_count++;
} }
else if (v_count==3 && process.env.BOARD.substr(0,6)=='BANGLE') {
v_str_hw="Tmp "+E.getTemperature();
v_count++;
}
else { else {
// text prefix has to be 4char // text prefix has to be 4char
stor=require("Storage").getStats(); stor=require("Storage").getStats();
if (v_switch==3) { if (v_count==4) {
v_str_hw="Fre "+process.memory().free; v_str_hw="Fre "+process.memory().free;
//+"/"+process.memory().total; //+"/"+process.memory().total;
v_switch++; v_count++;
} }
else if (v_switch==4) { else if (v_count==5) {
v_str_hw="Sto "+stor.freeBytes; v_str_hw="Sto "+stor.freeBytes;
v_switch++; v_count++;
} else if (v_switch==5) { } else if (v_count==6) {
v_str_hw="Tra "+stor.trashBytes; v_str_hw="Tra "+stor.trashBytes;
v_switch++; v_count++;
} else if (v_switch==6) { } else if (v_count==7) {
v_str_hw="Fil "+stor.fileCount; v_str_hw="Fil "+stor.fileCount;
v_switch=0; v_count=0;
} }
// 4 char are prefix // 4 char are prefix
if (v_str_hw.length>7) { if (v_str_hw.length>7) {
//replace 3 digits by k //replace 3 digits by k
//substring betw x and y v_str_hw=v_str_hw.substr(0,v_str_hw.length-3)+"k";
v_str_hw=v_str_hw.substr(0,v_str_hw.length-3)+"k"; }
} } //end else storage
} //else storage g.reset().setColor(v_color).setFont("6x8",v_bfont_size).setFontAlign(-1, 0);
g.reset().setFontVector(v_font_size).setFontAlign(-1, 0); //clean a longer previous string, care with br widgets
//clean a longer previous string, care with br widgets g.drawString(" ", this.x, this.y+11, true);
g.drawString(" ", this.x, this.y+11, true); g.drawString(v_str_hw, this.x, this.y+11, true);
g.drawString(v_str_hw, this.x, this.y+11, true); } //end draw
} //end draw
WIDGETS["wdhwbttm"]={area:"bl",width:60,draw:draw}; WIDGETS["wdhwbttm"]={area:"bl",width:100,draw:draw};
//{area:"bl",width:Bangle.CLOCK?0:60,draw:draw};
if (Bangle.isLCDOn) intervalRef = setInterval(()=>WIDGETS["wdhwbttm"].draw(), 10*1000); if (Bangle.isLCDOn) intervalRef = setInterval(()=>WIDGETS["wdhwbttm"].draw(), 10*1000);
})() })()

View File

@ -41,17 +41,12 @@ function ClockFace(options) {
this[k] = settings[k]; this[k] = settings[k];
}); });
} }
// these default to true // showDate defaults to true
["showDate", "loadWidgets"].forEach(k => { if (this.showDate===undefined) this.showDate = true;
if (this[k]===undefined) this[k] = true; // if (old) setting was to not load widgets, default to hiding them
}); if (this.hideWidgets===undefined && this.loadWidgets===false) this.hideWidgets = 1;
let s = require("Storage").readJSON("setting.json",1)||{}; let s = require("Storage").readJSON("setting.json",1)||{};
if ((global.__FILE__===undefined || global.__FILE__===s.clock)
&& s.clockHasWidgets!==this.loadWidgets) {
// save whether we can Fast Load
s.clockHasWidgets = this.loadWidgets;
require("Storage").writeJSON("setting.json", s);
}
// use global 24/12-hour setting if not set by clock-settings // use global 24/12-hour setting if not set by clock-settings
if (!('is12Hour' in this)) this.is12Hour = !!(s["12hour"]); if (!('is12Hour' in this)) this.is12Hour = !!(s["12hour"]);
} }
@ -92,7 +87,9 @@ ClockFace.prototype.start = function() {
.CLOCK is set by Bangle.setUI('clock') but we want to load widgets so we can check appRect and *then* .CLOCK is set by Bangle.setUI('clock') but we want to load widgets so we can check appRect and *then*
call setUI. see #1864 */ call setUI. see #1864 */
Bangle.CLOCK = 1; Bangle.CLOCK = 1;
if (this.loadWidgets) Bangle.loadWidgets(); Bangle.loadWidgets();
const widget_util = ["show", "hide", "swipeOn"][this.hideWidgets|0];
require("widget_utils")[widget_util]();
if (this.init) this.init.apply(this); if (this.init) this.init.apply(this);
const uiRemove = this._remove ? () => this.remove() : undefined; const uiRemove = this._remove ? () => this.remove() : undefined;
if (this._upDown) { if (this._upDown) {
@ -133,6 +130,7 @@ ClockFace.prototype.resume = function() {
}; };
ClockFace.prototype.remove = function() { ClockFace.prototype.remove = function() {
this._removed = true; this._removed = true;
require("widget_utils").show();
if (this._timeout) clearTimeout(this._timeout); if (this._timeout) clearTimeout(this._timeout);
Bangle.removeListener("lcdPower", this._onLcd); Bangle.removeListener("lcdPower", this._onLcd);
if (this._remove) this._remove.apply(this); if (this._remove) this._remove.apply(this);

View File

@ -140,7 +140,7 @@ For example:
// now // now
clock.showDate === false; clock.showDate === false;
clock.foo === 123; clock.foo === 123;
clock.loadWidgets === true; // default when not in settings file clock.hideWidgets === 0; // default when not in settings file
clock.is12Hour === ??; // not in settings file: uses global setting clock.is12Hour === ??; // not in settings file: uses global setting
clock.start(); clock.start();
@ -152,13 +152,14 @@ The following properties are automatically set on the clock:
* `is12Hour`: `true` if the "Time Format" setting is set to "12h", `false` for "24h". * `is12Hour`: `true` if the "Time Format" setting is set to "12h", `false` for "24h".
* `paused`: `true` while the clock is paused. (You don't need to check this inside your `draw()` code) * `paused`: `true` while the clock is paused. (You don't need to check this inside your `draw()` code)
* `showDate`: `true` (if not overridden through the settings file.) * `showDate`: `true` (if not overridden through the settings file.)
* `loadWidgets`: `true` (if not overridden through the settings file.) * `hideWidgets`: `0` (if not overridden through the settings file.)
If set to `false` before calling `start()`, the clock won't call `Bangle.loadWidgets();` for you. If set to `1` before calling `start()`, the clock calls `require("widget_utils")hide();` for you.
Best is to add a setting for this, but if you never want to load widgets, you could do this: (Bangle.js 2 only: `2` for swipe-down)
Best is to add a setting for this, but if you never want to show widgets, you could do this:
```js ```js
var ClockFace = require("ClockFace"); var ClockFace = require("ClockFace");
var clock = new ClockFace({draw: function(){/*...*/}}); var clock = new ClockFace({draw: function(){/*...*/}});
clock.loadWidgets = false; // prevent loading of widgets clock.hideWidgets = 1; // hide widgets
clock.start(); clock.start();
``` ```
@ -200,7 +201,7 @@ let menu = {
}; };
require("ClockFace_menu").addItems(menu, save, { require("ClockFace_menu").addItems(menu, save, {
showDate: settings.showDate, showDate: settings.showDate,
loadWidgets: settings.loadWidgets, hideWidgets: settings.hideWidgets,
}); });
E.showMenu(menu); E.showMenu(menu);
@ -213,7 +214,7 @@ let menu = {
/*LANG*/"< Back": back, /*LANG*/"< Back": back,
}; };
require("ClockFace_menu").addSettingsFile(menu, "<appid>.settings.json", [ require("ClockFace_menu").addSettingsFile(menu, "<appid>.settings.json", [
"showDate", "loadWidgets", "powerSave", "showDate", "hideWidgets", "powerSave",
]); ]);
E.showMenu(menu); E.showMenu(menu);

View File

@ -10,13 +10,12 @@ exports.addItems = function(menu, callback, items) {
let value = items[key]; let value = items[key];
const label = { const label = {
showDate:/*LANG*/"Show date", showDate:/*LANG*/"Show date",
loadWidgets:/*LANG*/"Load widgets", hideWidgets:/*LANG*/"Widgets",
powerSave:/*LANG*/"Power saving", powerSave:/*LANG*/"Power saving",
}[key]; }[key];
switch(key) { switch(key) {
// boolean options which default to true // boolean options which default to true
case "showDate": case "showDate":
case "loadWidgets":
if (value===undefined) value = true; if (value===undefined) value = true;
// fall through // fall through
case "powerSave": case "powerSave":
@ -25,6 +24,17 @@ exports.addItems = function(menu, callback, items) {
value: !!value, value: !!value,
onchange: v => callback(key, v), onchange: v => callback(key, v),
}; };
break;
case "hideWidgets":
let options = [/*LANG*/"Show",/*LANG*/"Hide"];
if (process.env.HWVERSION===2) options.push(/*LANG*/"Swipe");
menu[label] = {
value: value|0,
min: 0, max: options.length-1,
format: v => options[v|0],
onchange: v => callback(key, v),
};
} }
}); });
}; };
@ -39,6 +49,12 @@ exports.addItems = function(menu, callback, items) {
exports.addSettingsFile = function(menu, settingsFile, items) { exports.addSettingsFile = function(menu, settingsFile, items) {
let s = require("Storage").readJSON(settingsFile, true) || {}; let s = require("Storage").readJSON(settingsFile, true) || {};
// migrate "don't load widgets" to "hide widgets"
if (!("hideWidgets" in s) && ("loadWidgets" in s) && !s.loadWidgets) {
s.hideWidgets = 1;
}
delete s.loadWidgets;
function save(key, value) { function save(key, value) {
s[key] = value; s[key] = value;
require("Storage").writeJSON(settingsFile, s); require("Storage").writeJSON(settingsFile, s);

View File

@ -267,7 +267,7 @@ Layout.prototype.layout = function (l) {
}); });
} }
}; };
cb[l.type](l); if (cb[l.type]) cb[l.type](l);
}; };
Layout.prototype.debug = function(l,c) { Layout.prototype.debug = function(l,c) {
if (!l) l = this._l; if (!l) l = this._l;

28
modules/Layout.min.js vendored
View File

@ -1,14 +1,14 @@
function p(d,h){function b(e){"ram";e.id&&(a[e.id]=e);e.type||(e.type="");e.c&&e.c.forEach(b)}this._l=this.l=d;this.options=h||{};this.lazy=this.options.lazy||!1;this.physBtns=1;let f;if(2!=process.env.HWVERSION){this.physBtns=3;f=[];function e(l){"ram";"btn"==l.type&&f.push(l);l.c&&l.c.forEach(e)}e(d);f.length&&(this.physBtns=0,this.buttons=f,this.selectedButton=-1)}if(this.options.btns)if(d=this.options.btns,this.physBtns>=d.length){this.b=d;let e=Math.floor(Bangle.appRect.h/this.physBtns); function p(d,h){function b(e){"ram";e.id&&(a[e.id]=e);e.type||(e.type="");e.c&&e.c.forEach(b)}this._l=this.l=d;this.options=h||{};this.lazy=this.options.lazy||!1;this.physBtns=1;let f;if(2!=process.env.HWVERSION){this.physBtns=3;f=[];function e(l){"ram";"btn"==l.type&&f.push(l);l.c&&l.c.forEach(e)}e(d);f.length&&(this.physBtns=0,this.buttons=f,this.selectedButton=-1)}if(this.options.btns)if(d=this.options.btns,this.physBtns>=d.length){this.b=d;let e=Math.floor(Bangle.appRect.h/
for(2<this.physBtns&&1==d.length&&d.unshift({label:""});this.physBtns>d.length;)d.push({label:""});this._l.width=g.getWidth()-8;this._l={type:"h",filly:1,c:[this._l,{type:"v",pad:1,filly:1,c:d.map(l=>(l.type="txt",l.font="6x8",l.height=e,l.r=1,l))}]}}else this._l.width=g.getWidth()-32,this._l={type:"h",c:[this._l,{type:"v",c:d.map(e=>(e.type="btn",e.filly=1,e.width=32,e.r=1,e))}]},f&&f.push.apply(f,this._l.c[1].c);this.setUI();var a=this;b(this._l);this.updateNeeded=!0}function t(d,h,b,f,a){var e= this.physBtns);for(2<this.physBtns&&1==d.length&&d.unshift({label:""});this.physBtns>d.length;)d.push({label:""});this._l.width=g.getWidth()-8;this._l={type:"h",filly:1,c:[this._l,{type:"v",pad:1,filly:1,c:d.map(l=>(l.type="txt",l.font="6x8",l.height=e,l.r=1,l))}]}}else this._l.width=g.getWidth()-32,this._l={type:"h",c:[this._l,{type:"v",c:d.map(e=>(e.type="btn",e.filly=1,e.width=32,e.r=1,e))}]},f&&f.push.apply(f,this._l.c[1].c);this.setUI();var a=this;b(this._l);this.updateNeeded=!0}function t(d,
null==d.bgCol?a:g.toColor(d.bgCol);if(e!=a||"txt"==d.type||"btn"==d.type||"img"==d.type||"custom"==d.type){var l=d.c;delete d.c;var k="H"+E.CRC32(E.toJS(d));l&&(d.c=l);delete h[k]||((f[k]=[d.x,d.y,d.x+d.w-1,d.y+d.h-1]).bg=null==a?g.theme.bg:a,b&&(b.push(d),b=null))}if(d.c)for(var c of d.c)t(c,h,b,f,e)}p.prototype.setUI=function(){Bangle.setUI();let d;this.buttons&&(Bangle.setUI({mode:"updown",back:this.options.back,remove:this.options.remove},h=>{var b=this.selectedButton,f=this.buttons.length;if(void 0=== h,b,f,a){var e=null==d.bgCol?a:g.toColor(d.bgCol);if(e!=a||"txt"==d.type||"btn"==d.type||"img"==d.type||"custom"==d.type){var l=d.c;delete d.c;var k="H"+E.CRC32(E.toJS(d));l&&(d.c=l);delete h[k]||((f[k]=[d.x,d.y,d.x+d.w-1,d.y+d.h-1]).bg=null==a?g.theme.bg:a,b&&(b.push(d),b=null))}if(d.c)for(var c of d.c)t(c,h,b,f,e)}p.prototype.setUI=function(){Bangle.setUI();let d;this.buttons&&(Bangle.setUI({mode:"updown",back:this.options.back,remove:this.options.remove},h=>{var b=this.selectedButton,f=this.buttons.length;
h&&this.buttons[b])return this.buttons[b].cb();this.buttons[b]&&(delete this.buttons[b].selected,this.render(this.buttons[b]));b=(b+f+h)%f;this.buttons[b]&&(this.buttons[b].selected=1,this.render(this.buttons[b]));this.selectedButton=b}),d=!0);!this.options.back&&!this.options.remove||d||Bangle.setUI({mode:"custom",back:this.options.back,remove:this.options.remove});if(this.b){function h(b,f){.75<f.time-f.lastTime&&this.b[b].cbl?this.b[b].cbl(f):this.b[b].cb&&this.b[b].cb(f)}Bangle.btnWatches&&Bangle.btnWatches.forEach(clearWatch); if(void 0===h&&this.buttons[b])return this.buttons[b].cb();this.buttons[b]&&(delete this.buttons[b].selected,this.render(this.buttons[b]));b=(b+f+h)%f;this.buttons[b]&&(this.buttons[b].selected=1,this.render(this.buttons[b]));this.selectedButton=b}),d=!0);!this.options.back&&!this.options.remove||d||Bangle.setUI({mode:"custom",back:this.options.back,remove:this.options.remove});if(this.b){function h(b,f){.75<f.time-f.lastTime&&this.b[b].cbl?this.b[b].cbl(f):this.b[b].cb&&this.b[b].cb(f)}Bangle.btnWatches&&
Bangle.btnWatches=[];this.b[0]&&Bangle.btnWatches.push(setWatch(h.bind(this,0),BTN1,{repeat:!0,edge:-1}));this.b[1]&&Bangle.btnWatches.push(setWatch(h.bind(this,1),BTN2,{repeat:!0,edge:-1}));this.b[2]&&Bangle.btnWatches.push(setWatch(h.bind(this,2),BTN3,{repeat:!0,edge:-1}))}if(2==process.env.HWVERSION){function h(b,f){b.cb&&f.x>=b.x&&f.y>=b.y&&f.x<=b.x+b.w&&f.y<=b.y+b.h&&(2==f.type&&b.cbl?b.cbl(f):b.cb&&b.cb(f));b.c&&b.c.forEach(a=>h(a,f))}Bangle.touchHandler=(b,f)=>h(this._l,f);Bangle.on("touch", Bangle.btnWatches.forEach(clearWatch);Bangle.btnWatches=[];this.b[0]&&Bangle.btnWatches.push(setWatch(h.bind(this,0),BTN1,{repeat:!0,edge:-1}));this.b[1]&&Bangle.btnWatches.push(setWatch(h.bind(this,1),BTN2,{repeat:!0,edge:-1}));this.b[2]&&Bangle.btnWatches.push(setWatch(h.bind(this,2),BTN3,{repeat:!0,edge:-1}))}if(2==process.env.HWVERSION){function h(b,f){b.cb&&f.x>=b.x&&f.y>=b.y&&f.x<=b.x+b.w&&f.y<=b.y+b.h&&(2==f.type&&b.cbl?b.cbl(f):b.cb&&b.cb(f));b.c&&b.c.forEach(a=>h(a,f))}Bangle.touchHandler=
Bangle.touchHandler)}};p.prototype.render=function(d){function h(c){"ram";b.reset();void 0!==c.col&&b.setColor(c.col);void 0!==c.bgCol&&b.setBgColor(c.bgCol).clearRect(c.x,c.y,c.x+c.w-1,c.y+c.h-1);f[c.type](c)}d||(d=this._l);this.updateNeeded&&this.update();var b=g,f={"":function(){},txt:function(c){"ram";if(c.wrap){var m=b.setFont(c.font).setFontAlign(0,-1).wrapString(c.label,c.w),n=c.y+(c.h-b.getFontHeight()*m.length>>1);b.drawString(m.join("\n"),c.x+(c.w>>1),n)}else b.setFont(c.font).setFontAlign(0, (b,f)=>h(this._l,f);Bangle.on("touch",Bangle.touchHandler)}};p.prototype.render=function(d){function h(c){"ram";b.reset();void 0!==c.col&&b.setColor(c.col);void 0!==c.bgCol&&b.setBgColor(c.bgCol).clearRect(c.x,c.y,c.x+c.w-1,c.y+c.h-1);f[c.type](c)}d||(d=this._l);this.updateNeeded&&this.update();var b=g,f={"":function(){},txt:function(c){"ram";if(c.wrap){var m=b.setFont(c.font).setFontAlign(0,-1).wrapString(c.label,c.w),n=c.y+(c.h-b.getFontHeight()*m.length>>1);b.drawString(m.join("\n"),c.x+(c.w>>
0,c.r).drawString(c.label,c.x+(c.w>>1),c.y+(c.h>>1))},btn:function(c){"ram";var m=c.x+(0|c.pad),n=c.y+(0|c.pad),q=c.w-(c.pad<<1),r=c.h-(c.pad<<1);m=[m,n+4,m+4,n,m+q-5,n,m+q-1,n+4,m+q-1,n+r-5,m+q-5,n+r-1,m+4,n+r-1,m,n+r-5,m,n+4];n=c.selected?b.theme.bgH:b.theme.bg2;b.setColor(n).fillPoly(m).setColor(c.selected?b.theme.fgH:b.theme.fg2).drawPoly(m);void 0!==c.col&&b.setColor(c.col);c.src?b.setBgColor(n).drawImage("function"==typeof c.src?c.src():c.src,c.x+c.w/2,c.y+c.h/2,{scale:c.scale||void 0,rotate:.5* 1),n)}else b.setFont(c.font).setFontAlign(0,0,c.r).drawString(c.label,c.x+(c.w>>1),c.y+(c.h>>1))},btn:function(c){"ram";var m=c.x+(0|c.pad),n=c.y+(0|c.pad),q=c.w-(c.pad<<1),r=c.h-(c.pad<<1);m=[m,n+4,m+4,n,m+q-5,n,m+q-1,n+4,m+q-1,n+r-5,m+q-5,n+r-1,m+4,n+r-1,m,n+r-5,m,n+4];n=c.selected?b.theme.bgH:b.theme.bg2;b.setColor(n).fillPoly(m).setColor(c.selected?b.theme.fgH:b.theme.fg2).drawPoly(m);void 0!==c.col&&b.setColor(c.col);c.src?b.setBgColor(n).drawImage("function"==typeof c.src?c.src():c.src,c.x+
Math.PI*(c.r||0)}):b.setFont(c.font||"6x8:2").setFontAlign(0,0,c.r).drawString(c.label,c.x+c.w/2,c.y+c.h/2)},img:function(c){"ram";b.drawImage("function"==typeof c.src?c.src():c.src,c.x+c.w/2,c.y+c.h/2,{scale:c.scale||void 0,rotate:.5*Math.PI*(c.r||0)})},custom:function(c){"ram";c.render(c)},h:function(c){"ram";c.c.forEach(h)},v:function(c){"ram";c.c.forEach(h)}};if(this.lazy){this.rects||(this.rects={});var a=this.rects.clone(),e=[];t(d,a,e,this.rects,null);for(var l in a)delete this.rects[l];d= c.w/2,c.y+c.h/2,{scale:c.scale||void 0,rotate:.5*Math.PI*(c.r||0)}):b.setFont(c.font||"6x8:2").setFontAlign(0,0,c.r).drawString(c.label,c.x+c.w/2,c.y+c.h/2)},img:function(c){"ram";b.drawImage("function"==typeof c.src?c.src():c.src,c.x+c.w/2,c.y+c.h/2,{scale:c.scale||void 0,rotate:.5*Math.PI*(c.r||0)})},custom:function(c){"ram";c.render(c)},h:function(c){"ram";c.c.forEach(h)},v:function(c){"ram";c.c.forEach(h)}};if(this.lazy){this.rects||(this.rects={});var a=this.rects.clone(),e=[];t(d,a,e,this.rects,
Object.keys(a).map(c=>a[c]).reverse();for(var k of d)b.setBgColor(k.bg).clearRect.apply(g,k);e.forEach(h)}else h(d)};p.prototype.forgetLazyState=function(){this.rects={}};p.prototype.layout=function(d){var h={h:function(b){"ram";var f=b.x+(0|b.pad),a=0,e=b.c&&b.c.reduce((k,c)=>k+(0|c.fillx),0);e||(f+=b.w-b._w>>1,e=1);var l=f;b.c.forEach(k=>{k.x=0|l;f+=k._w;a+=0|k.fillx;l=f+Math.floor(a*(b.w-b._w)/e);k.w=0|l-k.x;k.h=0|(k.filly?b.h-(b.pad<<1):k._h);k.y=0|b.y+(0|b.pad)+((1+(0|k.valign))*(b.h-(b.pad<< null);for(var l in a)delete this.rects[l];d=Object.keys(a).map(c=>a[c]).reverse();for(var k of d)b.setBgColor(k.bg).clearRect.apply(g,k);e.forEach(h)}else h(d)};p.prototype.forgetLazyState=function(){this.rects={}};p.prototype.layout=function(d){var h={h:function(b){"ram";var f=b.x+(0|b.pad),a=0,e=b.c&&b.c.reduce((k,c)=>k+(0|c.fillx),0);e||(f+=b.w-b._w>>1,e=1);var l=f;b.c.forEach(k=>{k.x=0|l;f+=k._w;a+=0|k.fillx;l=f+Math.floor(a*(b.w-b._w)/e);k.w=0|l-k.x;k.h=0|(k.filly?b.h-(b.pad<<1):k._h);k.y=0|
1)-k.h)>>1);if(k.c)h[k.type](k)})},v:function(b){"ram";var f=b.y+(0|b.pad),a=0,e=b.c&&b.c.reduce((k,c)=>k+(0|c.filly),0);e||(f+=b.h-b._h>>1,e=1);var l=f;b.c.forEach(k=>{k.y=0|l;f+=k._h;a+=0|k.filly;l=f+Math.floor(a*(b.h-b._h)/e);k.h=0|l-k.y;k.w=0|(k.fillx?b.w-(b.pad<<1):k._w);k.x=0|b.x+(0|b.pad)+((1+(0|k.halign))*(b.w-(b.pad<<1)-k.w)>>1);if(k.c)h[k.type](k)})}};h[d.type](d)};p.prototype.debug=function(d,h){d||(d=this._l);h=h||1;g.setColor(h&1,h&2,h&4).drawRect(d.x+h-1,d.y+h-1,d.x+d.w-h,d.y+d.h-h); b.y+(0|b.pad)+((1+(0|k.valign))*(b.h-(b.pad<<1)-k.h)>>1);if(k.c)h[k.type](k)})},v:function(b){"ram";var f=b.y+(0|b.pad),a=0,e=b.c&&b.c.reduce((k,c)=>k+(0|c.filly),0);e||(f+=b.h-b._h>>1,e=1);var l=f;b.c.forEach(k=>{k.y=0|l;f+=k._h;a+=0|k.filly;l=f+Math.floor(a*(b.h-b._h)/e);k.h=0|l-k.y;k.w=0|(k.fillx?b.w-(b.pad<<1):k._w);k.x=0|b.x+(0|b.pad)+((1+(0|k.halign))*(b.w-(b.pad<<1)-k.w)>>1);if(k.c)h[k.type](k)})}};if(h[d.type])h[d.type](d)};p.prototype.debug=function(d,h){d||(d=this._l);h=h||1;g.setColor(h&
d.pad&&g.drawRect(d.x+d.pad-1,d.y+d.pad-1,d.x+d.w-d.pad,d.y+d.h-d.pad);h++;d.c&&d.c.forEach(b=>this.debug(b,h))};p.prototype.update=function(){function d(a){"ram";b[a.type](a);if(a.r&1){var e=a._w;a._w=a._h;a._h=e}a._w=Math.max(a._w+(a.pad<<1),0|a.width);a._h=Math.max(a._h+(a.pad<<1),0|a.height)}delete this.updateNeeded;var h=g,b={txt:function(a){"ram";a.font.endsWith("%")&&(a.font="Vector"+Math.round(h.getHeight()*a.font.slice(0,-1)/100));if(a.wrap)a._h=a._w=0;else{var e=g.setFont(a.font).stringMetrics(a.label); 1,h&2,h&4).drawRect(d.x+h-1,d.y+h-1,d.x+d.w-h,d.y+d.h-h);d.pad&&g.drawRect(d.x+d.pad-1,d.y+d.pad-1,d.x+d.w-d.pad,d.y+d.h-d.pad);h++;d.c&&d.c.forEach(b=>this.debug(b,h))};p.prototype.update=function(){function d(a){"ram";b[a.type](a);if(a.r&1){var e=a._w;a._w=a._h;a._h=e}a._w=Math.max(a._w+(a.pad<<1),0|a.width);a._h=Math.max(a._h+(a.pad<<1),0|a.height)}delete this.updateNeeded;var h=g,b={txt:function(a){"ram";a.font.endsWith("%")&&(a.font="Vector"+Math.round(h.getHeight()*a.font.slice(0,-1)/100));
a._w=e.width;a._h=e.height}},btn:function(a){"ram";a.font&&a.font.endsWith("%")&&(a.font="Vector"+Math.round(h.getHeight()*a.font.slice(0,-1)/100));var e=a.src?h.imageMetrics("function"==typeof a.src?a.src():a.src):h.setFont(a.font||"6x8:2").stringMetrics(a.label);a._h=16+e.height;a._w=20+e.width},img:function(a){"ram";var e=h.imageMetrics("function"==typeof a.src?a.src():a.src),l=a.scale||1;a._w=e.width*l;a._h=e.height*l},"":function(a){"ram";a._w=0;a._h=0},custom:function(a){"ram";a._w=0;a._h=0}, if(a.wrap)a._h=a._w=0;else{var e=g.setFont(a.font).stringMetrics(a.label);a._w=e.width;a._h=e.height}},btn:function(a){"ram";a.font&&a.font.endsWith("%")&&(a.font="Vector"+Math.round(h.getHeight()*a.font.slice(0,-1)/100));var e=a.src?h.imageMetrics("function"==typeof a.src?a.src():a.src):h.setFont(a.font||"6x8:2").stringMetrics(a.label);a._h=16+e.height;a._w=20+e.width},img:function(a){"ram";var e=h.imageMetrics("function"==typeof a.src?a.src():a.src),l=a.scale||1;a._w=e.width*l;a._h=e.height*l},
h:function(a){"ram";a.c.forEach(d);a._h=a.c.reduce((e,l)=>Math.max(e,l._h),0);a._w=a.c.reduce((e,l)=>e+l._w,0);null==a.fillx&&a.c.some(e=>e.fillx)&&(a.fillx=1);null==a.filly&&a.c.some(e=>e.filly)&&(a.filly=1)},v:function(a){"ram";a.c.forEach(d);a._h=a.c.reduce((e,l)=>e+l._h,0);a._w=a.c.reduce((e,l)=>Math.max(e,l._w),0);null==a.fillx&&a.c.some(e=>e.fillx)&&(a.fillx=1);null==a.filly&&a.c.some(e=>e.filly)&&(a.filly=1)}},f=this._l;d(f);delete b;f.fillx||f.filly?(f.w=Bangle.appRect.w,f.h=Bangle.appRect.h, "":function(a){"ram";a._w=0;a._h=0},custom:function(a){"ram";a._w=0;a._h=0},h:function(a){"ram";a.c.forEach(d);a._h=a.c.reduce((e,l)=>Math.max(e,l._h),0);a._w=a.c.reduce((e,l)=>e+l._w,0);null==a.fillx&&a.c.some(e=>e.fillx)&&(a.fillx=1);null==a.filly&&a.c.some(e=>e.filly)&&(a.filly=1)},v:function(a){"ram";a.c.forEach(d);a._h=a.c.reduce((e,l)=>e+l._h,0);a._w=a.c.reduce((e,l)=>Math.max(e,l._w),0);null==a.fillx&&a.c.some(e=>e.fillx)&&(a.fillx=1);null==a.filly&&a.c.some(e=>e.filly)&&(a.filly=1)}},f=this._l;
f.x=Bangle.appRect.x,f.y=Bangle.appRect.y):(f.w=f._w,f.h=f._h,f.x=Bangle.appRect.w-f.w>>1,f.y=Bangle.appRect.y+(Bangle.appRect.h-f.h>>1));this.layout(f)};p.prototype.clear=function(d){d||(d=this._l);g.reset();void 0!==d.bgCol&&g.setBgColor(d.bgCol);g.clearRect(d.x,d.y,d.x+d.w-1,d.y+d.h-1)};exports=p d(f);delete b;f.fillx||f.filly?(f.w=Bangle.appRect.w,f.h=Bangle.appRect.h,f.x=Bangle.appRect.x,f.y=Bangle.appRect.y):(f.w=f._w,f.h=f._h,f.x=Bangle.appRect.w-f.w>>1,f.y=Bangle.appRect.y+(Bangle.appRect.h-f.h>>1));this.layout(f)};p.prototype.clear=function(d){d||(d=this._l);g.reset();void 0!==d.bgCol&&g.setBgColor(d.bgCol);g.clearRect(d.x,d.y,d.x+d.w-1,d.y+d.h-1)};exports=p

View File

@ -299,6 +299,23 @@ exports.addInteractive = function(menu, options) {
options.redraw = function() { options.redraw = function() {
drawItem(menu[options.menuA].items[options.menuB]); drawItem(menu[options.menuA].items[options.menuB]);
}; };
options.setItem = function (menuA, menuB) {
if (!menu[menuA] || !menu[menuA].items[menuB] || (options.menuA == menuA && options.menuB == menuB)) {
// menuA or menuB did not exist or did not change
return false;
}
const oldMenuItem = menu[options.menuA].items[options.menuB];
if (oldMenuItem) {
menuHideItem(oldMenuItem);
oldMenuItem.removeAllListeners("draw");
}
options.menuA = menuA;
options.menuB = menuB;
menuShowItem(menu[options.menuA].items[options.menuB]);
return true;
}
return options; return options;
}; };

6
package-lock.json generated
View File

@ -987,9 +987,9 @@
"dev": true "dev": true
}, },
"json5": { "json5": {
"version": "1.0.1", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
"integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
"dev": true, "dev": true,
"requires": { "requires": {
"minimist": "^1.2.0" "minimist": "^1.2.0"