Merge branch 'espruino:master' into master
commit
89f82a5043
44
apps.json
44
apps.json
|
|
@ -185,7 +185,7 @@
|
||||||
{ "id": "setting",
|
{ "id": "setting",
|
||||||
"name": "Settings",
|
"name": "Settings",
|
||||||
"icon": "settings.png",
|
"icon": "settings.png",
|
||||||
"version":"0.28",
|
"version":"0.30",
|
||||||
"description": "A menu for setting up Bangle.js",
|
"description": "A menu for setting up Bangle.js",
|
||||||
"tags": "tool,system,b2",
|
"tags": "tool,system,b2",
|
||||||
"readme": "README.md",
|
"readme": "README.md",
|
||||||
|
|
@ -199,11 +199,11 @@
|
||||||
"sortorder" : -2
|
"sortorder" : -2
|
||||||
},
|
},
|
||||||
{ "id": "alarm",
|
{ "id": "alarm",
|
||||||
"name": "Default Alarm",
|
"name": "Default Alarm & Timer",
|
||||||
"shortName":"Alarms",
|
"shortName":"Alarms",
|
||||||
"icon": "app.png",
|
"icon": "app.png",
|
||||||
"version":"0.12",
|
"version":"0.13",
|
||||||
"description": "Set and respond to alarms",
|
"description": "Set and respond to alarms and timers",
|
||||||
"tags": "tool,alarm,widget,b2",
|
"tags": "tool,alarm,widget,b2",
|
||||||
"storage": [
|
"storage": [
|
||||||
{"name":"alarm.app.js","url":"app.js"},
|
{"name":"alarm.app.js","url":"app.js"},
|
||||||
|
|
@ -585,7 +585,7 @@
|
||||||
{ "id": "weather",
|
{ "id": "weather",
|
||||||
"name": "Weather",
|
"name": "Weather",
|
||||||
"icon": "icon.png",
|
"icon": "icon.png",
|
||||||
"version":"0.09",
|
"version":"0.10",
|
||||||
"description": "Show Gadgetbridge weather report",
|
"description": "Show Gadgetbridge weather report",
|
||||||
"readme": "readme.md",
|
"readme": "readme.md",
|
||||||
"tags": "widget,outdoors",
|
"tags": "widget,outdoors",
|
||||||
|
|
@ -1187,7 +1187,7 @@
|
||||||
{ "id": "widclk",
|
{ "id": "widclk",
|
||||||
"name": "Digital clock widget",
|
"name": "Digital clock widget",
|
||||||
"icon": "widget.png",
|
"icon": "widget.png",
|
||||||
"version":"0.05",
|
"version":"0.06",
|
||||||
"description": "A simple digital clock widget",
|
"description": "A simple digital clock widget",
|
||||||
"tags": "widget,clock",
|
"tags": "widget,clock",
|
||||||
"type":"widget",
|
"type":"widget",
|
||||||
|
|
@ -1236,9 +1236,9 @@
|
||||||
{ "id": "demoapp",
|
{ "id": "demoapp",
|
||||||
"name": "Demo Loop",
|
"name": "Demo Loop",
|
||||||
"icon": "app.png",
|
"icon": "app.png",
|
||||||
"version":"0.01",
|
"version":"0.02",
|
||||||
"description": "Simple demo app - displays Bangle.js, JS logo, graphics, and Bangle.js information",
|
"description": "Simple demo app - displays Bangle.js, JS logo, graphics, and Bangle.js information",
|
||||||
"tags": "",
|
"tags": "bno2",
|
||||||
"type":"app",
|
"type":"app",
|
||||||
"allow_emulator":true,
|
"allow_emulator":true,
|
||||||
"storage": [
|
"storage": [
|
||||||
|
|
@ -1328,14 +1328,13 @@
|
||||||
"id": "grocery",
|
"id": "grocery",
|
||||||
"name": "Grocery",
|
"name": "Grocery",
|
||||||
"icon": "grocery.png",
|
"icon": "grocery.png",
|
||||||
"version":"0.01",
|
"version":"0.02",
|
||||||
"description": "Simple grocery (shopping) list - Display a list of product and track if you already put them in your cart.",
|
"description": "Simple grocery (shopping) list - Display a list of product and track if you already put them in your cart.",
|
||||||
"tags": "tool,outdoors,shopping,list",
|
"tags": "tool,outdoors,shopping,list",
|
||||||
"type": "app",
|
"type": "app",
|
||||||
"custom":"grocery.html",
|
"custom":"grocery.html",
|
||||||
"storage": [
|
"storage": [
|
||||||
{"name":"grocery"},
|
{"name":"grocery.app.js", "url":"app.js"},
|
||||||
{"name":"grocery.app.js"},
|
|
||||||
{"name":"grocery.img","url":"grocery-icon.js","evaluate":true}
|
{"name":"grocery.img","url":"grocery-icon.js","evaluate":true}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
@ -2414,7 +2413,7 @@
|
||||||
"name": "Acceleration Logger",
|
"name": "Acceleration Logger",
|
||||||
"shortName":"Accel Log",
|
"shortName":"Accel Log",
|
||||||
"icon": "app.png",
|
"icon": "app.png",
|
||||||
"version":"0.02",
|
"version":"0.03",
|
||||||
"interface": "interface.html",
|
"interface": "interface.html",
|
||||||
"description": "Logs XYZ acceleration data to a CSV file that can be downloaded to your PC",
|
"description": "Logs XYZ acceleration data to a CSV file that can be downloaded to your PC",
|
||||||
"tags": "outdoor,b2",
|
"tags": "outdoor,b2",
|
||||||
|
|
@ -3537,10 +3536,11 @@
|
||||||
{ "id": "antonclk",
|
{ "id": "antonclk",
|
||||||
"name": "Anton Clock",
|
"name": "Anton Clock",
|
||||||
"icon": "app.png",
|
"icon": "app.png",
|
||||||
"version":"0.01",
|
"version":"0.02",
|
||||||
"description": "A simple clock using the bold Anton font.",
|
"description": "A simple clock using the bold Anton font.",
|
||||||
"tags":"clock,b2",
|
"tags":"clock,b2",
|
||||||
"type":"clock",
|
"type":"clock",
|
||||||
|
"allow_emulator":true,
|
||||||
"storage": [
|
"storage": [
|
||||||
{"name":"antonclk.app.js","url":"app.js"},
|
{"name":"antonclk.app.js","url":"app.js"},
|
||||||
{"name":"antonclk.img","url":"app-icon.js","evaluate":true}
|
{"name":"antonclk.img","url":"app-icon.js","evaluate":true}
|
||||||
|
|
@ -3549,13 +3549,27 @@
|
||||||
{ "id": "waveclk",
|
{ "id": "waveclk",
|
||||||
"name": "Wave Clock",
|
"name": "Wave Clock",
|
||||||
"icon": "app.png",
|
"icon": "app.png",
|
||||||
"version":"0.01",
|
"version":"0.02",
|
||||||
"description": "A clock using a wave image by [Lillith May](https://www.instagram.com/_lilustrations_/). **Note: This requires a bugfix for #2049 on Bangle.js 1**",
|
"description": "A clock using a wave image by [Lillith May](https://www.instagram.com/_lilustrations_/). **Note: This requires firmware 2v11 or later Bangle.js 1**",
|
||||||
"tags":"clock,b2",
|
"tags":"clock,b2",
|
||||||
"type":"clock",
|
"type":"clock",
|
||||||
|
"allow_emulator":true,
|
||||||
"storage": [
|
"storage": [
|
||||||
{"name":"waveclk.app.js","url":"app.js"},
|
{"name":"waveclk.app.js","url":"app.js"},
|
||||||
{"name":"waveclk.img","url":"app-icon.js","evaluate":true}
|
{"name":"waveclk.img","url":"app-icon.js","evaluate":true}
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{ "id": "floralclk",
|
||||||
|
"name": "Floral Clock",
|
||||||
|
"icon": "app.png",
|
||||||
|
"version":"0.01",
|
||||||
|
"description": "A clock with a flower background by [Lillith May](https://www.instagram.com/_lilustrations_/). **Note: This requires firmware 2v11 or later Bangle.js 1**",
|
||||||
|
"tags":"clock,b2",
|
||||||
|
"type":"clock",
|
||||||
|
"allow_emulator":true,
|
||||||
|
"storage": [
|
||||||
|
{"name":"floralclk.app.js","url":"app.js"},
|
||||||
|
{"name":"floralclk.img","url":"app-icon.js","evaluate":true}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -1,2 +1,3 @@
|
||||||
0.01: New App!
|
0.01: New App!
|
||||||
0.02: Use the new multiplatform 'Layout' library
|
0.02: Use the new multiplatform 'Layout' library
|
||||||
|
0.03: Exit as first menu option, dont show decimal places for seconds
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,9 @@ function getFileName(n) {
|
||||||
function showMenu() {
|
function showMenu() {
|
||||||
var menu = {
|
var menu = {
|
||||||
"" : { title : "Accel Logger" },
|
"" : { title : "Accel Logger" },
|
||||||
|
"Exit" : function() {
|
||||||
|
load();
|
||||||
|
},
|
||||||
"File No" : {
|
"File No" : {
|
||||||
value : fileNumber,
|
value : fileNumber,
|
||||||
min : 0,
|
min : 0,
|
||||||
|
|
@ -21,9 +24,6 @@ function showMenu() {
|
||||||
"View Logs" : function() {
|
"View Logs" : function() {
|
||||||
viewLogs();
|
viewLogs();
|
||||||
},
|
},
|
||||||
"Exit" : function() {
|
|
||||||
load();
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
E.showMenu(menu);
|
E.showMenu(menu);
|
||||||
}
|
}
|
||||||
|
|
@ -34,7 +34,7 @@ function viewLog(n) {
|
||||||
var records = 0, l = "", ll="";
|
var records = 0, l = "", ll="";
|
||||||
while ((l=f.readLine())!==undefined) {records++;ll=l;}
|
while ((l=f.readLine())!==undefined) {records++;ll=l;}
|
||||||
var length = 0;
|
var length = 0;
|
||||||
if (ll) length = (ll.split(",")[0]|0)/1000;
|
if (ll) length = Math.round( (ll.split(",")[0]|0)/1000 );
|
||||||
|
|
||||||
var menu = {
|
var menu = {
|
||||||
"" : { title : "Log "+n }
|
"" : { title : "Log "+n }
|
||||||
|
|
|
||||||
|
|
@ -10,3 +10,5 @@
|
||||||
0.10: Fix auto-snooze option (this stopped new alarms being added) (fix #506)
|
0.10: Fix auto-snooze option (this stopped new alarms being added) (fix #506)
|
||||||
0.11: Respect Quiet Mode
|
0.11: Respect Quiet Mode
|
||||||
0.12: Fix widget for bangle 2, now uses theme
|
0.12: Fix widget for bangle 2, now uses theme
|
||||||
|
Widgets now shown on Alarm screen
|
||||||
|
0.13: Alarm widget state now updates when setting/resetting an alarm
|
||||||
|
|
|
||||||
|
|
@ -18,8 +18,10 @@ function showAlarm(alarm) {
|
||||||
var buzzCount = 10;
|
var buzzCount = 10;
|
||||||
if (alarm.msg)
|
if (alarm.msg)
|
||||||
msg += "\n"+alarm.msg;
|
msg += "\n"+alarm.msg;
|
||||||
|
Bangle.loadWidgets();
|
||||||
|
Bangle.drawWidgets();
|
||||||
E.showPrompt(msg,{
|
E.showPrompt(msg,{
|
||||||
title:"ALARM!",
|
title:alarm.timer ? "TIMER!" : "ALARM!",
|
||||||
buttons : {"Sleep":true,"Ok":false} // default is sleep so it'll come back in 10 mins
|
buttons : {"Sleep":true,"Ok":false} // default is sleep so it'll come back in 10 mins
|
||||||
}).then(function(sleep) {
|
}).then(function(sleep) {
|
||||||
buzzCount = 0;
|
buzzCount = 0;
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ var alarms = require("Storage").readJSON("alarm.json",1)||[];
|
||||||
last : 0, // last day of the month we alarmed on - so we don't alarm twice in one day!
|
last : 0, // last day of the month we alarmed on - so we don't alarm twice in one day!
|
||||||
rp : true, // repeat
|
rp : true, // repeat
|
||||||
as : false, // auto snooze
|
as : false, // auto snooze
|
||||||
|
timer : 5, // OPTIONAL - if set, this is a timer and it's the time in minutes
|
||||||
}
|
}
|
||||||
];*/
|
];*/
|
||||||
|
|
||||||
|
|
@ -18,6 +19,12 @@ function formatTime(t) {
|
||||||
return hrs+":"+("0"+mins).substr(-2);
|
return hrs+":"+("0"+mins).substr(-2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function formatMins(t) {
|
||||||
|
mins = (0|t)%60;
|
||||||
|
hrs = 0|(t/60);
|
||||||
|
return hrs+":"+("0"+mins).substr(-2);
|
||||||
|
}
|
||||||
|
|
||||||
function getCurrentHr() {
|
function getCurrentHr() {
|
||||||
var time = new Date();
|
var time = new Date();
|
||||||
return time.getHours()+(time.getMinutes()/60)+(time.getSeconds()/3600);
|
return time.getHours()+(time.getMinutes()/60)+(time.getSeconds()/3600);
|
||||||
|
|
@ -25,17 +32,24 @@ function getCurrentHr() {
|
||||||
|
|
||||||
function showMainMenu() {
|
function showMainMenu() {
|
||||||
const menu = {
|
const menu = {
|
||||||
'': { 'title': 'Alarms' },
|
'': { 'title': 'Alarm/Timer' },
|
||||||
'New Alarm': ()=>editAlarm(-1)
|
'New Alarm': ()=>editAlarm(-1),
|
||||||
|
'New Timer': ()=>editTimer(-1)
|
||||||
};
|
};
|
||||||
alarms.forEach((alarm,idx)=>{
|
alarms.forEach((alarm,idx)=>{
|
||||||
txt = (alarm.on?"on ":"off ")+formatTime(alarm.hr);
|
if (alarm.timer) {
|
||||||
if (alarm.rp) txt += " (repeat)";
|
txt = "TIMER "+(alarm.on?"on ":"off ")+formatMins(alarm.timer);
|
||||||
|
} else {
|
||||||
|
txt = "ALARM "+(alarm.on?"on ":"off ")+formatTime(alarm.hr);
|
||||||
|
if (alarm.rp) txt += " (repeat)";
|
||||||
|
}
|
||||||
menu[txt] = function() {
|
menu[txt] = function() {
|
||||||
editAlarm(idx);
|
if (alarm.timer) editTimer(idx);
|
||||||
|
else editAlarm(idx);
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
menu['< Back'] = ()=>{load();};
|
menu['< Back'] = ()=>{load();};
|
||||||
|
if (WIDGETS["alarm"]) WIDGETS["alarm"].reload();
|
||||||
return E.showMenu(menu);
|
return E.showMenu(menu);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -55,7 +69,7 @@ function editAlarm(alarmIndex) {
|
||||||
as = a.as;
|
as = a.as;
|
||||||
}
|
}
|
||||||
const menu = {
|
const menu = {
|
||||||
'': { 'title': 'Alarms' },
|
'': { 'title': 'Alarm' },
|
||||||
'Hours': {
|
'Hours': {
|
||||||
value: hrs,
|
value: hrs,
|
||||||
onchange: function(v){if (v<0)v=23;if (v>23)v=0;hrs=v;this.value=v;} // no arrow fn -> preserve 'this'
|
onchange: function(v){if (v<0)v=23;if (v>23)v=0;hrs=v;this.value=v;} // no arrow fn -> preserve 'this'
|
||||||
|
|
@ -109,4 +123,59 @@ function editAlarm(alarmIndex) {
|
||||||
return E.showMenu(menu);
|
return E.showMenu(menu);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function editTimer(alarmIndex) {
|
||||||
|
var newAlarm = alarmIndex<0;
|
||||||
|
var hrs = 0;
|
||||||
|
var mins = 5;
|
||||||
|
var en = true;
|
||||||
|
if (!newAlarm) {
|
||||||
|
var a = alarms[alarmIndex];
|
||||||
|
mins = (0|a.timer)%60;
|
||||||
|
hrs = 0|(a.timer/60);
|
||||||
|
en = a.on;
|
||||||
|
}
|
||||||
|
const menu = {
|
||||||
|
'': { 'title': 'Timer' },
|
||||||
|
'Hours': {
|
||||||
|
value: hrs,
|
||||||
|
onchange: function(v){if (v<0)v=23;if (v>23)v=0;hrs=v;this.value=v;} // no arrow fn -> preserve 'this'
|
||||||
|
},
|
||||||
|
'Minutes': {
|
||||||
|
value: mins,
|
||||||
|
onchange: function(v){if (v<0)v=59;if (v>59)v=0;mins=v;this.value=v;} // no arrow fn -> preserve 'this'
|
||||||
|
},
|
||||||
|
'Enabled': {
|
||||||
|
value: en,
|
||||||
|
format: v=>v?"On":"Off",
|
||||||
|
onchange: v=>en=v
|
||||||
|
}
|
||||||
|
};
|
||||||
|
function getTimer() {
|
||||||
|
var d = new Date(Date.now() + ((hrs*60)+mins)*60000);
|
||||||
|
var hr = d.getHours() + (d.getMinutes()/60) + (d.getSeconds()/3600);
|
||||||
|
// Save alarm
|
||||||
|
return {
|
||||||
|
on : en,
|
||||||
|
timer : (hrs*60)+mins,
|
||||||
|
hr : hr,
|
||||||
|
rp : false, as: false
|
||||||
|
};
|
||||||
|
}
|
||||||
|
menu["> Save"] = function() {
|
||||||
|
if (newAlarm) alarms.push(getTimer());
|
||||||
|
else alarms[alarmIndex] = getTimer();
|
||||||
|
require("Storage").write("alarm.json",JSON.stringify(alarms));
|
||||||
|
showMainMenu();
|
||||||
|
};
|
||||||
|
if (!newAlarm) {
|
||||||
|
menu["> Delete"] = function() {
|
||||||
|
alarms.splice(alarmIndex,1);
|
||||||
|
require("Storage").write("alarm.json",JSON.stringify(alarms));
|
||||||
|
showMainMenu();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
menu['< Back'] = showMainMenu;
|
||||||
|
return E.showMenu(menu);
|
||||||
|
}
|
||||||
|
|
||||||
showMainMenu();
|
showMainMenu();
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,7 @@
|
||||||
(() => {
|
WIDGETS["alarm"]={area:"tl",width:0,draw:function() {
|
||||||
var alarms = require('Storage').readJSON('alarm.json',1)||[];
|
if (this.width) g.reset().drawImage(atob("GBgBAAAAAAAAABgADhhwDDwwGP8YGf+YMf+MM//MM//MA//AA//AA//AA//AA//AA//AB//gD//wD//wAAAAADwAABgAAAAAAAAA"),this.x,this.y);
|
||||||
alarms = alarms.filter(alarm=>alarm.on);
|
},reload:function() {
|
||||||
if (!alarms.length) return; // no alarms, no widget!
|
WIDGETS["alarm"].width = (require('Storage').readJSON('alarm.json',1)||[]).some(alarm=>alarm.on) ? 24 : 0;
|
||||||
delete alarms;
|
}
|
||||||
// add the widget
|
};
|
||||||
WIDGETS["alarm"]={area:"tl",width:24,draw:function() {
|
WIDGETS["alarm"].reload();
|
||||||
g.setColor(g.theme.fg);
|
|
||||||
g.drawImage(atob("GBgBAAAAAAAAABgADhhwDDwwGP8YGf+YMf+MM//MM//MA//AA//AA//AA//AA//AA//AB//gD//wD//wAAAAADwAABgAAAAAAAAA"),this.x,this.y);
|
|
||||||
}};
|
|
||||||
})()
|
|
||||||
|
|
|
||||||
|
|
@ -1 +1,2 @@
|
||||||
0.01: New App!
|
0.01: New App!
|
||||||
|
0.02: Load widgets after setUI so widclk knows when to hide
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ function queueDraw() {
|
||||||
function draw() {
|
function draw() {
|
||||||
var x = g.getWidth()/2;
|
var x = g.getWidth()/2;
|
||||||
var y = g.getHeight()/2;
|
var y = g.getHeight()/2;
|
||||||
g.reset();
|
g.reset();
|
||||||
var date = new Date();
|
var date = new Date();
|
||||||
var timeStr = require("locale").time(date,1);
|
var timeStr = require("locale").time(date,1);
|
||||||
var dateStr = require("locale").date(date).toUpperCase();
|
var dateStr = require("locale").date(date).toUpperCase();
|
||||||
|
|
@ -33,7 +33,7 @@ function draw() {
|
||||||
g.clearRect(0,y-8,g.getWidth(),y+8); // clear the background
|
g.clearRect(0,y-8,g.getWidth(),y+8); // clear the background
|
||||||
g.drawString(dateStr,x,y);
|
g.drawString(dateStr,x,y);
|
||||||
// queue draw in one minute
|
// queue draw in one minute
|
||||||
queueDraw();
|
queueDraw();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clear the screen once, at startup
|
// Clear the screen once, at startup
|
||||||
|
|
@ -49,9 +49,8 @@ Bangle.on('lcdPower',on=>{
|
||||||
drawTimeout = undefined;
|
drawTimeout = undefined;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
// Show launcher when middle button pressed
|
||||||
|
Bangle.setUI("clock");
|
||||||
// Load widgets
|
// Load widgets
|
||||||
Bangle.loadWidgets();
|
Bangle.loadWidgets();
|
||||||
Bangle.drawWidgets();
|
Bangle.drawWidgets();
|
||||||
// Show launcher when middle button pressed
|
|
||||||
Bangle.setUI("clock");
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1 +1,2 @@
|
||||||
0.01: New App!
|
0.01: New App!
|
||||||
|
0.02: Minor adjustment to fix out of memory errors
|
||||||
|
|
|
||||||
|
|
@ -60,8 +60,8 @@ var scenes = [
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
function() {
|
function() {
|
||||||
|
Bangle.setLCDMode("120x120");
|
||||||
var img = require("heatshrink").decompress(atob("oNBxH+5wA/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AHGpAAoQKv4ADCBQAeqsrAAejBw9/B4oABqt/IGepHw5CEQspALH5hBC5pAvv4/MAALFkIBWpPI6IHqpAu0Z3GfYOpRYdPQEhALYIp2FBYNVI4JAvvL4LH0yBYAFJAQQQ5Ay1JAFftBAQBYxCDv+qIGiCHIQiGnIBfOv5BJIQRAyIJkrvKEkIBrFBB4qEGIGRCNYsZAQIQV/IZDEiICRCDQVJAUIQVPC4lVIF6yJQYpAZ5t/FYvNIBepqtVIJGjIDoqBDY2pdYo3DfAhBIQLmpvIcDvIrC5oJEIAhTCGQmj5qgEC4t5e7YrBqt5BI6UFBg15v4XHbQwAQb4oAKv7NKABdVRoYATUAwnICqjZFIMdVE4+jXI4XGYCxBFFZN/M5OpCxUrvJ/ZFYmjvNVAAY+KCwpDBC6YAV5vNC9oA/AH4A/AHYA=="));
|
var img = require("heatshrink").decompress(atob("oNBxH+5wA/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AHGpAAoQKv4ADCBQAeqsrAAejBw9/B4oABqt/IGepHw5CEQspALH5hBC5pAvv4/MAALFkIBWpPI6IHqpAu0Z3GfYOpRYdPQEhALYIp2FBYNVI4JAvvL4LH0yBYAFJAQQQ5Ay1JAFftBAQBYxCDv+qIGiCHIQiGnIBfOv5BJIQRAyIJkrvKEkIBrFBB4qEGIGRCNYsZAQIQV/IZDEiICRCDQVJAUIQVPC4lVIF6yJQYpAZ5t/FYvNIBepqtVIJGjIDoqBDY2pdYo3DfAhBIQLmpvIcDvIrC5oJEIAhTCGQmj5qgEC4t5e7YrBqt5BI6UFBg15v4XHbQwAQb4oAKv7NKABdVRoYATUAwnICqjZFIMdVE4+jXI4XGYCxBFFZN/M5OpCxUrvJ/ZFYmjvNVAAY+KCwpDBC6YAV5vNC9oA/AH4A/AHYA=="));
|
||||||
|
|
||||||
g.clear();
|
g.clear();
|
||||||
y = 0;
|
y = 0;
|
||||||
var step = 4;
|
var step = 4;
|
||||||
|
|
@ -70,8 +70,7 @@ var scenes = [
|
||||||
g.clear();
|
g.clear();
|
||||||
g.drawImage(img,60,60,{rotate:Math.sin(y*0.03)*0.5});
|
g.drawImage(img,60,60,{rotate:Math.sin(y*0.03)*0.5});
|
||||||
g.flip();
|
g.flip();
|
||||||
}, 20);
|
}, 20);
|
||||||
Bangle.setLCDMode("120x120");
|
|
||||||
return function() {
|
return function() {
|
||||||
if (i) clearInterval(i);
|
if (i) clearInterval(i);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
0.01: New App!
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
require("heatshrink").decompress(atob("mEwhE+sVin0/tVjsdim84sdro1GAQNrAAlHAYVqABk/FINosc/AoNpF4cTGoMTnIhBo1qEgIvFABJACoAvEFwJaDGoNjnFpn5eCik/DYQwBAAQwOFIMUDYKBBLwQwBnwoBBAM3GIIEBhs5E4RLBPYqMKFwU4AAM+nwCBF4SJCAwMxXII2BnBeDJogAGNQIAFBIJMBRIYvCLQK+Bow7BhsNCINjm45BXwZgHF5ITBigoBF4NpQoIwBLwLJBn8Oh0NBoU4F4J6CF4RiKR47iCtIrBiaGBEgdknMOnBABiYKBtNkKoaUIdo5hCQoKvBYgKGBGAIJBMANjhqfBHgLQBNgKcBEpAxBBA9HHoiwBF4S3BcoM4Nwdim83sVEGAINBMQIfBEASYGLII4ECISFBnEyFgKHBGwRsDHYKfBaQOGrifCXw4qBNgIEBXoQHBCQZXBnArCAQNpnBWBFwUTBINiwGkwFcsbzDEwJcFG4pcCAAMUik/EIKJBn6JBMYNpnzABsY0BwGeAAN6wLnCEQQACF4ztCF4UUJ4QNDGAKTCtMTnASBHwOezAwCveIP4ReEeQzNDFwgvDDQU/oDlDJYVkF4e8z2Hx2Px2IAAKKEGo1qnAuBtLYBBwRJCAoIuCbgVqxAsCAQWB1mBwN6AANWmSwBJwRcCDIIuDnxAGAYU5HQmPF4W84QBBvWlGoOY4TIBmMxnJGCYYc5ik+coNjn8UhsUiqRDGQQUBQQJUBz3CzAxBYYYADvWGsTZBDoNHcQUTXgU+n1pB4LmBFQSUCAoNkw4uCF4QBBF4QFBAAIFBF4IjBoBMCn84nwtCMAIABm8TnLREXYd7KQSLBzoBDAQJlBBQN5w1osU/VAQuBnCLBGQNpGYM4R4LRCAATTBRgJcCy4kBz3I5HO5HHy4JBYwRfBcYIfBoE4m5YCho0BA4M4FwzzCxCMBEIO73guB5wAC5BgBSoWAF4KQBsdkKoKNChoACik4nIuHF4i0BdQOdF4XNAQK8Cz2lqzjCnCIBFwTnBS4IrBTQQuBdoLuCBAWOdoOYWgRfC5ovDy4vDriDCAAS8CFQYADdQgvCowvDSAK0CF4SPC4QwCvVcmUymMxFwSUBFwQoDFQToBAoIsBBoSQBMASRBy6QDXwIJCSIWAFwjzDWowAKGYOHwIhBYIOezooC3YuBF4d6GAK/BYAVkF6CUExBiBYQQCBFQIvCzAvCAYM3LoUTLwIeDF5pBDSQRgCLQYDBZQZrBz1cw9iiZeCWoQvWeYQuBfIIxCLwd6w1inEULyQvFtYvFEwOB0uBz4zCX4QuBnDsCDortNCQNHL4mYFwN7ZAOIfgN6AANcsc+m6NBDoRgQFwNGo5FBx2HKoZeBHYNqsg7BqtVsS8BRoReCL6AgBSYQ1CwJWBveHZYlkmMxLwM4h05sgADPwRRCF5ouDMIKKCxwPDsk4mM4XgMTXwLvBikOYYQvOBoQOBoE/JA4DBn8UFwNim8NF4QABhsNnIvQUgVAnMOVoQ4CAANqscUidiRoMNm4zBAAQHBF6CLDO4JIBGAVHXgYiBn1jn0NGYVoAAIvBIwYvOBgM/hyxBAAQXBHYU5RANjscTLwNjLgIuBny+FF5xeBhtcPYU+DYJeDRog0CCIYSBoAvRGAMUmOHJgcbF4QuBFIUNmIBBeYItCIIRNBd54ABisUVgNED4QJBn69Dm4uBh0OnIsBoArCFBoPDHgNqoAvBL4YvCb4JeBnxiCslkDogvRNQVGGALrBVobwBfAMNXoMTigsHDINHAAIvJGIdGn9ro4FBscNMANpF4LoBm4DChq1BFAJDBDobmMMIgvDA4UULwKHBMoLlBG4MynBeBCYQfFF56MBoAbDMAKzBnETm7oBGoM4hxeCQoJfCcJC/KAgIvFMAMNAASNBsQ1BLwVqFwIeELppCBF4dq"))
|
||||||
|
|
@ -0,0 +1,76 @@
|
||||||
|
function getImg() {
|
||||||
|
return require("heatshrink").decompress(atob("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"));
|
||||||
|
}
|
||||||
|
var IMAGEWIDTH = 176;
|
||||||
|
var IMAGEHEIGHT = 109;
|
||||||
|
|
||||||
|
|
||||||
|
Graphics.prototype.setFontDancingScript = function() {
|
||||||
|
// Actual height 44 (44 - 1)
|
||||||
|
var widths = atob("DBIhFB4bGRoeFhweDQ==");
|
||||||
|
var font = atob("AAAAAAAAAAAAAAMAAAAAAAHgAAAAAAD4AAAAAAA+AAAAAAAHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD4AAAAAAD8AAAAAAD+AAAAAAD/AAAAAAD/gAAAAAH/gAAAAAH/wAAAAAH/gAAAAAP/gAAAAAP/gAAAAAf/AAAAAAf/AAAAAA/+AAAAAA/+AAAAAB/+AAAAAB/8AAAAAB/8AAAAAA/4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH/8AAAAAf//4AAAAf///AAAAf///4AAAf////AAAf/8Af4AAP/gAA/AAP/AAADwAH+AAAAcAD+AAAAHAA+AAAABwAfAAAAAcAPAAAAAHADgAAAABwB4AAAAA8AcAAAAAOAHAAAAAHgBgAAAAHwAYAAAAD4AGAAAAD+ABwAAAD/AAcAAAD/gAHgAAH/wAA+AAP/wAAH+H//4AAB////4AAAP///4AAAA///4AAAAD//gAAAAAD8AAAAAAAAAAAGAAAAAAABwAAAAAAAcAAAAAAAHAAAAAAABwAAAAAAAcAAGAAAAPAADwAAA/wAA4AAB/8AAeAAP//AAPAD//7wAHwf//w8AB////gPAA///+ABwAf//4AAcAP/+AAADAH/wAAAAQB8AAAAAAAAAAAAAAAAAAAAAAAAAAAAADgAAAAAAB8AAAAAAAfAAAAAAAGwAAAAAABsAAAAAAAfAAAAAAAHwAAP4AAB4AAP/AAAeAAH/wAAHAAD/+AAD4AB+AgAB+AA8AAAA/gAOAAAAf8AHAAAAPvABwAAAPzwAYAAAH4eAGAAAH8HgBgAAD+B8AcAAD/AfAHAAH/AHwB4AH/gB8AP4//gAfAD///wAHwAf//wAB8AB//gAAeAAP/gAAHAAAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAfwAAAAAAP+AAAAAAH/wAAAAAB/+AAAAAAcfgAAAAAEB8AB/AAAAPAA/4AAABwAf+AAAAcAP/gAAAHADwQAAABwAwABAAAcAcAAYAAHAHAAOAADwBgAHwAB4AYAD+AB+AHAB/4B/ABwB+///wAeB/P//4AH//h//8AA//4P/+AAH/4B/+AAA/8AH/AAAH8AAEAAAAAAAAAAAAAAAAAAAAAAABgAAAAAAA4AAAAAAAeAAAAAAAPAAAAAAAHwAAAAAAD8AAAAAAB/AAAAAAA/wAAAAAAe8AAAAAAPPAAAAAAHjwAAAAADw8AAAAAB4PAAwAAA8DwP+AAAeA///wAAPAP//8AAHh////AAH3////wAD////AAAB///wAAAA//88AAAAf/gPAAAAf8ADgAAAHgAA4AAAAAAAMAAAAAAAAAfwAAAAAAP+AAAAAAH/wAAAAAB/+AAAAAA8PgAAAAwEA8AAAH8AAHAAAP/AABwAA//gAAcAD/4YAAHAH/gGAABwB/ABgAAcAfgAYAAPAD4AHAADwA+ABwAB4APgAeAB+AD4AH4B/AA+AA///wAPgAP//4AD4AB//8AB+AAP/+AAfgAB//AAHwAAH/AAB8AAAAAAAeAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA4AAAAAAf/4AAAAA///gAAAB///+AAAB////wAAB////+AAA//+B/gAA//8AD8AAf+OAAPAAP8HAABwAH8BgAAcAD8A4AAHAB+AOAABwAeADgAAcAPAA4AAHADgAOAADwBwADgAA8AcAA8AA+AGAAPgAfgBgAD+A/wAYAAf//4AGAAH//8ABwAA//+AAfgAH//AAD4AAf/AAAcAAA+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAAAAAHAA/AAAABwB/wAwAA8B/8AeAAPB//AHwADx//gB8AA9//wAfAAP/4IAHwAD/wAAB8AB/wAAAPAB/gAAADwB/wAAAA8A/8AAAAPA/PAAAADw/DwAAAA8/A8AAAAP/AOAAAAD/ADgAAAB/gAwAAAAAAAAAAAAAAAAABAAAAAAAH/AAAAAAD/4AAAAAB//AAAAAA//4AAOAAfA+AAf8APgHwAP/wHgA8AH/+DwAHAD//48ABwA///eAAcAeAf/AAHAHAB/gABwBwAP4AA8AYAB/AAPAGAAf4AHgBgAP/AD4AcAHv8B8AHgD5///AA8H8H//gAP/+A//wAB/+AH/4AAP/AAf8AAA/AAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwAAAAAAP/gAAeAAP/+AAPgAH//wAD8AD//+AAPAB///gAAwAfwD8AAMAPwAfAADADwADwAAwB4AAeAAcAcAAHgAHAHAAA4ADgBwAAOAB4AcAADAB8AHAAAwA/ABwAAcA/gAeAAGB/wAHwADh/4AA+AB//8AAP+D//8AAB////+AAAP///+AAAB///+AAAAP//8AAAAAf/4AAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAA4AAAAAAAeAAAAADAHgAAAAB4BwAAAAAeAIAAAAAHgAAAAAABwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
|
||||||
|
var scale = 1; // size multiplier for this font
|
||||||
|
g.setFontCustom(font, 46, widths, 50+(scale<<8)+(1<<16));
|
||||||
|
}
|
||||||
|
|
||||||
|
// timeout used to update every minute
|
||||||
|
var drawTimeout;
|
||||||
|
|
||||||
|
// schedule a draw for the next minute
|
||||||
|
function queueDraw() {
|
||||||
|
if (drawTimeout) clearTimeout(drawTimeout);
|
||||||
|
drawTimeout = setTimeout(function() {
|
||||||
|
drawTimeout = undefined;
|
||||||
|
draw();
|
||||||
|
}, 60000 - (Date.now() % 60000));
|
||||||
|
}
|
||||||
|
|
||||||
|
function draw() {
|
||||||
|
var x = g.getWidth()/2;
|
||||||
|
var y = 50;
|
||||||
|
g.reset().clearRect(0,24,g.getWidth(),g.getHeight()-IMAGEHEIGHT);
|
||||||
|
if (g.getWidth() == IMAGEWIDTH)
|
||||||
|
g.drawImage(getImg(),0,g.getHeight()-IMAGEHEIGHT);
|
||||||
|
else {
|
||||||
|
let scale = g.getWidth()/IMAGEWIDTH;
|
||||||
|
y *= scale;
|
||||||
|
g.drawImage(getImg(),0,g.getHeight()-IMAGEHEIGHT*scale,{scale:scale});
|
||||||
|
}
|
||||||
|
|
||||||
|
var date = new Date();
|
||||||
|
var dateStr = require("locale").date(date);
|
||||||
|
// draw time
|
||||||
|
g.setFont("DancingScript").setFontAlign(0,0).setColor("#f00");
|
||||||
|
g.drawString(date.getHours(), x,y);
|
||||||
|
y += 43;
|
||||||
|
g.drawString(date.getMinutes().toString().padStart(2,0), x,y);
|
||||||
|
// draw date
|
||||||
|
y += 22;
|
||||||
|
g.setFontAlign(0,0).setFont("6x8");
|
||||||
|
var p = g.getWidth()-60;
|
||||||
|
g.clearRect(p,y-4,g.getWidth()-p,y+3); // clear the background
|
||||||
|
g.drawString(dateStr,x,y);
|
||||||
|
// queue draw in one minute
|
||||||
|
queueDraw();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stop updates when LCD is off, restart when on
|
||||||
|
Bangle.on('lcdPower',on=>{
|
||||||
|
if (on) {
|
||||||
|
draw(); // draw immediately, queue redraw
|
||||||
|
} else { // stop draw timer
|
||||||
|
if (drawTimeout) clearTimeout(drawTimeout);
|
||||||
|
drawTimeout = undefined;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// set background colour
|
||||||
|
g.setTheme({bg:"#0ff"});
|
||||||
|
// Clear the screen once, at startup
|
||||||
|
g.clear();
|
||||||
|
// draw immediately at first, queue update
|
||||||
|
draw();
|
||||||
|
// Show launcher when middle button pressed
|
||||||
|
Bangle.setUI("clock");
|
||||||
|
// Load widgets
|
||||||
|
Bangle.loadWidgets();
|
||||||
|
Bangle.drawWidgets();
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 4.9 KiB |
|
|
@ -1 +1,2 @@
|
||||||
0.01: New App!
|
0.01: New App!
|
||||||
|
0.02: Refactor code to store grocery list in separate file
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
var filename = 'grocery_list.json';
|
||||||
|
var settings = require("Storage").readJSON(filename,1)|| { products: [] };
|
||||||
|
|
||||||
|
function updateSettings() {
|
||||||
|
require("Storage").writeJSON(filename, settings);
|
||||||
|
Bangle.buzz();
|
||||||
|
}
|
||||||
|
|
||||||
|
function twoChat(n){
|
||||||
|
if(n<10) return '0'+n;
|
||||||
|
return ''+n;
|
||||||
|
}
|
||||||
|
|
||||||
|
const mainMenu = settings.products.reduce(function(m, p, i){
|
||||||
|
const name = twoChat(p.quantity)+' '+p.name;
|
||||||
|
m[name] = {
|
||||||
|
value: p.ok,
|
||||||
|
format: v => v?'[x]':'[ ]',
|
||||||
|
onchange: v => {
|
||||||
|
settings.products[i].ok = v;
|
||||||
|
updateSettings();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return m;
|
||||||
|
}, {
|
||||||
|
'': { 'title': 'Grocery list' }
|
||||||
|
});
|
||||||
|
mainMenu['< Back'] = ()=>{load();};
|
||||||
|
E.showMenu(mainMenu);
|
||||||
|
|
@ -105,56 +105,9 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
document.getElementById("upload").addEventListener("click", function() {
|
document.getElementById("upload").addEventListener("click", function() {
|
||||||
|
|
||||||
|
|
||||||
var app = `
|
|
||||||
var newTime = ${Date.now()}
|
|
||||||
var products = ${JSON.stringify(products)}
|
|
||||||
var newTime = newTime;
|
|
||||||
var filename = 'grocery';
|
|
||||||
var settings = require("Storage").readJSON(filename,1)|| null;
|
|
||||||
function getSettings(){
|
|
||||||
return {
|
|
||||||
products : products,
|
|
||||||
date: newTime
|
|
||||||
};
|
|
||||||
}
|
|
||||||
if(!settings || !settings.date || settings.date < newTime){
|
|
||||||
settings = getSettings();
|
|
||||||
Bangle.buzz(500);
|
|
||||||
}
|
|
||||||
function updateSettings() {
|
|
||||||
require("Storage").writeJSON(filename, settings);
|
|
||||||
Bangle.buzz();
|
|
||||||
}
|
|
||||||
function twoChat(n){
|
|
||||||
if(n<10) return '0'+n;
|
|
||||||
return ''+n;
|
|
||||||
}
|
|
||||||
const mainMenu = settings.products.reduce(function(m, p, i){
|
|
||||||
const name = twoChat(p.quantity)+' '+p.name;
|
|
||||||
m[name] = {
|
|
||||||
value: p.ok,
|
|
||||||
format: v => v?'[x]':'[ ]',
|
|
||||||
onchange: v => {
|
|
||||||
settings.products[i].ok = v;
|
|
||||||
updateSettings();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
return m;
|
|
||||||
}, {
|
|
||||||
'': { 'title': 'Grocery list' }
|
|
||||||
});
|
|
||||||
mainMenu['< Back'] = ()=>{load();};
|
|
||||||
E.showMenu(mainMenu);
|
|
||||||
`;
|
|
||||||
|
|
||||||
var icon = `require("heatshrink").decompress(atob("mEwxH+AH4A/AH4AQ0QACF1nGAAIxpFoYwqFwwwnRggwGB4eFAggACLzwHCMAeF1WGAgOGw2x2IGCLzYGEF4YpBwotCFwJfWFwo1GSAYtBAIIABRq4vFMhAwBzoAFdzIuKAAOc4IAGGC4qEMZOiF44wXFxovleBYvIGCwmB0WjE4V/AgfG1IvCzujFQOjwoECF6WFwovBDYOFEwN/AgIwCAgOFBwYrBBAQEBzodCF6AAHww1CBpIODAAYvRDAWG2IEBAYYJFBxICCF6Ox1WxAAQfBAYQlCAAIOJAQIvUADQvn1WGR4RfbP4gAFBwgFCF7a5EdwQADF46/cL9wAQF94AGF85bB1TvmF47vdJ4bvFF8qPRFgLv/L7jPCaQq/fYYrvgJgoAGd/7v/F/4v/F5oAdF54weFyAA/AH4A3A="))`;
|
|
||||||
sendCustomizedApp({
|
sendCustomizedApp({
|
||||||
storage:[
|
storage:[
|
||||||
{name:"grocery.app.js", url:"app.js", content:app},
|
{ name:"grocery_list.json", content: JSON.stringify({products: products}) }
|
||||||
{name:"grocery.img", content:icon, evaluate:true},
|
|
||||||
{name:"grocery"}
|
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -31,3 +31,5 @@
|
||||||
0.26: Use Bangle.softOff if available as this keeps the time
|
0.26: Use Bangle.softOff if available as this keeps the time
|
||||||
0.27: Add Theme menu
|
0.27: Add Theme menu
|
||||||
0.28: Update Quiet Mode widget (if present)
|
0.28: Update Quiet Mode widget (if present)
|
||||||
|
0.29: Add Customize to Theme menu
|
||||||
|
0.30: Move '< Back' to the top of menus
|
||||||
|
|
@ -15,6 +15,7 @@ This is Bangle.js's settings menu
|
||||||
* **NOTE:** on some platforms enabling HID can cause you problems when trying to connect to Bangle.js to upload apps.
|
* **NOTE:** on some platforms enabling HID can cause you problems when trying to connect to Bangle.js to upload apps.
|
||||||
* **Set Time** Configure the current time - Note that this can be done much more easily by choosing 'Set Time' from the App Loader
|
* **Set Time** Configure the current time - Note that this can be done much more easily by choosing 'Set Time' from the App Loader
|
||||||
* **LCD** Configure settings about the screen. How long it stays on, how bright it is, and when it turns on - see below.
|
* **LCD** Configure settings about the screen. How long it stays on, how bright it is, and when it turns on - see below.
|
||||||
|
* **Theme** Adjust the colour scheme
|
||||||
* **Reset Settings** Reset the settings to defaults
|
* **Reset Settings** Reset the settings to defaults
|
||||||
* **Turn Off** Turn Bangle.js off
|
* **Turn Off** Turn Bangle.js off
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -75,6 +75,7 @@ function showMainMenu() {
|
||||||
var beepN = ["Off", "Piezo", "Vibrate"];
|
var beepN = ["Off", "Piezo", "Vibrate"];
|
||||||
const mainmenu = {
|
const mainmenu = {
|
||||||
'': { 'title': 'Settings' },
|
'': { 'title': 'Settings' },
|
||||||
|
'< Back': ()=>load(),
|
||||||
'Make Connectable': ()=>makeConnectable(),
|
'Make Connectable': ()=>makeConnectable(),
|
||||||
'App/Widget Settings': ()=>showAppSettingsMenu(),
|
'App/Widget Settings': ()=>showAppSettingsMenu(),
|
||||||
'BLE': ()=>showBLEMenu(),
|
'BLE': ()=>showBLEMenu(),
|
||||||
|
|
@ -117,7 +118,6 @@ function showMainMenu() {
|
||||||
'Theme': ()=>showThemeMenu(),
|
'Theme': ()=>showThemeMenu(),
|
||||||
'Reset Settings': ()=>showResetMenu(),
|
'Reset Settings': ()=>showResetMenu(),
|
||||||
'Turn Off': ()=>{ if (Bangle.softOff) Bangle.softOff(); else Bangle.off() },
|
'Turn Off': ()=>{ if (Bangle.softOff) Bangle.softOff(); else Bangle.off() },
|
||||||
'< Back': ()=>load()
|
|
||||||
};
|
};
|
||||||
return E.showMenu(mainmenu);
|
return E.showMenu(mainmenu);
|
||||||
}
|
}
|
||||||
|
|
@ -126,6 +126,7 @@ function showBLEMenu() {
|
||||||
var hidV = [false, "kbmedia", "kb", "joy"];
|
var hidV = [false, "kbmedia", "kb", "joy"];
|
||||||
var hidN = ["Off", "Kbrd & Media", "Kbrd","Joystick"];
|
var hidN = ["Off", "Kbrd & Media", "Kbrd","Joystick"];
|
||||||
E.showMenu({
|
E.showMenu({
|
||||||
|
'< Back': ()=>showMainMenu(),
|
||||||
'BLE': {
|
'BLE': {
|
||||||
value: settings.ble,
|
value: settings.ble,
|
||||||
format: boolFormat,
|
format: boolFormat,
|
||||||
|
|
@ -158,8 +159,7 @@ function showBLEMenu() {
|
||||||
'Whitelist': {
|
'Whitelist': {
|
||||||
value: settings.whitelist?(settings.whitelist.length+" devs"):"off",
|
value: settings.whitelist?(settings.whitelist.length+" devs"):"off",
|
||||||
onchange: () => setTimeout(showWhitelistMenu) // graphical_menu redraws after the call
|
onchange: () => setTimeout(showWhitelistMenu) // graphical_menu redraws after the call
|
||||||
},
|
}
|
||||||
'< Back': ()=>showMainMenu()
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -178,6 +178,8 @@ function showThemeMenu() {
|
||||||
m.draw();
|
m.draw();
|
||||||
}
|
}
|
||||||
var m = E.showMenu({
|
var m = E.showMenu({
|
||||||
|
'':{title:'Theme'},
|
||||||
|
'< Back': ()=>showMainMenu(),
|
||||||
'Dark BW': ()=>{
|
'Dark BW': ()=>{
|
||||||
upd({
|
upd({
|
||||||
fg:cl("#fff"), bg:cl("#000"),
|
fg:cl("#fff"), bg:cl("#000"),
|
||||||
|
|
@ -194,12 +196,69 @@ function showThemeMenu() {
|
||||||
dark:false
|
dark:false
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
'< Back': ()=>showMainMenu()
|
'Customize': ()=>showCustomThemeMenu(),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function showCustomThemeMenu() {
|
||||||
|
function cv(x) { return g.setColor(x).getColor(); }
|
||||||
|
function setT(t, v) {
|
||||||
|
let th = g.theme;
|
||||||
|
th[t] = v;
|
||||||
|
if (t==="bg") {
|
||||||
|
th['dark'] = (v===cv("#000"));
|
||||||
|
}
|
||||||
|
upd(th);
|
||||||
|
}
|
||||||
|
const rgb = {
|
||||||
|
black: "#000", white: "#fff",
|
||||||
|
red: "#f00", green: "#0f0", blue: "#00f",
|
||||||
|
cyan: "#0ff", magenta: "#f0f", yellow: "#ff0",
|
||||||
|
};
|
||||||
|
let colors = [], names = [];
|
||||||
|
for(const c in rgb) {
|
||||||
|
names.push(c);
|
||||||
|
colors.push(cv(rgb[c]));
|
||||||
|
}
|
||||||
|
function cn(v) {
|
||||||
|
const i = colors.indexOf(v);
|
||||||
|
return i!== -1 ? names[i] : v; // another color: just show value
|
||||||
|
}
|
||||||
|
let menu = {
|
||||||
|
'':{title:'Custom Theme'},
|
||||||
|
"< Back": () => showThemeMenu()
|
||||||
|
};
|
||||||
|
const labels = {
|
||||||
|
fg: 'Foreground', bg: 'Background',
|
||||||
|
fg2: 'Foreground 2', bg2: 'Background 2',
|
||||||
|
fgH: 'Highlight FG', bgH: 'Highlight BG',
|
||||||
|
};
|
||||||
|
["fg", "bg", "fg2", "bg2", "fgH", "bgH"].forEach(t => {
|
||||||
|
menu[labels[t]] = {
|
||||||
|
value: colors.indexOf(g.theme[t]),
|
||||||
|
format: () => cn(g.theme[t]),
|
||||||
|
onchange: function(v) {
|
||||||
|
// wrap around
|
||||||
|
if (v>=colors.length) {v = 0;}
|
||||||
|
if (v<0) {v = colors.length-1;}
|
||||||
|
this.value = v;
|
||||||
|
const c = colors[v];
|
||||||
|
// if we select the same fg and bg: set the other to the old color
|
||||||
|
// e.g. bg=black;fg=white, user selects fg=black -> bg changes to white automatically
|
||||||
|
// so users don't end up with a black-on-black menu
|
||||||
|
if (t === 'fg' && g.theme.bg === c) setT('bg', g.theme.fg);
|
||||||
|
if (t === 'bg' && g.theme.fg === c) setT('fg', g.theme.bg);
|
||||||
|
setT(t, c);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
|
menu["< Back"] = () => showThemeMenu();
|
||||||
|
m = E.showMenu(menu);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function showPasskeyMenu() {
|
function showPasskeyMenu() {
|
||||||
var menu = {
|
var menu = {
|
||||||
|
"< Back" : ()=>showBLEMenu(),
|
||||||
"Disable" : () => {
|
"Disable" : () => {
|
||||||
settings.passkey = undefined;
|
settings.passkey = undefined;
|
||||||
updateSettings();
|
updateSettings();
|
||||||
|
|
@ -220,12 +279,12 @@ function showPasskeyMenu() {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
})(i);
|
})(i);
|
||||||
menu['< Back']=()=>showBLEMenu();
|
|
||||||
E.showMenu(menu);
|
E.showMenu(menu);
|
||||||
}
|
}
|
||||||
|
|
||||||
function showWhitelistMenu() {
|
function showWhitelistMenu() {
|
||||||
var menu = {
|
var menu = {
|
||||||
|
"< Back" : ()=>showBLEMenu(),
|
||||||
"Disable" : () => {
|
"Disable" : () => {
|
||||||
settings.whitelist = undefined;
|
settings.whitelist = undefined;
|
||||||
updateSettings();
|
updateSettings();
|
||||||
|
|
@ -257,7 +316,6 @@ function showWhitelistMenu() {
|
||||||
showWhitelistMenu();
|
showWhitelistMenu();
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
menu['< Back']=()=>showBLEMenu();
|
|
||||||
E.showMenu(menu);
|
E.showMenu(menu);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,15 @@
|
||||||
var DateFormatter = require("slidingtext.dtfmt.js");
|
var DateFormatter = require("slidingtext.dtfmt.js");
|
||||||
|
|
||||||
const germanNumberStr = [ ["ZERO",""], // 0
|
const germanNumberStr = [ ["NULL",""], // 0
|
||||||
["EINS",""], // 1
|
["EINS",""], // 1
|
||||||
["ZWEI",""], //2
|
["ZWEI",""], //2
|
||||||
["DREI",''], //3
|
["DREI",''], //3
|
||||||
["VIER",''], //4
|
["VIER",''], //4
|
||||||
["FÜNF",''], //5
|
["FÜNF",''], //5
|
||||||
["SECHS",''], //6
|
["SECHS",''], //6
|
||||||
["SEIBEN",''], //7
|
["SIEBEN",''], //7
|
||||||
["ACHT",''], //8
|
["ACHT",''], //8
|
||||||
["NUEN",''], // 9,
|
["NEUN",''], // 9,
|
||||||
["ZEHN",''], // 10
|
["ZEHN",''], // 10
|
||||||
["ELF",''], // 11,
|
["ELF",''], // 11,
|
||||||
["ZWÖLF",''], // 12
|
["ZWÖLF",''], // 12
|
||||||
|
|
@ -22,7 +22,7 @@ const germanNumberStr = [ ["ZERO",""], // 0
|
||||||
["NEUN",'ZEHN'], // 19
|
["NEUN",'ZEHN'], // 19
|
||||||
];
|
];
|
||||||
|
|
||||||
const germanTensStr = ["ZERO",//0
|
const germanTensStr = ["NULL",//0
|
||||||
"ZEHN",//10
|
"ZEHN",//10
|
||||||
"ZWANZIG",//20
|
"ZWANZIG",//20
|
||||||
"DREIßIG",//30
|
"DREIßIG",//30
|
||||||
|
|
@ -38,7 +38,7 @@ const germanUnit = ["",//0
|
||||||
"VIERUND", //4
|
"VIERUND", //4
|
||||||
"FÜNFUND", //5
|
"FÜNFUND", //5
|
||||||
"SECHSUND", //6
|
"SECHSUND", //6
|
||||||
"SEIBENUND", //7
|
"SIEBENUND", //7
|
||||||
"ACHTUND", //8
|
"ACHTUND", //8
|
||||||
"NEUNUND" //9
|
"NEUNUND" //9
|
||||||
]
|
]
|
||||||
|
|
@ -91,4 +91,4 @@ class GermanDateFormatter extends DateFormatter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = GermanDateFormatter;
|
module.exports = GermanDateFormatter;
|
||||||
|
|
|
||||||
|
|
@ -1 +1,2 @@
|
||||||
0.01: New App!
|
0.01: New App!
|
||||||
|
0.02: Load widgets after setUI so widclk knows when to hide
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ function queueDraw() {
|
||||||
function draw() {
|
function draw() {
|
||||||
var x = g.getWidth()/2;
|
var x = g.getWidth()/2;
|
||||||
var y = 24+20;
|
var y = 24+20;
|
||||||
|
|
||||||
g.reset().clearRect(0,24,g.getWidth(),g.getHeight()-IMAGEHEIGHT);
|
g.reset().clearRect(0,24,g.getWidth(),g.getHeight()-IMAGEHEIGHT);
|
||||||
if (g.getWidth() == IMAGEWIDTH)
|
if (g.getWidth() == IMAGEWIDTH)
|
||||||
g.drawImage(getImg(),0,g.getHeight()-IMAGEHEIGHT);
|
g.drawImage(getImg(),0,g.getHeight()-IMAGEHEIGHT);
|
||||||
|
|
@ -65,8 +65,8 @@ Bangle.on('lcdPower',on=>{
|
||||||
drawTimeout = undefined;
|
drawTimeout = undefined;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
// Show launcher when middle button pressed
|
||||||
|
Bangle.setUI("clock");
|
||||||
// Load widgets
|
// Load widgets
|
||||||
Bangle.loadWidgets();
|
Bangle.loadWidgets();
|
||||||
Bangle.drawWidgets();
|
Bangle.drawWidgets();
|
||||||
// Show launcher when middle button pressed
|
|
||||||
Bangle.setUI("clock");
|
|
||||||
|
|
@ -5,4 +5,5 @@
|
||||||
0.06: Use setUI for launcher.
|
0.06: Use setUI for launcher.
|
||||||
0.07: Add theme support and unknown icon.
|
0.07: Add theme support and unknown icon.
|
||||||
0.08: Refactor and reduce widget ram usage.
|
0.08: Refactor and reduce widget ram usage.
|
||||||
0.09: Fix crash when weather.json is absent.
|
0.09: Fix crash when weather.json is absent.
|
||||||
|
0.10: Use new Layout library
|
||||||
|
|
@ -1,96 +1,106 @@
|
||||||
(() => {
|
const Layout = require('Layout');
|
||||||
const weather = require('weather');
|
const locale = require('locale');
|
||||||
let current = weather.get();
|
const weather = require('weather');
|
||||||
|
let current = weather.get();
|
||||||
|
|
||||||
function formatDuration(millis) {
|
Bangle.loadWidgets();
|
||||||
let pluralize = (n, w) => n + " " + w + (n == 1 ? "" : "s");
|
|
||||||
if (millis < 60000) return "< 1 minute";
|
|
||||||
if (millis < 3600000) return pluralize(Math.floor(millis/60000), "minute");
|
|
||||||
if (millis < 86400000) return pluralize(Math.floor(millis/3600000), "hour");
|
|
||||||
return pluralize(Math.floor(millis/86400000), "day");
|
|
||||||
}
|
|
||||||
|
|
||||||
function draw() {
|
var layout = new Layout({type:"v", bgCol: g.theme.bg, c: [
|
||||||
g.reset();
|
{filly: 1},
|
||||||
g.clearRect(0, 24, 239, 239);
|
{type: "h", filly: 0, c: [
|
||||||
|
{type: "custom", width: g.getWidth()/2, height: g.getWidth()/2, valign: -1, txt: "unknown", id: "icon",
|
||||||
|
render: l => weather.drawIcon(l.txt, l.x+l.w/2, l.y+l.h/2, l.w/2-5)},
|
||||||
|
{type: "v", fillx: 1, c: [
|
||||||
|
{type: "h", pad: 2, c: [
|
||||||
|
{type: "txt", font: "18%", id: "temp", label: "000"},
|
||||||
|
{type: "txt", font: "12%", valign: -1, id: "tempUnit", label: "°C"},
|
||||||
|
]},
|
||||||
|
{filly: 1},
|
||||||
|
{type: "txt", font: "6x8", pad: 2, halign: 1, label: "Humidity"},
|
||||||
|
{type: "txt", font: "9%", pad: 2, halign: 1, id: "hum", label: "000%"},
|
||||||
|
{filly: 1},
|
||||||
|
{type: "txt", font: "6x8", pad: 2, halign: -1, label: "Wind"},
|
||||||
|
{type: "h", halign: -1, c: [
|
||||||
|
{type: "txt", font: "9%", pad: 2, id: "wind", label: "00"},
|
||||||
|
{type: "txt", font: "6x8", pad: 2, valign: -1, id: "windUnit", label: "km/h"},
|
||||||
|
]},
|
||||||
|
]},
|
||||||
|
]},
|
||||||
|
{filly: 1},
|
||||||
|
{type: "txt", font: "9%", wrap: true, height: g.getHeight()*0.18, fillx: 1, id: "cond", label: "Weather condition"},
|
||||||
|
{filly: 1},
|
||||||
|
{type: "h", c: [
|
||||||
|
{type: "txt", font: "6x8", pad: 4, id: "loc", label: "Toronto"},
|
||||||
|
{fillx: 1},
|
||||||
|
{type: "txt", font: "6x8", pad: 4, id: "updateTime", label: "15 minutes ago"},
|
||||||
|
]},
|
||||||
|
{filly: 1},
|
||||||
|
]}, null, {lazy: true});
|
||||||
|
|
||||||
weather.drawIcon(current.txt, 65, 90, 55);
|
function formatDuration(millis) {
|
||||||
const locale = require("locale");
|
let pluralize = (n, w) => n + " " + w + (n == 1 ? "" : "s");
|
||||||
|
if (millis < 60000) return "< 1 minute";
|
||||||
|
if (millis < 3600000) return pluralize(Math.floor(millis/60000), "minute");
|
||||||
|
if (millis < 86400000) return pluralize(Math.floor(millis/3600000), "hour");
|
||||||
|
return pluralize(Math.floor(millis/86400000), "day");
|
||||||
|
}
|
||||||
|
|
||||||
g.reset();
|
function draw() {
|
||||||
|
layout.icon.txt = current.txt;
|
||||||
|
const temp = locale.temp(current.temp-273.15).match(/^(\D*\d*)(.*)$/);
|
||||||
|
layout.temp.label = temp[1];
|
||||||
|
layout.tempUnit.label = temp[2];
|
||||||
|
layout.hum.label = current.hum+"%";
|
||||||
|
const wind = locale.speed(current.wind).match(/^(\D*\d*)(.*)$/);
|
||||||
|
layout.wind.label = wind[1];
|
||||||
|
layout.windUnit.label = wind[2] + " " + current.wrose.toUpperCase();
|
||||||
|
layout.cond.label = current.txt.charAt(0).toUpperCase()+current.txt.slice(1);
|
||||||
|
layout.loc.label = current.loc;
|
||||||
|
layout.updateTime.label = `${formatDuration(Date.now() - current.time)} ago`;
|
||||||
|
layout.update();
|
||||||
|
layout.render();
|
||||||
|
}
|
||||||
|
|
||||||
const temp = locale.temp(current.temp-273.15).match(/^(\D*\d*)(.*)$/);
|
function drawUpdateTime() {
|
||||||
let width = g.setFont("Vector", 40).stringWidth(temp[1]);
|
if (!current || !current.time) return;
|
||||||
width += g.setFont("Vector", 20).stringWidth(temp[2]);
|
layout.updateTime.label = `${formatDuration(Date.now() - current.time)} ago`;
|
||||||
g.setFont("Vector", 40).setFontAlign(-1, -1, 0);
|
layout.update();
|
||||||
g.drawString(temp[1], 180-width/2, 70);
|
layout.render();
|
||||||
g.setFont("Vector", 20).setFontAlign(1, -1, 0);
|
}
|
||||||
g.drawString(temp[2], 180+width/2, 70);
|
|
||||||
|
|
||||||
g.setFont("6x8", 1);
|
function update() {
|
||||||
g.setFontAlign(-1, 0, 0);
|
current = weather.get();
|
||||||
g.drawString("Humidity", 135, 130);
|
NRF.removeListener("connect", update);
|
||||||
g.setFontAlign(1, 0, 0);
|
if (current) {
|
||||||
g.drawString(current.hum+"%", 225, 130);
|
draw();
|
||||||
if ('wind' in current) {
|
} else {
|
||||||
g.setFontAlign(-1, 0, 0);
|
layout.forgetLazyState();
|
||||||
g.drawString("Wind", 135, 142);
|
if (NRF.getSecurityStatus().connected) {
|
||||||
g.setFontAlign(1, 0, 0);
|
E.showMessage("Weather\nunknown\n\nIs Gadgetbridge\nweather\nreporting set\nup on your\nphone?");
|
||||||
g.drawString(locale.speed(current.wind)+' '+current.wrose.toUpperCase(), 225, 142);
|
|
||||||
}
|
|
||||||
|
|
||||||
g.setFont("6x8", 2).setFontAlign(0, 0, 0);
|
|
||||||
g.drawString(current.loc, 120, 170);
|
|
||||||
|
|
||||||
g.setFont("6x8", 1).setFontAlign(0, 0, 0);
|
|
||||||
g.drawString(current.txt.charAt(0).toUpperCase()+current.txt.slice(1), 120, 190);
|
|
||||||
|
|
||||||
drawUpdateTime();
|
|
||||||
|
|
||||||
g.flip();
|
|
||||||
}
|
|
||||||
|
|
||||||
function drawUpdateTime() {
|
|
||||||
if (!current || !current.time) return;
|
|
||||||
let text = `Last update received ${formatDuration(Date.now() - current.time)} ago`;
|
|
||||||
g.reset();
|
|
||||||
g.clearRect(0, 202, 239, 210);
|
|
||||||
g.setFont("6x8", 1).setFontAlign(0, 0, 0);
|
|
||||||
g.drawString(text, 120, 206);
|
|
||||||
}
|
|
||||||
|
|
||||||
function update() {
|
|
||||||
current = weather.get();
|
|
||||||
NRF.removeListener("connect", update);
|
|
||||||
if (current) {
|
|
||||||
draw();
|
|
||||||
} else if (NRF.getSecurityStatus().connected) {
|
|
||||||
E.showMessage("Weather unknown\n\nIs Gadgetbridge\nweather reporting\nset up on your\nphone?");
|
|
||||||
} else {
|
} else {
|
||||||
E.showMessage("Weather unknown\n\nGadgetbridge\nnot connected");
|
E.showMessage("Weather\nunknown\n\nGadgetbridge\nnot connected");
|
||||||
NRF.on("connect", update);
|
NRF.on("connect", update);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let interval = setInterval(drawUpdateTime, 60000);
|
let interval = setInterval(drawUpdateTime, 60000);
|
||||||
Bangle.on('lcdPower', (on) => {
|
Bangle.on('lcdPower', (on) => {
|
||||||
if (interval) {
|
if (interval) {
|
||||||
clearInterval(interval);
|
clearInterval(interval);
|
||||||
interval = undefined;
|
interval = undefined;
|
||||||
}
|
}
|
||||||
if (on) {
|
if (on) {
|
||||||
drawUpdateTime();
|
drawUpdateTime();
|
||||||
interval = setInterval(drawUpdateTime, 60000);
|
interval = setInterval(drawUpdateTime, 60000);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
weather.on("update", update);
|
weather.on("update", update);
|
||||||
|
|
||||||
update();
|
update();
|
||||||
|
|
||||||
// Show launcher when middle button pressed
|
// Show launcher when middle button pressed
|
||||||
Bangle.setUI("clock");
|
Bangle.setUI("clock");
|
||||||
|
|
||||||
Bangle.loadWidgets();
|
Bangle.drawWidgets();
|
||||||
Bangle.drawWidgets();
|
|
||||||
})()
|
|
||||||
|
|
|
||||||
|
|
@ -2,3 +2,4 @@
|
||||||
0.03: Ensure redrawing works with variable size widget system
|
0.03: Ensure redrawing works with variable size widget system
|
||||||
0.04: Fix regression stopping correct widget updates
|
0.04: Fix regression stopping correct widget updates
|
||||||
0.05: Don't show clock widget if already showing clock app
|
0.05: Don't show clock widget if already showing clock app
|
||||||
|
0.06: Use 7 segment font, update *on* the minute, use less memory
|
||||||
|
|
|
||||||
|
|
@ -1,30 +1,16 @@
|
||||||
(function() {
|
/* Simple clock that appears in the widget bar if no other clock
|
||||||
// don't show widget if we know we have a clock app running
|
is running. We update once per minute, but don't bother stopping
|
||||||
if (Bangle.CLOCK) return;
|
if the */
|
||||||
|
|
||||||
let intervalRef = null;
|
// don't show widget if we know we have a clock app running
|
||||||
var width = 5 * 6*2
|
if (!Bangle.CLOCK) WIDGETS["wdclk"]={area:"tl",width:52/* g.stringWidth("00:00") */,draw:function() {
|
||||||
|
g.reset().setFontCustom(atob("AAAAAAAAAAIAAAQCAQAAAd0BgMBdwAAAAAAAdwAB0RiMRcAAAERiMRdwAcAQCAQdwAcERiMRBwAd0RiMRBwAAEAgEAdwAd0RiMRdwAcERiMRdwAFAAd0QiEQdwAdwRCIRBwAd0BgMBAAABwRCIRdwAd0RiMRAAAd0QiEQAAAAAAAAAA="), 32, atob("BgAAAAAAAAAAAAAAAAYCAAYGBgYGBgYGBgYCAAAAAAAABgYGBgYG"), 512+9);
|
||||||
function draw() {
|
var time = require("locale").time(new Date(),1);
|
||||||
g.reset().setFont("6x8", 2).setFontAlign(-1, 0);
|
g.drawString(time, this.x, this.y+3, true); // 5 * 6*2 = 60
|
||||||
var time = require("locale").time(new Date(),1);
|
// queue draw in one minute
|
||||||
g.drawString(time, this.x, this.y+11, true); // 5 * 6*2 = 60
|
if (this.drawTimeout) clearTimeout(this.drawTimeout);
|
||||||
}
|
this.drawTimeout = setTimeout(()=>{
|
||||||
function clearTimers(){
|
this.drawTimeout = undefined;
|
||||||
if(intervalRef) {
|
this.draw();
|
||||||
clearInterval(intervalRef);
|
}, 60000 - (Date.now() % 60000));
|
||||||
intervalRef = null;
|
}};
|
||||||
}
|
|
||||||
}
|
|
||||||
function startTimers(){
|
|
||||||
intervalRef = setInterval(()=>WIDGETS["wdclk"].draw(), 60*1000);
|
|
||||||
WIDGETS["wdclk"].draw();
|
|
||||||
}
|
|
||||||
Bangle.on('lcdPower', (on) => {
|
|
||||||
clearTimers();
|
|
||||||
if (on) startTimers();
|
|
||||||
});
|
|
||||||
|
|
||||||
WIDGETS["wdclk"]={area:"tr",width:width,draw:draw};
|
|
||||||
if (Bangle.isLCDOn) intervalRef = setInterval(()=>WIDGETS["wdclk"].draw(), 60*1000);
|
|
||||||
})()
|
|
||||||
|
|
|
||||||
|
|
@ -11,16 +11,35 @@ var SETTINGS = {
|
||||||
pretokenise : true
|
pretokenise : true
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var DEVICE = process.argv[2];
|
||||||
|
|
||||||
var path = require('path');
|
var path = require('path');
|
||||||
var ROOTDIR = path.join(__dirname, '..');
|
var ROOTDIR = path.join(__dirname, '..');
|
||||||
var APPDIR = ROOTDIR+'/apps';
|
var APPDIR = ROOTDIR+'/apps';
|
||||||
var APPJSON = ROOTDIR+'/apps.json';
|
var APPJSON = ROOTDIR+'/apps.json';
|
||||||
var OUTFILE = path.join(ROOTDIR, '../Espruino/libs/banglejs/banglejs2_storage_default.c');
|
|
||||||
var APPS = [ // IDs of apps to install
|
|
||||||
"boot","launchb2","s7clk","setting",
|
|
||||||
"about","alarm","widlock","widbat","widbt"
|
|
||||||
];
|
|
||||||
var MINIFY = true;
|
var MINIFY = true;
|
||||||
|
var OUTFILE, APPS;
|
||||||
|
|
||||||
|
if (DEVICE=="BANGLEJS") {
|
||||||
|
var OUTFILE = path.join(ROOTDIR, '../Espruino/libs/banglejs/banglejs1_storage_default.c');
|
||||||
|
var APPS = [ // IDs of apps to install
|
||||||
|
"boot","launch","mclock","setting",
|
||||||
|
"about","alarm","widbat","widbt","welcome"
|
||||||
|
];
|
||||||
|
} else if (DEVICE=="BANGLEJS2") {
|
||||||
|
var OUTFILE = path.join(ROOTDIR, '../Espruino/libs/banglejs/banglejs2_storage_default.c');
|
||||||
|
var APPS = [ // IDs of apps to install
|
||||||
|
"boot","launchb2","s7clk","setting",
|
||||||
|
"about","alarm","widlock","widbat","widbt"
|
||||||
|
];
|
||||||
|
} else {
|
||||||
|
console.log("USAGE:");
|
||||||
|
console.log(" bin/firmwaremaker_c.js BANGLEJS");
|
||||||
|
console.log(" bin/firmwaremaker_c.js BANGLEJS2");
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
console.log("Device = ",DEVICE);
|
||||||
|
|
||||||
|
|
||||||
var fs = require("fs");
|
var fs = require("fs");
|
||||||
global.Const = {
|
global.Const = {
|
||||||
|
|
@ -36,6 +36,8 @@ layoutObject has:
|
||||||
* A `id` field. If specified the object is added with this name to the
|
* A `id` field. If specified the object is added with this name to the
|
||||||
returned `layout` object, so can be referenced as `layout.foo`
|
returned `layout` object, so can be referenced as `layout.foo`
|
||||||
* A `font` field, eg `6x8` or `30%` to use a percentage of screen height
|
* A `font` field, eg `6x8` or `30%` to use a percentage of screen height
|
||||||
|
* A `wrap` field to enable line wrapping. Requires some combination of `width`/`height`
|
||||||
|
and `fillx`/`filly` to be set. Not compatible with text rotation.
|
||||||
* A `col` field, eg `#f00` for red
|
* A `col` field, eg `#f00` for red
|
||||||
* A `bgCol` field for background color (will automatically fill on render)
|
* A `bgCol` field for background color (will automatically fill on render)
|
||||||
* A `halign` field to set horizontal alignment. `-1`=left, `1`=right, `0`=center
|
* A `halign` field to set horizontal alignment. `-1`=left, `1`=right, `0`=center
|
||||||
|
|
@ -71,6 +73,7 @@ Other functions:
|
||||||
* `layout.update()` - update positions of everything if contents have changed
|
* `layout.update()` - update positions of everything if contents have changed
|
||||||
* `layout.debug(obj)` - draw outlines for objects on screen
|
* `layout.debug(obj)` - draw outlines for objects on screen
|
||||||
* `layout.clear(obj)` - clear the given object (you can also just specify `bgCol` to clear before each render)
|
* `layout.clear(obj)` - clear the given object (you can also just specify `bgCol` to clear before each render)
|
||||||
|
* `layout.forgetLazyState()` - if lazy rendering is enabled, makes the next call to `render()` perform a full re-render
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
@ -138,7 +141,7 @@ function Layout(layout, buttons, options) {
|
||||||
if (l.c) l.c.forEach(idRecurser);
|
if (l.c) l.c.forEach(idRecurser);
|
||||||
}
|
}
|
||||||
idRecurser(layout);
|
idRecurser(layout);
|
||||||
this.update();
|
this.updateNeeded = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Layout.prototype.remove = function (l) {
|
Layout.prototype.remove = function (l) {
|
||||||
|
|
@ -152,6 +155,24 @@ Layout.prototype.remove = function (l) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function wrappedLines(str, maxWidth) {
|
||||||
|
var lines = [];
|
||||||
|
for (var unwrappedLine of str.split("\n")) {
|
||||||
|
var words = unwrappedLine.split(" ");
|
||||||
|
var line = words.shift();
|
||||||
|
for (var word of words) {
|
||||||
|
if (g.stringWidth(line + " " + word) > maxWidth) {
|
||||||
|
lines.push(line);
|
||||||
|
line = word;
|
||||||
|
} else {
|
||||||
|
line += " " + word;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lines.push(line);
|
||||||
|
}
|
||||||
|
return lines;
|
||||||
|
}
|
||||||
|
|
||||||
function prepareLazyRender(l, rectsToClear, drawList, rects, parentBg) {
|
function prepareLazyRender(l, rectsToClear, drawList, rects, parentBg) {
|
||||||
var bgCol = l.bgCol == null ? parentBg : g.toColor(l.bgCol);
|
var bgCol = l.bgCol == null ? parentBg : g.toColor(l.bgCol);
|
||||||
if (bgCol != parentBg || l.type == "txt" || l.type == "btn" || l.type == "img" || l.type == "custom") {
|
if (bgCol != parentBg || l.type == "txt" || l.type == "btn" || l.type == "img" || l.type == "custom") {
|
||||||
|
|
@ -176,6 +197,7 @@ function prepareLazyRender(l, rectsToClear, drawList, rects, parentBg) {
|
||||||
|
|
||||||
Layout.prototype.render = function (l) {
|
Layout.prototype.render = function (l) {
|
||||||
if (!l) l = this._l;
|
if (!l) l = this._l;
|
||||||
|
if (this.updateNeeded) this.update();
|
||||||
|
|
||||||
function render(l) {"ram"
|
function render(l) {"ram"
|
||||||
g.reset();
|
g.reset();
|
||||||
|
|
@ -187,7 +209,14 @@ Layout.prototype.render = function (l) {
|
||||||
var cb = {
|
var cb = {
|
||||||
"":function(){},
|
"":function(){},
|
||||||
"txt":function(l){
|
"txt":function(l){
|
||||||
g.setFont(l.font,l.fsz).setFontAlign(0,0,l.r).drawString(l.label, l.x+(l.w>>1), l.y+(l.h>>1));
|
if (l.wrap) {
|
||||||
|
g.setFont(l.font,l.fsz).setFontAlign(0,-1);
|
||||||
|
var lines = wrappedLines(l.label, l.w);
|
||||||
|
var y = l.y+((l.h-g.getFontHeight()*lines.length)>>1);
|
||||||
|
lines.forEach((line, i) => g.drawString(line, l.x+(l.w>>1), y+g.getFontHeight()*i));
|
||||||
|
} else {
|
||||||
|
g.setFont(l.font,l.fsz).setFontAlign(0,0,l.r).drawString(l.label, l.x+(l.w>>1), l.y+(l.h>>1));
|
||||||
|
}
|
||||||
}, "btn":function(l){
|
}, "btn":function(l){
|
||||||
var x = l.x+(0|l.pad);
|
var x = l.x+(0|l.pad);
|
||||||
var y = l.y+(0|l.pad);
|
var y = l.y+(0|l.pad);
|
||||||
|
|
@ -230,6 +259,10 @@ Layout.prototype.render = function (l) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Layout.prototype.forgetLazyState = function () {
|
||||||
|
this.rects = {};
|
||||||
|
}
|
||||||
|
|
||||||
Layout.prototype.layout = function (l) {
|
Layout.prototype.layout = function (l) {
|
||||||
// l = current layout element
|
// l = current layout element
|
||||||
// exw,exh = extra width/height available
|
// exw,exh = extra width/height available
|
||||||
|
|
@ -282,6 +315,7 @@ Layout.prototype.debug = function(l,c) {
|
||||||
if (l.c) l.c.forEach(n => this.debug(n,c));
|
if (l.c) l.c.forEach(n => this.debug(n,c));
|
||||||
};
|
};
|
||||||
Layout.prototype.update = function() {
|
Layout.prototype.update = function() {
|
||||||
|
delete this.updateNeeded;
|
||||||
var l = this._l;
|
var l = this._l;
|
||||||
var w = g.getWidth();
|
var w = g.getWidth();
|
||||||
var y = this.yOffset;
|
var y = this.yOffset;
|
||||||
|
|
@ -305,9 +339,13 @@ Layout.prototype.update = function() {
|
||||||
l.font = f[0];
|
l.font = f[0];
|
||||||
l.fsz = f[1];
|
l.fsz = f[1];
|
||||||
}
|
}
|
||||||
g.setFont(l.font,l.fsz);
|
if (l.wrap) {
|
||||||
l._h = g.getFontHeight();
|
l._h = l._w = 0;
|
||||||
l._w = g.stringWidth(l.label);
|
} else {
|
||||||
|
g.setFont(l.font,l.fsz);
|
||||||
|
l._h = g.getFontHeight();
|
||||||
|
l._w = g.stringWidth(l.label);
|
||||||
|
}
|
||||||
}, "btn": function(l) {
|
}, "btn": function(l) {
|
||||||
l._h = 24;
|
l._h = 24;
|
||||||
l._w = 14 + l.label.length*8;
|
l._w = 14 + l.label.length*8;
|
||||||
|
|
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
|
|
@ -0,0 +1,7 @@
|
||||||
|
var layout = new Layout({type:"v", c: [
|
||||||
|
{type:"h", c: [
|
||||||
|
{type:"txt", font:"10%", wrap: true, fillx: true, filly: true, label:"This is wrapping text that fills remaining space"},
|
||||||
|
{type:"txt", font:"6x8", wrap: true, width: 60, filly: true, label:"This is wrapping text in a narrow column"},
|
||||||
|
]},
|
||||||
|
{type:"txt", font:"6x8", wrap: true, fillx: true, height: 20, label:"This doesn't need to wrap"},
|
||||||
|
]});
|
||||||
Loading…
Reference in New Issue