Merge branch 'espruino:master' into master
|
|
@ -1,12 +1,34 @@
|
|||
// place your const, vars, functions or classes here
|
||||
|
||||
// special function to handle display switch on
|
||||
Bangle.on('lcdPower', (on) => {
|
||||
if (on) {
|
||||
// call your app function here
|
||||
// If you clear the screen, do Bangle.drawWidgets();
|
||||
// clear the screen
|
||||
g.clear();
|
||||
|
||||
var n = 0;
|
||||
|
||||
// redraw the screen
|
||||
function draw() {
|
||||
g.reset().clearRect(Bangle.appRect);
|
||||
g.setFont("6x8").setFontAlign(0,0).drawString("Up / Down",g.getWidth()/2,g.getHeight()/2 - 20);
|
||||
g.setFont("Vector",60).setFontAlign(0,0).drawString(n,g.getWidth()/2,g.getHeight()/2 + 30);
|
||||
}
|
||||
|
||||
// Respond to user input
|
||||
Bangle.setUI({mode: "updown"}, function(dir) {
|
||||
if (dir<0) {
|
||||
n--;
|
||||
draw();
|
||||
} else if (dir>0) {
|
||||
n++;
|
||||
draw();
|
||||
} else {
|
||||
n = 0;
|
||||
draw();
|
||||
}
|
||||
});
|
||||
|
||||
g.clear();
|
||||
// call your app function here
|
||||
// First draw...
|
||||
draw();
|
||||
|
||||
// Load widgets
|
||||
Bangle.loadWidgets();
|
||||
Bangle.drawWidgets();
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
"type": "clock",
|
||||
"tags": "clock",
|
||||
"supports": ["BANGLEJS","BANGLEJS2"],
|
||||
"readme": "README.md",
|
||||
"allow_emulator": true,
|
||||
"storage": [
|
||||
{"name":"aclock.app.js","url":"clock-analog.js"},
|
||||
|
|
|
|||
|
|
@ -14,3 +14,5 @@
|
|||
0.13: Alarm widget state now updates when setting/resetting an alarm
|
||||
0.14: Order of 'back' menu item
|
||||
0.15: Fix hour/minute wrapping code for new menu system
|
||||
0.16: Adding alarm library
|
||||
0.17: Moving alarm internals to 'sched' library
|
||||
|
|
|
|||
|
|
@ -0,0 +1,6 @@
|
|||
Default Alarm & Timer
|
||||
======================
|
||||
|
||||
This allows you to add/modify any running timers.
|
||||
|
||||
It uses the [`sched` library](https://github.com/espruino/BangleApps/blob/master/apps/sched) to handle the alarm scheduling in an efficient way that can work alongside other apps.
|
||||
|
|
@ -1,72 +0,0 @@
|
|||
// Chances are boot0.js got run already and scheduled *another*
|
||||
// 'load(alarm.js)' - so let's remove it first!
|
||||
clearInterval();
|
||||
|
||||
function formatTime(t) {
|
||||
var hrs = 0|t;
|
||||
var mins = Math.round((t-hrs)*60);
|
||||
return hrs+":"+("0"+mins).substr(-2);
|
||||
}
|
||||
|
||||
function getCurrentHr() {
|
||||
var time = new Date();
|
||||
return time.getHours()+(time.getMinutes()/60)+(time.getSeconds()/3600);
|
||||
}
|
||||
|
||||
function showAlarm(alarm) {
|
||||
var msg = formatTime(alarm.hr);
|
||||
var buzzCount = 10;
|
||||
if (alarm.msg)
|
||||
msg += "\n"+alarm.msg;
|
||||
Bangle.loadWidgets();
|
||||
Bangle.drawWidgets();
|
||||
E.showPrompt(msg,{
|
||||
title:alarm.timer ? /*LANG*/"TIMER!" : /*LANG*/"ALARM!",
|
||||
buttons : {/*LANG*/"Sleep":true,/*LANG*/"Ok":false} // default is sleep so it'll come back in 10 mins
|
||||
}).then(function(sleep) {
|
||||
buzzCount = 0;
|
||||
if (sleep) {
|
||||
if(alarm.ohr===undefined) alarm.ohr = alarm.hr;
|
||||
alarm.hr += 10/60; // 10 minutes
|
||||
} else {
|
||||
alarm.last = (new Date()).getDate();
|
||||
if (alarm.ohr!==undefined) {
|
||||
alarm.hr = alarm.ohr;
|
||||
delete alarm.ohr;
|
||||
}
|
||||
if (!alarm.rp) alarm.on = false;
|
||||
}
|
||||
require("Storage").write("alarm.json",JSON.stringify(alarms));
|
||||
load();
|
||||
});
|
||||
function buzz() {
|
||||
if ((require('Storage').readJSON('setting.json',1)||{}).quiet>1) return; // total silence
|
||||
Bangle.buzz(100).then(()=>{
|
||||
setTimeout(()=>{
|
||||
Bangle.buzz(100).then(function() {
|
||||
if (buzzCount--)
|
||||
setTimeout(buzz, 3000);
|
||||
else if(alarm.as) { // auto-snooze
|
||||
buzzCount = 10;
|
||||
setTimeout(buzz, 600000);
|
||||
}
|
||||
});
|
||||
},100);
|
||||
});
|
||||
}
|
||||
buzz();
|
||||
}
|
||||
|
||||
// Check for alarms
|
||||
var day = (new Date()).getDate();
|
||||
var hr = getCurrentHr()+10000; // get current time - 10s in future to ensure we alarm if we've started the app a tad early
|
||||
var alarms = require("Storage").readJSON("alarm.json",1)||[];
|
||||
var active = alarms.filter(a=>a.on&&(a.hr<hr)&&(a.last!=day));
|
||||
if (active.length) {
|
||||
// if there's an alarm, show it
|
||||
active = active.sort((a,b)=>a.hr-b.hr);
|
||||
showAlarm(active[0]);
|
||||
} else {
|
||||
// otherwise just go back to default app
|
||||
setTimeout(load, 100);
|
||||
}
|
||||
|
|
@ -1,36 +1,43 @@
|
|||
Bangle.loadWidgets();
|
||||
Bangle.drawWidgets();
|
||||
|
||||
var alarms = require("Storage").readJSON("alarm.json",1)||[];
|
||||
/*alarms = [
|
||||
{ on : true,
|
||||
hr : 6.5, // hours + minutes/60
|
||||
msg : "Eat chocolate",
|
||||
last : 0, // last day of the month we alarmed on - so we don't alarm twice in one day!
|
||||
rp : true, // repeat
|
||||
as : false, // auto snooze
|
||||
timer : 5, // OPTIONAL - if set, this is a timer and it's the time in minutes
|
||||
}
|
||||
];*/
|
||||
var alarms = require("sched").getAlarms();
|
||||
// An array of alarm objects (see sched/README.md)
|
||||
|
||||
// time in ms -> { hrs, mins }
|
||||
function decodeTime(t) {
|
||||
t = 0|t; // sanitise
|
||||
var hrs = 0|(t/3600000);
|
||||
return { hrs : hrs, mins : Math.round((t-hrs*3600000)/60000) };
|
||||
}
|
||||
|
||||
// time in { hrs, mins } -> ms
|
||||
function encodeTime(o) {
|
||||
return o.hrs*3600000 + o.mins*60000;
|
||||
}
|
||||
|
||||
function formatTime(t) {
|
||||
var hrs = 0|t;
|
||||
var mins = Math.round((t-hrs)*60);
|
||||
return hrs+":"+("0"+mins).substr(-2);
|
||||
var o = decodeTime(t);
|
||||
return o.hrs+":"+("0"+o.mins).substr(-2);
|
||||
}
|
||||
|
||||
function formatMins(t) {
|
||||
mins = (0|t)%60;
|
||||
hrs = 0|(t/60);
|
||||
return hrs+":"+("0"+mins).substr(-2);
|
||||
}
|
||||
|
||||
function getCurrentHr() {
|
||||
function getCurrentTime() {
|
||||
var time = new Date();
|
||||
return time.getHours()+(time.getMinutes()/60)+(time.getSeconds()/3600);
|
||||
return (
|
||||
time.getHours() * 3600000 +
|
||||
time.getMinutes() * 60000 +
|
||||
time.getSeconds() * 1000
|
||||
);
|
||||
}
|
||||
|
||||
function saveAndReload() {
|
||||
require("sched").setAlarms(alarms);
|
||||
require("sched").reload();
|
||||
}
|
||||
|
||||
function showMainMenu() {
|
||||
// Timer img "\0"+atob("DhKBAP////MDDAwwMGGBzgPwB4AeAPwHOBhgwMMzDez////w")
|
||||
// Alarm img "\0"+atob("FBSBAABgA4YcMPDGP8Zn/mx/48//PP/zD/8A//AP/wD/8A//AP/wH/+D//w//8AAAADwAAYA")
|
||||
const menu = {
|
||||
'': { 'title': 'Alarm/Timer' },
|
||||
/*LANG*/'< Back' : ()=>{load();},
|
||||
|
|
@ -38,140 +45,151 @@ function showMainMenu() {
|
|||
/*LANG*/'New Timer': ()=>editTimer(-1)
|
||||
};
|
||||
alarms.forEach((alarm,idx)=>{
|
||||
if (alarm.timer) {
|
||||
txt = /*LANG*/"TIMER "+(alarm.on?/*LANG*/"on ":/*LANG*/"off ")+formatMins(alarm.timer);
|
||||
} else {
|
||||
txt = /*LANG*/"ALARM "+(alarm.on?/*LANG*/"on ":/*LANG*/"off ")+formatTime(alarm.hr);
|
||||
if (alarm.rp) txt += /*LANG*/" (repeat)";
|
||||
}
|
||||
menu[txt] = function() {
|
||||
if (alarm.timer) editTimer(idx);
|
||||
else editAlarm(idx);
|
||||
var txt; // a leading space is currently required (JS error in Espruino 2v12)
|
||||
if (alarm.timer)
|
||||
txt = /*LANG*/"Timer"+" "+formatTime(alarm.timer);
|
||||
else
|
||||
txt = /*LANG*/"Alarm"+" "+formatTime(alarm.t);
|
||||
if (alarm.rp) txt += "\0"+atob("FBaBAAABgAAcAAHn//////wAHsABzAAYwAAMAADAAAAAAwAAMAADGAAzgAN4AD//////54AAOAABgAA=");
|
||||
menu[txt] = {
|
||||
value : "\0"+atob(alarm.on?"EhKBAH//v/////////////5//x//j//H+eP+Mf/A//h//z//////////3//g":"EhKBAH//v//8AA8AA8AA8AA8AA8AA8AA8AA8AA8AA8AA8AA8AA8AA///3//g"),
|
||||
onchange : function() {
|
||||
if (alarm.timer) editTimer(idx, alarm);
|
||||
else editAlarm(idx, alarm);
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
if (WIDGETS["alarm"]) WIDGETS["alarm"].reload();
|
||||
return E.showMenu(menu);
|
||||
}
|
||||
|
||||
function editAlarm(alarmIndex) {
|
||||
function editDOW(dow, onchange) {
|
||||
const menu = {
|
||||
'': { 'title': /*LANG*/'Days of Week' },
|
||||
'< Back' : () => onchange(dow)
|
||||
};
|
||||
for (var i = 0; i < 7; i++) (i => {
|
||||
var dayOfWeek = require("locale").dow({ getDay: () => i });
|
||||
menu[dayOfWeek] = {
|
||||
value: !!(dow&(1<<i)),
|
||||
format: v => v ? "Yes" : "No",
|
||||
onchange: v => v ? dow |= 1<<i : dow &= ~(1<<i),
|
||||
};
|
||||
})(i);
|
||||
E.showMenu(menu);
|
||||
}
|
||||
|
||||
function editAlarm(alarmIndex, alarm) {
|
||||
var newAlarm = alarmIndex<0;
|
||||
var hrs = 12;
|
||||
var mins = 0;
|
||||
var en = true;
|
||||
var repeat = true;
|
||||
var as = false;
|
||||
if (!newAlarm) {
|
||||
var a = alarms[alarmIndex];
|
||||
hrs = 0|a.hr;
|
||||
mins = Math.round((a.hr-hrs)*60);
|
||||
en = a.on;
|
||||
repeat = a.rp;
|
||||
as = a.as;
|
||||
var a = {
|
||||
t : 12*3600000, // 12 o clock default
|
||||
on : true,
|
||||
rp : true,
|
||||
as : false,
|
||||
dow : 0b1111111,
|
||||
last : 0,
|
||||
vibrate : ".."
|
||||
}
|
||||
if (!newAlarm) Object.assign(a, alarms[alarmIndex]);
|
||||
if (alarm) Object.assign(a,alarm);
|
||||
var t = decodeTime(a.t);
|
||||
|
||||
const menu = {
|
||||
'': { 'title': /*LANG*/'Alarm' },
|
||||
/*LANG*/'< Back' : showMainMenu,
|
||||
'< Back' : () => showMainMenu(),
|
||||
/*LANG*/'Hours': {
|
||||
value: hrs, min : 0, max : 23, wrap : true,
|
||||
onchange: v => hrs=v
|
||||
value: t.hrs, min : 0, max : 23, wrap : true,
|
||||
onchange: v => t.hrs=v
|
||||
},
|
||||
/*LANG*/'Minutes': {
|
||||
value: mins, min : 0, max : 59, wrap : true,
|
||||
onchange: v => mins=v
|
||||
value: t.mins, min : 0, max : 59, wrap : true,
|
||||
onchange: v => t.mins=v
|
||||
},
|
||||
/*LANG*/'Enabled': {
|
||||
value: en,
|
||||
value: a.on,
|
||||
format: v=>v?"On":"Off",
|
||||
onchange: v=>en=v
|
||||
onchange: v=>a.on=v
|
||||
},
|
||||
/*LANG*/'Repeat': {
|
||||
value: en,
|
||||
value: a.rp,
|
||||
format: v=>v?"Yes":"No",
|
||||
onchange: v=>repeat=v
|
||||
onchange: v=>a.rp=v
|
||||
},
|
||||
/*LANG*/'Days': {
|
||||
value: "SMTWTFS".split("").map((d,n)=>a.dow&(1<<n)?d:".").join(""),
|
||||
onchange: () => editDOW(a.dow, d=>{a.dow=d;editAlarm(alarmIndex,a)})
|
||||
},
|
||||
/*LANG*/'Vibrate': require("buzz_menu").pattern(a.vibrate, v => a.vibrate=v ),
|
||||
/*LANG*/'Auto snooze': {
|
||||
value: as,
|
||||
value: a.as,
|
||||
format: v=>v?"Yes":"No",
|
||||
onchange: v=>as=v
|
||||
onchange: v=>a.as=v
|
||||
}
|
||||
};
|
||||
function getAlarm() {
|
||||
var hr = hrs+(mins/60);
|
||||
var day = 0;
|
||||
// If alarm is for tomorrow not today (eg, in the past), set day
|
||||
if (hr < getCurrentHr())
|
||||
day = (new Date()).getDate();
|
||||
// Save alarm
|
||||
return {
|
||||
on : en, hr : hr,
|
||||
last : day, rp : repeat, as: as
|
||||
};
|
||||
}
|
||||
menu[/*LANG*/"> Save"] = function() {
|
||||
if (newAlarm) alarms.push(getAlarm());
|
||||
else alarms[alarmIndex] = getAlarm();
|
||||
require("Storage").write("alarm.json",JSON.stringify(alarms));
|
||||
menu[/*LANG*/"Save"] = function() {
|
||||
a.t = encodeTime(t);
|
||||
if (a.t < getCurrentTime())
|
||||
a.day = (new Date()).getDate();
|
||||
if (newAlarm) alarms.push(a);
|
||||
else alarms[alarmIndex] = a;
|
||||
saveAndReload();
|
||||
showMainMenu();
|
||||
};
|
||||
if (!newAlarm) {
|
||||
menu[/*LANG*/"> Delete"] = function() {
|
||||
menu[/*LANG*/"Delete"] = function() {
|
||||
alarms.splice(alarmIndex,1);
|
||||
require("Storage").write("alarm.json",JSON.stringify(alarms));
|
||||
saveAndReload();
|
||||
showMainMenu();
|
||||
};
|
||||
}
|
||||
return E.showMenu(menu);
|
||||
}
|
||||
|
||||
function editTimer(alarmIndex) {
|
||||
function editTimer(alarmIndex, alarm) {
|
||||
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;
|
||||
var a = {
|
||||
timer : 5*60*1000, // 5 minutes
|
||||
on : true,
|
||||
rp : false,
|
||||
as : false,
|
||||
dow : 0b1111111,
|
||||
last : 0,
|
||||
vibrate : ".."
|
||||
}
|
||||
if (!newAlarm) Object.assign(a, alarms[alarmIndex]);
|
||||
if (alarm) Object.assign(a,alarm);
|
||||
var t = decodeTime(a.timer);
|
||||
|
||||
const menu = {
|
||||
'': { 'title': /*LANG*/'Timer' },
|
||||
'< Back' : () => showMainMenu(),
|
||||
/*LANG*/'Hours': {
|
||||
value: hrs, min : 0, max : 23, wrap : true,
|
||||
onchange: v => hrs=v
|
||||
value: t.hrs, min : 0, max : 23, wrap : true,
|
||||
onchange: v => t.hrs=v
|
||||
},
|
||||
/*LANG*/'Minutes': {
|
||||
value: mins, min : 0, max : 59, wrap : true,
|
||||
onchange: v => mins=v
|
||||
value: t.mins, min : 0, max : 59, wrap : true,
|
||||
onchange: v => t.mins=v
|
||||
},
|
||||
/*LANG*/'Enabled': {
|
||||
value: en,
|
||||
format: v=>v?/*LANG*/"On":/*LANG*/"Off",
|
||||
onchange: v=>en=v
|
||||
}
|
||||
value: a.on,
|
||||
format: v=>v?"On":"Off",
|
||||
onchange: v=>a.on=v
|
||||
},
|
||||
/*LANG*/'Vibrate': require("buzz_menu").pattern(a.vibrate, v => a.vibrate=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));
|
||||
menu[/*LANG*/"Save"] = function() {
|
||||
a.timer = encodeTime(t);
|
||||
a.t = getCurrentTime() + a.timer;
|
||||
if (newAlarm) alarms.push(a);
|
||||
else alarms[alarmIndex] = a;
|
||||
saveAndReload();
|
||||
showMainMenu();
|
||||
};
|
||||
if (!newAlarm) {
|
||||
menu["> Delete"] = function() {
|
||||
menu[/*LANG*/"Delete"] = function() {
|
||||
alarms.splice(alarmIndex,1);
|
||||
require("Storage").write("alarm.json",JSON.stringify(alarms));
|
||||
saveAndReload();
|
||||
showMainMenu();
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,25 +0,0 @@
|
|||
// check for alarms
|
||||
(function() {
|
||||
var alarms = require('Storage').readJSON('alarm.json',1)||[];
|
||||
var time = new Date();
|
||||
var active = alarms.filter(a=>a.on);
|
||||
if (active.length) {
|
||||
active = active.sort((a,b)=>(a.hr-b.hr)+(a.last-b.last)*24);
|
||||
var hr = time.getHours()+(time.getMinutes()/60)+(time.getSeconds()/3600);
|
||||
if (!require('Storage').read("alarm.js")) {
|
||||
console.log("No alarm app!");
|
||||
require('Storage').write('alarm.json',"[]");
|
||||
} else {
|
||||
var t = 3600000*(active[0].hr-hr);
|
||||
if (active[0].last == time.getDate() || t < 0) t += 86400000;
|
||||
if (t<1000) t=1000;
|
||||
/* execute alarm at the correct time. We avoid execing immediately
|
||||
since this code will get called AGAIN when alarm.js is loaded. alarm.js
|
||||
will then clearInterval() to get rid of this call so it can proceed
|
||||
normally. */
|
||||
setTimeout(function() {
|
||||
load("alarm.js");
|
||||
},t);
|
||||
}
|
||||
}
|
||||
})();
|
||||
|
|
@ -1,18 +1,17 @@
|
|||
{
|
||||
"id": "alarm",
|
||||
"name": "Default Alarm & Timer",
|
||||
"name": "Alarm & Timer",
|
||||
"shortName": "Alarms",
|
||||
"version": "0.15",
|
||||
"description": "Set and respond to alarms and timers",
|
||||
"version": "0.17",
|
||||
"description": "Set alarms and timers on your Bangle",
|
||||
"icon": "app.png",
|
||||
"tags": "tool,alarm,widget",
|
||||
"supports": ["BANGLEJS","BANGLEJS2"],
|
||||
"readme": "README.md",
|
||||
"dependencies": {"scheduler":"type"},
|
||||
"storage": [
|
||||
{"name":"alarm.app.js","url":"app.js"},
|
||||
{"name":"alarm.boot.js","url":"boot.js"},
|
||||
{"name":"alarm.js","url":"alarm.js"},
|
||||
{"name":"alarm.img","url":"app-icon.js","evaluate":true},
|
||||
{"name":"alarm.wid.js","url":"widget.js"}
|
||||
],
|
||||
"data": [{"name":"alarm.json"}]
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
WIDGETS["alarm"]={area:"tl",width:0,draw:function() {
|
||||
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);
|
||||
},reload:function() {
|
||||
WIDGETS["alarm"].width = (require('Storage').readJSON('alarm.json',1)||[]).some(alarm=>alarm.on) ? 24 : 0;
|
||||
// don't include library here as we're trying to use as little RAM as possible
|
||||
WIDGETS["alarm"].width = (require('Storage').readJSON('sched.json',1)||[]).some(alarm=>alarm.on&&(alarm.hidden!==false)) ? 24 : 0;
|
||||
}
|
||||
};
|
||||
WIDGETS["alarm"].reload();
|
||||
|
|
|
|||
|
|
@ -8,4 +8,5 @@
|
|||
0.06: fixes #1271 - wrong settings name
|
||||
when weekday name and calendar weeknumber are on then display is <weekday short> #<calweek>
|
||||
week is buffered until date or timezone changes
|
||||
0.07: align default settings with app.js (otherwise the initial displayed settings will be confusing to users)
|
||||
0.07: align default settings with app.js (otherwise the initial displayed settings will be confusing to users)
|
||||
0.08: fixed calendar weeknumber not shortened to two digits
|
||||
|
|
@ -99,7 +99,7 @@ function updateState() {
|
|||
}
|
||||
|
||||
function isoStr(date) {
|
||||
return date.getFullYear() + "-" + ("0" + (date.getMonth() + 1)).substr(-2) + "-" + ("0" + date.getDate()).substr(-2);
|
||||
return date.getFullYear() + "-" + ("0" + (date.getMonth() + 1)).slice(-2) + "-" + ("0" + date.getDate()).slice(-2);
|
||||
}
|
||||
|
||||
var calWeekBuffer = [false,false,false]; //buffer tz, date, week no (once calculated until other tz or date is requested)
|
||||
|
|
@ -140,7 +140,7 @@ function draw() {
|
|||
g.setFontAlign(0, 0).setFont("Anton").drawString(timeStr, x, y); // draw time
|
||||
if (secondsScreen) {
|
||||
y += 65;
|
||||
var secStr = (secondsWithColon ? ":" : "") + ("0" + date.getSeconds()).substr(-2);
|
||||
var secStr = (secondsWithColon ? ":" : "") + ("0" + date.getSeconds()).slice(-2);
|
||||
if (doColor())
|
||||
g.setColor(0, 0, 1);
|
||||
g.setFont("AntonSmall");
|
||||
|
|
@ -193,7 +193,7 @@ function draw() {
|
|||
if (calWeek || weekDay) {
|
||||
var dowcwStr = "";
|
||||
if (calWeek)
|
||||
dowcwStr = " #" + ("0" + ISO8601calWeek(date)).substring(-2);
|
||||
dowcwStr = " #" + ("0" + ISO8601calWeek(date)).slice(-2);
|
||||
if (weekDay)
|
||||
dowcwStr = require("locale").dow(date, calWeek ? 1 : 0) + dowcwStr; //weekDay e.g. Monday or weekDayShort #<calWeek> e.g. Mon #01
|
||||
else //week #01
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"id": "antonclk",
|
||||
"name": "Anton Clock",
|
||||
"version": "0.07",
|
||||
"version": "0.08",
|
||||
"description": "A clock using the bold Anton font, optionally showing seconds and date in ISO-8601 format.",
|
||||
"readme":"README.md",
|
||||
"icon": "app.png",
|
||||
|
|
|
|||
|
|
@ -0,0 +1,2 @@
|
|||
0.01: New app!
|
||||
0.02: Fix bug with regenerating index, fix bug in word lookups
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
|
||||
# Spelling bee game
|
||||
|
||||
Word finding game inspired by the NYT spelling bee. Find as many words with 4 or more letters (must include the
|
||||
letter at the center of the 'hive') as you can.
|
||||
|
||||
|
||||
## Usage
|
||||
|
||||
- tap on letters to type out word
|
||||
- swipe left to delete last letter
|
||||
- swipe right to enter; the word will turn blue while it is being checked against the internal dictionary; once
|
||||
checked, it will turn red if the word is invalid, does not contain the central letter or has been guessed before or
|
||||
will turn green if it is a valid word; in the latter case, points will be awarded
|
||||
- swipe down to shuffle the 6 outer letters
|
||||
- swipe up to view a list of already guessed words; tap on any of them to return to the regular game.
|
||||
|
||||
|
||||
## Scoring
|
||||
|
||||
The number of correctly guessed words is displayed on the bottom left, the score on the bottom right. A single point
|
||||
is awarded for a 4 letter word, or the number of letters if longer. A pangram is a word that contains all 7 letters at
|
||||
least once and yields an additional 7 points. Each game contains at least one pangram.
|
||||
|
||||
|
||||
## Technical remarks
|
||||
The game uses an internal dictionary consisting of a newline separated list of English words ('bee.words', using the '2of12inf' word list).
|
||||
The dictionary is fairly large (~700kB of flash space) and thus requires appropriate space on the watch and will make installing the app somewhat
|
||||
slow. Because of its size it cannot be compressed (heatshrink needs to hold the compressed/uncompressed data in memory).
|
||||
In order to make checking the validity of a guessed word faster an index file ('bee_lindex.json') is installed with
|
||||
the app that facilitates faster word lookups. This index file is specific to the dictionary file used. If one were to
|
||||
replace the dictionary file with a different version (e.g. a different language) the index file has to be regenerated. The easiest
|
||||
way to do so is to delete (via the Web IDE or the fileman app on the watch) the file 'bee_lindex.json' - it will be regenerated (and saved,
|
||||
i.e. it only happens once) on app startup automatically, a process that takes roughly 30 seconds.
|
||||
|
||||

|
||||
|
|
@ -0,0 +1 @@
|
|||
require("heatshrink").decompress(atob("mEwxH+AH4A/AH4A/AE2JAAIKHnc7DyNPp4vRGAwuBGB4sBAAQvSGIovPFqYvHGAYvDGBYsGGhwvGGIQvEGBQnDMYhkNGBAvOvQABqyRTF5GJr4wLFwQACX6IwLsowJLYMrldVGAQvTsoADGBITD0YvDldPF6n+F4gyGGAdP5nMF4KKBGDJZDGI7EBcoOiGAK7DGAQvYRogxEr1Pp9VMAiSBBILBWeJIxCromBMAQwDAAZfTGBQyCxOCGAIvBGIV/F7AwMAAOIp95GAYACFqoyQMAIwGF7QADEQd5FgIADqvGF8DnEAAIvFGIWjF8CFE0QwHAAQudAAK0EGBQuecw3GqpemYIxiCGIa8cF4wwHdTwvJp9/F82jGA9VMQovf5jkHGIwvg4wvIAAgvg5miF9wwNF8QABF9QwF0YuoF4oxCqoulGBAAB42i0QvjGBPMF0gwIFswwHF1IA/AH4A/AH4AL"))
|
||||
|
After Width: | Height: | Size: 2.1 KiB |
|
|
@ -0,0 +1,195 @@
|
|||
|
||||
const S = require("Storage");
|
||||
var letters = [];
|
||||
var letterIdx = [];
|
||||
|
||||
var centers = [];
|
||||
|
||||
var word = '';
|
||||
|
||||
var foundWords = [];
|
||||
var score = 0;
|
||||
|
||||
var intervalID = -1;
|
||||
|
||||
function prepareLetterIdx () {
|
||||
"compile"
|
||||
var li = [0];
|
||||
if (S.read("bee_lindex.json")!==undefined) li = S.readJSON("bee_lindex.json"); // check for cached index
|
||||
else {
|
||||
for (var i=1; i<26; ++i) {
|
||||
var prefix = String.fromCharCode(97+i%26);
|
||||
console.log(prefix);
|
||||
li.push(S.read('bee.words').indexOf("\n"+prefix, li[i-1])+1);
|
||||
}
|
||||
li.push(S.read('bee.words').length);
|
||||
S.writeJSON("bee_lindex.json", li);
|
||||
}
|
||||
for (var i=0; i<26; ++i) letterIdx[i] = S.read("bee.words", li[i], li[i+1]-li[i]);
|
||||
}
|
||||
|
||||
function findWord (w) {
|
||||
"compile"
|
||||
var ci = w.charCodeAt(0)-97;
|
||||
var f = letterIdx[ci].indexOf("\n"+w+"\n");
|
||||
if (f>=0) return true;
|
||||
if (letterIdx[ci].substr(0, w.length)==w) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
function isPangram(w) {
|
||||
var ltrs = '';
|
||||
for (var i=0; i<w.length; ++i) if (ltrs.indexOf(w[i])===-1) ltrs += w[i];
|
||||
return ltrs.length==7;
|
||||
}
|
||||
|
||||
function checkWord (w) {
|
||||
if (w.indexOf(String.fromCharCode(97+letters[0]))==-1) return false; // does it contain central letter?
|
||||
if (foundWords.indexOf(w)>=0) return false; // already found
|
||||
if (findWord(w)) {
|
||||
foundWords.push(w);
|
||||
foundWords.sort();
|
||||
if (w.length==4) score++;
|
||||
else score += w.length;
|
||||
if (isPangram(w)) score += 7;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function getHexPoly(cx, cy, r, a) {
|
||||
var p = [];
|
||||
for (var i=0; i<6; ++i) p.push(cx+r*Math.sin((i+a)/3*Math.PI), cy+r*Math.cos((i+a)/3*Math.PI));
|
||||
return p;
|
||||
}
|
||||
|
||||
function drawHive() {
|
||||
w = g.getWidth();
|
||||
h = g.getHeight();
|
||||
const R = w/3.3;
|
||||
centers = getHexPoly(w/2, h/2+10, R, 0);
|
||||
centers.push(w/2, h/2+10);
|
||||
g.clear();
|
||||
g.setFont("Vector", w/7).setFontAlign(0, 0, 0);
|
||||
g.setColor(g.theme.fg);
|
||||
for (var i=0; i<6; ++i) {
|
||||
g.drawPoly(getHexPoly(centers[2*i], centers[2*i+1], 0.9*R/Math.sqrt(3), 0.5), {closed:true});
|
||||
g.drawString(String.fromCharCode(65+letters[i+1]), centers[2*i]+2, centers[2*i+1]+2);
|
||||
}
|
||||
g.setColor(1, 1, 0).fillPoly(getHexPoly(w/2, h/2+10, 0.9*R/Math.sqrt(3), 0.5));
|
||||
g.setColor(0).drawString(String.fromCharCode(65+letters[0]), w/2+2, h/2+10+2);
|
||||
}
|
||||
|
||||
function shuffleLetters(qAll) {
|
||||
for (var i=letters.length-1; i > 0; i--) {
|
||||
var j = (1-qAll) + Math.floor(Math.random()*(i+qAll));
|
||||
var temp = letters[i];
|
||||
letters[i] = letters[j];
|
||||
letters[j] = temp;
|
||||
}
|
||||
}
|
||||
|
||||
function pickLetters() {
|
||||
var ltrs = "";
|
||||
while (ltrs.length!==7) {
|
||||
ltrs = [];
|
||||
var j = Math.floor(26*Math.random());
|
||||
var i = Math.floor((letterIdx[j].length-10)*Math.random());
|
||||
while (letterIdx[j][i]!="\n" && i<letterIdx[j].length) ++i;
|
||||
if (i<letterIdx[j].length-1) {
|
||||
++i;
|
||||
while (letterIdx[j][i]!=="\n") {
|
||||
var c = letterIdx[j][i];
|
||||
if (ltrs.indexOf(c)===-1) ltrs += c;
|
||||
++i;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (var i=0; i<7; ++i) letters.push(ltrs.charCodeAt(i)-97);
|
||||
shuffleLetters(1);
|
||||
}
|
||||
|
||||
function drawWord(c) {
|
||||
g.clearRect(0, 0, g.getWidth()-1, 19);
|
||||
g.setColor(c).setFont("Vector", 20).setFontAlign(0, 0, 0).drawString(word, g.getWidth()/2, 11).flip();
|
||||
}
|
||||
|
||||
function touchHandler(e, x) {
|
||||
var hex = 0;
|
||||
var hex_d = 1e6;
|
||||
for (var i=0; i<7; ++i) {
|
||||
var d = (x.x-centers[2*i])*(x.x-centers[2*i]) + (x.y-centers[2*i+1])*(x.y-centers[2*i+1]);
|
||||
if (d < hex_d) {
|
||||
hex_d = d;
|
||||
hex = i+1;
|
||||
}
|
||||
}
|
||||
hex = hex%7;
|
||||
if (word.length <= 15) word += String.fromCharCode(letters[hex]+65);
|
||||
drawWord(g.theme.fg);
|
||||
}
|
||||
|
||||
function drawScore() {
|
||||
g.setColor(g.theme.fg).setFont("Vector", 20).setFontAlign(0, 0, 0);
|
||||
g.clearRect(0, g.getHeight()-22, 60, g.getHeight()-1);
|
||||
g.clearRect(g.getWidth()-60, g.getHeight()-22, g.getWidth(), g.getHeight()-1);
|
||||
g.drawString(foundWords.length.toString(), 30, g.getHeight()-11);
|
||||
g.drawString(score.toString(), g.getWidth()-30, g.getHeight()-11);
|
||||
}
|
||||
|
||||
function wordFound (c) {
|
||||
word = "";
|
||||
drawWord(g.theme.fg);
|
||||
drawScore();
|
||||
clearInterval(intervalID);
|
||||
intervalID = -1;
|
||||
}
|
||||
|
||||
function swipeHandler(d, e) {
|
||||
if (d==-1 && word.length>0) {
|
||||
word = word.slice(0, -1);
|
||||
drawWord(g.theme.fg);
|
||||
}
|
||||
if (d==1 && word.length>=4) {
|
||||
drawWord("#00f");
|
||||
drawWord((checkWord(word.toLowerCase()) ? "#0f0" : "#f00"));
|
||||
if (intervalID===-1) intervalID = setInterval(wordFound, 800);
|
||||
}
|
||||
if (e===1) {
|
||||
shuffleLetters(0);
|
||||
drawHive();
|
||||
drawScore();
|
||||
drawWord(g.theme.fg);
|
||||
}
|
||||
if (e===-1 && foundWords.length>0) showWordList();
|
||||
}
|
||||
|
||||
function showWordList() {
|
||||
Bangle.removeListener("touch", touchHandler);
|
||||
Bangle.removeListener("swipe", swipeHandler);
|
||||
E.showScroller({
|
||||
h : 20, c : foundWords.length,
|
||||
draw : (idx, r) => {
|
||||
g.clearRect(r.x,r.y,r.x+r.w-1,r.y+r.h-1).setFont("6x8:2");
|
||||
g.setColor(isPangram(foundWords[idx])?'#0f0':g.theme.fg).drawString(foundWords[idx].toUpperCase(),r.x+10,r.y+4);
|
||||
},
|
||||
select : (idx) => {
|
||||
setInterval(()=> {
|
||||
E.showScroller();
|
||||
drawHive();
|
||||
drawScore();
|
||||
drawWord(g.theme.fg);
|
||||
Bangle.on("touch", touchHandler);
|
||||
Bangle.on("swipe", swipeHandler);
|
||||
clearInterval();
|
||||
}, 100);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
prepareLetterIdx();
|
||||
pickLetters();
|
||||
drawHive();
|
||||
drawScore();
|
||||
Bangle.on("touch", touchHandler);
|
||||
Bangle.on("swipe", swipeHandler);
|
||||
|
|
@ -0,0 +1 @@
|
|||
[0,41048,80445,152390,198606,228714,257919,279071,303726,337982,343582,348026,367246,404452,419780,438696,496250,499697,544600,624304,659085,680996,691270,708186,708341,709916,710883]
|
||||
|
After Width: | Height: | Size: 1.3 KiB |
|
|
@ -0,0 +1,16 @@
|
|||
{ "id": "bee",
|
||||
"name": "Bee",
|
||||
"shortName":"Bee",
|
||||
"icon": "app.png",
|
||||
"version":"0.02",
|
||||
"description": "Spelling bee",
|
||||
"supports" : ["BANGLEJS2"],
|
||||
"readme": "README.md",
|
||||
"tags": "game,text",
|
||||
"storage": [
|
||||
{"name":"bee.app.js","url":"bee.app.js"},
|
||||
{"name":"bee.words","url":"bee_words_2of12"},
|
||||
{"name":"bee_lindex.json","url":"bee_lindex.json"},
|
||||
{"name":"bee.img","url":"app-icon.js","evaluate":true}
|
||||
]
|
||||
}
|
||||
|
|
@ -7,6 +7,7 @@
|
|||
"type": "clock",
|
||||
"tags": "clock",
|
||||
"supports": ["BANGLEJS","BANGLEJS2"],
|
||||
"readme": "README.md",
|
||||
"allow_emulator": true,
|
||||
"screenshots": [{"url":"berlin-clock-screenshot.png"}],
|
||||
"storage": [
|
||||
|
|
|
|||
|
|
@ -0,0 +1,2 @@
|
|||
0.01: New App
|
||||
0.02: app keeps track of statistics now
|
||||
|
|
@ -21,7 +21,8 @@ function buttonPushed(b) {
|
|||
layout.bt1.bgCol = wordle.keyColors.Z||g.theme.bg;
|
||||
layout.bt2.label = "<del>";
|
||||
layout.bt4.label = "<ent>";
|
||||
layout.bt3.label = layout.bt5.label = " ";
|
||||
layout.bt3.label = " ";
|
||||
layout.bt5.label = "<stat>";
|
||||
layout.bt6.label = "<";
|
||||
}
|
||||
}
|
||||
|
|
@ -30,6 +31,10 @@ function buttonPushed(b) {
|
|||
if (b!=6) {
|
||||
if ((keyStateIdx<=5 || b<=1) && inp.length<5) inp += String.fromCharCode(b+(keyStateIdx-1)*5+64);
|
||||
else if (layout.input.label.length>0 && b==2) inp = inp.slice(0,-1);
|
||||
if (keyStateIdx==6 && b==5) {
|
||||
wordle.drawStats();
|
||||
return;
|
||||
}
|
||||
layout.input.label = inp;
|
||||
}
|
||||
layout = getKeyLayout(inp);
|
||||
|
|
@ -82,6 +87,7 @@ class Wordle {
|
|||
this.word = this.words.slice(i, i+5).toUpperCase();
|
||||
}
|
||||
console.log(this.word);
|
||||
this.stats = require("Storage").readJSON("bordlestats.json") || {'1':0, '2':0, '3':0, '4':0, '5':0, '6':0, 'p':0, 'w':0, 's':0, 'ms':0};
|
||||
}
|
||||
render(clear) {
|
||||
h = g.getHeight();
|
||||
|
|
@ -109,7 +115,7 @@ class Wordle {
|
|||
layout = getKeyLayout("");
|
||||
wordle.render(true);
|
||||
});
|
||||
return 3;
|
||||
return 1;
|
||||
}
|
||||
this.guesses.push(w);
|
||||
this.nGuesses++;
|
||||
|
|
@ -130,13 +136,39 @@ class Wordle {
|
|||
this.guessColors[this.nGuesses].push(col);
|
||||
}
|
||||
if (correct==5) {
|
||||
E.showAlert("The word is\n"+this.word, "You won in "+(this.nGuesses+1)+" guesses!").then(function(){load();});
|
||||
return 1;
|
||||
}
|
||||
if (this.nGuesses==5) {
|
||||
E.showAlert("The word was\n"+this.word, "You lost!").then(function(){load();});
|
||||
E.showAlert("The word is\n"+this.word, "You won in "+(this.nGuesses+1)+" guesses!").then(function(){
|
||||
wordle.stats['p']++; wordle.stats['w']++; wordle.stats['s']++; wordle.stats[wordle.nGuesses+1]++;
|
||||
if (wordle.stats['s']>wordle.stats['ms']) wordle.stats['ms'] = wordle.stats['s'];
|
||||
require("Storage").writeJSON("bordlestats.json", wordle.stats);
|
||||
wordle.drawStats();
|
||||
});
|
||||
return 2;
|
||||
}
|
||||
if (this.nGuesses==5) {
|
||||
E.showAlert("The word was\n"+this.word, "You lost!").then(function(){
|
||||
wordle.stats['p']++; wordle.stats['s'] = 0;
|
||||
require("Storage").writeJSON("bordlestats.json", wordle.stats);
|
||||
wordle.drawStats();
|
||||
});
|
||||
return 3;
|
||||
}
|
||||
}
|
||||
drawStats() {
|
||||
E.showMessage(" ", "Statistics");
|
||||
var max = 1;
|
||||
for (i=1; i<=6; ++i) if (max<this.stats[i]) max = this.stats[i];
|
||||
var h = g.getHeight();
|
||||
var w = g.getWidth();
|
||||
g.setColor('#00f').setFontVector((h-40)/8).setFontAlign(-1, 0, 0);
|
||||
for (i=1; i<=6; ++i) {
|
||||
tw = this.stats[i]*(w-24)/max;
|
||||
g.setColor("#00f").fillRect(20, 52+(i-1)*(h-52)/6+2, 20+tw, 52+i*(h-52)/6-2);
|
||||
g.setColor("#fff").drawString(i.toString(), 1, 52+(i-0.5)*(h-52)/6);
|
||||
g.drawString(this.stats[i].toString(), tw>20 ? 25 : 25+tw, 52+(i-0.5)*(h-52)/6);
|
||||
}
|
||||
g.setFontVector((h-40)/9).setColor("#fff").drawString("P:"+this.stats["p"]+" W:"+this.stats["w"]+" S:"+this.stats["s"]+" M:"+this.stats["ms"], 4, 34);
|
||||
Bangle.setUI();
|
||||
Bangle.on("touch", (e) => { load(); });
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
"name": "Bordle",
|
||||
"shortName":"Bordle",
|
||||
"icon": "app.png",
|
||||
"version":"0.01",
|
||||
"version":"0.02",
|
||||
"description": "Bangle version of a popular word search game",
|
||||
"supports" : ["BANGLEJS2"],
|
||||
"readme": "README.md",
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
"screenshots": [{"url":"screenshot_calculator.png"}],
|
||||
"tags": "app,tool",
|
||||
"supports": ["BANGLEJS","BANGLEJS2"],
|
||||
"readme": "README.md",
|
||||
"storage": [
|
||||
{"name":"calculator.app.js","url":"app.js"},
|
||||
{"name":"calculator.img","url":"calculator-icon.js","evaluate":true}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
"type": "clock",
|
||||
"tags": "clock,cli,command,bash,shell",
|
||||
"supports": ["BANGLEJS","BANGLEJS2"],
|
||||
"readme": "README.md",
|
||||
"allow_emulator": true,
|
||||
"storage": [
|
||||
{"name":"cliock.app.js","url":"app.js"},
|
||||
|
|
|
|||
|
|
@ -3,3 +3,4 @@
|
|||
0.03: fix metadata.json to allow setting as clock
|
||||
0.04: added heart rate which is switched on when cycled to it through up/down touch on rhs
|
||||
0.05: changed text to uppercase, just looks better, removed colons on text
|
||||
0.06: better contrast for light theme, use fg color instead of dithered for ring
|
||||
|
|
|
|||
|
|
@ -28,5 +28,6 @@ See [#1248](https://github.com/espruino/BangleApps/issues/1248)
|
|||
|
||||
## Screenshots
|
||||

|
||||

|
||||
|
||||
It is worth looking at the real thing though as the screenshot does not do it justice.
|
||||
It is worth looking at the real thing though as the screenshots do not do it justice.
|
||||
|
|
|
|||
|
|
@ -41,10 +41,17 @@ Graphics.prototype.setFontRoboto20 = function(scale) {
|
|||
};
|
||||
|
||||
function assignPalettes() {
|
||||
// palette for 0-40%
|
||||
pal1 = new Uint16Array([g.theme.bg, g.toColor(settings.gy), g.toColor(settings.fg), g.toColor("#00f")]);
|
||||
// palette for 50-100%
|
||||
pal2 = new Uint16Array([g.theme.bg, g.toColor(settings.fg), g.toColor(settings.gy), g.toColor("#00f")]);
|
||||
if (g.theme.dark) {
|
||||
// palette for 0-40%
|
||||
pal1 = new Uint16Array([g.theme.bg, g.toColor(settings.gy), g.toColor(settings.fg), g.toColor("#00f")]);
|
||||
// palette for 50-100%
|
||||
pal2 = new Uint16Array([g.theme.bg, g.toColor(settings.fg), g.toColor(settings.gy), g.toColor("#00f")]);
|
||||
} else {
|
||||
// palette for 0-40%
|
||||
pal1 = new Uint16Array([g.theme.bg, g.theme.fg, g.toColor(settings.fg), g.toColor("#00f")]);
|
||||
// palette for 50-100%
|
||||
pal2 = new Uint16Array([g.theme.bg, g.toColor(settings.fg), g.theme.fg, g.toColor("#00f")]);
|
||||
}
|
||||
}
|
||||
|
||||
function setSmallFont20() {
|
||||
|
|
@ -109,10 +116,10 @@ function updateSunRiseSunSet(now, lat, lon, line){
|
|||
const infoData = {
|
||||
ID_DATE: { calc: () => {var d = (new Date()).toString().split(" "); return d[2] + ' ' + d[1] + ' ' + d[3];} },
|
||||
ID_DAY: { calc: () => {var d = require("locale").dow(new Date()).toLowerCase(); return d[0].toUpperCase() + d.substring(1);} },
|
||||
ID_SR: { calc: () => 'Sunrise ' + sunRise },
|
||||
ID_SS: { calc: () => 'Sunset ' + sunSet },
|
||||
ID_STEP: { calc: () => 'Steps ' + getSteps() },
|
||||
ID_BATT: { calc: () => 'Battery ' + E.getBattery() + '%' },
|
||||
ID_SR: { calc: () => 'SUNRISE ' + sunRise },
|
||||
ID_SS: { calc: () => 'SUNSET ' + sunSet },
|
||||
ID_STEP: { calc: () => 'STEPS ' + getSteps() },
|
||||
ID_BATT: { calc: () => 'BATTERY ' + E.getBattery() + '%' },
|
||||
ID_HRM: { calc: () => hrmCurrent }
|
||||
};
|
||||
|
||||
|
|
@ -225,7 +232,7 @@ function drawSteps() {
|
|||
setSmallFont();
|
||||
g.setFontAlign(0,0);
|
||||
g.setColor(g.theme.fg);
|
||||
g.drawString('Steps ' + getSteps(), w/2, (3*h/4) - 4);
|
||||
g.drawString('STEPS ' + getSteps(), w/2, (3*h/4) - 4);
|
||||
drawingSteps = false;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
{ "id": "daisy",
|
||||
"name": "Daisy",
|
||||
"version":"0.05",
|
||||
"version":"0.06",
|
||||
"dependencies": {"mylocation":"app"},
|
||||
"description": "A clock based on the Pastel clock with large ring guage for steps",
|
||||
"description": "A beautiful digital clock with large ring guage, idle timer and a cyclic information line that includes, day, date, steps, battery, sunrise and sunset times",
|
||||
"icon": "app.png",
|
||||
"type": "clock",
|
||||
"tags": "clock",
|
||||
"supports" : ["BANGLEJS2"],
|
||||
"screenshots": [{"url":"screenshot_daisy2.jpg"}],
|
||||
"screenshots": [{"url":"screenshot_daisy3.png"}],
|
||||
"readme": "README.md",
|
||||
"storage": [
|
||||
{"name":"daisy.app.js","url":"app.js"},
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 4.7 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 3.2 KiB |
|
|
@ -1,9 +1,9 @@
|
|||
{
|
||||
"id": "doztime",
|
||||
"name": "Dozenal Time",
|
||||
"shortName": "Dozenal Time",
|
||||
"name": "Dozenal Digital Time",
|
||||
"shortName": "Dozenal Digital",
|
||||
"version": "0.05",
|
||||
"description": "A dozenal Holocene calendar and dozenal diurnal clock",
|
||||
"description": "A dozenal Holocene calendar and dozenal diurnal digital clock",
|
||||
"icon": "app.png",
|
||||
"type": "clock",
|
||||
"tags": "clock",
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
"type": "clock",
|
||||
"tags": "clock",
|
||||
"supports": ["BANGLEJS","BANGLEJS2"],
|
||||
"readme": "README.md",
|
||||
"allow_emulator": true,
|
||||
"storage": [
|
||||
{"name":"ffcniftyb.app.js","url":"app.js"},
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
"type": "clock",
|
||||
"tags": "clock",
|
||||
"supports": ["BANGLEJS","BANGLEJS2"],
|
||||
"readme": "README.md",
|
||||
"allow_emulator": true,
|
||||
"storage": [
|
||||
{"name":"floralclk.app.js","url":"app.js"},
|
||||
|
|
|
|||
|
|
@ -4,4 +4,6 @@
|
|||
0.04: Bug fix score reset after Game Over, new icon
|
||||
0.05: Chevron marker on the randomly added square
|
||||
0.06: Fixed issue 1609 added a message popup state handler to control unwanted screen redraw
|
||||
0.07: Optimized the mover algorithm for efficiency (work in progress)
|
||||
0.07: Optimized the mover algorithm for efficiency (work in progress)
|
||||
0.08: Bug fix at end of the game with victorious splash and glorious orchestra
|
||||
0.09: Added settings menu, removed symbol selection button (*), added highscore reset
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
|
||||
# Play the game of 1024
|
||||
|
||||
Move the tiles by swiping to the lefthand, righthand or up- and downward side of the watch.
|
||||
Move the tiles by swiping left, right, up- or downward over the watchface.
|
||||
|
||||
When two tiles with the same number are squashed together they will add up as exponentials:
|
||||
|
||||
|
|
@ -21,16 +21,28 @@ Use the side **BTN** to exit the game, score and tile positions will be saved.
|
|||
|
||||
## Buttons on the screen
|
||||
|
||||
- Button **U**: Undo the last move. There are currently a maximum of 4 undo levels. The level is indicated with a small number in the lower righthand corner of the Undo button
|
||||
- Button **\***: Change the text on the tile to number, capitals or Roman numbers
|
||||
- Button **R**: Reset the game. The Higscore will be remembered. You will be prompted first.
|
||||
- Button **U**: Undo the last move. There are currently a maximum of 9 undo levels. The level is indicated with a small number in the lower righthand corner of the Undo button
|
||||
- You can set the maximum undo level in the Apps settings menu.
|
||||
|
||||
- Button **R**: Reset the game. The Highscore will be remembered. You will be prompted first.
|
||||
- The highscore value can be reset in the Apps settings menu.
|
||||
|
||||
Apps setting: 
|
||||
|
||||
- Stuff you can change in de 1024 Game settings:
|
||||
- Symbols on the cells: numerical, alphabetical or Roman
|
||||
- Undo levels [0-9]
|
||||
- Exit: how to exit the game: long or short press
|
||||
- Debug mode: on or off. This will log all kinds of stuff in the console of the Web IDE
|
||||
- Reset Highsccore: Tired of looking at the old highscore? Now you can set it to 0 again.
|
||||
|
||||
### Credits
|
||||
|
||||
Game 1024 is based on Saming's 2048 and Misho M. Petkovic 1024game.org and conceptually similar to Threes by Asher Vollmer.
|
||||
|
||||
In Dark theme with numbers:
|
||||

|
||||

|
||||
|
||||
In Light theme with characters:
|
||||

|
||||

|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,21 @@
|
|||
const debugMode = 'off'; // valid values are: off, test, production, development
|
||||
let settings = Object.assign({
|
||||
// default values
|
||||
maxUndoLevels: 4,
|
||||
charIndex: 0,
|
||||
clockMode: true,
|
||||
debugMode: false,
|
||||
}, require('Storage').readJSON("game1024.settings.json", true) || {});
|
||||
|
||||
const clockMode = settings.clockMode!==undefined ? settings.clockMode : true;
|
||||
const debugMode = settings.debugMode!==undefined ? settings.debugMode : false; // #settings -- valid values are: true or false
|
||||
const maxUndoLevels = settings.maxUndoLevels!==undefined ? settings.maxUndoLevels : 4; // #settings
|
||||
const charIndex = settings.charIndex!==undefined ? settings.charIndex : 0; // #settings -- plain numbers on the grid
|
||||
|
||||
delete settings; // remove unneeded settings from memory
|
||||
|
||||
const middle = {x:Math.floor(g.getWidth()/2)-20, y: Math.floor(g.getHeight()/2)};
|
||||
const rows = 4, cols = 4;
|
||||
const borderWidth = 6;
|
||||
const rows = 4, cols = 4; // #settings
|
||||
const borderWidth = 6;
|
||||
const sqWidth = (Math.floor(Bangle.appRect.w - 48) / rows) - borderWidth;
|
||||
const cellColors = [{bg:'#00FFFF', fg: '#000000'},
|
||||
{bg:'#FF00FF', fg: '#000000'}, {bg:'#808000', fg: '#FFFFFF'}, {bg:'#0000FF', fg: '#FFFFFF'}, {bg:'#008000', fg: '#FFFFFF'},
|
||||
|
|
@ -13,12 +27,8 @@ const cellChars = [
|
|||
['0','A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J'],
|
||||
['0','I', 'II', 'III', 'IV', 'V', 'VI', 'VII','VIII', 'IX', 'X']
|
||||
];
|
||||
// const numInitialCells = 2;
|
||||
const maxUndoLevels = 4;
|
||||
const noExceptions = true;
|
||||
let charIndex = 0; // plain numbers on the grid
|
||||
const themeBg = g.theme.bg;
|
||||
|
||||
const themeBg = g.theme.bg;
|
||||
|
||||
const scores = {
|
||||
currentScore: 0,
|
||||
|
|
@ -78,12 +88,12 @@ const snapshot = {
|
|||
updCounter: function() {
|
||||
this.counter = ++this.counter > this.interval ? 0 : this.counter;
|
||||
},
|
||||
dump: {gridsize: rows * cols, expVals: [], score: 0, highScore: 0, charIndex: charIndex},
|
||||
dump: {gridsize: rows * cols, expVals: [], score: 0, highScore: 0},
|
||||
write: function() {
|
||||
require("Storage").writeJSON(this.snFileName, this.dump);
|
||||
},
|
||||
read: function () {
|
||||
let sn = require("Storage").readJSON(this.snFileName, noExceptions);
|
||||
let sn = require("Storage").readJSON(this.snFileName, true);
|
||||
if ((typeof sn == "undefined") || (sn.gridsize !== rows * cols)) {
|
||||
require("Storage").writeJSON(this.snFileName, this.dump);
|
||||
return false;
|
||||
|
|
@ -101,7 +111,6 @@ const snapshot = {
|
|||
});
|
||||
this.dump.score = scores.currentScore;
|
||||
this.dump.highScore = scores.highScore;
|
||||
this.dump.charIndex = charIndex;
|
||||
},
|
||||
make: function () {
|
||||
this.updCounter();
|
||||
|
|
@ -118,7 +127,7 @@ const snapshot = {
|
|||
});
|
||||
scores.currentScore = this.dump.score ? this.dump.score : 0;
|
||||
scores.highScore = this.dump.highScore ? this.dump.highScore : 0 ;
|
||||
charIndex = this.dump.charIndex ? this.dump.charIndex : 0 ;
|
||||
if (this.dump.hasOwnProperty('charIndex')) delete this.dump.charIndex; // depricated in v0.09
|
||||
}
|
||||
},
|
||||
reset: function () {
|
||||
|
|
@ -129,12 +138,11 @@ const snapshot = {
|
|||
}
|
||||
this.dump.score = 0;
|
||||
this.dump.highScore = scores.highScore;
|
||||
this.dump.charIndex = charIndex;
|
||||
this.write();
|
||||
debug(() => console.log("reset D U M P E D!", this.dump));
|
||||
}
|
||||
};
|
||||
const btnAtribs = {x: 134, w: 42, h: 42, fg:'#C0C0C0', bg:'#800000'};
|
||||
const btnAtribs = {x: 134, w: 42, h: 50, fg:'#C0C0C0', bg:'#800000'};
|
||||
const buttons = {
|
||||
all: [],
|
||||
draw: function () {
|
||||
|
|
@ -162,6 +170,7 @@ const buttons = {
|
|||
*/
|
||||
|
||||
const mover = {
|
||||
gameWon: false,
|
||||
direction: {
|
||||
up: {name: 'up', step: 1, innerBegin: 0, innerEnd: rows-1, outerBegin: 0, outerEnd: cols-1, iter: rows -1,
|
||||
sqIndex: function (i,o) {return i*(cols) + o;}, sqNextIndex: function (i,o) {return i < rows -1 ? (i+1)*(cols) + o : -1;}
|
||||
|
|
@ -313,7 +322,7 @@ class Cell {
|
|||
}
|
||||
drawBg() {
|
||||
debug(()=>console.log("Drawbg!!"));
|
||||
if (this.isRndm == true) {
|
||||
if (this.isRndm) {
|
||||
debug(()=>console.log('Random: (ax)', this.ax));
|
||||
g.setColor(this.getColor(this.expVal).bg)
|
||||
.fillRect(this.x0, this.y0, this.x1, this.y1)
|
||||
|
|
@ -364,7 +373,7 @@ class Cell {
|
|||
this.isRndm = true;
|
||||
}
|
||||
drawRndmIndicator(){
|
||||
if (this.isRndm == true) {
|
||||
if (this.isRndm) {
|
||||
debug(()=>console.log('Random: (ax)', this.ax));
|
||||
g.setColor(this.getColor(0).bg)
|
||||
.fillPoly(this.ax,this.ay,this.bx,this.by,this.cx,this.cy);
|
||||
|
|
@ -373,8 +382,9 @@ class Cell {
|
|||
}
|
||||
|
||||
function undoGame() {
|
||||
g.clear();
|
||||
if (scores.lastScores.length > 0) {
|
||||
|
||||
if (scores.lastScores.length) {
|
||||
g.clear();
|
||||
allSquares.forEach(sq => {
|
||||
sq.popFromUndo();
|
||||
sq.drawBg();
|
||||
|
|
@ -385,9 +395,9 @@ function undoGame() {
|
|||
buttons.draw();
|
||||
updUndoLvlIndex();
|
||||
snapshot.make();
|
||||
Bangle.loadWidgets();
|
||||
Bangle.drawWidgets();
|
||||
}
|
||||
Bangle.loadWidgets();
|
||||
Bangle.drawWidgets();
|
||||
}
|
||||
function addToUndo() {
|
||||
allSquares.forEach(sq => {
|
||||
|
|
@ -397,7 +407,7 @@ function addToUndo() {
|
|||
}
|
||||
function addToScore (val) {
|
||||
scores.add(val);
|
||||
if (val == 10) messageYouWin();
|
||||
if (val == 10) mover.gameWon = true;
|
||||
}
|
||||
function createGrid () {
|
||||
let cn =0;
|
||||
|
|
@ -421,15 +431,30 @@ function messageGameOver () {
|
|||
.drawString("O V E R !", middle.x+12, middle.y+25);
|
||||
}
|
||||
function messageYouWin () {
|
||||
g.setColor("#1a0d00")
|
||||
const c = (g.theme.dark) ? {"fg": "#FFFFFF", "bg": "#808080"} : {"fg": "#FF0000", "bg": "#000000"};
|
||||
g.setColor(c.bg)
|
||||
.setFont12x20(2)
|
||||
.setFontAlign(0,0,0)
|
||||
.drawString("YOU HAVE", middle.x+18, middle.y-24)
|
||||
.drawString("W O N ! !", middle.x+18, middle.y+24);
|
||||
g.setColor("#FF0808")
|
||||
g.setColor(c.fg)
|
||||
.drawString("YOU HAVE", middle.x+17, middle.y-25)
|
||||
.drawString("W O N ! !", middle.x+17, middle.y+25);
|
||||
Bangle.buzz(200, 1);
|
||||
for (let r=0;r<4;r++){
|
||||
Bangle.buzz(200,0.2)
|
||||
.then((result) => {
|
||||
Bangle.buzz(200,0.5)
|
||||
.then((result)=>{
|
||||
Bangle.buzz(200,0.8)
|
||||
.then((result)=>{
|
||||
Bangle.buzz(200,1)
|
||||
.then((result)=>{
|
||||
Bangle.buzz(500,0);
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
function makeRandomNumber () {
|
||||
return Math.ceil(2*Math.random());
|
||||
|
|
@ -471,8 +496,8 @@ function initGame() {
|
|||
drawGrid();
|
||||
scores.draw();
|
||||
buttons.draw();
|
||||
// Clock mode allows short-press on button to exit
|
||||
Bangle.setUI("clock");
|
||||
// #settings Clock mode allows short-press on button to exit
|
||||
if(clockMode) Bangle.setUI("clock");
|
||||
// Load widgets
|
||||
Bangle.loadWidgets();
|
||||
Bangle.drawWidgets();
|
||||
|
|
@ -491,8 +516,8 @@ function drawPopUp(message,cb) {
|
|||
rDims.x+10, rDims.y2-40
|
||||
]);
|
||||
buttons.all.forEach(btn => {btn.disable();});
|
||||
const btnYes = new Button('yes', rDims.x+16, rDims.y2-80, 54, btnAtribs.h, 'YES', btnAtribs.fg, btnAtribs.bg, cb, true);
|
||||
const btnNo = new Button('no', rDims.x2-80, rDims.y2-80, 54, btnAtribs.h, 'NO', btnAtribs.fg, btnAtribs.bg, cb, true);
|
||||
const btnYes = new Button('yes', rDims.x+16, rDims.y2-88, 54, btnAtribs.h, 'YES', btnAtribs.fg, btnAtribs.bg, cb, true);
|
||||
const btnNo = new Button('no', rDims.x2-80, rDims.y2-88, 54, btnAtribs.h, 'NO', btnAtribs.fg, btnAtribs.bg, cb, true);
|
||||
btnYes.draw();
|
||||
btnNo.draw();
|
||||
g.setColor('#000000');
|
||||
|
|
@ -527,6 +552,7 @@ function handlePopUpClicks(btn) {
|
|||
function resetGame() {
|
||||
g.clear();
|
||||
scores.reset();
|
||||
mover.gameWon=false;
|
||||
allSquares.forEach(sq => {sq.setExpVal(0);sq.removeUndo();sq.setRndmFalse();});
|
||||
addRandomNumber();
|
||||
addRandomNumber();
|
||||
|
|
@ -543,14 +569,8 @@ function resetGame() {
|
|||
* @param {function} func function to call like console.log()
|
||||
*/
|
||||
const debug = (func) => {
|
||||
switch (debugMode) {
|
||||
case "development":
|
||||
if (typeof func === 'function') {
|
||||
func();
|
||||
}
|
||||
break;
|
||||
case "off":
|
||||
default: break;
|
||||
if (debugMode) {
|
||||
if (typeof func === 'function') func();
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -653,6 +673,12 @@ function runGame(dir){
|
|||
debug(() => console.log("G A M E O V E R !!"));
|
||||
snapshot.reset();
|
||||
messageGameOver();
|
||||
} else {
|
||||
if (mover.gameWon) {
|
||||
debug(() => console.log("Y O U H A V E W O N !!"));
|
||||
snapshot.reset();
|
||||
messageYouWin();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -667,13 +693,9 @@ function updUndoLvlIndex() {
|
|||
.drawString(scores.lastScores.length, x, y);
|
||||
}
|
||||
}
|
||||
function incrCharIndex() {
|
||||
charIndex++;
|
||||
if (charIndex >= cellChars.length) charIndex = 0;
|
||||
drawGrid();
|
||||
}
|
||||
|
||||
buttons.add(new Button('undo', btnAtribs.x, 25, btnAtribs.w, btnAtribs.h, 'U', btnAtribs.fg, btnAtribs.bg, undoGame, true));
|
||||
buttons.add(new Button('chars', btnAtribs.x, 71, btnAtribs.w, 31, '*', btnAtribs.fg, btnAtribs.bg, function(){incrCharIndex();}, true));
|
||||
|
||||
buttons.add(new Button('restart', btnAtribs.x, 106, btnAtribs.w, btnAtribs.h, 'R', btnAtribs.fg, btnAtribs.bg, function(){drawPopUp('Do you want\nto restart?',handlePopUpClicks);}, true));
|
||||
|
||||
initGame();
|
||||
|
|
|
|||
|
After Width: | Height: | Size: 3.5 KiB |
|
Before Width: | Height: | Size: 4.3 KiB |
|
After Width: | Height: | Size: 3.8 KiB |
|
Before Width: | Height: | Size: 4.0 KiB |
|
After Width: | Height: | Size: 3.6 KiB |
|
|
@ -1,7 +1,7 @@
|
|||
{ "id": "game1024",
|
||||
"name": "1024 Game",
|
||||
"shortName" : "1024 Game",
|
||||
"version": "0.07",
|
||||
"version": "0.09",
|
||||
"icon": "game1024.png",
|
||||
"screenshots": [ {"url":"screenshot.png" } ],
|
||||
"readme":"README.md",
|
||||
|
|
@ -12,6 +12,7 @@
|
|||
"supports" : ["BANGLEJS2"],
|
||||
"storage": [
|
||||
{"name":"game1024.app.js","url":"app.js"},
|
||||
{"name":"game1024.settings.js","url":"settings.js"},
|
||||
{"name":"game1024.img","url":"app-icon.js","evaluate":true}
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 5.9 KiB After Width: | Height: | Size: 3.4 KiB |
|
|
@ -0,0 +1,70 @@
|
|||
(function(back) {
|
||||
var FILE = "game1024.settings.json";
|
||||
var scoreFile = "game1024.json";
|
||||
// Load settings
|
||||
var settings = Object.assign({
|
||||
maxUndoLevels: 5,
|
||||
charIndex: 0,
|
||||
clockMode: true,
|
||||
debugMode: false,
|
||||
}, require('Storage').readJSON(FILE, true) || {});
|
||||
|
||||
function writeSettings() {
|
||||
require('Storage').writeJSON(FILE, settings);
|
||||
}
|
||||
var symbols = ["1 2 3 ...", "A B C ...", "I II III..."];
|
||||
var settingsMenu = {
|
||||
"" : { "title" : "1024 Game" },
|
||||
"< Back" : () => back(),
|
||||
"Symbols": {
|
||||
value: 0|settings.charIndex,
|
||||
min:0,max:symbols.length-1,
|
||||
format: v=>symbols[v],
|
||||
onchange: v=> { settings.charIndex=v; writeSettings();}
|
||||
}
|
||||
,
|
||||
"Undo levels:": {
|
||||
value: 0|settings.maxUndoLevels, // 0| converts undefined to 0
|
||||
min: 0, max: 9,
|
||||
onchange: v => {
|
||||
settings.maxUndoLevels = v;
|
||||
writeSettings();
|
||||
}
|
||||
},
|
||||
"Exit press:": {
|
||||
value: !settings.debugMode, // ! converts undefined to true
|
||||
format: v => v?"short":"long",
|
||||
onchange: v => {
|
||||
settings.debugMode = v;
|
||||
writeSettings();
|
||||
},
|
||||
},
|
||||
"Debug mode:": {
|
||||
value: !!settings.debugMode, // !! converts undefined to false
|
||||
format: v => v?"On":"Off",
|
||||
onchange: v => {
|
||||
settings.debugMode = v;
|
||||
writeSettings();
|
||||
}
|
||||
},
|
||||
"Reset Highscore": () => {
|
||||
E.showPrompt('Reset Highscore?').then((v) => {
|
||||
let delay = 50;
|
||||
if (v) {
|
||||
delay = 500;
|
||||
let sF = require("Storage").readJSON(scoreFile, true);
|
||||
if (typeof sF !== "undefined") {
|
||||
E.showMessage('Resetting');
|
||||
sF.highScore = 0;
|
||||
require("Storage").writeJSON(scoreFile, sF);
|
||||
} else {
|
||||
E.showMessage('No highscore!');
|
||||
}
|
||||
}
|
||||
setTimeout(() => E.showMenu(settingsMenu), delay);
|
||||
});
|
||||
}
|
||||
}
|
||||
// Show the menu
|
||||
E.showMenu(settingsMenu);
|
||||
})
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
0.20: New App!
|
||||
|
||||
|
|
@ -0,0 +1,114 @@
|
|||
|
||||
Graphics.prototype.setFontLECO1976Regular42 = function(scale) {
|
||||
// Actual height 42 (41 - 0)
|
||||
g.setFontCustom(atob("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH/AAAAAAAAH/AAAAAAAAH/AAAAAAAAH/AAAAAAAAH/AAAAAAAAH/AAAAAAAAH/AAAAAAAAH/AAAAAAAAD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAAAAAA/AAAAAAAAH/AAAAAAAA//AAAAAAAP//AAAAAAB///AAAAAAP///AAAAAB////AAAAAf////AAAAD////4AAAAf////AAAAH////4AAAA////+AAAAA////wAAAAA///+AAAAAA///gAAAAAA//8AAAAAAA//gAAAAAAA/4AAAAAAAA/AAAAAAAAA4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAA/4AAAH/AAA/4AAAH/AAA/4AAAH/AAA/4AAAH/AAA/4AAAH/AAA/4AAAH/AAA/4AAAH/AAA/4AAAH/AAA/4AAAH/AAA/4AAAH/AAA/4AAAH/AAA/4AAAH/AAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/4AAAH/AAA/4AAAH/AAA/4AAAH/AAA/4AAAH/AAA/4AAAH/AAA/4AAAH/AAA/4AAAH/AAA/4AAAH/AAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAAAAAAAH/AAAAAAAAH/AAAAAAAAH/AAAAAAAAH/AAAAAAAAH/AAAAAAAAH/AAAAAAAAH/AAAAAAAAH/AAAAAAAAD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//h////AAA//h////AAA//h////AAA//h////AAA//h////AAA//h////AAA//h////AAA//h////AAA//h////AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA////wH/AAA////wH/AAA////wH/AAA////wH/AAA////wH/AAA////wH/AAA////wH/AAA////wH/AAA////gD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/4AAAH/AAA/4AAAH/AAA/4AAAH/AAA/4AAAH/AAA/4B/gH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////wAAAAA////wAAAAA////wAAAAA////wAAAAA////wAAAAA////wAAAAA////wAAAAA////wAAAAA////wAAAAAAAB/wAAAAAAAB/wAAAAAAAB/wAAAAAAAB/wAAAAAAAB/wAAAAAAAB/wAAAAAAAB/wAAAAAAAB/wAAAAAAAB/wAAAAAAAB/wAAAAAAAB/wAAAAAAAB/wAAAAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////x//AAA////x//AAA////x//AAA////x//AAA////x//AAA////x//AAA////x//AAA////x//AAA////x//AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B////AAA/4B////AAA/4B////AAA/4B////AAA/4B////AAA/4B////AAA/4B////AAA/4B////AAA/wB////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B////AAA/4B////AAA/4B////AAA/4B////AAA/4B////AAA/4B////AAA/4B////AAA/4B////AAA/wB////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//gAAAAAAA//gAAAAAAA//gAAAAAAA//gAAAAAAA//gAAAAAAA//gAAAAAAA//gAAAAAAA//gAAAAAAA//gAAAAAAA/4AAAAAAAA/4AAAAAAAA/4AAAAAAAA/4AAAAAAAA/4AAAAAAAA/4AAAAAAAA/4AAAAAAAA/4AAAAAAAA/4AAAAAAAA/4AAAAAAAA/4AAAAAAAA/4AAAAAAAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////wH/AAA////wH/AAA////wH/AAA////wH/AAA////wH/AAA////wH/AAA////wH/AAA////wH/AAA////wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP+AAH/AAAAP+AAH/AAAAP+AAH/AAAAP+AAH/AAAAP+AAH/AAAAP+AAH/AAAAP+AAH/AAAAP+AAH/AAAAH+AAD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"), 46, atob("ERkmHyYmJiYmJCYmEQ=="), 60+(scale<<8)+(1<<16));
|
||||
};
|
||||
|
||||
Graphics.prototype.setFontLECO1976Regular22 = function(scale) {
|
||||
// Actual height 22 (21 - 0)
|
||||
g.setFontCustom(atob("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAP/nA/+cD/5wP/nAAAAAAAAPwAA/gAD+AAPwAAAAAD+AAP4AA/gAAAAAAAAAAAAAcOAP//A//8D//wP//AHDgAcOAP//A//8D//wP//AHDgAAAAAAAAH/jgf+OB/44H/jj8OP/w4//Dj/8OPxw/4HD/gcP+Bw/4AAAAAAAP+AA/8AD/wQOHHA4c8D//wP/8A//gAD4AAfAAH/8A//wP//A84cDjhwIP/AA/8AB/wAAAAAAAD//wP//A//8D//wOHHA4ccDhxwOHHA4f8Dh/wOH/A4f8ABwAAAAAAAAD8AAP4AA/gAD8AAAAAAAAAAAEAAD+AB//A///v/D//gB/wABwAAAAAADgAA/wAf/4P8///wf/4AP8AAOAAAAAAAAAyAAHcAAPwAD/gAP/AA/8AA/AAH8AAMwAAAAAAAAAAAAADgAAOAAA4AAf8AD/wAP/AA/8AAOAAA4AADgAAAAAAAAAAD8AAfwAB/AAD8AAAAAAAADgAAOAAA4AADgAAOAAA4AADgAAAAAAAAAADgAAOAAA4AADgAAAAAAAAABwAB/AA/8A//gP/gA/wADwAAIAAAAAAD//wP//A//8D//wOAHA4AcDgBwOAHA//8D//wP//A//8AAAAAAAA4AcDgBwOAHA//8D//wP//A//8AABwAAHAAAcAAAAAAAA+f8D5/wPn/A+f8DhxwOHHA4ccDhxwP/HA/8cD/xwP/HAAAAAAAAOAHA4AcDhxwOHHA4ccDhxwOHHA4ccD//wP//A//8D//wAAAAAAAD/wAP/AA/8AD/wAAHAAAcAABwAAHAA//8D//wP//A//8AAAAAAAA/98D/3wP/fA/98DhxwOHHA4ccDhxwOH/A4f8Dh/wOH/AAAAAAAAP//A//8D//wP//A4ccDhxwOHHA4ccDh/wOH/A4f8Dh/wAAAAAAAD4AAPgAA+AADgAAOAAA4AADgAAP//A//8D//wP//AAAAAAAAP//A//8D//wP//A4ccDhxwOHHA4ccD//wP//A//8D//wAAAAAAAD/xwP/HA/8cD/xwOHHA4ccDhxwOHHA//8D//wP//A//8AAAAAAAAOA4A4DgDgOAOA4AAAAAAAAOA/A4H8DgfwOA/AAAAAAAAB4AAPwAA/AAD8AAf4ABzgAPPAA8cAHh4AAAAAAAAAAAAHHAAccABxwAHHAAccABxwAHHAAccABxwAHHAAAAAAAAAOHAA4cADzwAPPAAf4AB/gAD8AAPwAAeAAB4AAAAAAAAA+AAD4AAPgAA+ecDh9wOH3A4fcDhwAP/AA/8AD/wAP/AAAAAAAAAP//4///j//+P//44ADjn/OOf845/zjnHOP8c4//zj//OP/84AAAAAAAP//A//8D//wP//A4cADhwAOHAA4cAD//wP//A//8D//wAAAAAAAD//wP//A//8D//wOHHA4ccDhxwOHHA//8D//wP9/A/j8AAAAAAAA//8D//wP//A//8DgBwOAHA4AcDgBwOAHA4AcDgBwOAHAAAAAAAAP//A//8D//wP//A4AcDgBwOAHA8A8D//wH/+AP/wAf+AAAAAAAAD//wP//A//8D//wOHHA4ccDhxwOHHA4ccDhxwOAHA4AcAAAAAAAA//8D//wP//A//8DhwAOHAA4cADhwAOHAA4cADgAAOAAAAAAD//wP//A//8D//wOAHA4ccDhxwOHHA4f8Dh/wOH/A4f8AAAAAAAA//8D//wP//A//8ABwAAHAAAcAABwAP//A//8D//wP//AAAAAAAAP//A//8D//wP//AAAAAAAAOAHA4AcDgBwOAHA4AcDgBwOAHA//8D//wP//A//8AAAAAAAA//8D//wP//A//8AHwAA/AAP8AB/wAPn/A8f8DB/wIH/AAAAAAAAP//A//8D//wP//AAAcAABwAAHAAAcAABwAAHAAAAAAAAP//A//8D//wP//Af8AAP+AAH/AAD8AAHwAD/AB/wAf8AP+AA//8D//wP//AAAAAAAAP//A//8D//wP//AfwAAfwAAfwAAfwAAfwP//A//8D//wAAAAAAAAAAAP//A//8D//wP//A4AcDgBwOAHA4AcD//wP//A//8D//wAAAAAAAD//wP//A//8D//wOHAA4cADhwAOHAA/8AD/wAP/AA/8AAAAAP//A//8D//wP//A4AcDgBwOAHA4AcD//+P//4///j//+AAA4AADgAAAP//A//8D//wP//A4eADh+AOH8A4f4D/3wP/HA/8MD/wQAAAAAAAD/xwP/HA/8cD/xwOHHA4ccDhxwOHHA4f8Dh/wOH/A4f8AAAAAAAA4AADgAAOAAA//8D//wP//A//8DgAAOAAA4AADgAAAAAA//8D//wP//A//8AABwAAHAAAcAABwP//A//8D//wP//AAAADAAAPgAA/wAD/4AB/8AA/8AAfwAB/AA/8Af+AP/AA/wAD4AAMAAA4AAD+AAP/gA//8AH/wAB/AAf8Af/wP/4A/4AD/gAP/4AH/8AB/wAB/AB/8D//wP/gA/gADgAAIABA4AcDwDwPw/Afn4Af+AA/wAD/AA//AH5+A/D8DwDwOAHAgAEAAAAP/AA/8AD/wAP/AAAf8AB/wAH/AAf8D/wAP/AA/8AD/wAAAAAAAADh/wOH/A4f8Dh/wOHHA4ccDhxwOHHA/8cD/xwP/HA/8cAAAAAAAAf//9///3///f//9wAA3AADcAAMAAAOAAA/gAD/wAH/8AB/8AA/wAAPAAAEAAAAHAADcAANwAB3///f//9///wAA"), 32, atob("BwYLDg4UDwYJCQwMBgkGCQ4MDg4ODg4NDg4GBgwMDA4PDg4ODg4NDg4GDQ4MEg8ODQ8ODgwODhQODg4ICQg="), 22+(scale<<8)+(1<<16));
|
||||
};
|
||||
|
||||
|
||||
require("Font7x11Numeric7Seg").add(Graphics);
|
||||
|
||||
|
||||
var temperature = 13;
|
||||
|
||||
//the following 2 sections are used from waveclk to schedule minutely updates
|
||||
// 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 drawBackground() {
|
||||
g.setBgColor(0,0,0);
|
||||
g.setColor(1,1,1);
|
||||
g.clear();
|
||||
}
|
||||
|
||||
function digit(num){
|
||||
return String.fromCharCode(num + 48);
|
||||
}
|
||||
function timeString(h, m){
|
||||
return digit(h/10) + digit(h%10) + ":" + digit(m/10) + digit(m%10);
|
||||
}
|
||||
function dayString(w){
|
||||
return digit(w/10) + digit(w%10);
|
||||
}
|
||||
|
||||
function getSteps() {
|
||||
if (WIDGETS.wpedom !== undefined) {
|
||||
return WIDGETS.wpedom.getSteps();
|
||||
}
|
||||
return '????';
|
||||
}
|
||||
|
||||
|
||||
|
||||
function draw(){
|
||||
drawBackground();
|
||||
var date = new Date();
|
||||
var h = date.getHours(), m = date.getMinutes();
|
||||
var d = date.getDate(), w = date.getDay();
|
||||
|
||||
g.setBgColor(0,0,0);
|
||||
g.setColor(1,1,1);
|
||||
|
||||
|
||||
// g.setFont('Vector', 30);
|
||||
// g.setFont("7x11Numeric7Seg", 5);
|
||||
g.setFontLECO1976Regular42();
|
||||
g.setFontAlign(0, -1);
|
||||
g.drawString(timeString(h, m), g.getWidth()/2,28);
|
||||
g.drawString(dayString(w), g.getWidth()*3/4,88);
|
||||
g.setColor(0,1,0);
|
||||
g.fillRect(0,76,g.getWidth(), 80);
|
||||
g.reset();
|
||||
|
||||
// Steps
|
||||
g.setFontLECO1976Regular22();
|
||||
g.setFontAlign(-1, -1);
|
||||
g.drawString(getSteps(), 8, 88);
|
||||
|
||||
// g.drawString(temperature, 4, 108);
|
||||
|
||||
|
||||
// widget redraw
|
||||
Bangle.drawWidgets();
|
||||
queueDraw();
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////
|
||||
// Bangle.setBarometerPower(true);
|
||||
|
||||
Bangle.loadWidgets();
|
||||
draw();
|
||||
|
||||
|
||||
// Bangle.on('pressure', function(e){
|
||||
// temperature = e.temperature;
|
||||
// draw();
|
||||
// });
|
||||
|
||||
//the following section is also from waveclk
|
||||
Bangle.on('lcdPower',on=>{
|
||||
if (on) {
|
||||
draw(); // draw immediately, queue redraw
|
||||
} else { // stop draw timer
|
||||
if (drawTimeout) clearTimeout(drawTimeout);
|
||||
drawTimeout = undefined;
|
||||
}
|
||||
});
|
||||
|
||||
Bangle.setUI("clock");
|
||||
|
||||
Bangle.drawWidgets();
|
||||
|
|
@ -0,0 +1,202 @@
|
|||
Graphics.prototype.setFontLECO1976Regular42 = function (scale) {
|
||||
// Actual height 42 (41 - 0)
|
||||
g.setFontCustom(atob("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH/AAAAAAAAH/AAAAAAAAH/AAAAAAAAH/AAAAAAAAH/AAAAAAAAH/AAAAAAAAH/AAAAAAAAH/AAAAAAAAD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAAAAAA/AAAAAAAAH/AAAAAAAA//AAAAAAAP//AAAAAAB///AAAAAAP///AAAAAB////AAAAAf////AAAAD////4AAAAf////AAAAH////4AAAA////+AAAAA////wAAAAA///+AAAAAA///gAAAAAA//8AAAAAAA//gAAAAAAA/4AAAAAAAA/AAAAAAAAA4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAA/4AAAH/AAA/4AAAH/AAA/4AAAH/AAA/4AAAH/AAA/4AAAH/AAA/4AAAH/AAA/4AAAH/AAA/4AAAH/AAA/4AAAH/AAA/4AAAH/AAA/4AAAH/AAA/4AAAH/AAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/4AAAH/AAA/4AAAH/AAA/4AAAH/AAA/4AAAH/AAA/4AAAH/AAA/4AAAH/AAA/4AAAH/AAA/4AAAH/AAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAAAAAAAH/AAAAAAAAH/AAAAAAAAH/AAAAAAAAH/AAAAAAAAH/AAAAAAAAH/AAAAAAAAH/AAAAAAAAH/AAAAAAAAD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//h////AAA//h////AAA//h////AAA//h////AAA//h////AAA//h////AAA//h////AAA//h////AAA//h////AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA////wH/AAA////wH/AAA////wH/AAA////wH/AAA////wH/AAA////wH/AAA////wH/AAA////wH/AAA////gD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/4AAAH/AAA/4AAAH/AAA/4AAAH/AAA/4AAAH/AAA/4B/gH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////wAAAAA////wAAAAA////wAAAAA////wAAAAA////wAAAAA////wAAAAA////wAAAAA////wAAAAA////wAAAAAAAB/wAAAAAAAB/wAAAAAAAB/wAAAAAAAB/wAAAAAAAB/wAAAAAAAB/wAAAAAAAB/wAAAAAAAB/wAAAAAAAB/wAAAAAAAB/wAAAAAAAB/wAAAAAAAB/wAAAAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////x//AAA////x//AAA////x//AAA////x//AAA////x//AAA////x//AAA////x//AAA////x//AAA////x//AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B////AAA/4B////AAA/4B////AAA/4B////AAA/4B////AAA/4B////AAA/4B////AAA/4B////AAA/wB////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B////AAA/4B////AAA/4B////AAA/4B////AAA/4B////AAA/4B////AAA/4B////AAA/4B////AAA/wB////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//gAAAAAAA//gAAAAAAA//gAAAAAAA//gAAAAAAA//gAAAAAAA//gAAAAAAA//gAAAAAAA//gAAAAAAA//gAAAAAAA/4AAAAAAAA/4AAAAAAAA/4AAAAAAAA/4AAAAAAAA/4AAAAAAAA/4AAAAAAAA/4AAAAAAAA/4AAAAAAAA/4AAAAAAAA/4AAAAAAAA/4AAAAAAAA/4AAAAAAAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////wH/AAA////wH/AAA////wH/AAA////wH/AAA////wH/AAA////wH/AAA////wH/AAA////wH/AAA////wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA/4B/wH/AAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAA///////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP+AAH/AAAAP+AAH/AAAAP+AAH/AAAAP+AAH/AAAAP+AAH/AAAAP+AAH/AAAAP+AAH/AAAAP+AAH/AAAAH+AAD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"), 46, atob("ERkmHyYmJiYmJCYmEQ=="), 60 + (scale << 8) + (1 << 16));
|
||||
};
|
||||
|
||||
Graphics.prototype.setFontLECO1976Regular22 = function (scale) {
|
||||
// Actual height 22 (21 - 0)
|
||||
g.setFontCustom(atob("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAP/nA/+cD/5wP/nAAAAAAAAPwAA/gAD+AAPwAAAAAD+AAP4AA/gAAAAAAAAAAAAAcOAP//A//8D//wP//AHDgAcOAP//A//8D//wP//AHDgAAAAAAAAH/jgf+OB/44H/jj8OP/w4//Dj/8OPxw/4HD/gcP+Bw/4AAAAAAAP+AA/8AD/wQOHHA4c8D//wP/8A//gAD4AAfAAH/8A//wP//A84cDjhwIP/AA/8AB/wAAAAAAAD//wP//A//8D//wOHHA4ccDhxwOHHA4f8Dh/wOH/A4f8ABwAAAAAAAAD8AAP4AA/gAD8AAAAAAAAAAAEAAD+AB//A///v/D//gB/wABwAAAAAADgAA/wAf/4P8///wf/4AP8AAOAAAAAAAAAyAAHcAAPwAD/gAP/AA/8AA/AAH8AAMwAAAAAAAAAAAAADgAAOAAA4AAf8AD/wAP/AA/8AAOAAA4AADgAAAAAAAAAAD8AAfwAB/AAD8AAAAAAAADgAAOAAA4AADgAAOAAA4AADgAAAAAAAAAADgAAOAAA4AADgAAAAAAAAABwAB/AA/8A//gP/gA/wADwAAIAAAAAAD//wP//A//8D//wOAHA4AcDgBwOAHA//8D//wP//A//8AAAAAAAA4AcDgBwOAHA//8D//wP//A//8AABwAAHAAAcAAAAAAAA+f8D5/wPn/A+f8DhxwOHHA4ccDhxwP/HA/8cD/xwP/HAAAAAAAAOAHA4AcDhxwOHHA4ccDhxwOHHA4ccD//wP//A//8D//wAAAAAAAD/wAP/AA/8AD/wAAHAAAcAABwAAHAA//8D//wP//A//8AAAAAAAA/98D/3wP/fA/98DhxwOHHA4ccDhxwOH/A4f8Dh/wOH/AAAAAAAAP//A//8D//wP//A4ccDhxwOHHA4ccDh/wOH/A4f8Dh/wAAAAAAAD4AAPgAA+AADgAAOAAA4AADgAAP//A//8D//wP//AAAAAAAAP//A//8D//wP//A4ccDhxwOHHA4ccD//wP//A//8D//wAAAAAAAD/xwP/HA/8cD/xwOHHA4ccDhxwOHHA//8D//wP//A//8AAAAAAAAOA4A4DgDgOAOA4AAAAAAAAOA/A4H8DgfwOA/AAAAAAAAB4AAPwAA/AAD8AAf4ABzgAPPAA8cAHh4AAAAAAAAAAAAHHAAccABxwAHHAAccABxwAHHAAccABxwAHHAAAAAAAAAOHAA4cADzwAPPAAf4AB/gAD8AAPwAAeAAB4AAAAAAAAA+AAD4AAPgAA+ecDh9wOH3A4fcDhwAP/AA/8AD/wAP/AAAAAAAAAP//4///j//+P//44ADjn/OOf845/zjnHOP8c4//zj//OP/84AAAAAAAP//A//8D//wP//A4cADhwAOHAA4cAD//wP//A//8D//wAAAAAAAD//wP//A//8D//wOHHA4ccDhxwOHHA//8D//wP9/A/j8AAAAAAAA//8D//wP//A//8DgBwOAHA4AcDgBwOAHA4AcDgBwOAHAAAAAAAAP//A//8D//wP//A4AcDgBwOAHA8A8D//wH/+AP/wAf+AAAAAAAAD//wP//A//8D//wOHHA4ccDhxwOHHA4ccDhxwOAHA4AcAAAAAAAA//8D//wP//A//8DhwAOHAA4cADhwAOHAA4cADgAAOAAAAAAD//wP//A//8D//wOAHA4ccDhxwOHHA4f8Dh/wOH/A4f8AAAAAAAA//8D//wP//A//8ABwAAHAAAcAABwAP//A//8D//wP//AAAAAAAAP//A//8D//wP//AAAAAAAAOAHA4AcDgBwOAHA4AcDgBwOAHA//8D//wP//A//8AAAAAAAA//8D//wP//A//8AHwAA/AAP8AB/wAPn/A8f8DB/wIH/AAAAAAAAP//A//8D//wP//AAAcAABwAAHAAAcAABwAAHAAAAAAAAP//A//8D//wP//Af8AAP+AAH/AAD8AAHwAD/AB/wAf8AP+AA//8D//wP//AAAAAAAAP//A//8D//wP//AfwAAfwAAfwAAfwAAfwP//A//8D//wAAAAAAAAAAAP//A//8D//wP//A4AcDgBwOAHA4AcD//wP//A//8D//wAAAAAAAD//wP//A//8D//wOHAA4cADhwAOHAA/8AD/wAP/AA/8AAAAAP//A//8D//wP//A4AcDgBwOAHA4AcD//+P//4///j//+AAA4AADgAAAP//A//8D//wP//A4eADh+AOH8A4f4D/3wP/HA/8MD/wQAAAAAAAD/xwP/HA/8cD/xwOHHA4ccDhxwOHHA4f8Dh/wOH/A4f8AAAAAAAA4AADgAAOAAA//8D//wP//A//8DgAAOAAA4AADgAAAAAA//8D//wP//A//8AABwAAHAAAcAABwP//A//8D//wP//AAAADAAAPgAA/wAD/4AB/8AA/8AAfwAB/AA/8Af+AP/AA/wAD4AAMAAA4AAD+AAP/gA//8AH/wAB/AAf8Af/wP/4A/4AD/gAP/4AH/8AB/wAB/AB/8D//wP/gA/gADgAAIABA4AcDwDwPw/Afn4Af+AA/wAD/AA//AH5+A/D8DwDwOAHAgAEAAAAP/AA/8AD/wAP/AAAf8AB/wAH/AAf8D/wAP/AA/8AD/wAAAAAAAADh/wOH/A4f8Dh/wOHHA4ccDhxwOHHA/8cD/xwP/HA/8cAAAAAAAAf//9///3///f//9wAA3AADcAAMAAAOAAA/gAD/wAH/8AB/8AA/wAAPAAAEAAAAHAADcAANwAB3///f//9///wAA"), 32, atob("BwYLDg4UDwYJCQwMBgkGCQ4MDg4ODg4NDg4GBgwMDA4PDg4ODg4NDg4GDQ4MEg8ODQ8ODgwODhQODg4ICQg="), 22 + (scale << 8) + (1 << 16));
|
||||
};
|
||||
|
||||
|
||||
require("Font7x11Numeric7Seg").add(Graphics);
|
||||
|
||||
|
||||
// the following 2 sections are used from waveclk to schedule minutely updates
|
||||
// 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 drawBackground() {
|
||||
g.setBgColor(0, 0, 0);
|
||||
g.setColor(1, 1, 1);
|
||||
g.clear();
|
||||
}
|
||||
|
||||
function digit(num) {
|
||||
return String.fromCharCode(num + 48);
|
||||
}
|
||||
|
||||
function timeString(h, m) {
|
||||
return digit(h / 10) + digit(h % 10) + ":" + digit(m / 10) + digit(m % 10);
|
||||
}
|
||||
|
||||
function dayString(w) {
|
||||
return digit(w / 10) + digit(w % 10);
|
||||
}
|
||||
|
||||
function getSteps() {
|
||||
if (WIDGETS.wpedom !== undefined) {
|
||||
return WIDGETS.wpedom.getSteps();
|
||||
}
|
||||
return '????';
|
||||
}
|
||||
|
||||
/**
|
||||
* draws calender week view (-1,0,1) for given date
|
||||
*/
|
||||
function drawCal() {
|
||||
d = /*this.date ? this.date : */ new Date();
|
||||
|
||||
const DAY_NAME_FONT_SIZE = 10;
|
||||
const CAL_Y = g.getHeight() - 44; // Bangle.appRect.y+this.DATE_FONT_SIZE()+10+this.TIME_FONT_SIZE()+3;
|
||||
const CAL_AREA_H = 44; // g.getHeight()-CAL_Y+24; //+24: top widgtes only
|
||||
const CELL_W = g.getWidth() / 7; //cell width
|
||||
const CELL_H = (CAL_AREA_H - DAY_NAME_FONT_SIZE) / 3; //cell heigth
|
||||
const DAY_NUM_FONT_SIZE = Math.min(CELL_H + 3, 15); //size down, max 15
|
||||
|
||||
const wdStrt = 1;
|
||||
|
||||
const ABR_DAY = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
|
||||
const IS_SUNDAY = [1, 0, 0, 0, 0, 1, 1]; // what days are sunday?
|
||||
const nrgb = ["#000", "#FFF", "#F00", "#0F0", "#00F", "#FF0"]; //fg, r ,g , b
|
||||
const suClr = 5; // sunday color fg
|
||||
const tdyMrkClr = 3; // today bk
|
||||
const tdyNumClr = 0; // today fg
|
||||
|
||||
g.setFont("Vector", DAY_NAME_FONT_SIZE + 3);
|
||||
g.setColor(nrgb[1]);
|
||||
g.setFontAlign(-1, -1);
|
||||
// g.clearRect(Bangle.appRect.x, CAL_Y, Bangle.appRect.x2, CAL_Y+CAL_AREA_H);
|
||||
|
||||
//draw grid & Headline
|
||||
const dNames = ABR_DAY.map((a) => a.length <= 2 ? a : a.substr(0, 2)); //force shrt 2
|
||||
for (var dNo = 0; dNo < dNames.length; dNo++) {
|
||||
const dIdx = wdStrt >= 0 ? ((wdStrt + dNo) % 7) : ((dNo + d.getDay() + 4) % 7);
|
||||
const dName = dNames[dIdx];
|
||||
// if(dNo>0) { g.drawLine(dNo*CELL_W, CAL_Y, dNo*CELL_W, CAL_Y+CAL_AREA_H-1);}
|
||||
|
||||
|
||||
var colTx = 0;
|
||||
var colBk = 1;
|
||||
if (IS_SUNDAY[dIdx]) {
|
||||
colBk = suClr;
|
||||
}
|
||||
|
||||
g.setColor(nrgb[colBk]);
|
||||
g.fillRect(dNo * CELL_W, CAL_Y, dNo * CELL_W + CELL_W, CAL_Y + DAY_NAME_FONT_SIZE - 1);
|
||||
g.setColor(nrgb[colTx]);
|
||||
g.drawString(dName, dNo * CELL_W + (CELL_W - g.stringWidth(dName)) / 2 + 2, CAL_Y - 1);
|
||||
// g.setColor(nrgb[clTxt]);
|
||||
}
|
||||
g.setColor(nrgb[1]);
|
||||
var nextY = CAL_Y + DAY_NAME_FONT_SIZE;
|
||||
|
||||
// horizontal lines
|
||||
// for(i=0; i<3; i++){ const y=nextY+i*CELL_H; g.drawLine(Bangle.appRect.x, y, Bangle.appRect.x2, y); }
|
||||
|
||||
g.setFont("Vector", DAY_NUM_FONT_SIZE);
|
||||
|
||||
g.setFont("7x11Numeric7Seg", 1);
|
||||
|
||||
//write days
|
||||
const tdyDate = d.getDate();
|
||||
const days = wdStrt >= 0 ? 7 + ((7 + d.getDay() - wdStrt) % 7) : 10; //start day (week before=7 days + days in this week realtive to week start) or fixed 7+3 days
|
||||
var rD = new Date(d.getTime());
|
||||
rD.setDate(rD.getDate() - days);
|
||||
var rDate = rD.getDate();
|
||||
for (var y = 0; y < 3; y++) {
|
||||
for (var x = 0; x < dNames.length; x++) {
|
||||
if (rDate === tdyDate) { //today
|
||||
g.setColor(nrgb[tdyMrkClr]); //today marker color or fg color
|
||||
|
||||
// rectangle
|
||||
g.fillRect(x * CELL_W, nextY + CELL_H - 1, x * CELL_W + CELL_W, nextY + CELL_H + CELL_H - 1);
|
||||
g.setColor(nrgb[tdyNumClr]); //today color or fg color
|
||||
|
||||
// simulate "bold"
|
||||
g.drawString(rDate, 1 + x * CELL_W + ((CELL_W - g.stringWidth(rDate)) / 2) + 2, nextY + ((CELL_H - DAY_NUM_FONT_SIZE + 2) / 2) + (CELL_H * y));
|
||||
|
||||
} else if (IS_SUNDAY[rD.getDay()]) { //sundays
|
||||
g.setColor(nrgb[suClr]);
|
||||
} else { //default
|
||||
g.setColor(nrgb[1]);
|
||||
}
|
||||
g.drawString(rDate, x * CELL_W + ((CELL_W - g.stringWidth(rDate)) / 2) + 2, nextY + ((CELL_H - DAY_NUM_FONT_SIZE + 2) / 2) + (CELL_H * y));
|
||||
rD.setDate(rDate + 1);
|
||||
rDate = rD.getDate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function draw() {
|
||||
g.reset();
|
||||
drawBackground();
|
||||
var date = new Date();
|
||||
var h = date.getHours(),
|
||||
m = date.getMinutes();
|
||||
var d = date.getDate(),
|
||||
w = date.getDay(); // d=1..31; w=0..6
|
||||
|
||||
g.setBgColor(0, 0, 0);
|
||||
g.setColor(1, 1, 1);
|
||||
|
||||
|
||||
// g.setFont('Vector', 30);
|
||||
// g.setFont("7x11Numeric7Seg", 5);
|
||||
g.setFontLECO1976Regular42();
|
||||
g.setFontAlign(0, -1);
|
||||
g.drawString(timeString(h, m), g.getWidth() / 2, 28);
|
||||
g.drawString(dayString(d), g.getWidth() * 3 / 4, 88);
|
||||
g.setColor(0, 1, 0);
|
||||
g.fillRect(0, 76, g.getWidth(), 80);
|
||||
g.reset();
|
||||
|
||||
// Steps
|
||||
g.setFontLECO1976Regular22();
|
||||
g.setFontAlign(-1, -1);
|
||||
g.drawString(getSteps(), 8, 88);
|
||||
|
||||
drawCal();
|
||||
|
||||
|
||||
// widget redraw
|
||||
Bangle.drawWidgets();
|
||||
queueDraw();
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////
|
||||
// Bangle.setBarometerPower(true);
|
||||
|
||||
Bangle.loadWidgets();
|
||||
draw();
|
||||
|
||||
|
||||
// Bangle.on('pressure', function(e){
|
||||
// temperature = e.temperature;
|
||||
// draw();
|
||||
// });
|
||||
|
||||
//the following section is also from waveclk
|
||||
Bangle.on('lcdPower', on => {
|
||||
if (on) {
|
||||
draw(); // draw immediately, queue redraw
|
||||
} else { // stop draw timer
|
||||
if (drawTimeout) clearTimeout(drawTimeout);
|
||||
drawTimeout = undefined;
|
||||
}
|
||||
});
|
||||
|
||||
Bangle.setUI("clock");
|
||||
|
||||
Bangle.drawWidgets();
|
||||
|
|
@ -0,0 +1 @@
|
|||
require("heatshrink").decompress(atob("mEw4UA///ssp4XthFCBwUBqoABqAaGBZcFBZdX1W1qgLHrwLKqv/6oLJAAILHioLJn5qBAAYLEBQoLeHQQABv4LjGAgLYq2qAAOlBbBHFBdPAKcQLdWcb7jAAoLcn4LKgEVHQVUBQsAgoLLq//6oLIr2q2oXJBZQvCqALGgILTA="))
|
||||
|
After Width: | Height: | Size: 2.6 KiB |
|
After Width: | Height: | Size: 1.3 KiB |
|
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"id": "glbasic",
|
||||
"name": "GLBasic Clock",
|
||||
"shortName": "GLBasic",
|
||||
"version": "0.20",
|
||||
"description": "A clock with large numbers",
|
||||
"dependencies": {"widpedom":"app"},
|
||||
"icon": "icon48.png",
|
||||
"screenshots": [{"url":"glbasic_screenshot.png"}],
|
||||
"type": "clock",
|
||||
"tags": "clock",
|
||||
"supports": ["BANGLEJS", "BANGLEJS2"],
|
||||
"storage": [
|
||||
{"name":"glbasic.app.js","url":"glbasic.app.js"},
|
||||
{"name":"glbasic.img","url":"glbasic.icon.js","evaluate":true}
|
||||
]
|
||||
}
|
||||
|
|
@ -8,6 +8,7 @@
|
|||
"tags": "clock",
|
||||
"screenshots": [{"url":"bangle1-high-contrast-clock-screenshot.png"}],
|
||||
"supports": ["BANGLEJS"],
|
||||
"readme": "README.md",
|
||||
"allow_emulator": true,
|
||||
"storage": [
|
||||
{"name":"hcclock.app.js","url":"hcclock.app.js"},
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
"type": "clock",
|
||||
"tags": "clock",
|
||||
"supports": ["BANGLEJS","BANGLEJS2"],
|
||||
"readme": "README.md",
|
||||
"screenshots": [{"url":"bangle1-impercise-word-clock-screenshot.png"}],
|
||||
"allow_emulator": true,
|
||||
"storage": [
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
"type": "clock",
|
||||
"tags": "clock",
|
||||
"supports": ["BANGLEJS","BANGLEJS2"],
|
||||
"readme": "README.md",
|
||||
"allow_emulator": true,
|
||||
"storage": [
|
||||
{"name":"intclock.app.js","url":"app.js"},
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
"icon": "intervals.png",
|
||||
"tags": "",
|
||||
"supports": ["BANGLEJS"],
|
||||
"readme": "README.md",
|
||||
"storage": [
|
||||
{"name":"intervals.app.js","url":"intervals.app.js"},
|
||||
{"name":"intervals.img","url":"intervals-icon.js","evaluate":true}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
"tags": "tool,system,ios,apple,messages,notifications",
|
||||
"dependencies": {"messages":"app"},
|
||||
"supports": ["BANGLEJS","BANGLEJS2"],
|
||||
"readme": "README.md",
|
||||
"storage": [
|
||||
{"name":"ios.app.js","url":"app.js"},
|
||||
{"name":"ios.img","url":"app-icon.js","evaluate":true},
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
0.01: New App!
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
# Swipe Keyboard
|
||||
|
||||
A library that provides the ability to input text by swiping PalmOS Graffiti-style characters onto the screen.
|
||||
|
||||
To get a legend of available characters, just tap the screen.
|
||||
|
||||
|
||||
## Usage
|
||||
|
||||
In your app's metadata, add:
|
||||
|
||||
```
|
||||
"dependencies": {"textinput":"type"},
|
||||
```
|
||||
|
||||
From inside your app, call:
|
||||
|
||||
```
|
||||
Bangle.loadWidgets();
|
||||
Bangle.drawWidgets();
|
||||
require("textinput").input({text:"Foo"}).then(result => {
|
||||
console.log("Text input", E.toJS(result));
|
||||
});
|
||||
```
|
||||
|
||||
The first argument to `input` is an object containing the following:
|
||||
|
||||
* `text` - initial text to edit
|
||||
|
||||
(in the future, the ability to restrict usage of newline/etc may be added)
|
||||
|
||||
## Make your own
|
||||
|
||||
You can create your own keyboard input apps. Just ensure that they have
|
||||
`"type":"textinput",` in their metadata and provide a library called `textinput`
|
||||
that exports an `input` method.
|
||||
|
After Width: | Height: | Size: 2.0 KiB |
|
|
@ -0,0 +1,110 @@
|
|||
/* To make your own strokes, type:
|
||||
|
||||
Bangle.on('stroke',print)
|
||||
|
||||
on the left of the IDE, then do a stroke and copy out the Uint8Array line
|
||||
*/
|
||||
exports.getStrokes = function(cb) {
|
||||
cb("a", new Uint8Array([58, 159, 58, 155, 62, 144, 69, 127, 77, 106, 86, 90, 94, 77, 101, 68, 108, 62, 114, 59, 121, 59, 133, 61, 146, 70, 158, 88, 169, 107, 176, 124, 180, 135, 183, 144, 185, 152]));
|
||||
cb("b", new Uint8Array([51, 47, 51, 77, 56, 123, 60, 151, 65, 163, 68, 164, 68, 144, 67, 108, 67, 76, 72, 43, 104, 51, 121, 74, 110, 87, 109, 95, 131, 117, 131, 140, 109, 152, 88, 157]));
|
||||
cb("c", new Uint8Array([153, 62, 150, 62, 145, 62, 136, 62, 123, 62, 106, 65, 85, 70, 65, 75, 50, 82, 42, 93, 37, 106, 36, 119, 36, 130, 40, 140, 49, 147, 61, 153, 72, 156, 85, 157, 106, 158, 116, 158]));
|
||||
cb("d", new Uint8Array([57, 178, 57, 176, 55, 171, 52, 163, 50, 154, 49, 146, 47, 135, 45, 121, 44, 108, 44, 97, 44, 85, 44, 75, 44, 66, 44, 58, 44, 48, 44, 38, 46, 31, 48, 26, 58, 21, 75, 20, 99, 26, 120, 35, 136, 51, 144, 70, 144, 88, 137, 110, 124, 131, 106, 145, 88, 153]));
|
||||
cb("e", new Uint8Array([150, 72, 141, 69, 114, 68, 79, 69, 48, 77, 32, 81, 31, 85, 46, 91, 73, 95, 107, 100, 114, 103, 83, 117, 58, 134, 66, 143, 105, 148, 133, 148, 144, 148]));
|
||||
cb("f", new Uint8Array([157, 52, 155, 52, 148, 52, 137, 52, 124, 52, 110, 52, 96, 52, 83, 52, 74, 52, 67, 52, 61, 52, 57, 52, 55, 52, 52, 52, 52, 54, 52, 58, 52, 64, 54, 75, 58, 97, 59, 117, 60, 130]));
|
||||
cb("g", new Uint8Array([160, 66, 153, 62, 129, 58, 90, 56, 58, 57, 38, 65, 31, 86, 43, 125, 69, 152, 116, 166, 145, 154, 146, 134, 112, 116, 85, 108, 97, 106, 140, 106, 164, 106]));
|
||||
cb("h", new Uint8Array([58, 50, 58, 55, 58, 64, 58, 80, 58, 102, 58, 122, 58, 139, 58, 153, 58, 164, 58, 171, 58, 177, 58, 179, 58, 181, 58, 180, 58, 173, 58, 163, 59, 154, 61, 138, 64, 114, 68, 95, 72, 84, 80, 79, 91, 79, 107, 82, 123, 93, 137, 111, 145, 130, 149, 147, 150, 154, 150, 159]));
|
||||
cb("i", new Uint8Array([89, 48, 89, 49, 89, 51, 89, 55, 89, 60, 89, 68, 89, 78, 89, 91, 89, 103, 89, 114, 89, 124, 89, 132, 89, 138, 89, 144, 89, 148, 89, 151, 89, 154, 89, 156, 89, 157, 89, 158]));
|
||||
cb("j", new Uint8Array([130, 57, 130, 61, 130, 73, 130, 91, 130, 113, 130, 133, 130, 147, 130, 156, 130, 161, 130, 164, 130, 166, 129, 168, 127, 168, 120, 168, 110, 168, 91, 167, 81, 167, 68, 167]));
|
||||
cb("k", new Uint8Array([149, 63, 147, 68, 143, 76, 136, 89, 126, 106, 114, 123, 100, 136, 86, 147, 72, 153, 57, 155, 45, 152, 36, 145, 29, 131, 26, 117, 26, 104, 27, 93, 30, 86, 35, 80, 45, 77, 62, 80, 88, 96, 113, 116, 130, 131, 140, 142, 145, 149, 148, 153]));
|
||||
cb("l", new Uint8Array([42, 55, 42, 59, 42, 69, 44, 87, 44, 107, 44, 128, 44, 143, 44, 156, 44, 163, 44, 167, 44, 169, 45, 170, 49, 170, 59, 169, 76, 167, 100, 164, 119, 162, 139, 160, 163, 159]));
|
||||
cb("m", new Uint8Array([49, 165, 48, 162, 46, 156, 44, 148, 42, 138, 42, 126, 42, 113, 43, 101, 45, 91, 47, 82, 49, 75, 51, 71, 54, 70, 57, 70, 61, 74, 69, 81, 75, 91, 84, 104, 94, 121, 101, 132, 103, 137, 106, 130, 110, 114, 116, 92, 125, 75, 134, 65, 139, 62, 144, 66, 148, 83, 151, 108, 155, 132, 157, 149]));
|
||||
cb("n", new Uint8Array([50, 165, 50, 160, 50, 153, 50, 140, 50, 122, 50, 103, 50, 83, 50, 65, 50, 52, 50, 45, 50, 43, 52, 52, 57, 67, 66, 90, 78, 112, 93, 131, 104, 143, 116, 152, 127, 159, 135, 160, 141, 150, 148, 125, 154, 96, 158, 71, 161, 56, 162, 49]));
|
||||
cb("o", new Uint8Array([107, 58, 104, 58, 97, 61, 87, 68, 75, 77, 65, 88, 58, 103, 54, 116, 53, 126, 55, 135, 61, 143, 75, 149, 91, 150, 106, 148, 119, 141, 137, 125, 143, 115, 146, 104, 146, 89, 142, 78, 130, 70, 116, 65, 104, 62]));
|
||||
cb("p", new Uint8Array([52, 59, 52, 64, 54, 73, 58, 88, 61, 104, 65, 119, 67, 130, 69, 138, 71, 145, 71, 147, 71, 148, 71, 143, 70, 133, 68, 120, 67, 108, 67, 97, 67, 89, 68, 79, 72, 67, 83, 60, 99, 58, 118, 58, 136, 63, 146, 70, 148, 77, 145, 84, 136, 91, 121, 95, 106, 97, 93, 97, 82, 97]));
|
||||
cb("q", new Uint8Array([95, 59, 93, 59, 88, 59, 79, 59, 68, 61, 57, 67, 50, 77, 48, 89, 48, 103, 50, 117, 55, 130, 65, 140, 76, 145, 85, 146, 94, 144, 101, 140, 105, 136, 106, 127, 106, 113, 100, 98, 92, 86, 86, 79, 84, 75, 84, 72, 91, 69, 106, 67, 126, 67, 144, 67, 158, 67, 168, 67, 173, 67, 177, 67]));
|
||||
cb("r", new Uint8Array([53, 49, 53, 62, 53, 91, 53, 127, 53, 146, 53, 147, 53, 128, 53, 94, 53, 69, 62, 44, 82, 42, 94, 50, 92, 68, 82, 85, 77, 93, 80, 102, 95, 119, 114, 134, 129, 145, 137, 150]));
|
||||
cb("s", new Uint8Array([159, 72, 157, 70, 155, 68, 151, 66, 145, 63, 134, 60, 121, 58, 108, 56, 96, 55, 83, 55, 73, 55, 64, 56, 57, 60, 52, 65, 49, 71, 49, 76, 50, 81, 55, 87, 71, 94, 94, 100, 116, 104, 131, 108, 141, 114, 145, 124, 142, 135, 124, 146, 97, 153, 70, 157, 52, 158]));
|
||||
cb("t", new Uint8Array([45, 55, 48, 55, 55, 55, 72, 55, 96, 55, 120, 55, 136, 55, 147, 55, 152, 55, 155, 55, 157, 55, 158, 56, 158, 60, 156, 70, 154, 86, 151, 102, 150, 114, 148, 125, 148, 138, 148, 146]));
|
||||
cb("u", new Uint8Array([35, 52, 35, 59, 35, 73, 35, 90, 36, 114, 38, 133, 42, 146, 49, 153, 60, 157, 73, 158, 86, 156, 100, 152, 112, 144, 121, 131, 127, 114, 132, 97, 134, 85, 135, 73, 136, 61, 136, 56]));
|
||||
cb("v", new Uint8Array([36, 55, 37, 59, 40, 68, 45, 83, 51, 100, 58, 118, 64, 132, 69, 142, 71, 149, 73, 156, 76, 158, 77, 160, 77, 159, 80, 151, 82, 137, 84, 122, 86, 111, 90, 91, 91, 78, 91, 68, 91, 63, 92, 61, 97, 61, 111, 61, 132, 61, 150, 61, 162, 61]));
|
||||
cb("w", new Uint8Array([33, 58, 34, 81, 39, 127, 44, 151, 48, 161, 52, 162, 57, 154, 61, 136, 65, 115, 70, 95, 76, 95, 93, 121, 110, 146, 119, 151, 130, 129, 138, 84, 140, 56, 140, 45]));
|
||||
cb("x", new Uint8Array([56, 63, 56, 67, 57, 74, 60, 89, 66, 109, 74, 129, 85, 145, 96, 158, 107, 164, 117, 167, 128, 164, 141, 155, 151, 140, 159, 122, 166, 105, 168, 89, 170, 81, 170, 73, 169, 66, 161, 63, 141, 68, 110, 83, 77, 110, 55, 134, 47, 145]));
|
||||
cb("y", new Uint8Array([42, 56, 42, 70, 48, 97, 62, 109, 85, 106, 109, 90, 126, 65, 134, 47, 137, 45, 137, 75, 127, 125, 98, 141, 70, 133, 65, 126, 92, 137, 132, 156, 149, 166]));
|
||||
cb("z", new Uint8Array([29, 62, 35, 62, 43, 62, 63, 62, 87, 62, 110, 62, 125, 62, 134, 62, 138, 62, 136, 63, 122, 68, 103, 77, 85, 91, 70, 107, 59, 120, 50, 132, 47, 138, 43, 143, 41, 148, 42, 151, 53, 155, 80, 157, 116, 158, 146, 158, 163, 158]));
|
||||
cb("\b", new Uint8Array([183, 103, 182, 103, 180, 103, 176, 103, 169, 103, 159, 103, 147, 103, 133, 103, 116, 103, 101, 103, 85, 103, 73, 103, 61, 103, 52, 103, 38, 103, 34, 103, 29, 103, 27, 103, 26, 103, 25, 103, 24, 103]));
|
||||
cb(" ", new Uint8Array([39, 118, 40, 118, 41, 118, 44, 118, 47, 118, 52, 118, 58, 118, 66, 118, 74, 118, 84, 118, 94, 118, 104, 117, 114, 116, 123, 116, 130, 116, 144, 116, 149, 116, 154, 116, 158, 116, 161, 116, 163, 116]));
|
||||
};
|
||||
|
||||
exports.input = function(options) {
|
||||
options = options||{};
|
||||
var text = options.text;
|
||||
if ("string"!=typeof text) text="";
|
||||
|
||||
Bangle.strokes = {};
|
||||
exports.getStrokes( (id,s) => Bangle.strokes[id] = Unistroke.new(s) );
|
||||
|
||||
var flashToggle = false;
|
||||
const R = Bangle.appRect;
|
||||
|
||||
function draw(noclear) {
|
||||
g.reset();
|
||||
if (!noclear) g.clearRect(R);
|
||||
var l = g.setFont("6x8:4").wrapString(text+(flashToggle?"_":" "), R.w-8);
|
||||
if (l.length>4) l=l.slice(-4);
|
||||
g.drawString(l.join("\n"),R.x+4,R.y+4);
|
||||
}
|
||||
|
||||
function show() {
|
||||
g.reset();
|
||||
g.clearRect(R).setColor("#f00");
|
||||
var n=0;
|
||||
exports.getStrokes((id,s) => {
|
||||
var x = n%6;
|
||||
var y = (n-x)/6;
|
||||
s = g.transformVertices(s, {scale:0.16, x:R.x+x*30-4, y:R.y+y*30-4});
|
||||
g.fillRect(s[0]-1,s[1]-2,s[0]+1,s[1]+1);
|
||||
g.drawPoly(s);
|
||||
n++;
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
function strokeHandler(o) {
|
||||
//print(o);
|
||||
if (!flashInterval)
|
||||
flashInterval = setInterval(() => {
|
||||
flashToggle = !flashToggle;
|
||||
draw();
|
||||
}, 1000);
|
||||
if (o.stroke!==undefined) {
|
||||
var ch = o.stroke;
|
||||
if (ch=="\b") text = text.slice(0,-1);
|
||||
else text += ch;
|
||||
}
|
||||
flashToggle = true;
|
||||
draw();
|
||||
}
|
||||
Bangle.on('stroke',strokeHandler);
|
||||
g.reset().clearRect(R);
|
||||
show();
|
||||
draw(true);
|
||||
var flashInterval;
|
||||
|
||||
return new Promise((resolve,reject) => {
|
||||
var l;//last event
|
||||
Bangle.setUI({mode:"custom", drag:e=>{
|
||||
if (l) g.reset().setColor("#f00").drawLine(l.x,l.y,e.x,e.y);
|
||||
l = e.b ? e : 0;
|
||||
},touch:() => {
|
||||
if (flashInterval) clearInterval(flashInterval);
|
||||
flashInterval = undefined;
|
||||
show();
|
||||
}, back:()=>{
|
||||
Bangle.removeListener("stroke", strokeHandler);
|
||||
clearInterval(flashInterval);
|
||||
Bangle.setUI();
|
||||
g.clearRect(Bangle.appRect);
|
||||
resolve(text);
|
||||
}});
|
||||
});
|
||||
};
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
{ "id": "kbswipe",
|
||||
"name": "Swipe keyboard",
|
||||
"version":"0.01",
|
||||
"description": "A library for text input via PalmOS style swipe gestures (beta!)",
|
||||
"icon": "app.png",
|
||||
"type":"textinput",
|
||||
"tags": "keyboard",
|
||||
"supports" : ["BANGLEJS2"],
|
||||
"screenshots": [{"url":"screenshot.png"}],
|
||||
"readme": "README.md",
|
||||
"storage": [
|
||||
{"name":"textinput","url":"lib.js"}
|
||||
]
|
||||
}
|
||||
|
After Width: | Height: | Size: 3.7 KiB |
|
|
@ -0,0 +1 @@
|
|||
0.01: New App!
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
# Touch Keyboard
|
||||
|
||||
A library that provides an on-screen keyboard for text input.
|
||||
|
||||
## Usage
|
||||
|
||||
In your app's metadata, add:
|
||||
|
||||
```
|
||||
"dependencies": {"textinput":"type"},
|
||||
```
|
||||
|
||||
From inside your app, call:
|
||||
|
||||
```
|
||||
Bangle.loadWidgets();
|
||||
Bangle.drawWidgets();
|
||||
require("textinput").input({text:"Foo"}).then(result => {
|
||||
console.log("Text input", E.toJS(result));
|
||||
});
|
||||
```
|
||||
|
||||
The first argument to `input` is an object containing the following:
|
||||
|
||||
* `text` - initial text to edit
|
||||
|
||||
(in the future, the ability to restrict usage of newline/etc may be added)
|
||||
|
||||
## Make your own
|
||||
|
||||
You can create your own keyboard input apps. Just ensure that they have
|
||||
`"type":"textinput",` in their metadata and provide a library called `textinput`
|
||||
that exports an `input` method.
|
||||
|
||||
## To-do
|
||||
|
||||
Make this Bangle.js 1 compatible (use left/right touch and up/down buttons)
|
||||
|
After Width: | Height: | Size: 506 B |
|
|
@ -0,0 +1,132 @@
|
|||
exports.input = function(options) {
|
||||
options = options||{};
|
||||
var text = options.text;
|
||||
if ("string"!=typeof text) text="";
|
||||
|
||||
// Key Maps for Keyboard
|
||||
var KEYMAPLOWER = [
|
||||
"`1234567890-=\b",
|
||||
"\2qwertyuiop[]\n",
|
||||
"\2asdfghjkl;'#\n",
|
||||
" \\zxcvbnm,./ ",
|
||||
];
|
||||
var KEYMAPUPPER = [
|
||||
"¬!\"£$%^&*()_+\b",
|
||||
"\2QWERTYUIOP{}\n",
|
||||
"\2ASDFGHJKL:@~\n",
|
||||
" |ZXCVBNM<>? ",
|
||||
];
|
||||
var KEYIMGL = Graphics.createImage(`
|
||||
|
||||
|
||||
#
|
||||
###
|
||||
#####
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
`);KEYIMGL.transparent=0;
|
||||
var KEYIMGR = Graphics.createImage(`
|
||||
|
||||
|
||||
#
|
||||
##
|
||||
#####
|
||||
##
|
||||
#
|
||||
|
||||
|
||||
|
||||
###
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
#####
|
||||
###
|
||||
#
|
||||
|
||||
#`);KEYIMGR.transparent=0;
|
||||
/* If a char in the keymap is >=128,
|
||||
subtract 128 and look in this array for
|
||||
multi-character key codes*/
|
||||
var KEYEXTRA = [
|
||||
String.fromCharCode(27,91,68), // 0x80 left
|
||||
String.fromCharCode(27,91,67), // 0x81 right
|
||||
String.fromCharCode(27,91,65), // 0x82 up
|
||||
String.fromCharCode(27,91,66), // 0x83 down
|
||||
String.fromCharCode(27,91,53,126), // 0x84 page up
|
||||
String.fromCharCode(27,91,54,126), // 0x85 page down
|
||||
];
|
||||
// state
|
||||
const R = Bangle.appRect;
|
||||
var kbx = 0, kby = 0, kbdx = 0, kbdy = 0, kbShift = false, flashToggle = false;
|
||||
const PX=12, PY=16, DRAGSCALE=24;
|
||||
var xoff = 3, yoff = g.getHeight()-PY*4;
|
||||
|
||||
function draw() {
|
||||
var map = kbShift ? KEYMAPUPPER : KEYMAPLOWER;
|
||||
//g.drawImage(KEYIMG,0,yoff);
|
||||
g.reset().setFont("6x8:2");
|
||||
g.clearRect(R);
|
||||
if (kbx>=0)
|
||||
g.setColor(g.theme.bgH).fillRect(xoff+kbx*PX,yoff+kby*PY, xoff+(kbx+1)*PX-1,yoff+(kby+1)*PY-1).setColor(g.theme.fg);
|
||||
g.drawImage(KEYIMGL,xoff,yoff+PY,{scale:2});
|
||||
g.drawImage(KEYIMGR,xoff+PX*13,yoff,{scale:2});
|
||||
g.drawString(map[0],xoff,yoff);
|
||||
g.drawString(map[1],xoff,yoff+PY);
|
||||
g.drawString(map[2],xoff,yoff+PY*2);
|
||||
g.drawString(map[3],xoff,yoff+PY*3);
|
||||
var l = g.setFont("6x8:4").wrapString(text+(flashToggle?"_":" "), R.w-8);
|
||||
if (l.length>2) l=l.slice(-2);
|
||||
g.drawString(l.join("\n"),R.x+4,R.y+4);
|
||||
|
||||
g.flip();
|
||||
}
|
||||
g.reset().clearRect(R);
|
||||
draw();
|
||||
var flashInterval = setInterval(() => {
|
||||
flashToggle = !flashToggle;
|
||||
draw();
|
||||
}, 1000);
|
||||
|
||||
return new Promise((resolve,reject) => {
|
||||
|
||||
Bangle.setUI({mode:"custom", drag:e=>{
|
||||
kbdx += e.dx;
|
||||
kbdy += e.dy;
|
||||
var dx = Math.round(kbdx/DRAGSCALE), dy = Math.round(kbdy/DRAGSCALE);
|
||||
kbdx -= dx*DRAGSCALE;
|
||||
kbdy -= dy*DRAGSCALE;
|
||||
if (dx || dy) {
|
||||
kbx = (kbx+dx+15)%15;
|
||||
kby = (kby+dy+4)%4;
|
||||
draw();
|
||||
}
|
||||
},touch:()=>{
|
||||
var map = kbShift ? KEYMAPUPPER : KEYMAPLOWER;
|
||||
var ch = map[kby][kbx];
|
||||
if (ch=="\2") kbShift=!kbShift;
|
||||
else if (ch=="\b") text = text.slice(0,-1);
|
||||
else text += ch;
|
||||
Bangle.buzz(20);
|
||||
draw();
|
||||
},back:()=>{
|
||||
clearInterval(flashInterval);
|
||||
Bangle.setUI();
|
||||
g.clearRect(Bangle.appRect);
|
||||
resolve(text);
|
||||
}});
|
||||
});
|
||||
};
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
{ "id": "kbtouch",
|
||||
"name": "Touch keyboard",
|
||||
"version":"0.01",
|
||||
"description": "A library for text input via onscreen keyboard",
|
||||
"icon": "app.png",
|
||||
"type":"textinput",
|
||||
"tags": "keyboard",
|
||||
"supports" : ["BANGLEJS2"],
|
||||
"screenshots": [{"url":"screenshot.png"}],
|
||||
"readme": "README.md",
|
||||
"storage": [
|
||||
{"name":"textinput","url":"lib.js"}
|
||||
]
|
||||
}
|
||||
|
After Width: | Height: | Size: 3.1 KiB |
|
|
@ -39,11 +39,13 @@ these conversions */
|
|||
const charFallbacks = {
|
||||
"ą":"a",
|
||||
"ā":"a",
|
||||
"å":"a",
|
||||
"č":"c",
|
||||
"ć":"c",
|
||||
"ě":"e",
|
||||
"ę":"e",
|
||||
"ē":"e",
|
||||
"æ":"e",
|
||||
"ģ":"g",
|
||||
"i":"ī",
|
||||
"ķ":"k",
|
||||
|
|
@ -53,6 +55,7 @@ const charFallbacks = {
|
|||
"ņ":"n",
|
||||
"ő":"o",
|
||||
"ó":"o",
|
||||
"ø":"o",
|
||||
"ř":"r",
|
||||
"ś":"s",
|
||||
"š":"s",
|
||||
|
|
@ -681,6 +684,24 @@ var locales = {
|
|||
day: "Pirmdiena,Otrdiena,Trešdiena,Ceturtdiena,Piektdiena,Sestdiena,Svētdiena",
|
||||
trans: { yes: "jā", Yes: "Jā", no: "nē", No: "Nē", ok: "labi", on: "Ieslēgt", off: "Izslēgt", "< Back": "< Atpakaļ" }
|
||||
},
|
||||
"no_NB": { // Using charfallbacks
|
||||
lang: "no_NB",
|
||||
decimal_point: ",",
|
||||
thousands_sep: " ",
|
||||
currency_symbol: "kr",
|
||||
int_curr_symbol: "NOK",
|
||||
speed: "kmh",
|
||||
distance: { 0: "m", 1: "km" },
|
||||
temperature: "°C",
|
||||
ampm: { 0: "", 1: "" },
|
||||
timePattern: { 0: "%HH:%MM:%SS", 1: "%HH:%MM" },
|
||||
datePattern: { 0: "%d. %b %Y", "1": "%d.%m.%Y" }, // 1. Mar 2020 // 01.03.20
|
||||
abmonth: "Jan,Feb,Mar,Apr,Mai,Jun,Jul,Aug,Sep,Okt,Nov,Des",
|
||||
month: "Januar,Februar,Mars,April,Mai,Juni,Juli,August,September,Oktober,November,Desember",
|
||||
abday: "Ma,Ti,On,To,Fr,Lø,Sø",
|
||||
day: "Mandag,Tirsdag,Onsdag,Torsdag,Fredag,Lørdag,Søndag",
|
||||
trans: { yes: "ja", Yes: "Ja", no: "nei", No: "Nei", ok: "ok", on: "på", off: "av", "< Back": "< Tilbake", "Delete": "Slett", "Mark Unread": "Merk som ulest" }
|
||||
},
|
||||
/*,
|
||||
"he_IL": { // This won't work until we get a font - see https://github.com/espruino/BangleApps/issues/399
|
||||
codePage : "ISO8859-8",
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
0.01: Create New App !
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
Denti :
|
||||
This teeth washing assistan helps you to wash your teeth
|
||||
|
|
@ -0,0 +1 @@
|
|||
require("heatshrink").decompress(atob("mEw4kA///A4M79/6823gvb70/qvLrXrrXdqmyzl2gvTzn0glS4ttuZh9iMQCykBvsRC6vUC6sdppIUgMb2Ol+IYBGaBGB6Oll1xGKMRpsfi/FrQXRjtHutai/uC6EBunRj9SrB5DPppeBj/njVV0IICu1xUpscqvBvgSCC5qlCuN1kqnCI5xGB69VwP1qJ2QUoMR4tcuOBA4LXOUoOKi/lq8RgMd64YMUoXCr8XFgMXs1p6JeM7cRjVS0PZtN5s2Z3oXKiKlBivHjl4swACu4XJgIWB6mxv0l0MZC4eZ3YXHKgPdolLuMR+tXC4lmzq/GQQNEonduILBDwOWC4lmBgLRG3vREQcBFwoABtfRC4kXaIKyFjAHBjtmy4EBvoXFjtBNA0X13u0N5j/O5+BEwhGBDwZICgPykUil0RwUikfqC4kR3YGCgOGwIuBCwIAB+NSkXh/3xIwlIiEBC4MbDgMaCoMl8U+AQNajXhIwcUIwIXBI4ceC4UcmVXJoMfC4nUVooABjhGC0LEBJAM+C4alBew5HCGAPu8QEBC4bsB2IXLAAk+0KlHXwoXLUop1BgK/CmQXG9ynCjtHIwUB3ZLDgJaCC4qJBLwJGDC4zvCAAbvBBoUReYZHCMAcTCYWvGgMu95CDRo7AFl8RiqmCCZSQGqKtCRwYAMgLqB4JYBmXuwIXP4UiRIXj9xyDCpTDBuUuYoWDRwYAKWIUVl4SCjXnC5I5DjORCQMxCQUf8JdNZITMEAggAvA="))
|
||||
|
|
@ -0,0 +1,99 @@
|
|||
var i = 0;
|
||||
var counter = 10;
|
||||
var counterInterval;
|
||||
|
||||
var img = Graphics.createImage(`
|
||||
|
||||
##### #####
|
||||
# ##### #
|
||||
# #
|
||||
# #
|
||||
## ##
|
||||
## ##
|
||||
## ##
|
||||
# #### #
|
||||
# # # #
|
||||
# # # #
|
||||
## ##
|
||||
## ##
|
||||
`);
|
||||
var img1 = Graphics.createImage(`
|
||||
|
||||
|
||||
### # ##### ## ####
|
||||
# # # # # # #
|
||||
# # ### # # ####
|
||||
# # # ###### # #
|
||||
### #### ##### # # # #
|
||||
|
||||
##### #####
|
||||
# ##### #
|
||||
# #
|
||||
# #
|
||||
## ##
|
||||
## ##
|
||||
## ##
|
||||
# #### #
|
||||
# # # #
|
||||
# # # #
|
||||
## ##
|
||||
## ##
|
||||
`);
|
||||
g.setColor('#012345');
|
||||
|
||||
function outOfTime() {
|
||||
if (counterInterval) return;
|
||||
E.showMessage("Out of Time", "My Timer");
|
||||
Bangle.beep(200, 4000)
|
||||
.then(() => new Promise(resolve => setTimeout(resolve,200)))
|
||||
.then(() => Bangle.beep(200, 3000));
|
||||
// again, 10 secs later
|
||||
setTimeout(outOfTime, 10000);
|
||||
g.setColor('#' + Math.floor(Math.random()*16777215).toString(16).padStart(6, '0'));
|
||||
}
|
||||
|
||||
function immagine(){
|
||||
g.drawImage(img1, 90, 20, {scale:2});
|
||||
}
|
||||
|
||||
function countDown() {
|
||||
counter--;
|
||||
// Out of time
|
||||
if (counter<=0) {
|
||||
clearInterval(counterInterval);
|
||||
counterInterval = undefined;
|
||||
setWatch(startTimer, (process.env.HWVERSION==2) ? BTN1 : BTN2);
|
||||
g.clear(img);
|
||||
outOfTime();
|
||||
return;
|
||||
|
||||
}
|
||||
g.clear(1);
|
||||
g.setFontAlign(0,0); // center font
|
||||
g.setFont("Vector",80); // vector font, 80px
|
||||
// draw the current counter value
|
||||
g.drawImage(img, 90, 20, {scale:2});
|
||||
g.drawString(counter,120,120);
|
||||
g.drawLine(50,50,180,50);
|
||||
g.drawLine(50,51,180,51);
|
||||
g.drawLine(50,52,180,52);
|
||||
// optional - this keeps the watch LCD lit up
|
||||
Bangle.setLCDPower(1);
|
||||
if (counter<=5){
|
||||
immagine();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
function startTimer() {
|
||||
counter = 10;
|
||||
countDown();
|
||||
if (!counterInterval)
|
||||
counterInterval = setInterval(countDown, 1000);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
startTimer();
|
||||
|
After Width: | Height: | Size: 11 KiB |
|
|
@ -0,0 +1,15 @@
|
|||
{ "id": "megadenti",
|
||||
"name": "Denti",
|
||||
"shortName":"My Denti",
|
||||
"icon": "brush-teeth.png",
|
||||
"version":"0.01",
|
||||
"description": "This app allows you wash your teeth in an efficent way. A coloured timer guides you while your smile becomes bright!",
|
||||
"tags": "game",
|
||||
"supports": ["BANGLEJS"],
|
||||
"allow_emulator": true,
|
||||
"readme": "README.md",
|
||||
"storage": [
|
||||
{"name":"megadenti.app.js","url":"app.js"},
|
||||
{"name":"megadenti.img","url":"app-icon.js","evaluate":true}
|
||||
]
|
||||
}
|
||||
|
|
@ -40,3 +40,6 @@
|
|||
0.25: Fix widget memory usage issues if message received and watch repeatedly calls Bangle.drawWidgets (fix #1550)
|
||||
0.26: Setting to auto-open music
|
||||
0.27: Add 'mark all read' option to popup menu (fix #1624)
|
||||
0.28: Option to auto-unlock the watch when a new message arrives
|
||||
0.29: Fix message list overwrites on Bangle.js 1 (fix #1642)
|
||||
0.30: Add new Icons (Youtube, Twitch, MS TODO, Teams, Snapchat, Signal, Post & DHL, Nina, Lieferando, Kalender, Discord, Corona Warn, Bibel)
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ to the clock where a ringing bell will be shown in the Widget bar.
|
|||
is chosen if there isn't much message text, but this specifies the smallest the font should get before
|
||||
it starts getting clipped.
|
||||
* `Auto-Open Music` - Should the app automatically open when the phone starts playing music?
|
||||
* `Unlock Watch` - Should the app unlock the watch when a new message arrives, so you can touch the buttons at the bottom of the app?
|
||||
|
||||
## New Messages
|
||||
|
||||
|
|
|
|||
|
|
@ -82,31 +82,45 @@ function getNegImage() {
|
|||
return atob("FhaBADAAMeAB78AP/4B/fwP4/h/B/P4D//AH/4AP/AAf4AB/gAP/AB/+AP/8B/P4P4fx/A/v4B//AD94AHjAAMA=");
|
||||
}
|
||||
/*
|
||||
* icons should be 24x24px with 1bpp colors and transparancy
|
||||
* icons should be 24x24px with 1bpp colors and 'Transparency to Color'
|
||||
* http://www.espruino.com/Image+Converter
|
||||
*/
|
||||
function getMessageImage(msg) {
|
||||
if (msg.img) return atob(msg.img);
|
||||
var s = (msg.src||"").toLowerCase();
|
||||
if (s=="alarm" || s =="alarmclockreceiver") return atob("GBjBAP////8AAAAAAAACAEAHAOAefng5/5wTgcgHAOAOGHAMGDAYGBgYGBgYGBgYGBgYDhgYBxgMATAOAHAHAOADgcAB/4AAfgAAAAAAAAA=");
|
||||
if (s=="alarm" || s =="alarmclockreceiver") return atob("GBjBAP////8AAAAAAAACAEAHAOAefng5/5wTgcgHAOAOGHAMGDAYGBgYGBgYGBgYGBgYDhgYBxgMATAOAHAHAOADgcAB/4AAfgAAAAAAAAA=");
|
||||
if (s=="bibel") return atob("GBgBAAAAA//wD//4D//4H//4H/f4H/f4H+P4H4D4H4D4H/f4H/f4H/f4H/f4H/f4H//4H//4H//4GAAAEAAAEAAACAAAB//4AAAA");
|
||||
if (s=="calendar") return atob("GBiBAAAAAAAAAAAAAA//8B//+BgAGBgAGBgAGB//+B//+B//+B9m2B//+B//+Btm2B//+B//+Btm+B//+B//+A//8AAAAAAAAAAAAA==");
|
||||
if (s=="corona-warn") return atob("GBgBAAAAABwAAP+AAf/gA//wB/PwD/PgDzvAHzuAP8EAP8AAPAAAPMAAP8AAH8AAHzsADzuAB/PAB/PgA//wAP/gAH+AAAwAAAAA");
|
||||
if (s=="discord") return atob("GBgBAAAAAAAAAAAAAIEABwDgDP8wH//4H//4P//8P//8P//8Pjx8fhh+fzz+f//+f//+e//ePH48HwD4AgBAAAAAAAAAAAAAAAAA");
|
||||
if (s=="facebook") return getFBIcon();
|
||||
if (s=="gmail") return getNotificationImage();
|
||||
if (s=="google home") return atob("GBiCAAAAAAAAAAAAAAAAAAAAAoAAAAAACqAAAAAAKqwAAAAAqroAAAACquqAAAAKq+qgAAAqr/qoAACqv/6qAAKq//+qgA6r///qsAqr///6sAqv///6sAqv///6sAqv///6sA6v///6sA6v///qsA6qqqqqsA6qqqqqsA6qqqqqsAP7///vwAAAAAAAAAAAAAAAAA==");
|
||||
if (s=="hangouts") return atob("FBaBAAH4AH/gD/8B//g//8P//H5n58Y+fGPnxj5+d+fmfj//4//8H//B//gH/4A/8AA+AAHAABgAAAA=");
|
||||
if (s=="home assistant") return atob("FhaBAAAAAADAAAeAAD8AAf4AD/3AfP8D7fwft/D/P8ec572zbzbNsOEhw+AfD8D8P4fw/z/D/P8P8/w/z/AAAAA=");
|
||||
if (s=="instagram") return atob("GBiBAAAAAAAAAAAAAAAAAAP/wAYAYAwAMAgAkAh+EAjDEAiBEAiBEAiBEAiBEAjDEAh+EAgAEAwAMAYAYAP/wAAAAAAAAAAAAAAAAA==");
|
||||
if (s=="gmail") return getNotificationImage();
|
||||
if (s=="google home") return atob("GBiCAAAAAAAAAAAAAAAAAAAAAoAAAAAACqAAAAAAKqwAAAAAqroAAAACquqAAAAKq+qgAAAqr/qoAACqv/6qAAKq//+qgA6r///qsAqr///6sAqv///6sAqv///6sAqv///6sA6v///6sA6v///qsA6qqqqqsA6qqqqqsA6qqqqqsAP7///vwAAAAAAAAAAAAAAAAA==");
|
||||
if (s=="kalender") return atob("GBgBBgBgBQCgff++RQCiRgBiQAACf//+QAACQAACR//iRJkiRIEiR//iRNsiRIEiRJkiR//iRIEiRIEiR//iQAACQAACf//+AAAA");
|
||||
if (s=="lieferando") return atob("GBgBABgAAH5wAP9wAf/4A//4B//4D//4H//4P/88fV8+fV4//V4//Vw/HVw4HVw4HBg4HBg4HBg4HDg4Hjw4Hj84Hj44Hj44Hj44");
|
||||
if (s=="mail") return getNotificationImage();
|
||||
if (s=="messenger") return getFBIcon();
|
||||
if (s=="outlook mail") return getNotificationImage();
|
||||
if (s=="nina") return atob("GBgBAAAABAAQCAAICAAIEAAEEgAkJAgSJBwSKRxKSj4pUn8lVP+VVP+VUgAlSgApKQBKJAASJAASEgAkEAAECAAICAAIBAAQAAAA");
|
||||
if (s=="outlook mail") return atob("HBwBAAAAAAAAAAAIAAAfwAAP/gAB/+AAP/5/A//v/D/+/8P/7/g+Pv8Dye/gPd74w5znHDnOB8Oc4Pw8nv/Dwe/8Pj7/w//v/D/+/8P/7/gf/gAA/+AAAfwAAACAAAAAAAAAAAA=");
|
||||
if (s=="phone") return atob("FxeBABgAAPgAAfAAB/AAD+AAH+AAP8AAP4AAfgAA/AAA+AAA+AAA+AAB+AAB+AAB+OAB//AB//gB//gA//AA/8AAf4AAPAA=");
|
||||
if (s=="post & dhl") return atob("GBgBAPgAE/5wMwZ8NgN8NgP4NgP4HgP4HgPwDwfgD//AB/+AAf8AAAAABs7AHcdgG4MwAAAAGESAFESAEkSAEnyAEkSAFESAGETw");
|
||||
if (s=="signal") return atob("GBgBAAAAAGwAAQGAAhggCP8QE//AB//oJ//kL//wD//0D//wT//wD//wL//0J//kB//oA//ICf8ABfxgBYBAADoABMAABAAAAAAA");
|
||||
if (s=="skype") return atob("GhoBB8AAB//AA//+Af//wH//+D///w/8D+P8Afz/DD8/j4/H4fP5/A/+f4B/n/gP5//B+fj8fj4/H8+DB/PwA/x/A/8P///B///gP//4B//8AD/+AAA+AA==");
|
||||
if (s=="slack") return atob("GBiBAAAAAAAAAABAAAHvAAHvAADvAAAPAB/PMB/veD/veB/mcAAAABzH8B3v+B3v+B3n8AHgAAHuAAHvAAHvAADGAAAAAAAAAAAAAA==");
|
||||
if (s=="sms message") return getNotificationImage();
|
||||
if (s=="threema") return atob("GBjB/4Yx//8AAAAAAAAAAAAAfgAB/4AD/8AH/+AH/+AP//AP2/APw/APw/AHw+AH/+AH/8AH/4AH/gAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=");
|
||||
if (s=="twitter") return atob("GhYBAABgAAB+JgA/8cAf/ngH/5+B/8P8f+D///h///4f//+D///g///wD//8B//+AP//gD//wAP/8AB/+AB/+AH//AAf/AAAYAAA");
|
||||
if (s=="snapchat") return atob("GBgBAAAAAAAAAH4AAf+AAf+AA//AA//AA//AA//AA//AH//4D//wB//gA//AB//gD//wH//4f//+P//8D//wAf+AAH4AAAAAAAAA");
|
||||
if (s=="teams") return atob("GBgBAAAAAAAAAAQAAB4AAD8IAA8cP/M+f/scf/gIeDgAfvvefvvffvvffvvffvvff/vff/veP/PeAA/cAH/AAD+AAD8AAAQAAAAA");
|
||||
if (s=="telegram") return atob("GBiBAAAAAAAAAAAAAAAAAwAAHwAA/wAD/wAf3gD/Pgf+fh/4/v/z/P/H/D8P/Acf/AM//AF/+AF/+AH/+ADz+ADh+ADAcAAAMAAAAA==");
|
||||
if (s=="threema") return atob("GBjB/4Yx//8AAAAAAAAAAAAAfgAB/4AD/8AH/+AH/+AP//AP2/APw/APw/AHw+AH/+AH/8AH/4AH/gAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=");
|
||||
if (s=="to do") return atob("GBgBAAAAAAAAAAAwAAB4AAD8AAH+AAP/DAf/Hg//Px/+f7/8///4///wf//gP//AH/+AD/8AB/4AA/wAAfgAAPAAAGAAAAAAAAAA");
|
||||
if (s=="twitch") return atob("GBgBH//+P//+P//+eAAGeAAGeAAGeDGGeDOGeDOGeDOGeDOGeDOGeDOGeAAOeAAOeAAcf4/4f5/wf7/gf//Af/+AA/AAA+AAAcAA");
|
||||
if (s=="twitter") return atob("GhYBAABgAAB+JgA/8cAf/ngH/5+B/8P8f+D///h///4f//+D///g///wD//8B//+AP//gD//wAP/8AB/+AB/+AH//AAf/AAAYAAA");
|
||||
if (s=="whatsapp") return atob("GBiBAAB+AAP/wAf/4A//8B//+D///H9//n5//nw//vw///x///5///4///8e//+EP3/APn/wPn/+/j///H//+H//8H//4H//wMB+AA==");
|
||||
if (s=="wordfeud") return atob("GBgCWqqqqqqlf//////9v//////+v/////++v/////++v8///Lu+v8///L++v8///P/+v8v//P/+v9v//P/+v+fx/P/+v+Pk+P/+v/PN+f/+v/POuv/+v/Ofdv/+v/NvM//+v/I/Y//+v/k/k//+v/i/w//+v/7/6//+v//////+v//////+f//////9Wqqqqqql");
|
||||
if (s=="youtube") return atob("GBgBAAAAAAAAAAAAAAAAAf8AH//4P//4P//8P//8P5/8P4/8f4P8f4P8P4/8P5/8P//8P//8P//4H//4Af8AAAAAAAAAAAAAAAAA");
|
||||
if (msg.id=="music") return atob("FhaBAH//+/////////////h/+AH/4Af/gB/+H3/7/f/v9/+/3/7+f/vB/w8H+Dwf4PD/x/////////////3//+A=");
|
||||
if (msg.id=="back") return getBackImage();
|
||||
return getNotificationImage();
|
||||
|
|
@ -115,28 +129,38 @@ function getMessageImageCol(msg,def) {
|
|||
return {
|
||||
// generic colors, using B2-safe colors
|
||||
"alarm": "#fff",
|
||||
"calendar": "#f00",
|
||||
"mail": "#ff0",
|
||||
"music": "#f0f",
|
||||
"phone": "#0f0",
|
||||
"sms message": "#0ff",
|
||||
// brands, according to https://www.schemecolor.com/?s (picking one for multicolored logos)
|
||||
// all dithered on B2, but we only use the color for the icons. (Could maybe pick the closest 3-bit color for B2?)
|
||||
"bibel": "#54342c",
|
||||
"discord": "#738adb",
|
||||
"facebook": "#4267b2",
|
||||
"gmail": "#ea4335",
|
||||
"google home": "#fbbc05",
|
||||
"home assistant": "#fff", // ha-blue is #41bdf5, but that's the background
|
||||
"hangouts": "#1ba261",
|
||||
"home assistant": "#fff", // ha-blue is #41bdf5, but that's the background
|
||||
"instagram": "#dd2a7b",
|
||||
"liferando": "#ee5c00",
|
||||
"messenger": "#0078ff",
|
||||
"nina": "#e57004",
|
||||
"outlook mail": "#0072c6",
|
||||
"post & dhl": "#f2c101",
|
||||
"signal": "#00f",
|
||||
"skype": "#00aff0",
|
||||
"slack": "#e51670",
|
||||
"threema": "#000",
|
||||
"snapchat": "#ff0",
|
||||
"teams": "#464eb8",
|
||||
"telegram": "#0088cc",
|
||||
"threema": "#000",
|
||||
"to do": "#3999e5",
|
||||
"twitch": "#6441A4",
|
||||
"twitter": "#1da1f2",
|
||||
"whatsapp": "#4fce5d",
|
||||
"wordfeud": "#e7d3c7",
|
||||
"youtube": "#f00",
|
||||
}[(msg.src||"").toLowerCase()]||(def !== undefined?def:g.theme.fg);
|
||||
}
|
||||
|
||||
|
|
@ -457,6 +481,7 @@ function checkMessages(options) {
|
|||
var msg = MESSAGES[idx-1];
|
||||
if (msg && msg.new) g.setBgColor(g.theme.bgH).setColor(g.theme.fgH);
|
||||
else g.setColor(g.theme.fg);
|
||||
g.clearRect(r.x,r.y,r.x+r.w, r.y+r.h);
|
||||
if (idx==0) msg = {id:"back", title:"< Back"};
|
||||
if (!msg) return;
|
||||
var x = r.x+2, title = msg.title, body = msg.body;
|
||||
|
|
|
|||
|
|
@ -57,15 +57,23 @@ exports.pushMessage = function(event) {
|
|||
// otherwise load messages/show widget
|
||||
var loadMessages = Bangle.CLOCK || event.important;
|
||||
// first, buzz
|
||||
var quiet = (require('Storage').readJSON('setting.json',1)||{}).quiet;
|
||||
if (!quiet && loadMessages && global.WIDGETS && WIDGETS.messages)
|
||||
var quiet = (require('Storage').readJSON('setting.json',1)||{}).quiet;
|
||||
var unlockWatch = (require('Storage').readJSON('messages.settings.json',1)||{}).unlockWatch;
|
||||
if (!quiet && loadMessages && global.WIDGETS && WIDGETS.messages){
|
||||
WIDGETS.messages.buzz();
|
||||
if(unlockWatch != false){
|
||||
Bangle.setLocked(false);
|
||||
Bangle.setLCDPower(1); // turn screen on
|
||||
}
|
||||
}
|
||||
// after a delay load the app, to ensure we have all the messages
|
||||
if (exports.messageTimeout) clearTimeout(exports.messageTimeout);
|
||||
exports.messageTimeout = setTimeout(function() {
|
||||
exports.messageTimeout = undefined;
|
||||
// if we're in a clock or it's important, go straight to messages app
|
||||
if (loadMessages) return load("messages.app.js");
|
||||
if (loadMessages){
|
||||
return load("messages.app.js");
|
||||
}
|
||||
if (!quiet && (!global.WIDGETS || !WIDGETS.messages)) return Bangle.buzz(); // no widgets - just buzz to let someone know
|
||||
WIDGETS.messages.show();
|
||||
}, 500);
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"id": "messages",
|
||||
"name": "Messages",
|
||||
"version": "0.27",
|
||||
"version": "0.30",
|
||||
"description": "App to display notifications from iOS and Gadgetbridge/Android",
|
||||
"icon": "app.png",
|
||||
"type": "app",
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
if (settings.vibrate===undefined) settings.vibrate=".";
|
||||
if (settings.repeat===undefined) settings.repeat=4;
|
||||
if (settings.unreadTimeout===undefined) settings.unreadTimeout=60;
|
||||
settings.unlockWatch=!!settings.unlockWatch;
|
||||
settings.openMusic=!!settings.openMusic;
|
||||
settings.maxUnreadTimeout=240;
|
||||
return settings;
|
||||
|
|
@ -14,18 +15,10 @@
|
|||
require('Storage').writeJSON("messages.settings.json", settings);
|
||||
}
|
||||
|
||||
var vibPatterns = [/*LANG*/"Off", ".", "-", "--", "-.-", "---"];
|
||||
var mainmenu = {
|
||||
"" : { "title" : /*LANG*/"Messages" },
|
||||
"< Back" : back,
|
||||
/*LANG*/'Vibrate': {
|
||||
value: Math.max(0,vibPatterns.indexOf(settings().vibrate)),
|
||||
min: 0, max: vibPatterns.length,
|
||||
format: v => vibPatterns[v]||"Off",
|
||||
onchange: v => {
|
||||
updateSetting("vibrate", vibPatterns[v]);
|
||||
}
|
||||
},
|
||||
/*LANG*/'Vibrate': require("buzz_menu").pattern(settings().vibrate, v => updateSetting("vibrate", v)),
|
||||
/*LANG*/'Repeat': {
|
||||
value: settings().repeat,
|
||||
min: 0, max: 10,
|
||||
|
|
@ -49,6 +42,11 @@
|
|||
format: v => v?/*LANG*/'Yes':/*LANG*/'No',
|
||||
onchange: v => updateSetting("openMusic", v)
|
||||
},
|
||||
/*LANG*/'Unlock Watch': {
|
||||
value: !!settings().unlockWatch,
|
||||
format: v => v?/*LANG*/'Yes':/*LANG*/'No',
|
||||
onchange: v => updateSetting("unlockWatch", v)
|
||||
},
|
||||
};
|
||||
E.showMenu(mainmenu);
|
||||
})
|
||||
|
|
|
|||
|
|
@ -32,14 +32,7 @@ draw:function() {
|
|||
Bangle.drawWidgets();
|
||||
},buzz:function() {
|
||||
if ((require('Storage').readJSON('setting.json',1)||{}).quiet) return; // never buzz during Quiet Mode
|
||||
let v = (require('Storage').readJSON("messages.settings.json", true) || {}).vibrate || ".";
|
||||
function b() {
|
||||
var c = v[0];
|
||||
v = v.substr(1);
|
||||
if (c==".") Bangle.buzz().then(()=>setTimeout(b,100));
|
||||
if (c=="-") Bangle.buzz(500).then(()=>setTimeout(b,100));
|
||||
}
|
||||
b();
|
||||
require("buzz").pattern((require('Storage').readJSON("messages.settings.json", true) || {}).vibrate || ".");
|
||||
},touch:function(b,c) {
|
||||
var w=WIDGETS["messages"];
|
||||
if (!w||!w.width||c.x<w.x||c.x>w.x+w.width||c.y<w.y||c.y>w.y+w.iconwidth) return;
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
"type": "clock",
|
||||
"tags": "numerals,clock",
|
||||
"supports": ["BANGLEJS","BANGLEJS2"],
|
||||
"readme": "README.md",
|
||||
"allow_emulator": true,
|
||||
"screenshots": [{"url":"bangle1-numerals-screenshot.png"}],
|
||||
"storage": [
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
"type": "clock",
|
||||
"tags": "clock",
|
||||
"supports": ["BANGLEJS"],
|
||||
"readme": "README.md",
|
||||
"allow_emulator": true,
|
||||
"screenshots": [{"url":"bangle1-pipboy-themed-clock-screenshot.png"}],
|
||||
"storage": [
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
"type": "boot",
|
||||
"tags": "system",
|
||||
"supports": ["BANGLEJS","BANGLEJS2"],
|
||||
"readme": "README.md",
|
||||
"screenshots": [{"url":"pro-menu-screenshot.png"}],
|
||||
"storage": [
|
||||
{"name":"promenu.boot.js","url":"boot.js","supports": ["BANGLEJS"]},
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
"shortName": "Q Alarm",
|
||||
"icon": "app.png",
|
||||
"version": "0.04",
|
||||
"description": "Alarm and timer app with days of week and 'hard' option.",
|
||||
"description": "[Not recommended - use 'Alarm & Timer' app] Alarm and timer app with days of week and 'hard' option.",
|
||||
"tags": "tool,alarm,widget",
|
||||
"supports": ["BANGLEJS", "BANGLEJS2"],
|
||||
"storage": [
|
||||
|
|
|
|||
|
|
@ -10,4 +10,5 @@
|
|||
0.09: Fix broken start/stop if recording not enabled (fix #1561)
|
||||
0.10: Don't allow the same setting to be chosen for 2 boxes (fix #1578)
|
||||
0.11: Notifications fixes
|
||||
0.12: Fix for recorder not stopping at end of run. Bug introduced in 0.11
|
||||
0.12: Fix for recorder not stopping at end of run. Bug introduced in 0.11
|
||||
0.13: Revert #1578 (stop duplicate entries) as with 2v12 menus it causes other boxes to be wiped (fix #1643)
|
||||
|
|
|
|||
|
|
@ -14,7 +14,8 @@ the red `STOP` in the bottom right turns to a green `RUN`.
|
|||
shown will increase, even if you are standing still.
|
||||
* `TIME` - the elapsed time for your run
|
||||
* `PACE` - the number of minutes it takes you to run a given distance, configured in settings (default 1km) **based on your run so far**
|
||||
* `HEART` - Your heart rate
|
||||
* `HEART (BPM)` - Your current heart rate
|
||||
* `Max BPM` - Your maximum heart rate reached during the run
|
||||
* `STEPS` - Steps since you started exercising
|
||||
* `CADENCE` - Steps per second based on your step rate *over the last minute*
|
||||
* `GPS` - this is green if you have a GPS lock. GPS is turned on automatically
|
||||
|
|
@ -35,7 +36,7 @@ Under `Settings` -> `App` -> `Run` you can change settings for this app.
|
|||
record GPS/HRM/etc data every time you start a run?
|
||||
* `Pace` is the distance that pace should be shown over - 1km, 1 mile, 1/2 Marathon or 1 Marathon
|
||||
* `Boxes` leads to a submenu where you can configure what is shown in each of the 6 boxes on the display.
|
||||
Available stats are "Time", "Distance", "Steps", "Heart (BPM)", "Pace (avg)", "Pace (curr)", "Speed", and "Cadence".
|
||||
Available stats are "Time", "Distance", "Steps", "Heart (BPM)", "Max BPM", "Pace (avg)", "Pace (curr)", "Speed", and "Cadence".
|
||||
Any box set to "-" will display no information.
|
||||
* Box 1 is the top left (defaults to "Distance")
|
||||
* Box 2 is the top right (defaults to "Time")
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{ "id": "run",
|
||||
"name": "Run",
|
||||
"version":"0.12",
|
||||
"version":"0.13",
|
||||
"description": "Displays distance, time, steps, cadence, pace and more for runners.",
|
||||
"icon": "app.png",
|
||||
"tags": "run,running,fitness,outdoors,gps",
|
||||
|
|
|
|||
|
|
@ -42,11 +42,6 @@
|
|||
value: Math.max(statsIDs.indexOf(settings[boxID]),0),
|
||||
format: v => statsList[v].name,
|
||||
onchange: v => {
|
||||
for (var i=1;i<=6;i++)
|
||||
if (settings["B"+i]==statsIDs[v]) {
|
||||
settings["B"+i]="";
|
||||
boxMenu["Box "+i].value=0;
|
||||
}
|
||||
settings[boxID] = statsIDs[v];
|
||||
saveSettings();
|
||||
},
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
0.01: New App!
|
||||
|
|
@ -0,0 +1,89 @@
|
|||
Sched: Scheduling library for alarms and timers
|
||||
====================================
|
||||
|
||||
This provides boot code, a library and tools for alarms and timers.
|
||||
|
||||
Other apps can use this to provide alarm functionality.
|
||||
|
||||
App
|
||||
---
|
||||
|
||||
The Alarm app allows you to add/modify any running timers.
|
||||
|
||||
|
||||
Internals / Library
|
||||
-------------------
|
||||
|
||||
Alarms are stored in an array in `sched.json`, and take the form:
|
||||
|
||||
```
|
||||
{
|
||||
id : "mytimer", // optional ID for this alarm/timer, so apps can easily find *their* timers
|
||||
appid : "myappid", // optional app ID for alarms that you set/use for your app
|
||||
on : true, // is the alarm enabled?
|
||||
t : 23400000, // Time of day since midnight in ms (if a timer, this is set automatically when timer starts)
|
||||
dow : 0b1111111, // Binary encoding for days of the week to run alarm on
|
||||
// SUN = 1
|
||||
// MON = 2
|
||||
// TUE = 4
|
||||
// WED = 8
|
||||
// THU = 16
|
||||
// FRI = 32
|
||||
// SAT = 64
|
||||
|
||||
date : "2022-04-04", // OPTIONAL date for the alarm, in YYYY-MM-DD format
|
||||
// eg (new Date()).toISOString().substr(0,10)
|
||||
msg : "Eat food", // message to display.
|
||||
last : 0, // last day of the month we alarmed on - so we don't alarm twice in one day!
|
||||
rp : true, // repeat the alarm every day?
|
||||
vibrate : "...", // OPTIONAL pattern of '.', '-' and ' ' to use for when buzzing out this alarm (defaults to '..' if not set)
|
||||
hidden : false, // OPTIONAL if false, the widget should not show an icon for this alarm
|
||||
as : false, // auto snooze
|
||||
timer : 5*60*1000, // OPTIONAL - if set, this is a timer and it's the time in ms
|
||||
js : "load('myapp.js')" // OPTIONAL - a JS command to execute when the alarm activates (*instead* of loading 'sched.js')
|
||||
// when this code is run, you're responsible for setting alarm.on=false (or removing the alarm)
|
||||
data : { ... } // OPTIONAL - your app can store custom data in here if needed (don't store a lot of data here)
|
||||
}
|
||||
```
|
||||
|
||||
The [`sched` library](https://github.com/espruino/BangleApps/blob/master/apps/sched/lib.js) contains
|
||||
a few helpful functions for getting/setting alarms and timers, but is intentionally sparse so as not to
|
||||
use too much RAM.
|
||||
|
||||
It can be used as follows:
|
||||
|
||||
```
|
||||
// add/update an existing alarm
|
||||
require("sched").setAlarm("mytimer", {
|
||||
msg : "Wake up",
|
||||
timer : 10*60*1000, // 10 Minutes
|
||||
});
|
||||
// Ensure the widget and alarm timer updates to schedule the new alarm properly
|
||||
require("sched").reload();
|
||||
|
||||
// Get the time to the next alarm for us
|
||||
var timeToNext = require("sched").getTimeToAlarm(require("sched").getAlarm("mytimer"));
|
||||
// timeToNext===undefined if no alarm or alarm disabled
|
||||
|
||||
// delete an alarm
|
||||
require("sched").setAlarm("mytimer", undefined);
|
||||
// reload after deleting...
|
||||
require("sched").reload();
|
||||
|
||||
// Or add an alarm that runs your own code - in this case
|
||||
// loading the settings app. The alarm will not be removed/stopped
|
||||
// automatically.
|
||||
require("sched").setAlarm("customrunner", {
|
||||
appid : "myapp",
|
||||
js : "load('setting.app.js')",
|
||||
timer : 1*60*1000, // 1 Minute
|
||||
});
|
||||
|
||||
// If you have been specifying `appid` you can also find any alarms that
|
||||
// your app has created with the following:
|
||||
require("sched").getAlarms().filter(a=>a.appid=="myapp");
|
||||
```
|
||||
|
||||
If your app requires alarms, you can specify that the alarms app needs to
|
||||
be installed by adding `"dependencies": {"scheduler":"type"},` to your app's
|
||||
metadata.
|
||||
|
|
@ -0,0 +1 @@
|
|||
require("heatshrink").decompress(atob("mEwwkGswAhiMRCCAREAo4eHBIQLEAgwYHsIJDiwHB5gACBpIhHCoYZEGA4gFCw4ABGA4HEjgXJ4IXGAwcUB4VEmf//8zogICoJIFAodMBoNDCoIADmgJB4gXIFwXDCwoABngwFC4guB4k/CQXwh4EC+YMCC44iBp4qDC4n/+gNBC41sEIJCEC4v/GAPGC4dhXYRdFC4xhCCYIXCdQRdDC5HzegQXCsxGHC45IDCwQXCUgwXHJAIXGRogXJSIIXcOw4XIPAYXcBwv/mEDBAwXOgtQC65QGC5vzoEAJAx3Nmk/mEABIiPN+dDAQIwFC4zXGFwKRCGAjvMFwQECGAgXI4YuGGAUvAgU8C4/EFwwGCAgdMC4p4EFwobFOwoXDJAIoEAApGBC4xIEABJGHGAapEAAqNBFwwXD4heI+YuBC5BIBVQhdHIw4wD5inFS4IKCCxFmigNCokzCoMzogICoIWIsMRjgPCAA3BiMWC48RBQIXJEgMRFxAJCCw4lEC44IECooOIBAaBJKwhgIAH4ACA=="))
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
|
|
@ -0,0 +1,25 @@
|
|||
// check for alarms
|
||||
(function() { // run in closure to ensure allocated vars get removed
|
||||
if (Bangle.SCHED) {
|
||||
clearTimeout(Bangle.SCHED);
|
||||
delete Bangle.SCHED;
|
||||
}
|
||||
var alarms = require('Storage').readJSON('sched.json',1)||[];
|
||||
var time = new Date();
|
||||
var active = alarms.filter(a=>a.on && (a.dow>>time.getDay())&1 && (!a.date || a.date==time.toISOString().substr(0,10)));
|
||||
if (active.length) {
|
||||
active = active.sort((a,b)=>(a.t-b.t)+(a.last-b.last)*86400000);
|
||||
var currentTime = (time.getHours()*3600000)+(time.getMinutes()*60000)+(time.getSeconds()*1000);
|
||||
var t = active[0].t-currentTime;
|
||||
if (active[0].last == time.getDate() || t < -60000) t += 86400000;
|
||||
if (t<1000) t=1000; // start alarm min 1 sec from now
|
||||
/* execute alarm at the correct time. We avoid execing immediately
|
||||
since this code will get called AGAIN when alarm.js is loaded. alarm.js
|
||||
will then clearInterval() to get rid of this call so it can proceed
|
||||
normally.
|
||||
If active[0].js is defined, just run that code as-is and not alarm.js */
|
||||
Bangle.SCHED = setTimeout(active[0].js||'load("sched.js")',t);
|
||||
} else { // check for new alarms at midnight (so day of week works)
|
||||
Bangle.SCHED = setTimeout('eval(require("Storage").read("sched.boot.js"))', 86400000 - (Date.now()%86400000));
|
||||
}
|
||||
})();
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
// Return an array of all alarms
|
||||
exports.getAlarms = function() {
|
||||
return require("Storage").readJSON("sched.json",1)||[];
|
||||
};
|
||||
// Write a list of alarms back to storage
|
||||
exports.setAlarms = function(alarms) {
|
||||
return require("Storage").writeJSON("sched.json",alarms);
|
||||
};
|
||||
// Return an alarm object based on ID
|
||||
exports.getAlarm = function(id) {
|
||||
return exports.getAlarms().find(a=>a.id==id);
|
||||
};
|
||||
// Given a list of alarms from getAlarms, return a list of active alarms for the given time (or current time if time not specified)
|
||||
exports.getActiveAlarms = function(alarms, time) {
|
||||
if (!time) time = new Date();
|
||||
var currentTime = (time.getHours()*3600000)+(time.getMinutes()*60000)+(time.getSeconds()*1000)
|
||||
+10000;// get current time - 10s in future to ensure we alarm if we've started the app a tad early
|
||||
return alarms.filter(a=>a.on&&(a.t<currentTime)&&(a.last!=time.getDate()) && (!a.date || a.date==time.toISOString().substr(0,10))).sort((a,b)=>a.t-b.t);
|
||||
}
|
||||
// Set an alarm object based on ID. Leave 'alarm' undefined to remove it
|
||||
exports.setAlarm = function(id, alarm) {
|
||||
var alarms = exports.getAlarms().filter(a=>a.id!=id);
|
||||
if (alarm !== undefined) {
|
||||
alarm.id = id;
|
||||
if (alarm.dow===undefined) alarm.dow = 0b1111111;
|
||||
if (alarm.on!==false) alarm.on=true;
|
||||
if (alarm.timer) { // if it's a timer, set the start time as a time from *now*
|
||||
var time = new Date();
|
||||
var currentTime = (time.getHours()*3600000)+(time.getMinutes()*60000)+(time.getSeconds()*1000);
|
||||
alarm.t = currentTime + alarm.timer;
|
||||
}
|
||||
alarms.push(alarm);
|
||||
}
|
||||
exports.setAlarms(alarms);
|
||||
};
|
||||
/// Get time until the given alarm (object). Return undefined if alarm not enabled, or if 86400000 or more, alarm could me *more* than a day in the future
|
||||
exports.getTimeToAlarm = function(alarm, time) {
|
||||
if (!alarm) return undefined;
|
||||
if (!time) time = new Date();
|
||||
var active = alarm.on && (alarm.dow>>time.getDay())&1 && (!alarm.date || alarm.date==time.toISOString().substr(0,10));
|
||||
if (!active) return undefined;
|
||||
var currentTime = (time.getHours()*3600000)+(time.getMinutes()*60000)+(time.getSeconds()*1000);
|
||||
var t = alarm.t-currentTime;
|
||||
if (alarm.last == time.getDate() || t < -60000) t += 86400000;
|
||||
return t;
|
||||
};
|
||||
/// Force a reload of the current alarms and widget
|
||||
exports.reload = function() {
|
||||
eval(require("Storage").read("sched.boot.js"));
|
||||
if (WIDGETS["alarm"]) {
|
||||
WIDGETS["alarm"].reload();
|
||||
Bangle.drawWidgets();
|
||||
}
|
||||
};
|
||||