Merge branch 'espruino:master' into sleeplog_v0.10_beta
|
@ -256,6 +256,7 @@ and which gives information about the app for the Launcher.
|
||||||
// 'clock' - a clock - required for clocks to automatically start
|
// 'clock' - a clock - required for clocks to automatically start
|
||||||
// 'widget' - a widget
|
// 'widget' - a widget
|
||||||
// 'bootloader' - an app that at startup (app.boot.js) but doesn't have a launcher entry for 'app.js'
|
// 'bootloader' - an app that at startup (app.boot.js) but doesn't have a launcher entry for 'app.js'
|
||||||
|
// 'settings' - apps that appear in Settings->Apps (with appname.settings.js) but that have no 'app.js'
|
||||||
// 'RAM' - code that runs and doesn't upload anything to storage
|
// 'RAM' - code that runs and doesn't upload anything to storage
|
||||||
// 'launch' - replacement 'Launcher'
|
// 'launch' - replacement 'Launcher'
|
||||||
// 'textinput' - provides a 'textinput' library that allows text to be input on the Bangle
|
// 'textinput' - provides a 'textinput' library that allows text to be input on the Bangle
|
||||||
|
|
|
@ -3,3 +3,4 @@
|
||||||
0.03: Do not alarm while charging
|
0.03: Do not alarm while charging
|
||||||
0.04: Obey system quiet mode
|
0.04: Obey system quiet mode
|
||||||
0.05: Battery optimisation, add the pause option, bug fixes
|
0.05: Battery optimisation, add the pause option, bug fixes
|
||||||
|
0.06: Add a temperature threshold to detect (and not alert) if the BJS isn't worn. Better support for the peoples using the app at night
|
||||||
|
|
|
@ -11,4 +11,5 @@ Different settings can be personalized:
|
||||||
- Dismiss delay: Delay added before the next alert if the alert is dismissed. From 5 to 60 min
|
- Dismiss delay: Delay added before the next alert if the alert is dismissed. From 5 to 60 min
|
||||||
- Pause delay: Same as Dismiss delay but longer (usefull for meetings and such). From 30 to 240 min
|
- Pause delay: Same as Dismiss delay but longer (usefull for meetings and such). From 30 to 240 min
|
||||||
- Min steps: Minimal amount of steps to count as an activity
|
- Min steps: Minimal amount of steps to count as an activity
|
||||||
|
- Temp Threshold: Temperature threshold to determine if the watch is worn
|
||||||
|
|
||||||
|
|
|
@ -2,17 +2,17 @@ function run() {
|
||||||
if (isNotWorn()) return;
|
if (isNotWorn()) return;
|
||||||
let now = new Date();
|
let now = new Date();
|
||||||
let h = now.getHours();
|
let h = now.getHours();
|
||||||
let health = Bangle.getHealthStatus("day");
|
|
||||||
|
|
||||||
if (h >= activityreminder_settings.startHour && h < activityreminder_settings.endHour) {
|
if (isDuringAlertHours(h)) {
|
||||||
|
let health = Bangle.getHealthStatus("day");
|
||||||
if (health.steps - activityreminder_data.stepsOnDate >= activityreminder_settings.minSteps // more steps made than needed
|
if (health.steps - activityreminder_data.stepsOnDate >= activityreminder_settings.minSteps // more steps made than needed
|
||||||
|| health.steps < activityreminder_data.stepsOnDate) { // new day or reboot of the watch
|
|| health.steps < activityreminder_data.stepsOnDate) { // new day or reboot of the watch
|
||||||
activityreminder_data.stepsOnDate = health.steps;
|
activityreminder_data.stepsOnDate = health.steps;
|
||||||
activityreminder_data.stepsDate = now;
|
activityreminder_data.stepsDate = now;
|
||||||
activityreminder.saveData(activityreminder_data);
|
activityreminder.saveData(activityreminder_data);
|
||||||
/* todo in a futur release
|
/* todo in a futur release
|
||||||
add settimer to trigger like 10 secs after the stepsDate + minSteps
|
Add settimer to trigger like 30 secs after going in this part cause the person have been walking
|
||||||
cancel all other timers of this app
|
(pass some argument to run() to handle long walks and not triggering so often)
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,10 +24,30 @@ function run() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function isNotWorn() {
|
function isNotWorn() {
|
||||||
// todo in a futur release check temperature and mouvement in a futur release
|
return (Bangle.isCharging() || activityreminder_settings.tempThreshold >= E.getTemperature());
|
||||||
return Bangle.isCharging();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isDuringAlertHours(h) {
|
||||||
|
if(activityreminder_settings.startHour < activityreminder_settings.endHour){ // not passing through midnight
|
||||||
|
return (h >= activityreminder_settings.startHour && h < activityreminder_settings.endHour)
|
||||||
|
} else{ // passing through midnight
|
||||||
|
return (h >= activityreminder_settings.startHour || h < activityreminder_settings.endHour)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Bangle.on('midnight', function() {
|
||||||
|
/*
|
||||||
|
Usefull trick to have the app working smothly for people using it at night
|
||||||
|
*/
|
||||||
|
let now = new Date();
|
||||||
|
let h = now.getHours();
|
||||||
|
if (activityreminder_settings.enabled && isDuringAlertHours(h)){
|
||||||
|
// updating only the steps and keeping the original stepsDate on purpose
|
||||||
|
activityreminder_data.stepsOnDate = 0;
|
||||||
|
activityreminder.saveData(activityreminder_data);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
const activityreminder = require("activityreminder");
|
const activityreminder = require("activityreminder");
|
||||||
const activityreminder_settings = activityreminder.loadSettings();
|
const activityreminder_settings = activityreminder.loadSettings();
|
||||||
if (activityreminder_settings.enabled) {
|
if (activityreminder_settings.enabled) {
|
||||||
|
@ -39,7 +59,7 @@ if (activityreminder_settings.enabled) {
|
||||||
setInterval(run, 60000);
|
setInterval(run, 60000);
|
||||||
/* todo in a futur release
|
/* todo in a futur release
|
||||||
increase setInterval time to something that is still sensible (5 mins ?)
|
increase setInterval time to something that is still sensible (5 mins ?)
|
||||||
add settimer to trigger like 10 secs after the stepsDate + minSteps
|
when we added a settimer
|
||||||
cancel all other timers of this app
|
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,8 @@ exports.loadSettings = function () {
|
||||||
maxInnactivityMin: 30,
|
maxInnactivityMin: 30,
|
||||||
dismissDelayMin: 15,
|
dismissDelayMin: 15,
|
||||||
pauseDelayMin: 120,
|
pauseDelayMin: 120,
|
||||||
minSteps: 50
|
minSteps: 50,
|
||||||
|
tempThreshold: 27
|
||||||
}, storage.readJSON("activityreminder.s.json", true) || {});
|
}, storage.readJSON("activityreminder.s.json", true) || {});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
"name": "Activity Reminder",
|
"name": "Activity Reminder",
|
||||||
"shortName":"Activity Reminder",
|
"shortName":"Activity Reminder",
|
||||||
"description": "A reminder to take short walks for the ones with a sedentary lifestyle",
|
"description": "A reminder to take short walks for the ones with a sedentary lifestyle",
|
||||||
"version":"0.05",
|
"version":"0.06",
|
||||||
"icon": "app.png",
|
"icon": "app.png",
|
||||||
"type": "app",
|
"type": "app",
|
||||||
"tags": "tool,activity",
|
"tags": "tool,activity",
|
||||||
|
|
|
@ -55,7 +55,7 @@
|
||||||
},
|
},
|
||||||
'Pause delay': {
|
'Pause delay': {
|
||||||
value: settings.pauseDelayMin,
|
value: settings.pauseDelayMin,
|
||||||
min: 30, max: 240,
|
min: 30, max: 240, step: 5,
|
||||||
onchange: v => {
|
onchange: v => {
|
||||||
settings.pauseDelayMin = v;
|
settings.pauseDelayMin = v;
|
||||||
activityreminder.writeSettings(settings);
|
activityreminder.writeSettings(settings);
|
||||||
|
@ -66,11 +66,20 @@
|
||||||
},
|
},
|
||||||
'Min steps': {
|
'Min steps': {
|
||||||
value: settings.minSteps,
|
value: settings.minSteps,
|
||||||
min: 10, max: 500,
|
min: 10, max: 500, step: 10,
|
||||||
onchange: v => {
|
onchange: v => {
|
||||||
settings.minSteps = v;
|
settings.minSteps = v;
|
||||||
activityreminder.writeSettings(settings);
|
activityreminder.writeSettings(settings);
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
'Temp Threshold': {
|
||||||
|
value: settings.tempThreshold,
|
||||||
|
min: 20, max: 40, step: 0.5,
|
||||||
|
format: v => v + "°C",
|
||||||
|
onchange: v => {
|
||||||
|
settings.tempThreshold = v;
|
||||||
|
activityreminder.writeSettings(settings);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
|
|
|
@ -29,3 +29,4 @@
|
||||||
0.27: New UI!
|
0.27: New UI!
|
||||||
0.28: Fix bug with alarms not firing when configured to fire only once
|
0.28: Fix bug with alarms not firing when configured to fire only once
|
||||||
0.29: Fix wrong 'dow' handling in new timer if first day of week is Monday
|
0.29: Fix wrong 'dow' handling in new timer if first day of week is Monday
|
||||||
|
0.30: Fix "Enable All"
|
||||||
|
|
|
@ -86,7 +86,8 @@ function showEditAlarmMenu(selectedAlarm, alarmIndex) {
|
||||||
const menu = {
|
const menu = {
|
||||||
"": { "title": isNew ? /*LANG*/"New Alarm" : /*LANG*/"Edit Alarm" },
|
"": { "title": isNew ? /*LANG*/"New Alarm" : /*LANG*/"Edit Alarm" },
|
||||||
"< Back": () => {
|
"< Back": () => {
|
||||||
saveAlarm(alarm, alarmIndex, time);
|
prepareAlarmForSave(alarm, alarmIndex, time);
|
||||||
|
saveAndReload();
|
||||||
showMainMenu();
|
showMainMenu();
|
||||||
},
|
},
|
||||||
/*LANG*/"Hour": {
|
/*LANG*/"Hour": {
|
||||||
|
@ -144,7 +145,7 @@ function showEditAlarmMenu(selectedAlarm, alarmIndex) {
|
||||||
E.showMenu(menu);
|
E.showMenu(menu);
|
||||||
}
|
}
|
||||||
|
|
||||||
function saveAlarm(alarm, alarmIndex, time) {
|
function prepareAlarmForSave(alarm, alarmIndex, time) {
|
||||||
alarm.t = require("time_utils").encodeTime(time);
|
alarm.t = require("time_utils").encodeTime(time);
|
||||||
alarm.last = alarm.t < require("time_utils").getCurrentTimeMillis() ? new Date().getDate() : 0;
|
alarm.last = alarm.t < require("time_utils").getCurrentTimeMillis() ? new Date().getDate() : 0;
|
||||||
|
|
||||||
|
@ -153,8 +154,6 @@ function saveAlarm(alarm, alarmIndex, time) {
|
||||||
} else {
|
} else {
|
||||||
alarms[alarmIndex] = alarm;
|
alarms[alarmIndex] = alarm;
|
||||||
}
|
}
|
||||||
|
|
||||||
saveAndReload();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function saveAndReload() {
|
function saveAndReload() {
|
||||||
|
@ -251,7 +250,8 @@ function showEditTimerMenu(selectedTimer, timerIndex) {
|
||||||
const menu = {
|
const menu = {
|
||||||
"": { "title": isNew ? /*LANG*/"New Timer" : /*LANG*/"Edit Timer" },
|
"": { "title": isNew ? /*LANG*/"New Timer" : /*LANG*/"Edit Timer" },
|
||||||
"< Back": () => {
|
"< Back": () => {
|
||||||
saveTimer(timer, timerIndex, time);
|
prepareTimerForSave(timer, timerIndex, time);
|
||||||
|
saveAndReload();
|
||||||
showMainMenu();
|
showMainMenu();
|
||||||
},
|
},
|
||||||
/*LANG*/"Hours": {
|
/*LANG*/"Hours": {
|
||||||
|
@ -293,7 +293,7 @@ function showEditTimerMenu(selectedTimer, timerIndex) {
|
||||||
E.showMenu(menu);
|
E.showMenu(menu);
|
||||||
}
|
}
|
||||||
|
|
||||||
function saveTimer(timer, timerIndex, time) {
|
function prepareTimerForSave(timer, timerIndex, time) {
|
||||||
timer.timer = require("time_utils").encodeTime(time);
|
timer.timer = require("time_utils").encodeTime(time);
|
||||||
timer.t = require("time_utils").getCurrentTimeMillis() + timer.timer;
|
timer.t = require("time_utils").getCurrentTimeMillis() + timer.timer;
|
||||||
timer.last = 0;
|
timer.last = 0;
|
||||||
|
@ -303,8 +303,6 @@ function saveTimer(timer, timerIndex, time) {
|
||||||
} else {
|
} else {
|
||||||
alarms[timerIndex] = timer;
|
alarms[timerIndex] = timer;
|
||||||
}
|
}
|
||||||
|
|
||||||
saveAndReload();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function showAdvancedMenu() {
|
function showAdvancedMenu() {
|
||||||
|
@ -327,7 +325,16 @@ function enableAll(on) {
|
||||||
} else {
|
} else {
|
||||||
E.showPrompt(/*LANG*/"Are you sure?", { title: on ? /*LANG*/"Enable All" : /*LANG*/"Disable All" }).then((confirm) => {
|
E.showPrompt(/*LANG*/"Are you sure?", { title: on ? /*LANG*/"Enable All" : /*LANG*/"Disable All" }).then((confirm) => {
|
||||||
if (confirm) {
|
if (confirm) {
|
||||||
alarms.forEach(alarm => alarm.on = on);
|
alarms.forEach((alarm, i) => {
|
||||||
|
alarm.on = on;
|
||||||
|
if (on) {
|
||||||
|
if (alarm.timer) {
|
||||||
|
prepareTimerForSave(alarm, i, require("time_utils").decodeTime(alarm.timer))
|
||||||
|
} else {
|
||||||
|
prepareAlarmForSave(alarm, i, require("time_utils").decodeTime(alarm.t))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
saveAndReload();
|
saveAndReload();
|
||||||
showMainMenu();
|
showMainMenu();
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
"id": "alarm",
|
"id": "alarm",
|
||||||
"name": "Alarms & Timers",
|
"name": "Alarms & Timers",
|
||||||
"shortName": "Alarms",
|
"shortName": "Alarms",
|
||||||
"version": "0.29",
|
"version": "0.30",
|
||||||
"description": "Set alarms and timers on your Bangle",
|
"description": "Set alarms and timers on your Bangle",
|
||||||
"icon": "app.png",
|
"icon": "app.png",
|
||||||
"tags": "tool,alarm,widget",
|
"tags": "tool,alarm,widget",
|
||||||
|
|
|
@ -9,3 +9,5 @@
|
||||||
0.09: Fix time/date disappearing after fullscreen notification
|
0.09: Fix time/date disappearing after fullscreen notification
|
||||||
0.10: Use ClockFace library
|
0.10: Use ClockFace library
|
||||||
0.11: Use ClockFace.is12Hour
|
0.11: Use ClockFace.is12Hour
|
||||||
|
0.12: Add settings to hide date,widgets
|
||||||
|
0.13: Add font setting
|
||||||
|
|
|
@ -4,3 +4,7 @@ A simple digital clock showing seconds as a horizontal bar.
|
||||||
| 24hr style | 12hr style |
|
| 24hr style | 12hr style |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
|  |  |
|
|  |  |
|
||||||
|
|
||||||
|
## Settings
|
||||||
|
* `Show date`: display date at the bottom of screen
|
||||||
|
* `Font`: choose between bitmap or vector fonts
|
|
@ -51,24 +51,25 @@ function dateText(date) {
|
||||||
const ClockFace = require("ClockFace"),
|
const ClockFace = require("ClockFace"),
|
||||||
clock = new ClockFace({
|
clock = new ClockFace({
|
||||||
precision:1,
|
precision:1,
|
||||||
|
settingsFile:'barclock.settings.json',
|
||||||
init: function() {
|
init: function() {
|
||||||
const Layout = require("Layout");
|
const Layout = require("Layout");
|
||||||
this.layout = new Layout({
|
this.layout = new Layout({
|
||||||
type: "v", c: [
|
type: "v", c: [
|
||||||
{
|
{
|
||||||
type: "h", c: [
|
type: "h", c: [
|
||||||
{id: "time", label: "88:88", type: "txt", font: "6x8:5", col:g.theme.fg, bgCol: g.theme.bg}, // size updated below
|
{id: "time", label: "88:88", type: "txt", font: "6x8:5", col:g.theme.fg, bgCol: g.theme.bg}, // updated below
|
||||||
{id: "ampm", label: " ", type: "txt", font: "6x8:2", col:g.theme.fg, bgCol: g.theme.bg},
|
{id: "ampm", label: " ", type: "txt", font: "6x8:2", col:g.theme.fg, bgCol: g.theme.bg},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{id: "bar", type: "custom", fraction: 0, fillx: 1, height: 6, col: g.theme.fg2, render: renderBar},
|
{id: "bar", type: "custom", fraction: 0, fillx: 1, height: 6, col: g.theme.fg2, render: renderBar},
|
||||||
{height: 40},
|
this.showDate ? {height: 40} : {},
|
||||||
{id: "date", type: "txt", font: "10%", valign: 1},
|
this.showDate ? {id: "date", type: "txt", font: "10%", valign: 1} : {},
|
||||||
],
|
],
|
||||||
}, {lazy: true});
|
}, {lazy: true});
|
||||||
// adjustments based on screen size and whether we display am/pm
|
// adjustments based on screen size and whether we display am/pm
|
||||||
let thickness; // bar thickness, same as time font "pixel block" size
|
let thickness; // bar thickness, same as time font "pixel block" size
|
||||||
if (this.is12Hour) {
|
if (this.is12Hour && locale.hasMeridian) {
|
||||||
// Maximum font size = (<screen width> - <ampm: 2chars * (2*6)px>) / (5chars * 6px)
|
// Maximum font size = (<screen width> - <ampm: 2chars * (2*6)px>) / (5chars * 6px)
|
||||||
thickness = Math.floor((Bangle.appRect.w-24)/(5*6));
|
thickness = Math.floor((Bangle.appRect.w-24)/(5*6));
|
||||||
} else {
|
} else {
|
||||||
|
@ -76,13 +77,23 @@ const ClockFace = require("ClockFace"),
|
||||||
thickness = Math.floor(Bangle.appRect.w/(5*6));
|
thickness = Math.floor(Bangle.appRect.w/(5*6));
|
||||||
}
|
}
|
||||||
this.layout.bar.height = thickness+1;
|
this.layout.bar.height = thickness+1;
|
||||||
|
if (this.font===1) { // vector
|
||||||
|
const B2 = process.env.HWVERSION>1;
|
||||||
|
if (this.is12Hour && locale.hasMeridian) {
|
||||||
|
this.layout.time.font = "Vector:"+(B2 ? 50 : 60);
|
||||||
|
this.layout.ampm.font = "Vector:"+(B2 ? 20 : 40);
|
||||||
|
} else {
|
||||||
|
this.layout.time.font = "Vector:"+(B2 ? 60 : 80);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
this.layout.time.font = "6x8:"+thickness;
|
this.layout.time.font = "6x8:"+thickness;
|
||||||
|
}
|
||||||
this.layout.update();
|
this.layout.update();
|
||||||
},
|
},
|
||||||
update: function(date, c) {
|
update: function(date, c) {
|
||||||
if (c.m) this.layout.time.label = timeText(date);
|
if (c.m) this.layout.time.label = timeText(date);
|
||||||
if (c.h) this.layout.ampm.label = ampmText(date);
|
if (c.h) this.layout.ampm.label = ampmText(date);
|
||||||
if (c.d) this.layout.date.label = dateText(date);
|
if (c.d && this.showDate) this.layout.date.label = dateText(date);
|
||||||
const SECONDS_PER_MINUTE = 60;
|
const SECONDS_PER_MINUTE = 60;
|
||||||
if (c.s) this.layout.bar.fraction = date.getSeconds()/SECONDS_PER_MINUTE;
|
if (c.s) this.layout.bar.fraction = date.getSeconds()/SECONDS_PER_MINUTE;
|
||||||
this.layout.render();
|
this.layout.render();
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"id": "barclock",
|
"id": "barclock",
|
||||||
"name": "Bar Clock",
|
"name": "Bar Clock",
|
||||||
"version": "0.11",
|
"version": "0.13",
|
||||||
"description": "A simple digital clock showing seconds as a bar",
|
"description": "A simple digital clock showing seconds as a bar",
|
||||||
"icon": "clock-bar.png",
|
"icon": "clock-bar.png",
|
||||||
"screenshots": [{"url":"screenshot.png"},{"url":"screenshot_pm.png"}],
|
"screenshots": [{"url":"screenshot.png"},{"url":"screenshot_pm.png"}],
|
||||||
|
@ -12,6 +12,10 @@
|
||||||
"allow_emulator": true,
|
"allow_emulator": true,
|
||||||
"storage": [
|
"storage": [
|
||||||
{"name":"barclock.app.js","url":"clock-bar.js"},
|
{"name":"barclock.app.js","url":"clock-bar.js"},
|
||||||
|
{"name":"barclock.settings.js","url":"settings.js"},
|
||||||
{"name":"barclock.img","url":"clock-bar-icon.js","evaluate":true}
|
{"name":"barclock.img","url":"clock-bar-icon.js","evaluate":true}
|
||||||
|
],
|
||||||
|
"data": [
|
||||||
|
{"name":"barclock.settings.json"}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
(function(back) {
|
||||||
|
let s = require('Storage').readJSON("barclock.settings.json", true) || {};
|
||||||
|
|
||||||
|
function saver(key) {
|
||||||
|
return value => {
|
||||||
|
s[key] = value;
|
||||||
|
require('Storage').writeJSON("barclock.settings.json", s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const fonts = [/*LANG*/"Bitmap",/*LANG*/"Vector"];
|
||||||
|
const menu = {
|
||||||
|
"": {"title": /*LANG*/"Bar Clock"},
|
||||||
|
/*LANG*/"< Back": back,
|
||||||
|
/*LANG*/"Show date": require("ClockFace_menu").showDate(s.showDate, saver('showDate')),
|
||||||
|
/*LANG*/"Load widgets": require("ClockFace_menu").loadWidgets(s.loadWidgets, saver('loadWidgets')),
|
||||||
|
/*LANG*/"Font": {
|
||||||
|
value: s.font|0,
|
||||||
|
min:0,max:1,wrap:true,
|
||||||
|
format:v=>fonts[v],
|
||||||
|
onchange:saver('font'),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
E.showMenu(menu);
|
||||||
|
});
|
|
@ -0,0 +1,9 @@
|
||||||
|
0.01: Please forgive me
|
||||||
|
0.02: Now tells time!
|
||||||
|
0.03: Interaction
|
||||||
|
0.04: Shows day of week
|
||||||
|
0.05: Shows day of month
|
||||||
|
0.06: Updates every 5 minutes when locked, or when unlock occurs. Also shows nr of steps.
|
||||||
|
0.07: Step count resets at midnight
|
||||||
|
0.08: Step count stored in memory to survive reloads. Now shows step count daily and since last reboot.
|
||||||
|
0.09: NOW it really should reset daily (instead of every other day...)
|
|
@ -0,0 +1,23 @@
|
||||||
|
# Barcode clockwatchface
|
||||||
|
|
||||||
|
A scannable EAN-8 compatible clockwatchface for your Bangle 2
|
||||||
|
|
||||||
|
The format of the bars are
|
||||||
|
|
||||||
|
`||HHmm||MMwc||`
|
||||||
|
|
||||||
|
* Left section: HHmm
|
||||||
|
* H: Hours
|
||||||
|
* m: Minutes
|
||||||
|
* Right section: MM9c
|
||||||
|
* M: Day of month
|
||||||
|
* w: Day of week
|
||||||
|
* c: Calculated EAN-8 digit checksum
|
||||||
|
|
||||||
|
Apart from that
|
||||||
|
|
||||||
|
* The upper left section displays total number of steps per day
|
||||||
|
* The upper right section displays total number of steps from last boot ("stepuptime")
|
||||||
|
* The face updates every 5 minutes or on demant by pressing the hardware button
|
||||||
|
|
||||||
|
This clockwathface is aware of theme choice, so it will adapt to Light/Dark themes.
|
|
@ -0,0 +1,428 @@
|
||||||
|
/* Sizes */
|
||||||
|
let checkBarWidth = 10;
|
||||||
|
let checkBarHeight = 140;
|
||||||
|
|
||||||
|
let digitBarWidth = 14;
|
||||||
|
let digitBarHeight = 100;
|
||||||
|
|
||||||
|
let textBarWidth = 56;
|
||||||
|
let textBarHeight = 20;
|
||||||
|
|
||||||
|
let textWidth = 14;
|
||||||
|
let textHeight = 20;
|
||||||
|
|
||||||
|
/* Offsets */
|
||||||
|
var startOffsetX = 17;
|
||||||
|
var startOffsetY = 30;
|
||||||
|
|
||||||
|
let startBarOffsetX = startOffsetX;
|
||||||
|
let startBarOffsetY = startOffsetY;
|
||||||
|
|
||||||
|
let upperTextBarLeftOffsetX = startBarOffsetX + checkBarWidth;
|
||||||
|
let upperTextBarLeftOffsetY = startOffsetY;
|
||||||
|
|
||||||
|
let midBarOffsetX = upperTextBarLeftOffsetX + textBarWidth;
|
||||||
|
let midBarOffsetY = startOffsetY;
|
||||||
|
|
||||||
|
let upperTextBarRightOffsetX = midBarOffsetX + checkBarWidth;
|
||||||
|
let upperTextBarRightOffsetY = startOffsetY;
|
||||||
|
|
||||||
|
let endBarOffsetX = upperTextBarRightOffsetX + textBarWidth;
|
||||||
|
let endBarOffsetY = startOffsetY;
|
||||||
|
|
||||||
|
let leftBarsStartX = startBarOffsetX + checkBarWidth;
|
||||||
|
let leftBarsStartY = upperTextBarLeftOffsetY + textBarHeight;
|
||||||
|
|
||||||
|
let rightBarsStartX = midBarOffsetX + checkBarWidth;
|
||||||
|
let rightBarsStartY = upperTextBarRightOffsetY + textBarHeight;
|
||||||
|
|
||||||
|
/* Utilities */
|
||||||
|
let stepCount = require("Storage").readJSON("stepCount",1);
|
||||||
|
if(stepCount === undefined) stepCount = 0;
|
||||||
|
let intCaster = num => Number(num);
|
||||||
|
|
||||||
|
var drawTimeout;
|
||||||
|
|
||||||
|
function renderWatch(l) {
|
||||||
|
g.setFont("4x6",2);
|
||||||
|
|
||||||
|
// work out how to display the current time
|
||||||
|
|
||||||
|
var d = new Date();
|
||||||
|
var h = d.getHours(), m = d.getMinutes();
|
||||||
|
var time = h + ":" + ("0"+m).substr(-2);
|
||||||
|
//var month = ("0" + (d.getMonth()+1)).slice(-2);
|
||||||
|
var dayOfMonth = ('0' + d.getDate()).slice(-2);
|
||||||
|
var dayOfWeek = d.getDay() || 7;
|
||||||
|
var concatTime = ("0"+h).substr(-2) + ("0"+m).substr(-2) + dayOfMonth + dayOfWeek;
|
||||||
|
|
||||||
|
const chars = String(concatTime).split("").map((concatTime) => {
|
||||||
|
return Number(concatTime);
|
||||||
|
});
|
||||||
|
const checkSum = calculateChecksum(chars);
|
||||||
|
concatTime += checkSum;
|
||||||
|
|
||||||
|
drawCheckBar(startBarOffsetX, startBarOffsetY);
|
||||||
|
|
||||||
|
drawLDigit(chars[0], 0, leftBarsStartY);
|
||||||
|
drawLDigit(chars[1], 1, leftBarsStartY);
|
||||||
|
drawLDigit(chars[2], 2, leftBarsStartY);
|
||||||
|
drawLDigit(chars[3], 3, leftBarsStartY);
|
||||||
|
|
||||||
|
g.drawString(getStepCount(), startOffsetX + checkBarWidth + 3, startOffsetY + 4);
|
||||||
|
g.drawString(concatTime.substring(0,4), startOffsetX + checkBarWidth + 3, startOffsetY + textBarHeight + digitBarHeight + 6);
|
||||||
|
|
||||||
|
drawCheckBar(midBarOffsetX, midBarOffsetY);
|
||||||
|
|
||||||
|
drawRDigit(chars[4], 0, rightBarsStartY);
|
||||||
|
drawRDigit(chars[5], 1, rightBarsStartY);
|
||||||
|
drawRDigit(chars[6], 2, rightBarsStartY);
|
||||||
|
drawRDigit(checkSum, 3, rightBarsStartY);
|
||||||
|
|
||||||
|
g.drawString(Bangle.getStepCount(), midBarOffsetX + checkBarWidth + 3, startOffsetY + 4);
|
||||||
|
g.drawString(concatTime.substring(4), midBarOffsetX + checkBarWidth + 3, startOffsetY + textBarHeight + digitBarHeight + 6);
|
||||||
|
|
||||||
|
drawCheckBar(endBarOffsetX, endBarOffsetY);
|
||||||
|
|
||||||
|
// schedule a draw for the next minute
|
||||||
|
if (drawTimeout) {
|
||||||
|
clearTimeout(drawTimeout);
|
||||||
|
}
|
||||||
|
drawTimeout = setTimeout(function() {
|
||||||
|
drawTimeout = undefined;
|
||||||
|
layout.render(layout.watch);
|
||||||
|
}, (1000 * 60 * 5) - (Date.now() % (1000 * 60 * 5)));
|
||||||
|
}
|
||||||
|
|
||||||
|
function drawLDigit(digit, index, offsetY) {
|
||||||
|
switch(digit) {
|
||||||
|
case 0:
|
||||||
|
drawLZeroWithOffset(leftBarsStartX+(digitBarWidth*index), offsetY);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
drawLOneWithOffset(leftBarsStartX+(digitBarWidth*index), offsetY);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
drawLTwoWithOffset(leftBarsStartX+(digitBarWidth*index), offsetY);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
drawLThreeWithOffset(leftBarsStartX+(digitBarWidth*index), offsetY);
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
drawLFourWithOffset(leftBarsStartX+(digitBarWidth*index), offsetY);
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
drawLFiveWithOffset(leftBarsStartX+(digitBarWidth*index), offsetY);
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
drawLSixWithOffset(leftBarsStartX+(digitBarWidth*index), offsetY);
|
||||||
|
break;
|
||||||
|
case 7:
|
||||||
|
drawLSevenWithOffset(leftBarsStartX+(digitBarWidth*index), offsetY);
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
drawLEightWithOffset(leftBarsStartX+(digitBarWidth*index), offsetY);
|
||||||
|
break;
|
||||||
|
case 9:
|
||||||
|
drawLNineWithOffset(leftBarsStartX+(digitBarWidth*index), offsetY);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function drawRDigit(digit, index, offsetY) {
|
||||||
|
switch(digit) {
|
||||||
|
case 0:
|
||||||
|
drawRZeroWithOffset(rightBarsStartX+(digitBarWidth*index), offsetY);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
drawROneWithOffset(rightBarsStartX+(digitBarWidth*index), offsetY);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
drawRTwoWithOffset(rightBarsStartX+(digitBarWidth*index), offsetY);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
drawRThreeWithOffset(rightBarsStartX+(digitBarWidth*index), offsetY);
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
drawRFourWithOffset(rightBarsStartX+(digitBarWidth*index), offsetY);
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
drawRFiveWithOffset(rightBarsStartX+(digitBarWidth*index), offsetY);
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
drawRSixWithOffset(rightBarsStartX+(digitBarWidth*index), offsetY);
|
||||||
|
break;
|
||||||
|
case 7:
|
||||||
|
drawRSevenWithOffset(rightBarsStartX+(digitBarWidth*index), offsetY);
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
drawREightWithOffset(rightBarsStartX+(digitBarWidth*index), offsetY);
|
||||||
|
break;
|
||||||
|
case 9:
|
||||||
|
drawRNineWithOffset(rightBarsStartX+(digitBarWidth*index), offsetY);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
LEAN
|
||||||
|
|
||||||
|
01234567890123
|
||||||
|
xxxx xx
|
||||||
|
xx xxxx
|
||||||
|
xxxxxxxx xx
|
||||||
|
xx xxxx
|
||||||
|
xxxx xx
|
||||||
|
xx xxxxxxxx
|
||||||
|
xxxxxx xxxx
|
||||||
|
xxxx xxxxxx
|
||||||
|
xx xxxx
|
||||||
|
xxxx xx
|
||||||
|
*/
|
||||||
|
function drawLOneWithOffset(offset, offsetY) {
|
||||||
|
let barOneX = 4;
|
||||||
|
let barTwoX = 12;
|
||||||
|
g.fillRect(barOneX+offset,offsetY+0,barOneX+3+offset,offsetY+digitBarHeight);
|
||||||
|
g.fillRect(barTwoX+offset,offsetY+0,barTwoX+1+offset,offsetY+digitBarHeight);
|
||||||
|
//g.drawString("1",offset+3,offsetY+digitHeight+5);
|
||||||
|
}
|
||||||
|
|
||||||
|
function drawLTwoWithOffset(offset, offsetY) {
|
||||||
|
let barOneX = 4;
|
||||||
|
let barTwoX = 10;
|
||||||
|
g.fillRect(barOneX+offset,offsetY+0,barOneX+1+offset,offsetY+digitBarHeight);
|
||||||
|
g.fillRect(barTwoX+offset,offsetY+0,barTwoX+3+offset,offsetY+digitBarHeight);
|
||||||
|
//g.drawString("2",offset+3,offsetY+digitHeight+5);
|
||||||
|
}
|
||||||
|
|
||||||
|
function drawLThreeWithOffset(offset, offsetY) {
|
||||||
|
let barOneX = 2;
|
||||||
|
let barTwoX = 12;
|
||||||
|
g.fillRect(barOneX+offset,offsetY+0,barOneX+7+offset,offsetY+digitBarHeight);
|
||||||
|
g.fillRect(barTwoX+offset,offsetY+0,barTwoX+1+offset,offsetY+digitBarHeight);
|
||||||
|
//g.drawString("3",offset+3,offsetY+digitHeight+5);
|
||||||
|
}
|
||||||
|
|
||||||
|
function drawLFourWithOffset(offset, offsetY) {
|
||||||
|
let barOneX = 2;
|
||||||
|
let barTwoX = 10;
|
||||||
|
g.fillRect(barOneX+offset,offsetY+0,barOneX+1+offset,offsetY+digitBarHeight);
|
||||||
|
g.fillRect(barTwoX+offset,offsetY+0,barTwoX+3+offset,offsetY+digitBarHeight);
|
||||||
|
//g.drawString("4",offset+3,offsetY+digitHeight+5);
|
||||||
|
}
|
||||||
|
|
||||||
|
function drawLFiveWithOffset(offset, offsetY) {
|
||||||
|
let barOneX = 2;
|
||||||
|
let barTwoX = 12;
|
||||||
|
g.fillRect(barOneX+offset,offsetY+0,barOneX+3+offset,offsetY+digitBarHeight);
|
||||||
|
g.fillRect(barTwoX+offset,offsetY+0,barTwoX+1+offset,offsetY+digitBarHeight);
|
||||||
|
//g.drawString("5",offset+3,offsetY+digitHeight+5);
|
||||||
|
}
|
||||||
|
|
||||||
|
function drawLSixWithOffset(offset, offsetY) {
|
||||||
|
let barOneX = 2;
|
||||||
|
let barTwoX = 6;
|
||||||
|
g.fillRect(barOneX+offset,offsetY+0,barOneX+1+offset,offsetY+digitBarHeight);
|
||||||
|
g.fillRect(barTwoX+offset,offsetY+0,barTwoX+7+offset,offsetY+digitBarHeight);
|
||||||
|
//g.drawString("6",offset+3,offsetY+digitHeight+5);
|
||||||
|
}
|
||||||
|
|
||||||
|
function drawLSevenWithOffset(offset, offsetY) {
|
||||||
|
let barOneX = 2;
|
||||||
|
let barTwoX = 10;
|
||||||
|
g.fillRect(barOneX+offset,offsetY+0,barOneX+5+offset,offsetY+digitBarHeight);
|
||||||
|
g.fillRect(barTwoX+offset,offsetY+0,barTwoX+3+offset,offsetY+digitBarHeight);
|
||||||
|
//g.drawString("7",offset+3,offsetY+digitHeight+5);
|
||||||
|
}
|
||||||
|
|
||||||
|
function drawLEightWithOffset(offset, offsetY) {
|
||||||
|
let barOneX = 2;
|
||||||
|
let barTwoX = 8;
|
||||||
|
g.fillRect(barOneX+offset,offsetY+0,barOneX+3+offset,offsetY+digitBarHeight);
|
||||||
|
g.fillRect(barTwoX+offset,offsetY+0,barTwoX+5+offset,offsetY+digitBarHeight);
|
||||||
|
//g.drawString("8",offset+3,offsetY+digitHeight+5);
|
||||||
|
}
|
||||||
|
|
||||||
|
function drawLNineWithOffset(offset, offsetY) {
|
||||||
|
let barOneX = 6;
|
||||||
|
let barTwoX = 10;
|
||||||
|
g.fillRect(barOneX+offset,offsetY+0,barOneX+1+offset,offsetY+digitBarHeight);
|
||||||
|
g.fillRect(barTwoX+offset,offsetY+0,barTwoX+3+offset,offsetY+digitBarHeight);
|
||||||
|
//g.drawString("9",offset+3,offsetY+digitHeight+5);
|
||||||
|
}
|
||||||
|
|
||||||
|
function drawLZeroWithOffset(offset, offsetY) {
|
||||||
|
let barOneX = 6;
|
||||||
|
let barTwoX = 12;
|
||||||
|
g.fillRect(barOneX+offset,offsetY+0,barOneX+3+offset,offsetY+digitBarHeight);
|
||||||
|
g.fillRect(barTwoX+offset,offsetY+0,barTwoX+1+offset,offsetY+digitBarHeight);
|
||||||
|
//g.drawString("0",offset+3,offsetY+digitHeight+5);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
REAN
|
||||||
|
|
||||||
|
01234567890123
|
||||||
|
xxxx xxxx
|
||||||
|
xxxx xxxx
|
||||||
|
xx xx
|
||||||
|
xx xxxxxx
|
||||||
|
xx xxxxxx
|
||||||
|
xx xx
|
||||||
|
xx xx
|
||||||
|
xx xx
|
||||||
|
xxxxxx xx
|
||||||
|
xxxxxx xx
|
||||||
|
|
||||||
|
*/
|
||||||
|
function drawROneWithOffset(offset, offsetY) {
|
||||||
|
let barOneX = 0;
|
||||||
|
let barTwoX = 8;
|
||||||
|
g.fillRect(offset+barOneX,offsetY+0,offset+barOneX+3,offsetY+digitBarHeight);
|
||||||
|
g.fillRect(offset+barTwoX,offsetY+0,offset+barTwoX+3,offsetY+digitBarHeight);
|
||||||
|
//g.drawString("1",offset+2,offsetY+textHeight+5);
|
||||||
|
}
|
||||||
|
|
||||||
|
function drawRTwoWithOffset(offset, offsetY) {
|
||||||
|
let barOneX = 0;
|
||||||
|
let barTwoX = 6;
|
||||||
|
g.fillRect(offset+barOneX,offsetY+0,offset+barOneX+3,offsetY+digitBarHeight);
|
||||||
|
g.fillRect(offset+barTwoX,offsetY+0,offset+barTwoX+3,offsetY+digitBarHeight);
|
||||||
|
//g.drawString("2",offset+2,offsetY+textHeight+5);
|
||||||
|
}
|
||||||
|
|
||||||
|
function drawRThreeWithOffset(offset, offsetY) {
|
||||||
|
let barOneX = 0;
|
||||||
|
let barTwoX = 10;
|
||||||
|
g.fillRect(barOneX+offset,offsetY+0,barOneX+1+offset,offsetY+digitBarHeight);
|
||||||
|
g.fillRect(barTwoX+offset,offsetY+0,barTwoX+1+offset,offsetY+digitBarHeight);
|
||||||
|
//g.drawString("3",offset+2,offsetY+textHeight+5);
|
||||||
|
}
|
||||||
|
|
||||||
|
function drawRFourWithOffset(offset, offsetY) {
|
||||||
|
let barOneX = 0;
|
||||||
|
let barTwoX = 4;
|
||||||
|
g.fillRect(barOneX+offset,offsetY+0,barOneX+1+offset,offsetY+digitBarHeight);
|
||||||
|
g.fillRect(barTwoX+offset,offsetY+0,barTwoX+5+offset,offsetY+digitBarHeight);
|
||||||
|
//g.drawString("4",offset+2,offsetY+textHeight+5);
|
||||||
|
}
|
||||||
|
|
||||||
|
function drawRFiveWithOffset(offset, offsetY) {
|
||||||
|
let barOneX = 0;
|
||||||
|
let barTwoX = 6;
|
||||||
|
g.fillRect(barOneX+offset,offsetY+0,barOneX+1+offset,offsetY+digitBarHeight);
|
||||||
|
g.fillRect(barTwoX+offset,offsetY+0,barTwoX+5+offset,offsetY+digitBarHeight);
|
||||||
|
//g.drawString("5",offset+2,offsetY+textHeight+5);
|
||||||
|
}
|
||||||
|
|
||||||
|
function drawRSixWithOffset(offset, offsetY) {
|
||||||
|
let barOneX = 0;
|
||||||
|
let barTwoX = 4;
|
||||||
|
g.fillRect(barOneX+offset,offsetY+0,barOneX+1+offset,offsetY+digitBarHeight);
|
||||||
|
g.fillRect(barTwoX+offset,offsetY+0,barTwoX+1+offset,offsetY+digitBarHeight);
|
||||||
|
//g.drawString("6",offset+2,offsetY+textHeight+5);
|
||||||
|
}
|
||||||
|
|
||||||
|
function drawRSevenWithOffset(offset, offsetY) {
|
||||||
|
let barOneX = 0;
|
||||||
|
let barTwoX = 8;
|
||||||
|
g.fillRect(barOneX+offset,offsetY+0,barOneX+1+offset,offsetY+digitBarHeight);
|
||||||
|
g.fillRect(barTwoX+offset,offsetY+0,barTwoX+1+offset,offsetY+digitBarHeight);
|
||||||
|
//g.drawString("7",offset+2,offsetY+textHeight+5);
|
||||||
|
}
|
||||||
|
|
||||||
|
function drawREightWithOffset(offset, offsetY) {
|
||||||
|
let barOneX = 0;
|
||||||
|
let barTwoX = 6;
|
||||||
|
g.fillRect(offset+barOneX,offsetY+0,offset+barOneX+1,offsetY+digitBarHeight);
|
||||||
|
g.fillRect(offset+barTwoX,offsetY+0,offset+barTwoX+1,offsetY+digitBarHeight);
|
||||||
|
//g.drawString("8",offset+2,offsetY+textHeight+5);
|
||||||
|
}
|
||||||
|
|
||||||
|
function drawRNineWithOffset(offset, offsetY) {
|
||||||
|
let barOneX = 0;
|
||||||
|
let barTwoX = 8;
|
||||||
|
g.fillRect(barOneX+offset,offsetY+0,barOneX+5+offset,offsetY+digitBarHeight);
|
||||||
|
g.fillRect(barTwoX+offset,offsetY+0,barTwoX+1+offset,offsetY+digitBarHeight);
|
||||||
|
//g.drawString("9",offset+2,offsetY+textHeight+5);
|
||||||
|
}
|
||||||
|
|
||||||
|
function drawRZeroWithOffset(offset, offsetY) {
|
||||||
|
let barOneX = 0;
|
||||||
|
let barTwoX = 10;
|
||||||
|
g.fillRect(barOneX+offset,offsetY+0,barOneX+5+offset,offsetY+digitBarHeight);
|
||||||
|
g.fillRect(barTwoX+offset,offsetY+0,barTwoX+1+offset,offsetY+digitBarHeight);
|
||||||
|
//g.drawString("0",offset+2,offsetY+textHeight+5);
|
||||||
|
}
|
||||||
|
|
||||||
|
function drawCheckBar(offsetX, offsetY) {
|
||||||
|
const barOneX = offsetX+2;
|
||||||
|
const barOneWidth = 1;
|
||||||
|
const barTwoX = offsetX+6;
|
||||||
|
const barTwoWidth = 1;
|
||||||
|
g.fillRect(barOneX,offsetY,barOneX+barOneWidth,offsetY+checkBarHeight);
|
||||||
|
g.fillRect(barTwoX,offsetY,barTwoX+barTwoWidth,offsetY+checkBarHeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
function calculateChecksum(digits) {
|
||||||
|
let oddSum = digits[6] + digits[4] + digits[2] + digits[0];
|
||||||
|
let evenSum = digits[5] + digits[3] + digits[1];
|
||||||
|
|
||||||
|
let checkSum = (10 - ((3 * oddSum + evenSum) % 10)) % 10;
|
||||||
|
|
||||||
|
return checkSum;
|
||||||
|
}
|
||||||
|
|
||||||
|
function storeStepCount() {
|
||||||
|
stepCount = Bangle.getStepCount();
|
||||||
|
require("Storage").writeJSON("stepCount",stepCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getStepCount() {
|
||||||
|
let accumulatedSteps = Bangle.getStepCount();
|
||||||
|
if(accumulatedSteps <= stepCount) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return accumulatedSteps - stepCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
function resetAtMidnight() {
|
||||||
|
let now = new Date();
|
||||||
|
let night = new Date(
|
||||||
|
now.getFullYear(),
|
||||||
|
now.getMonth(),
|
||||||
|
now.getDate(), // the next day, ...
|
||||||
|
23, 58, 0 // ...at 00:00:00 hours
|
||||||
|
);
|
||||||
|
let msToMidnight = night.getTime() - now.getTime();
|
||||||
|
|
||||||
|
setTimeout(function() {
|
||||||
|
storeStepCount(); // <-- This is the function being called at midnight.
|
||||||
|
resetAtMidnight(); // Then, reset again next midnight.
|
||||||
|
}, msToMidnight);
|
||||||
|
}
|
||||||
|
|
||||||
|
resetAtMidnight();
|
||||||
|
|
||||||
|
// The layout, referencing the custom renderer
|
||||||
|
var Layout = require("Layout");
|
||||||
|
var layout = new Layout( {
|
||||||
|
type:"v", c: [
|
||||||
|
{type:"custom", render:renderWatch, id:"watch", bgCol:g.theme.bg, fillx:1, filly:1 }
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
// Clear the screen once, at startup
|
||||||
|
g.clear();
|
||||||
|
Bangle.loadWidgets();
|
||||||
|
Bangle.drawWidgets();
|
||||||
|
Bangle.setUI("clock");
|
||||||
|
layout.render();
|
||||||
|
|
||||||
|
Bangle.on('lock', function(locked) {
|
||||||
|
if(!locked) {
|
||||||
|
layout.render();
|
||||||
|
}
|
||||||
|
});
|
After Width: | Height: | Size: 2.7 KiB |
|
@ -0,0 +1 @@
|
||||||
|
E.toArrayBuffer(atob("MDAE///+ifnD6khY+bTIiDTIn8gWq8n+if/////+ifnD6khY+bTIiDTIn8gWq8n+if/////+ifnD6khY+bTIiDTIn8gWq8n+if/////+ifnD6khY+bTIiDTIn8gWq8n+if/////+ifnD6khY+bTIiDTIn8gWq8n+if/////+ifnD6khY+bTIiDTIn8gWq8n+if/////+ifnD6khY+bTIiDTIn8gWq8n+if/////+ifnD6khY+bTIiDTIn8gWq8n+if/////+ifnD6khY+bTIiDTIn8gWq8n+if/////+ifnD6khY+bTIiDTIn8gWq8n+if/////+ifnD6khY+bTIiDTIn8gWq8n+if/////+ifnD6khY+bTIiDTIn8gWq8n+if/////+ifnD6khY+bTIiDTIn8gWq8n+if/////+ifnD6khY+bTIiDTIn8gWq8n+if/////+ifnD6khY+bTIiDTIn8gWq8n+if/////+ifnD6khY+bTIiDTIn8gWq8n+if/////+ifnD6khY+bTIiDTIn8gWq8n+if/////+ifnD6khY+bTIiDTIn8gWq8n+if/////+ifnD6khY+bTIiDTIn8gWq8n+if/////+ifnD6khY+bTIiDTIn8gWq8n+if/////+ifnD6khY+bTIiDTIn8gWq8n+if/////+ifnD6khY+bTIiDTIn8gWq8n+if/////+ifnD6khY+bTIiDTIn8gWq8n+if/////+ifnD6khY+bTIiDTIn8gWq8n+if/////+ifnD6khY+bTIiDTIn8gWq8n+if/////+ifnD6khY+bTIiDTIn8gWq8n+if/////+ifnD6khY+bTIiDTIn8gWq8n+if/////+ifnD6khY+bTIiDTIn8gWq8n+if/////+ifnD6khY+bTIiDTIn8gWq8n+if/////+ifnD6khY+bTIiDTIn8gWq8n+if/////+ifnD6khY+bTIiDTIn8gWq8n+if/////+ifnD6khY+bTIiDTIn8gWq8n+if/////+ifrV6mlp+rXYiFXZr8k4q8r+if/////+if7+///u//79ie7/7//u///+if/////+ifnP6t+378r+ienvyf/K/7v+if/////+ifrfx6/I78j+ibe/+e/W75n+if/////+iee/+t/Z77f+iervyv/r/7v+if//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////"))
|
After Width: | Height: | Size: 2.3 KiB |
|
@ -0,0 +1,16 @@
|
||||||
|
{ "id": "barcode",
|
||||||
|
"name": "Barcode clock",
|
||||||
|
"shortName":"Barcode clock",
|
||||||
|
"icon": "barcode.icon.png",
|
||||||
|
"version":"0.09",
|
||||||
|
"description": "EAN-8 compatible barcode clock.",
|
||||||
|
"tags": "barcode,ean,ean-8,watchface,clock,clockface",
|
||||||
|
"type": "clock",
|
||||||
|
"supports" : ["BANGLEJS2"],
|
||||||
|
"storage": [
|
||||||
|
{"name":"barcode.app.js","url":"barcode.app.js"},
|
||||||
|
{"name":"barcode.img","url":"barcode.icon.js","evaluate":true}
|
||||||
|
],
|
||||||
|
"readme":"README.md",
|
||||||
|
"screenshots": [{"url":"barcode.clock.png"}]
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
0.01: Initial version
|
||||||
|
0.02: setTimeout bug fix; no leading zero on date; lightmode; 12 hour format; cleanup
|
||||||
|
0.03: Internationalisation; bug fix - battery icon responds promptly to charging state
|
|
@ -0,0 +1,14 @@
|
||||||
|
# Big Digit Clock
|
||||||
|
|
||||||
|
There are a number of big digit clocks available for the Bangle, but this is
|
||||||
|
the first which shows all the essential information that a clock needs to show
|
||||||
|
in a manner that is easy to read by those with poor eyesight.
|
||||||
|
|
||||||
|
The clock shows the time-of-day, the day-of-week and the day-of-month, as well
|
||||||
|
as an easy-to-see icon showing the current charge on the battery.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## Creator
|
||||||
|
|
||||||
|
Created by [Deirdre O'Byrne](https://github.com/deirdreobyrne)
|
|
@ -0,0 +1,91 @@
|
||||||
|
// <link href="https://fonts.googleapis.com/css2?family=Open+Sans:wght@600&display=swap" rel="stylesheet">
|
||||||
|
|
||||||
|
Graphics.prototype.setFontOpenSans = function(scale) {
|
||||||
|
// Actual height 48 (50 - 3)
|
||||||
|
this.setFontCustom(
|
||||||
|
atob('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB+AAAAAAAAAP8AAAAAAAAB/wAAAAAAAAH/gAAAAAAAAf+AAAAAAAAB/4AAAAAAAAH/gAAAAAAAAf8AAAAAAAAA/wAAAAAAAAB+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAAAAAAAAAPAAAAAAAAAH8AAAAAAAAD/wAAAAAAAA//AAAAAAAAf/8AAAAAAAP//wAAAAAAH///AAAAAAB///4AAAAAA///8AAAAAAf///AAAAAAH///gAAAAAD///wAAAAAB///4AAAAAAf//+AAAAAAP///AAAAAAH///gAAAAAA///4AAAAAAD//8AAAAAAAP/+AAAAAAAA//gAAAAAAAD/wAAAAAAAAP4AAAAAAAAA8AAAAAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB/gAAAAAAAP///AAAAAAH////gAAAAD/////gAAAAf/////gAAAH//////AAAA//////+AAAD//////8AAAf//////4AAD//4AH//gAAP/gAAAf/AAA/4AAAAf8AAH/AAAAA/4AAf4AAAAB/gAB/AAAAAD+AAH8AAAAAP4AAfwAAAAA/gAB/AAAAAD+AAH8AAAAAP4AAf4AAAAB/gAB/gAAAAH+AAD/gAAAB/wAAP/gAAAf/AAA//4AAf/8AAB///////gAAD//////8AAAH//////wAAAP/////+AAAAf/////wAAAA/////8AAAAAf////AAAAAAf///gAAAAAAB//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABwAAAAAAAAAHgAAAAAAAAA/AAAAAAAAAH+AAAAAAAAA/4AAAAAAAAD/AAAAAAAAAf8AAAAAAAAD/gAAAAAAAAf8AAAAAAAAB/gAAAAAAAAP8AAAAAAAAB/wAAAAAAAAP///////AAA///////8AAD///////wAAP///////AAA///////8AAD///////wAAP///////AAA///////8AAD///////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAD8AAAOAAAAAfwAAB+AAAAD/AAAH8AAAAf8AAA/wAAAH/wAAH/AAAA//AAAf4AAAH/8AAD/gAAA//wAAP8AAAH//AAA/gAAA//8AAD+AAAH//wAAf4AAA/9/AAB/AAAH/n8AAH8AAA/8fwAAfwAAH/h/AAB/AAA/8H8AAH8AAH/gfwAAfwAA/8B/AAB/gAH/gH8AAH+AB/8AfwAAP8Af/gB/AAA////8AH8AAD////gAfwAAH///8AB/AAAf///gAH8AAA///8AAfwAAB///gAB/AAAD//4AAH8AAAH/+AAAfwAAAH/gAAB/AAAAAAAAAH8AAAAAAAAAfwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPwAAAYAAAAB/gAAB4AAAAD+AAAPwAAAAP4AAA/gAAAAfwAAH+AAAAB/AAAf4AAAAH8AAD/AB+AAfwAAP8AH4AA/gAA/gAfgAD+AAH+AB+AAP4AAfwAH4AA/gAB/AAfgAD+AAH8AB+AAP4AAfwAH4AA/gAB/AA/wAD+AAH8AD/AAP4AAfwAP8AA/gAB/AA/wAD+AAH+AH/AAf4AAf4Af+AB/AAA/wH/8AP8AAD////4D/wAAP//+////AAAf//7///4AAB///P///gAAD//8f//8AAAP//h///gAAAf/8D//+AAAA//gH//wAAAA/4AP/8AAAAAAAAP/AAAAAAAAAHgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD8AAAAAAAAA/wAAAAAAAAH/AAAAAAAAB/8AAAAAAAAP/wAAAAAAAD//AAAAAAAAf/8AAAAAAAH//wAAAAAAA/+/AAAAAAAP/z8AAAAAAB/8PwAAAAAAf/g/AAAAAAD/4D8AAAAAAf/APwAAAAAH/4A/AAAAAA/+AD8AAAAAP/wAPwAAAAB/8AA/AAAAAf/gAD8AAAAD/4AAPwAAAA//AAA/AAAAD///////wAAP///////AAA///////8AAD///////wAAP///////AAA///////8AAD///////wAAP///////AAAAAAAA/AAAAAAAAAD8AAAAAAAAAPwAAAAAAAAA/AAAAAAAAAD8AAAAAAAAAPwAAAAAAAAA/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPwAAAAAAQAB/gAAAD//gAD+AAA////AAP8AAD///8AAfwAAP///wAB/AAA////AAH8AAD///8AAf4AAP///wAA/gAA////AAD+AAD/+H8AAP4AAP4AfwAA/gAA/gB+AAD+AAD+AH4AAP4AAP4AfwAA/gAA/gB/AAD+AAD+AH8AAP4AAP4AfwAB/gAA/gB/AAH+AAD+AH+AA/wAAP4Af8AD/AAA/gB/4A/8AAD+AD////gAAP4AP///+AAA/gAf///wAAD+AB////AAAP4AD///4AAA/gAH///AAAAAAAP//4AAAAAAAf/+AAAAAAAAf/gAAAAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAf//AAAAAAAf///gAAAAAP////gAAAAD/////gAAAAf/////AAAAD/////+AAAA//////8AAAD//////4AAAf/8/4//gAAD/8H+Af/AAAP/AfgAf8AAB/wD+AA/wAAH+APwAB/gAA/wB/AAD+AAD+AH4AAP4AAP4AfgAA/gAB/gB+AAD+AAH8AH4AAP4AAfwAfgAA/gAB/AB/AAH+AAH8AH8AAf4AAfwAf4AD/AAB/AB/4A/8AAH8AH////wAAfwAP///+AAB/AA////4AAH8AB////AAAfwAD///4AAA/AAH///AAAAAAAP//4AAAAAAAP/+AAAAAAAAP/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP4AAAAAAAAA/gAAAAAAAAD+AAAAAAAAAP4AAAAAAAAA/gAAAAAAAAD+AAAAAAAAAP4AAAAADAAA/gAAAAB8AAD+AAAAAfwAAP4AAAAH/AAA/gAAAB/8AAD+AAAAf/wAAP4AAAP//AAA/gAAD//8AAD+AAA///wAAP4AAP//8AAA/gAD///AAAD+AB///wAAAP4Af//4AAAA/gH//+AAAAD+B///gAAAAP4f//wAAAAA/v//8AAAAAD////AAAAAAP///wAAAAAA///4AAAAAAD//+AAAAAAAP//gAAAAAAA//wAAAAAAAD/8AAAAAAAAP/AAAAAAAAA/wAAAAAAAAD4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHAAAAAAAAAH/wAAAAH8AB//gAAAB/8AP//gAAAf/8B//+AAAB//4P//8AAAP//w///4AAB///n///gAAH//+////AAA/////gf8AAD/h//4AfwAAP4B//AB/gAB/gD/4AD+AAH8AP/gAP4AAfwAf8AA/gAB/AA/wAB+AAH4AD/AAH4AAfwAP8AAfgAB/AB/4AD+AAH8AH/gAP4AAfwA//AA/gAA/gH/+AH+AAD/h//8AfwAAP//+/4D/AAAf//7///8AAB///H///gAAD//4P//+AAAP//g///wAAAf/8B//+AAAA//gD//wAAAA/4AH/+AAAAAAAAH/wAAAAAAAAH4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD8AAAAAAAAD//AAAAAAAA///AAAAAAAH//+AAPwAAB///8AA/gAAP///4AD+AAA////wAP4AAH////AA/gAAf///8AD+AAD/4B/4AP4AAP+AB/gA/gAA/gAD+AD+AAH+AAP4AP4AAfwAAfgA/gAB/AAB+AD+AAH8AAH4AP4AAfwAAfgB/AAB/AAB+AH8AAH8AAH4A/wAAf4AA/AH+AAA/gAD8A/4AAD/gAfwH/gAAP/AD+B/8AAAf/g/w//gAAB//////+AAAD//////wAAAH/////+AAAAP/////wAAAAf////8AAAAA/////AAAAAA////wAAAAAAf//4AAAAAAAH/gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB+AAAfgAAAAP8AAD/AAAAA/4AAf8AAAAH/gAB/4AAAAf+AAH/gAAAB/4AAf+AAAAH/gAB/4AAAAf+AAH/AAAAA/wAAP8AAAAB+AAAfgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=='),
|
||||||
|
46,
|
||||||
|
atob("EhklJSUlJSUlJSUlEg=="),
|
||||||
|
64+(scale<<8)+(1<<16)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
var drawTimeout;
|
||||||
|
|
||||||
|
// schedule a draw for the next minute
|
||||||
|
function queueDraw() {
|
||||||
|
if (drawTimeout) clearTimeout(drawTimeout);
|
||||||
|
drawTimeout = setTimeout(function () {
|
||||||
|
draw();
|
||||||
|
}, 60300 - (Date.now() % 60000)); // We aim for 300ms into the next minute to ensure we make it!
|
||||||
|
}
|
||||||
|
|
||||||
|
function draw() {
|
||||||
|
var date = new Date();
|
||||||
|
var h = date.getHours(),
|
||||||
|
m = date.getMinutes();
|
||||||
|
var d = date.getDate(),
|
||||||
|
w = date.getDay(); // d=1..31; w=0..6
|
||||||
|
const level = E.getBattery();
|
||||||
|
const width = level + (level/2);
|
||||||
|
var is12Hour = (require("Storage").readJSON("setting.json", 1) || {})["12hour"];
|
||||||
|
var dows = require("date_utils").dows(0,1);
|
||||||
|
|
||||||
|
g.reset();
|
||||||
|
g.clear();
|
||||||
|
|
||||||
|
g.setFontOpenSans();
|
||||||
|
g.setFontAlign(0, -1);
|
||||||
|
if (is12Hour) {
|
||||||
|
if (h > 12) h -= 12;
|
||||||
|
if (h == 0) h = 12;
|
||||||
|
g.drawString(h + ":" + ("0"+m).substr(-2), g.getWidth() / 2, 30);
|
||||||
|
} else {
|
||||||
|
g.drawString(("0"+h).substr(-2) + ":" + ("0"+m).substr(-2), g.getWidth() / 2, 30);
|
||||||
|
}
|
||||||
|
g.setFontAlign(1, -1);
|
||||||
|
g.drawString(d, g.getWidth() -6, 98);
|
||||||
|
g.setFont('Vector', 52);
|
||||||
|
g.setFontAlign(-1, -1);
|
||||||
|
g.drawString(dows[w].slice(0,2).toUpperCase(), 6, 103);
|
||||||
|
|
||||||
|
g.fillRect(9,159,166,171);
|
||||||
|
g.fillRect(167,163,170,167);
|
||||||
|
if (Bangle.isCharging()) {
|
||||||
|
g.setColor(1,1,0);
|
||||||
|
} else if (level > 40) {
|
||||||
|
g.setColor(0,1,0);
|
||||||
|
} else {
|
||||||
|
g.setColor(1,0,0);
|
||||||
|
}
|
||||||
|
g.fillRect(12,162,12+width,168);
|
||||||
|
if (level < 100) {
|
||||||
|
g.setColor(g.theme.bg);
|
||||||
|
g.fillRect(12+width+1,162,162,168);
|
||||||
|
}
|
||||||
|
|
||||||
|
g.setColor(0, 1, 0);
|
||||||
|
g.fillRect(0, 90, g.getWidth(), 94);
|
||||||
|
|
||||||
|
// widget redraw
|
||||||
|
Bangle.drawWidgets();
|
||||||
|
queueDraw();
|
||||||
|
}
|
||||||
|
|
||||||
|
Bangle.on('lcdPower', on => {
|
||||||
|
if (on) {
|
||||||
|
draw(); // draw immediately, queue redraw
|
||||||
|
} else { // stop draw timer
|
||||||
|
if (drawTimeout) clearTimeout(drawTimeout);
|
||||||
|
drawTimeout = undefined;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Bangle.on('charging', (charging) => {
|
||||||
|
draw();
|
||||||
|
});
|
||||||
|
|
||||||
|
Bangle.loadWidgets();
|
||||||
|
draw();
|
||||||
|
|
||||||
|
Bangle.setUI("clock");
|
|
@ -0,0 +1 @@
|
||||||
|
require("heatshrink").decompress(atob("mEwgJC/AAMD4F4AgN4g/D/4FB/E/AoUH/F/AoOAh4FCz4FD4EPAoUHAoOHwAFDx/AAoUfAol/g4RD/w1Cg/B/AFD4fwn4XC4fg8/wAoPH//P7AFE9wFE8YFEEwcf4+BwAFBiACBAoUwAQPAAQMgAQNAArIjFF4sYgEBAoUIAoIRChi3B8AFBg8Ah/wAoIVBjH8ZAXguF+AoSDBn7WEh4FEg4"))
|
After Width: | Height: | Size: 7.9 KiB |
|
@ -0,0 +1,17 @@
|
||||||
|
{ "id": "bigdclock",
|
||||||
|
"name": "Big digit clock containing just the essentials",
|
||||||
|
"shortName":"Big digit clk",
|
||||||
|
"version":"0.03",
|
||||||
|
"description": "A clock containing just the essentials, made as easy to read as possible for those of us that need glasses. It contains the time, the day-of-week, the day-of-month, and the current battery state-of-charge.",
|
||||||
|
"icon": "bigdclock.png",
|
||||||
|
"type": "clock",
|
||||||
|
"tags": "clock",
|
||||||
|
"allow_emulator":true,
|
||||||
|
"supports" : ["BANGLEJS2"],
|
||||||
|
"readme": "README.md",
|
||||||
|
"screenshots": [ { "url":"screenshot.png" } ],
|
||||||
|
"storage": [
|
||||||
|
{"name":"bigdclock.app.js","url":"bigdclock.app.js"},
|
||||||
|
{"name":"bigdclock.img","url":"bigdclock.icon.js","evaluate":true}
|
||||||
|
]
|
||||||
|
}
|
After Width: | Height: | Size: 3.1 KiB |
|
@ -7,3 +7,4 @@
|
||||||
0.07: Fix off-by-one-error on previous month
|
0.07: Fix off-by-one-error on previous month
|
||||||
0.08: Do not register as watch, manually start clock on button
|
0.08: Do not register as watch, manually start clock on button
|
||||||
read start of week from system settings
|
read start of week from system settings
|
||||||
|
0.09: Fix scope of let variables
|
||||||
|
|
|
@ -16,6 +16,12 @@ const white = "#ffffff";
|
||||||
const red = "#d41706";
|
const red = "#d41706";
|
||||||
const blue = "#0000ff";
|
const blue = "#0000ff";
|
||||||
const yellow = "#ffff00";
|
const yellow = "#ffff00";
|
||||||
|
let bgColor = color4;
|
||||||
|
let bgColorMonth = color1;
|
||||||
|
let bgColorDow = color2;
|
||||||
|
let bgColorWeekend = color3;
|
||||||
|
let fgOtherMonth = gray1;
|
||||||
|
let fgSameMonth = white;
|
||||||
|
|
||||||
let settings = require('Storage').readJSON("calendar.json", true) || {};
|
let settings = require('Storage').readJSON("calendar.json", true) || {};
|
||||||
let startOnSun = ((require("Storage").readJSON("setting.json", true) || {}).firstDayOfWeek || 0) === 0;
|
let startOnSun = ((require("Storage").readJSON("setting.json", true) || {}).firstDayOfWeek || 0) === 0;
|
||||||
|
@ -27,19 +33,12 @@ if (settings.ndColors === undefined)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (settings.ndColors === true) {
|
if (settings.ndColors === true) {
|
||||||
let bgColor = white;
|
bgColor = white;
|
||||||
let bgColorMonth = blue;
|
bgColorMonth = blue;
|
||||||
let bgColorDow = black;
|
bgColorDow = black;
|
||||||
let bgColorWeekend = yellow;
|
bgColorWeekend = yellow;
|
||||||
let fgOtherMonth = blue;
|
fgOtherMonth = blue;
|
||||||
let fgSameMonth = black;
|
fgSameMonth = black;
|
||||||
} else {
|
|
||||||
let bgColor = color4;
|
|
||||||
let bgColorMonth = color1;
|
|
||||||
let bgColorDow = color2;
|
|
||||||
let bgColorWeekend = color3;
|
|
||||||
let fgOtherMonth = gray1;
|
|
||||||
let fgSameMonth = white;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function getDowLbls(locale) {
|
function getDowLbls(locale) {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"id": "calendar",
|
"id": "calendar",
|
||||||
"name": "Calendar",
|
"name": "Calendar",
|
||||||
"version": "0.08",
|
"version": "0.09",
|
||||||
"description": "Simple calendar",
|
"description": "Simple calendar",
|
||||||
"icon": "calendar.png",
|
"icon": "calendar.png",
|
||||||
"screenshots": [{"url":"screenshot_calendar.png"}],
|
"screenshots": [{"url":"screenshot_calendar.png"}],
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
1.00: New App!
|
||||||
|
1.01: Use fractional numbers and scale the points to keep working consistently on whole screen
|
|
@ -6,6 +6,7 @@ A simple calibration app for the touchscreen
|
||||||
Once lauched touch the cross that appear on the screen to make
|
Once lauched touch the cross that appear on the screen to make
|
||||||
another spawn elsewhere.
|
another spawn elsewhere.
|
||||||
|
|
||||||
each new touch on the screen will help to calibrate the offset
|
Each new touch on the screen will help to calibrate the offset
|
||||||
of your finger on the screen. After five or more input, press
|
of your finger on the screen. After four or more inputs, press
|
||||||
the button to save the calibration and close the application.
|
the button to save the calibration and close the application. Quality
|
||||||
|
of the calibration gets better with every touch on a cross.
|
||||||
|
|
|
@ -1,40 +1,60 @@
|
||||||
class BanglejsApp {
|
class BanglejsApp {
|
||||||
constructor() {
|
constructor() {
|
||||||
|
this.maxSamples = 16;
|
||||||
|
this.target = {
|
||||||
|
xMin: Math.floor(0.1 * g.getWidth()),
|
||||||
|
xMax: Math.floor(0.9 * g.getWidth()),
|
||||||
|
yMin: Math.floor(0.1 * g.getHeight()),
|
||||||
|
yMax: Math.floor(0.9 * g.getHeight()),
|
||||||
|
};
|
||||||
this.x = 0;
|
this.x = 0;
|
||||||
this.y = 0;
|
this.y = 0;
|
||||||
|
this.step = 0;
|
||||||
this.settings = {
|
this.settings = {
|
||||||
xoffset: 0,
|
xoffset: [0],
|
||||||
yoffset: 0,
|
yoffset: [0],
|
||||||
|
xMaxActual: [this.target.xMax],
|
||||||
|
yMaxActual: [this.target.yMax],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
load_settings() {
|
load_settings() {
|
||||||
let settings = require('Storage').readJSON('calibration.json', true) || {active: false};
|
let settings = require('Storage').readJSON('calibration.json', true) || {active: false};
|
||||||
|
|
||||||
// do nothing if the calibration is deactivated
|
|
||||||
if (settings.active === true) {
|
|
||||||
// cancel the calibration offset
|
|
||||||
Bangle.on('touch', function(button, xy) {
|
|
||||||
xy.x += settings.xoffset;
|
|
||||||
xy.y += settings.yoffset;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (!settings.xoffset) settings.xoffset = 0;
|
|
||||||
if (!settings.yoffset) settings.yoffset = 0;
|
|
||||||
|
|
||||||
console.log('loaded settings:');
|
console.log('loaded settings:');
|
||||||
console.log(settings);
|
console.log(settings);
|
||||||
|
|
||||||
return settings;
|
return settings;
|
||||||
}
|
}
|
||||||
|
|
||||||
save_settings() {
|
getMedian(array){
|
||||||
this.settings.active = true;
|
array.sort();
|
||||||
this.settings.reload = false;
|
let i = Math.floor(array.length/2);
|
||||||
require('Storage').writeJSON('calibration.json', this.settings);
|
if ( array.length % 2 && array.length > 1 ){
|
||||||
|
return (array[i]+array[i+1])/2;
|
||||||
|
} else {
|
||||||
|
return array[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
console.log('saved settings:');
|
getMedianSettings(){
|
||||||
console.log(this.settings);
|
let medianSettings = {
|
||||||
|
xoffset: this.getMedian(this.settings.xoffset),
|
||||||
|
yoffset: this.getMedian(this.settings.yoffset)
|
||||||
|
};
|
||||||
|
|
||||||
|
medianSettings.xscale = this.target.xMax / (medianSettings.xoffset + this.getMedian(this.settings.xMaxActual));
|
||||||
|
medianSettings.yscale = this.target.yMax / (medianSettings.yoffset + this.getMedian(this.settings.yMaxActual));
|
||||||
|
return medianSettings;
|
||||||
|
}
|
||||||
|
|
||||||
|
save_settings() {
|
||||||
|
let settingsToSave = this.getMedianSettings();
|
||||||
|
settingsToSave.active = true;
|
||||||
|
settingsToSave.reload = false;
|
||||||
|
require('Storage').writeJSON('calibration.json', settingsToSave);
|
||||||
|
|
||||||
|
console.log('saved settings:', settingsToSave);
|
||||||
}
|
}
|
||||||
|
|
||||||
explain() {
|
explain() {
|
||||||
|
@ -46,29 +66,78 @@ class BanglejsApp {
|
||||||
}
|
}
|
||||||
|
|
||||||
drawTarget() {
|
drawTarget() {
|
||||||
this.x = 16 + Math.floor(Math.random() * (g.getWidth() - 32));
|
switch (this.step){
|
||||||
this.y = 40 + Math.floor(Math.random() * (g.getHeight() - 80));
|
case 0:
|
||||||
|
this.x = this.target.xMin;
|
||||||
|
this.y = this.target.yMin;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
this.x = this.target.xMax;
|
||||||
|
this.y = this.target.yMin;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
this.x = this.target.xMin;
|
||||||
|
this.y = this.target.yMax;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
this.x = this.target.xMax;
|
||||||
|
this.y = this.target.yMax;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
g.clearRect(0, 24, g.getWidth(), g.getHeight() - 24);
|
g.clearRect(0, 0, g.getWidth(), g.getHeight());
|
||||||
|
g.setColor(g.theme.fg);
|
||||||
g.drawLine(this.x, this.y - 5, this.x, this.y + 5);
|
g.drawLine(this.x, this.y - 5, this.x, this.y + 5);
|
||||||
g.drawLine(this.x - 5, this.y, this.x + 5, this.y);
|
g.drawLine(this.x - 5, this.y, this.x + 5, this.y);
|
||||||
g.setFont('Vector', 10);
|
g.setFont('Vector', 10);
|
||||||
g.drawString('current offset: ' + this.settings.xoffset + ', ' + this.settings.yoffset, 0, 24);
|
let medianSettings = this.getMedianSettings();
|
||||||
|
g.drawString('current offset: ' + medianSettings.xoffset.toFixed(3) + ', ' + medianSettings.yoffset.toFixed(3), 2, (g.getHeight()/2)-6);
|
||||||
|
g.drawString('current scale: ' + medianSettings.xscale.toFixed(3) + ', ' + medianSettings.yscale.toFixed(3), 2, (g.getHeight()/2)+6);
|
||||||
}
|
}
|
||||||
|
|
||||||
setOffset(xy) {
|
setOffset(xy) {
|
||||||
this.settings.xoffset = Math.round((this.settings.xoffset + (this.x - Math.floor((this.x + xy.x)/2)))/2);
|
switch (this.step){
|
||||||
this.settings.yoffset = Math.round((this.settings.yoffset + (this.y - Math.floor((this.y + xy.y)/2)))/2);
|
case 0:
|
||||||
|
this.settings.xoffset.push(this.x - xy.x);
|
||||||
|
this.settings.yoffset.push(this.y - xy.y);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
this.settings.xMaxActual.push(xy.x);
|
||||||
|
this.settings.yoffset.push(this.y - xy.y);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
this.settings.xoffset.push(this.x - xy.x);
|
||||||
|
this.settings.yMaxActual.push(xy.y);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
this.settings.xMaxActual.push(xy.x);
|
||||||
|
this.settings.yMaxActual.push(xy.y);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let c in this.settings){
|
||||||
|
if (this.settings[c].length > this.maxSamples) this.settings[c] = this.settings[c].slice(1, this.maxSamples);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nextStep() {
|
||||||
|
this.step++;
|
||||||
|
if ( this.step == 4 ) this.step = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
E.srand(Date.now());
|
E.srand(Date.now());
|
||||||
Bangle.loadWidgets();
|
|
||||||
Bangle.drawWidgets();
|
|
||||||
|
|
||||||
calibration = new BanglejsApp();
|
calibration = new BanglejsApp();
|
||||||
calibration.load_settings();
|
calibration.load_settings();
|
||||||
|
Bangle.disableCalibration = true;
|
||||||
|
|
||||||
|
function touchHandler (btn, xy){
|
||||||
|
if (xy) calibration.setOffset(xy);
|
||||||
|
calibration.nextStep();
|
||||||
|
calibration.drawTarget();
|
||||||
|
}
|
||||||
|
|
||||||
let modes = {
|
let modes = {
|
||||||
mode : 'custom',
|
mode : 'custom',
|
||||||
|
@ -76,10 +145,7 @@ let modes = {
|
||||||
calibration.save_settings(this.settings);
|
calibration.save_settings(this.settings);
|
||||||
load();
|
load();
|
||||||
},
|
},
|
||||||
touch : function(btn, xy) {
|
touch : touchHandler,
|
||||||
calibration.setOffset(xy);
|
|
||||||
calibration.drawTarget();
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
Bangle.setUI(modes);
|
Bangle.setUI(modes);
|
||||||
calibration.drawTarget();
|
calibration.drawTarget();
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
let cal_settings = require('Storage').readJSON("calibration.json", true) || {active: false};
|
let cal_settings = require('Storage').readJSON("calibration.json", true) || {active: false};
|
||||||
Bangle.on('touch', function(button, xy) {
|
Bangle.on('touch', function(button, xy) {
|
||||||
// do nothing if the calibration is deactivated
|
// do nothing if the calibration is deactivated
|
||||||
if (cal_settings.active === false) return;
|
if (cal_settings.active === false || Bangle.disableCalibration) return;
|
||||||
|
|
||||||
// reload the calibration offset at each touch event /!\ bad for the flash memory
|
// reload the calibration offset at each touch event /!\ bad for the flash memory
|
||||||
if (cal_settings.reload === true) {
|
if (cal_settings.reload === true) {
|
||||||
|
@ -9,6 +9,6 @@ Bangle.on('touch', function(button, xy) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// apply the calibration offset
|
// apply the calibration offset
|
||||||
xy.x += cal_settings.xoffset;
|
xy.x = E.clip(Math.round((xy.x + (cal_settings.xoffset || 0)) * (cal_settings.xscale || 1)),0,g.getWidth());
|
||||||
xy.y += cal_settings.yoffset;
|
xy.y = E.clip(Math.round((xy.y + (cal_settings.yoffset || 0)) * (cal_settings.yscale || 1)),0,g.getHeight());
|
||||||
});
|
});
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
"name": "Touchscreen Calibration",
|
"name": "Touchscreen Calibration",
|
||||||
"shortName":"Calibration",
|
"shortName":"Calibration",
|
||||||
"icon": "calibration.png",
|
"icon": "calibration.png",
|
||||||
"version":"1.00",
|
"version":"1.01",
|
||||||
"description": "A simple calibration app for the touchscreen",
|
"description": "A simple calibration app for the touchscreen",
|
||||||
"supports": ["BANGLEJS","BANGLEJS2"],
|
"supports": ["BANGLEJS","BANGLEJS2"],
|
||||||
"readme": "README.md",
|
"readme": "README.md",
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
0.0: Main App.
|
||||||
|
0.1: Performance Fixes.
|
||||||
|
0.2: Correct Screen Clear and Draw.
|
||||||
|
0.3: Minor Fixes.
|
||||||
|
0.4: Clear Old Time on Screen Before Draw new Time
|
||||||
|
0.5: Update Date and Time to use Native date Funcions
|
||||||
|
0.6: Add Settings Page
|
||||||
|
0.7: Update Rocket Sequences Scope to not use memory all time
|
||||||
|
0.8: Update Some Variable Scopes to not use memory until need
|
||||||
|
0.9: Remove ESLint spaces
|
|
@ -0,0 +1,10 @@
|
||||||
|
# cassioWatch
|
||||||
|
|
||||||
|
 
|
||||||
|
|
||||||
|
Clock with Space Cassio Watch Style.
|
||||||
|
|
||||||
|
It displays current temperature,day,steps,battery.heartbeat and weather.
|
||||||
|
|
||||||
|
**To-do**:
|
||||||
|
Integrate heartbeat and Weather, Align and change size of some elements.
|
|
@ -0,0 +1,133 @@
|
||||||
|
require("Font6x12").add(Graphics);
|
||||||
|
require("Font8x12").add(Graphics);
|
||||||
|
require("Font7x11Numeric7Seg").add(Graphics);
|
||||||
|
|
||||||
|
let ClockInterval;
|
||||||
|
let RocketInterval;
|
||||||
|
let BatteryInterval;
|
||||||
|
|
||||||
|
function bigThenSmall(big, small, x, y) {
|
||||||
|
g.setFont("7x11Numeric7Seg", 2);
|
||||||
|
g.drawString(big, x, y);
|
||||||
|
x += g.stringWidth(big);
|
||||||
|
g.setFont("8x12");
|
||||||
|
g.drawString(small, x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
function ClearIntervals(inoreclock) {
|
||||||
|
if (RocketInterval) clearInterval(RocketInterval);
|
||||||
|
if (BatteryInterval) clearInterval(BatteryInterval);
|
||||||
|
RocketInterval = undefined;
|
||||||
|
BatteryInterval = undefined;
|
||||||
|
if (inoreclock) return;
|
||||||
|
if (ClockInterval) clearInterval(ClockInterval);
|
||||||
|
ClockInterval = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getBackgroundImage() {
|
||||||
|
return require("heatshrink").decompress(atob("2GwwkGIf4AfgMRkUiiIHCiMRiAMDAwYCCBAYVDAHMv/4ACkBIBAgPxBgM/BYXyAoICBCowA5gRADKQUDKAYMCmYCBiBXBCo4A5J4MxiMSKQUf+YBBBgSiBgc/kBXBBAMyCoK2CK/btCiUhfAJLCkBkDiMQgBXDCoUvNAJX+AAU/+MB/8wAQIAC+cQK5hoDgIEBBIQFEAYIPHBIgBBAQQIDBwZXSKIMxgJaBgEjmZYCmBXLgLBBkkAgUhiMxBIM0iMSCoMRkZECkQJEichBINDiETAgISBiQTDK6MvJAXzVIQrBBYMCK5E/K4kwGIJXFgdAMgQQBiYiCDgU0HQSlCgMikIEBEAMTDYJXQ+UikYDBj6nCAAMTWoJ6BK4oVEK4c0oQ+BK4MjAgMDJoJXHNYJXHBwa0BohcDY4QAKgJQE+LzBNwJVBkQMEkBXBCoyvFJAVAKISaBiMiHQRIDkVBoSyCK5CvBAgavNDAJAC+cQn5DCgSpBl4MDgBXBgCsBCoYoMLAKREgIKDBJIdKK5oA/AH4A/AH4A/ADUBIH4APiAFEi1mAGUADrkRKwUGK2ZXes1gK2xXfD8A3/K/4AWgxX/ACtga2AwIHLkAgCwvJw6RcDgIABK+w4cK/I4dsEGP5BXtSAQ6BV/5XSG4RX/K6Y3fK+42CK/5XTGwcGK/5XSVwY5cK+o1DAAayYsAhDsCv4K7BTBK4YeYK7CyFVzJXFFIpXtVwYiYK/rmZKYYDDELJXXG4YiaK/Y0aKgQAEK+gkdKt5XGKzqv5GTpX6ETlgK4xWrKTyxKVthXmAGRX/K/5X/AH5X/K/4gBAH4A/AFz/uAH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AH4A/AHNggEGHfEAgAEHKyQXVK0qTCAggbUK+6SDAApzXK/5BRDYZX3KxBBSYqxXngyvaV25XEd4ZCSsAcBAoRZ2dQZXBLwgaQCIYeCAGirCS4YGCDSJXCC6ZaodYICBZzSw4S4I+XDgSv4K4rzCK/47RAQTMaWHI9YV3TscV3aVagByBK3SwCSqyt8AAQ+XK/4A/AH4A/AH4A3gAA/AH4AuZbdggwc3ADpX/K/5XxsEAgA+XK/o8BgBX/K64/WK/4/XK/5X/K/5XvgBX/K64cYHrw4CSTFggCuXK4oDCEQJXYDS6ScDgg4CPKyRCAAZX0HAgBDK+LlYK4oeBAwZ9aK+lgAoQGBgyvzDIIDBK66sCG4JXYCwIBDK7ADCK+xZCHwJXzGoQ8BK7DpBAAaSXSgRXZO4okCK+IaXV4oABEILSWSYjRCHSo3BDSxXEAAIcBAISvyKawcIAYIGCK/4cUH4YlaHS0AHgI1XOg5YBPrY6WHgRXfAGRXDHzBX8VoJX/K68ADjRX6sBX/K/5X/K8wdcK/UAG7B0iKzZYbK/BWDAH4A/hWpzWhIf4ASgOpzIAB0EAhhH/AB8ZzGJ1WazMA4pH/AB+pxOZxOpzVMqA2ugUzmcgD7cKVYOqzGqpnRFw8ykchK8kviEBmQFBgMiFocSCAcSkUQAgMikRsHhWqxOq0Ut4mqBw0DC4IxBD4wpBHAQMCA4cCGJIAFj8hDIQuBkMTCwU/AYQJBiUxFoPxiIVDK4kyxUz4cxl+KK5MfDQXyD4UCmMSmAEBAQQHDgMTmIxHAAqpBmaqCFwMDEYZRBgEjCQQBB+USK5E/ns/0Uzwc6K48ykYkCK4IfCc4I4CK4QHEBAYAMiICBmYuDmQEBh8iAgRXCLISvJO4MqwcklEiK5CADV4oaBV4oHEK6Eve4JNCbwRfCiMTFoMDkMRSAJXCD49azWp0UqzWayJXIQwcAO4cCkMCFIJOCA4XxK6KPBkR6DTwYyBAwYPEAggfFzORpWK1OZyAOHJ4QfERAUSEgQxIIIgAr1URWIOZzOgGtwAhgMZzWq1OaIv4ASKgOqzTkvAEmq1WgFtQA=="));
|
||||||
|
}
|
||||||
|
|
||||||
|
function getRocketSequences() {
|
||||||
|
return {
|
||||||
|
1: require("heatshrink").decompress(atob("qFGwkCkQAiiEBEkUgKQhPhE8ogCE8YhCiQoEE7pKEPIgncTQ4neEwpQCPoh1eJYYwCJ7QmHKAh1hZIpOjPAUBJ0ZQCTzEhExZ1lPAZ1kKDQmOJ65O2E65OPOy5O2E64mPOyxO/J2wnPJyx2QJ35O/J2khE0p2POq52PEy4nOiQnlOrEhiSfMJrEggQnLJzB1CPBQmZkInMEzBQDPBImbPBR1ZEoRMCZYImhgQgEE0BzFKAgmaDwLDFKAbqdYQwHBOrcgDgLBFJrsiiRNGYbpLBY4Ymhd4omkkUhE0pQEEwUBJjrHBd4QmCdzoiBDwYrCPLyZHF4QnagQeCE8UgJwYniJwgnIOzwfFO0wJCJzMQE4gyFEzR2FBQombkInDQI4AakAnBTYS+ZE5BMDE0LEES7YnLE0R3FAEQA=")),
|
||||||
|
2: require("heatshrink").decompress(atob("qFGwkCkQAikMAgIliKYon/AA0gEAQniEwIhCAgYndEIjqBE8CaGKogmgKAp1fKAgncExBQBBQR1gKAp7BJ0IndExR4CE0idaOpYnbExqeYJxxPYEx0BJ0x2XExx2XJ20QE6xONJi5OPGwJOlBwLFkLoLFlBwJOkOwJOlE4JOkTjBOOE/52Pdi5OPEy7FnE5wmXE5xOZT5gmYEoMiiB1lgR4KTLAkDPBJ1WIAYDDKA4mWJwchDwYEDTjQiDJQh4GYLAhHFosSJy6OCTIxaEEywbBKYwjEEzMgUQxQFBogAURwZOGOjTKJdTYnOEryfHE0JQEfIpQgYQMAgJLeAgrtfTI4ndgSaFE4h0bdQkSZQpOfEAgIBO0AnEdrh2FJAb1EdbInEBIpObOwhOEEzYnFXzZ2HE4QlhE4QlDFMKcDYooniO0QnDT0YnCE0ciA")),
|
||||||
|
3: require("heatshrink").decompress(atob("qFGwkEogAjiMUEkVAKYgnhPYolgOQIniOYZ4FOcLqBE8CaGKojpgKAomhEYUQE7gmHKAIxCE0QkCPYR1gZIgnZExR4CJ0idmE7ZONYzImNgEUJ0p3YJRh2ZJJwnXOpQhBdkpaETsMEGQhOhE7jFLUYpOfTzgmKE4hOiE4hOigEUJ0rvCEywnPEqx2OTjBOOE7ImOTsqeZE5zFYoJOmT5kBJzEAih4LdK5mBAQInKOqoYDEgR4JEypHDEYbxJOq5ABdgZ7CEzZOEJQgnGihOYEIzJFTionCKYxWGEy9ADAYnGUIYmWog/EdBFAEy7KIKAwnjKwLqWE5pMeT48CVQpQfgMjKEtEiAnfEQJQCgJSCTcB6FJzkEdYcUE8FAdQghDOzonKTjh2EZAidcDoInHJzodBOwx/BE8JxcOwsAOwQmhJgSXDObwnFEwUUO0LFGE8aeiE4YmiokQE0tE")),
|
||||||
|
4: require("heatshrink").decompress(atob("qFGwkCkQAjiMSEkRTFE/4AGkMAgQCBE8MgEIYEDE7whDdQIngTQxVEE0ChFTjxQFE7jnFKAgxCOsBQFZgJ1gE7wmKPAROkTrTEHGAwnYiBHJFAaeXOoyXBEQZPac5AsFgJOhAoh2XJwwnFKoROdE4J9GJzwnIiQmVkInPAC0QE5AJFE64mHY5DFdE4SBEYr5JDJ0hKDJ0jCZJxoACgInmKLAmOTq5OOEy5OPTsxOYE5wmXO5wlYkAnMOqshiRNCgR4LOC8CkJCCEzxHDAgYnJOqpAEDoZ4HEyodDEQpQHdCsQOwwFHEyzoCPYzJGEy0gEwaZGA4acVEQSjHKAomXkQYEYAwlZeRKYDE8gjCYa7zJEwcCkImfKAb4FAD0hdTh4LgRSBOcR0CJz0gYYrrgN4QnEYrxOEE4bEeiAnGF4J2idL6VDE8ohBE0gnFE0J0BE4QGBiROgdIQABgJ2hJoTtjYgZSEE8ScgE4omikUQTcQADA=")),
|
||||||
|
5: require("heatshrink").decompress(atob("qFGwkCkQAikMAgIliKYonhiAnjkEATIIniEwIhCAgYndEIhQFYUZVEE0BQFOr5QEeQQmiKAL1DOr5QEE7ROCDgZVEAoInZDwchFQQoDPAJOdEQYrBdrZFDOYwncEJDsDVIpOXgJxEE4pObEAgGFgJOaE48BaIhOZJ5ZObY5ROcE441CE6xOGPAwtCJzpGCJ0hHDkI1DJzwoEJzInLFg52dUo5O/J35OzE54mWOx4mXJxx1XE54mXkUhExkSJzCfMOrAlBPBiZXgQDBAQQmgJgh4JOqoYEFYwmaDoZzEFgh1YDgkiiAFEKAroXJJAGFiQmVkCNDTIz5EJy57HKAomXkQYEJoqaYeRadEJrAnJEQUAgJPiAoYmeT4cCkAnBE0BKCJkT1EkDCeJYYiDOkLDFFL5wBE4guCPDhEBEwQiDY70CkInDiQnCJzkhOwhKDdzp2Idb4nEE0B0Bdo4niE0J0CeYhOhgESUYYnidsgnEE0KeCE0gnDE0ciA")),
|
||||||
|
6: require("heatshrink").decompress(atob("qFGwkCkQA/ABEgKQZPhEwgABEsAoGJkBxBE8JKEAowAbJIhQEgLDiPooAdKA4ncTZAndSwhQEFoInaJQkSKAwlZdgwnfSgYADE4h1ZDwInlcggnIOzAdCE8i7EY5J3XDgYhGd4pOZEI52bSYwGCOAJ2bYIodEOzZOFFAjFcEwwAIE6xOHABBO/J34ndEyx2PJ00BJ00SJ0p1XE54mXOxxO/J5wmYgQnMOrB2BPBgkWiJ1CPBbBYAYR4KiTAXRwIrFTjgZDJYZ4IEyoiEIwrDcEJJQFOqwiBDARxFFwgmXkAYDEogsBF4QmXEQJ7GUYYkBEzDKJAgYmdEQbKFEzonEKYgngJwgmfZggmjKQghgiBRGkBzeTgUikJRgc47LDErTnDEAkQJzkCJwYnEJzonEJIaddOwhJEJzgdBE4hYEJzieJADgnEE0KUCXzoAGkJLEiB2hOgQDBT0TsDT0YmlE4YmjkQ=")),
|
||||||
|
7: require("heatshrink").decompress(atob("qFGwkCkQAhkIpBiQlhkBSEJ8InlEIIoFE7whEE8pQFE7giBJQoneI4MCTYhQDE7YdCYYondEQYnEPwZ1bE5BQCJzonHkR2ZEAkBE4pNBE7zHFYrYhFUgonaXAQeEEwruZEYcgiROHJ7AfDAwxOeAAURiAmHE65HIOzwmOJ35OPE6xOPO35O/J35O/J1gnPEyx2PEy5OOOq5OnE5xOYO5omZgJQMJrQnLiQnagR4JOq5nCDgZ1fEYRLDE5DoZkUQNoZ4GOrJKGAoomXOw7lCAwYmYDgJSEAAUBA4QDBJzB6FOQrDXJwTJFdLjJKE9jDYZRAmkKAwmhKAgmiKAYmBkApdJIgjCKYIncOQYvJYTovGE84lagR2DE4xOakBOEgJXFOjYnEJAbtdOwggEkAmbDgInDE0B0BE4QgcE5AkiXYbpCOLonGYo4nhPMYnCUEgnBY0kiA==")),
|
||||||
|
8: require("heatshrink").decompress(atob("qFGwkCkQA/ABBSEJ8MgE4kBEsBPFE7xMCOIJ3hOYgFEE7rCGE70gE4pQBiAndYQwjBUohOZD4ZQFE7YkBE5AICYbZ2GE7sggJRCAA8iYzZOITroALE7EhExh4CAC0QExpPXOponZExx2XJ24nWdh52XdhzF/Yu5O/J35O0E55OXOx5O/J2omXE5x1XO54mYgQnMJrR4LOrciiAmiJgR4KEzIjDPBAlYiAiEeI51YkEBE4J5CD4KceTQQcBJgRQFdTZDCJIjDcNIqhGdTQmCkByFTTInDKgoAEE7ZEEJwhPdE1R1FE0InEE0R3DEwTGcDwomEE7hKFPYqafE8ROCE5DJbE5B/IEqh2ED4gnCJrMCJwgnEiB2bE4qeFEzUggQmIBQLEaEQImHLIImaE4YfcOw4lEFMLECS7onJO8wmkE4QljAAIA==")),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
let rocket_sequence = 1;
|
||||||
|
|
||||||
|
let settings = require('Storage').readJSON("cassioWatch.settings.json", true) || {};
|
||||||
|
let rocketSpeed = settings.rocketSpeed || 700;
|
||||||
|
delete settings;
|
||||||
|
|
||||||
|
g.clear();
|
||||||
|
|
||||||
|
function DrawClock() {
|
||||||
|
g.setFont("7x11Numeric7Seg", 3);
|
||||||
|
g.clearRect(80, 57, 170, 96);
|
||||||
|
g.setColor(0, 255, 255);
|
||||||
|
g.drawRect(80, 57, 170, 96);
|
||||||
|
g.fillRect(80, 57, 170, 96);
|
||||||
|
g.setColor(0, 0, 0);
|
||||||
|
g.drawString(require("locale").time(new Date(), 1), 70, 60);
|
||||||
|
g.setFont("8x12", 2);
|
||||||
|
g.drawString(require("locale").dow(new Date(), 2).toUpperCase(), 18, 130);
|
||||||
|
g.setFont("8x12");
|
||||||
|
g.drawString(require("locale").month(new Date(), 2).toUpperCase(), 80, 126);
|
||||||
|
g.setFont("8x12", 2);
|
||||||
|
const time = new Date().getDate();
|
||||||
|
g.drawString(time < 10 ? "0" + time : time, 78, 137);
|
||||||
|
}
|
||||||
|
|
||||||
|
function DrawBattery() {
|
||||||
|
bigThenSmall(E.getBattery(), "%", 135, 21);
|
||||||
|
}
|
||||||
|
|
||||||
|
function DrawRocket() {
|
||||||
|
let Rocket = getRocketSequences();
|
||||||
|
g.clearRect(5, 62, 63, 115);
|
||||||
|
g.setColor(0, 255, 255);
|
||||||
|
g.drawRect(5, 62, 63, 115);
|
||||||
|
g.fillRect(5, 62, 63, 115);
|
||||||
|
g.drawImage(Rocket[rocket_sequence], 5, 65, { scale: 0.7 });
|
||||||
|
g.setColor(0, 0, 0);
|
||||||
|
rocket_sequence = rocket_sequence + 1;
|
||||||
|
if (rocket_sequence > 8) rocket_sequence = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
function DrawScene() {
|
||||||
|
g.reset();
|
||||||
|
g.clear();
|
||||||
|
g.setColor(0, 255, 255);
|
||||||
|
g.fillRect(0, 0, g.getWidth(), g.getHeight());
|
||||||
|
let background = getBackgroundImage();
|
||||||
|
g.drawImage(background, 0, 0, { scale: 1 });
|
||||||
|
g.setColor(0, 0, 0);
|
||||||
|
g.setFont("6x12");
|
||||||
|
g.drawString("Launching Process", 30, 20);
|
||||||
|
g.setFont("8x12");
|
||||||
|
g.drawString("ACTIVATE", 40, 35);
|
||||||
|
g.setFont("8x12", 2);
|
||||||
|
g.drawString("30", 142, 132);
|
||||||
|
g.drawString("55", 95, 98);
|
||||||
|
g.setFont("8x12", 1);
|
||||||
|
g.drawString(Bangle.getStepCount(), 143, 104);
|
||||||
|
ClockInterval = setInterval(DrawClock, 30000);
|
||||||
|
DrawClock();
|
||||||
|
RocketInterval = setInterval(DrawRocket, rocketSpeed);
|
||||||
|
DrawRocket();
|
||||||
|
BatteryInterval = setInterval(DrawBattery, 5 * 60000);
|
||||||
|
DrawBattery();
|
||||||
|
}
|
||||||
|
|
||||||
|
Bangle.on("lcdPower", (on) => {
|
||||||
|
if (!on) {
|
||||||
|
g.clear();
|
||||||
|
ClearIntervals(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Bangle.on("lock", (locked) => {
|
||||||
|
if (locked) {
|
||||||
|
ClearIntervals(true);
|
||||||
|
} else {
|
||||||
|
ClearIntervals();
|
||||||
|
DrawScene();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
g.reset();
|
||||||
|
g.clear();
|
||||||
|
Bangle.setUI("clock");
|
||||||
|
DrawScene();
|
||||||
|
|
||||||
|
if (Bangle.isLocked()) {
|
||||||
|
ClearIntervals(true);
|
||||||
|
}
|
After Width: | Height: | Size: 4.7 KiB |
|
@ -0,0 +1 @@
|
||||||
|
require("heatshrink").decompress(atob("lkswkGswAHtGIxGGBhATJAAYXNCYoWOFIwWNChQWKBYWYCxIqTxGJFgwnDnACBkUiCwuYFQo9ECYIAClAsJxIUElAUDwQWEyxAHBwITBmczmUiCwprHCgMjmUhiIYBA4JCGIAeCwQUBCYIXBiUyFggVCFQsziMjmdCkcxiZbBiJCEFQZUBmND93uolEochFgpWEIAUUCgIACp00iZVBzIVEAoJABmUeConu8cRiNEoMZNwIrCzEiiUxpwVF901IwNN6JuBtGJlAVBkchCg3umkSiMNCoIAEQIJWFkgCB8UYinUjIVFxEhKwszDAUU7tRCg2hilTH4xVB6kRzAUGBQIVECYVEorEDAAeBptBiUenw7BCYQACieCCosd6MYwUVBwNUAQYvBeYOJCYVoxVeoK5BAAq0C8MjiM4LALFCilNCAQpCN4lBmUoFQQVCxTlBiMieI3uqUoagIVDRAeCkclCgvlkciFYdmsxwDlESmTdE8lRmSCECosiFgMhqgUDkZABBwWYCoNpIIYXBmchiKLBkYqBNggVBNwIsECwMikQUBlEiBgWJCoRCEEQITDNIJrEIAQABZYOYnIWBFoQUGIAZCCTYYWCAAQUExIUDFggNDAA5AEFg4AIIAhvGEYU4ChgWHAAoUIWYpdFFRIWHChxEICZoWFFBIA=="))
|
|
@ -0,0 +1,18 @@
|
||||||
|
{
|
||||||
|
"id": "cassioWatch",
|
||||||
|
"name": "Cassio Watch",
|
||||||
|
"description": "Animated Clock with Space Cassio Watch Style",
|
||||||
|
"screenshots": [{ "url": "screens/screen_night.png" },{ "url": "screens/screen_day.png" }],
|
||||||
|
"icon": "app.png",
|
||||||
|
"version": "0.9",
|
||||||
|
"type": "clock",
|
||||||
|
"tags": "clock, weather, cassio, retro",
|
||||||
|
"supports": ["BANGLEJS2"],
|
||||||
|
"allow_emulator": true,
|
||||||
|
"readme": "README.md",
|
||||||
|
"storage": [
|
||||||
|
{ "name": "cassioWatch.app.js", "url": "app.js" },
|
||||||
|
{"name":"cassioWatch.settings.js","url":"settings.js"},
|
||||||
|
{ "name": "cassioWatch.img", "url": "icon.js", "evaluate": true }
|
||||||
|
]
|
||||||
|
}
|
After Width: | Height: | Size: 63 KiB |
After Width: | Height: | Size: 60 KiB |
|
@ -0,0 +1,24 @@
|
||||||
|
(function(back) {
|
||||||
|
var FILE = "cassioWatch.settings.json";
|
||||||
|
var settings = Object.assign({
|
||||||
|
rocketSpeed: 700,
|
||||||
|
}, require('Storage').readJSON(FILE, true) || {});
|
||||||
|
|
||||||
|
function writeSettings() {
|
||||||
|
require('Storage').writeJSON(FILE, settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
E.showMenu({
|
||||||
|
"" : { "title" : "Cassio Watch" },
|
||||||
|
"< Back" : () => back(),
|
||||||
|
'Rocket Speed': {
|
||||||
|
value: 0|settings.rocketSpeed,
|
||||||
|
min: 100, max: 60000,
|
||||||
|
onchange: v => {
|
||||||
|
settings.rocketSpeed = v;
|
||||||
|
writeSettings();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
})
|
After Width: | Height: | Size: 6.1 KiB |
|
@ -0,0 +1,2 @@
|
||||||
|
0.01: New clock
|
||||||
|
0.02: Use ClockFace library, add settings
|
|
@ -0,0 +1,111 @@
|
||||||
|
Graphics.prototype.setFont15x32N = function() {
|
||||||
|
this.setFontCustom(atob(
|
||||||
|
// 15x32.png, converted using http://ebfc.mattbrailsford.com/
|
||||||
|
"/////oAAAAKAAAACgAAAAoAAAAKAAAACgf//AoEAAQKB//8CgAAAAoAAAAKAAAACgAAAAoAAAAL////+/wAB/oEAAQKBAAECgf//AoAAAAKAAAACgAAAAoAAAAKAAAACgAAAAoAAAAKAAAAC////AgAAAQIAAAH+/w///oEIAAKBCAACgQgAAoEIAAKBCAACgQg/AoEIIQKB+CECgAAhAoAAIQKAACECgAAhAoAAIQL//+H+/w/h/oEIIQKBCCECgQghAoEIIQKBCCECgQghAoEIIQKB+D8CgAAAAoAAAAKAAAACgAAAAoAAAAL////+///gAIAAIACAACAAgAAgAIAAIAD/+CAAAAggAAAIIAAACD/+//gAAoAAAAKAAAACgAAAAoAAAAL////+///h/oAAIQKAACECgAAhAoAAIQKAACECgfghAoEIIQKBCD8CgQgAAoEIAAKBCAACgQgAAoEIAAL/D//+/////oAAAAKAAAACgAAAAoAAAAKAAAACgfg/AoEIIQKBCD8CgQgAAoEIAAKBCAACgQgAAoEIAAL/D//+/wAAAIEAAACBAAAAgQAAAIEAAACBAAAAgQAAAIH///6AAAACgAAAAoAAAAKAAAACgAAAAoAAAAL////+/////oAAAAKAAAACgAAAAoAAAAKAAAACgfg/AoEIIQKB+D8CgAAAAoAAAAKAAAACgAAAAoAAAAL////+///h/oAAIQKAACECgAAhAoAAIQKAACECgfghAoEIIQKB+D8CgAAAAoAAAAKAAAACgAAAAoAAAAL////+"
|
||||||
|
), "0".charCodeAt(0), 15, 32);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add coordinates for nth tooth to vertices
|
||||||
|
* @param {array} poly Array to add points to
|
||||||
|
* @param {number} n Tooth number
|
||||||
|
*/
|
||||||
|
function addTooth(poly, n) {
|
||||||
|
const
|
||||||
|
tau = Math.PI*2, arc = tau/clock.teeth,
|
||||||
|
e = arc*clock.edge, p = arc*clock.point, s = (arc-(e+p))/2; // edge,point,slopes
|
||||||
|
const sin = Math.sin, cos = Math.cos,
|
||||||
|
x = clock.x, y = clock.y,
|
||||||
|
r2 = clock.r2, r3 = clock.r3;
|
||||||
|
let r = (n-1)*arc+e/2; // rads
|
||||||
|
poly.push(x+r2*sin(r), y-r2*cos(r));
|
||||||
|
r += s;
|
||||||
|
poly.push(x+r3*sin(r), y-r3*cos(r));
|
||||||
|
r += p;
|
||||||
|
poly.push(x+r3*sin(r), y-r3*cos(r));
|
||||||
|
r += s;
|
||||||
|
poly.push(x+r2*sin(r), y-r2*cos(r));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {number} n Tooth number to fill (1-based)
|
||||||
|
* @param col Fill color
|
||||||
|
*/
|
||||||
|
function fillTooth(n, col) {
|
||||||
|
if (!n) return; // easiest to check here
|
||||||
|
let poly = [];
|
||||||
|
addTooth(poly, n);
|
||||||
|
g.setColor(col).fillPoly(poly)
|
||||||
|
.setColor(g.theme.fg2).drawPoly(poly); // fillPoly colored over the outline
|
||||||
|
}
|
||||||
|
|
||||||
|
const ClockFace = require("ClockFace");
|
||||||
|
const clock = new ClockFace({
|
||||||
|
precision: 1,
|
||||||
|
settingsFile: "cogclock.settings.json",
|
||||||
|
init: function() {
|
||||||
|
this.r1 = 84; // inner radius
|
||||||
|
this.r3 = Math.min(Bangle.appRect.w/2, Bangle.appRect.h/2); // outer radius
|
||||||
|
this.r2 = (this.r1*3+this.r3*2)/5;
|
||||||
|
this.teeth = 12;
|
||||||
|
this.edge = 0.45;
|
||||||
|
this.point = 0.35; // as fraction of arc
|
||||||
|
this.x = Bangle.appRect.x+Bangle.appRect.w/2;
|
||||||
|
this.y = Bangle.appRect.y+Bangle.appRect.h/2;
|
||||||
|
},
|
||||||
|
draw: function(d) {
|
||||||
|
const x = this.x, y = this.y;
|
||||||
|
g.setColor(g.theme.bg2).fillCircle(x, y, this.r2) // fill cog
|
||||||
|
.setColor(g.theme.bg).fillCircle(x, y, this.r1) // clear center
|
||||||
|
.setColor(g.theme.fg2).drawCircle(x, y, this.r1); // draw inner border
|
||||||
|
let poly = []; // complete teeth outline
|
||||||
|
for(let t = 1; t<=this.teeth; t++) {
|
||||||
|
fillTooth(t, g.theme.bg2);
|
||||||
|
addTooth(poly, t);
|
||||||
|
}
|
||||||
|
g.drawPoly(poly, true); // draw outer border
|
||||||
|
if (!this.showDate) {
|
||||||
|
// draw top/bottom rectangles (instead of year/date)
|
||||||
|
g.reset()
|
||||||
|
.fillRect(x-30, y-60, x+29, y-33).clearRect(x-28, y-58, x+27, y-33)
|
||||||
|
.fillRect(x-30, y+60, x+29, y+30).clearRect(x-28, y+58, x+27, y+30);
|
||||||
|
}
|
||||||
|
this.tooth = 0;
|
||||||
|
this.update(d, {s: 1, m: 1, h: 1, d: 1});
|
||||||
|
},
|
||||||
|
update: function(d, c) {
|
||||||
|
g.reset();
|
||||||
|
const pad2 = num => (num<10 ? "0" : "")+num,
|
||||||
|
year = d.getFullYear(),
|
||||||
|
date = pad2(d.getDate())+pad2(d.getMonth()),
|
||||||
|
time = pad2(d.getHours())+pad2(d.getMinutes()),
|
||||||
|
tooth = Math.round(d.getSeconds()/60*this.teeth);
|
||||||
|
const x = this.x, y = this.y;
|
||||||
|
if (c.m) {
|
||||||
|
g.setFont("15x32N:2").setFontAlign(0, 0) // center middle
|
||||||
|
.drawString(time, x, y, true);
|
||||||
|
}
|
||||||
|
if (this.showDate) {
|
||||||
|
if (c.d) {
|
||||||
|
g.setFont("15x32N").setFontAlign(0, -1) // center top
|
||||||
|
.drawString(year, x, y+32, true)
|
||||||
|
.setFont("15x32N").setFontAlign(0, 1) // center bottom
|
||||||
|
.drawString(date, x, y-32, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tooth!==this.tooth) {
|
||||||
|
if (tooth>this.tooth) {
|
||||||
|
for(let t = this.tooth; t<=tooth; t++) { // fill missing teeth
|
||||||
|
fillTooth(t, g.theme.fg2);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for(let t = this.tooth; t>tooth; t--) { // erase extraneous teeth
|
||||||
|
fillTooth(t, g.theme.bg2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.tooth = tooth;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
clock.start();
|
|
@ -0,0 +1 @@
|
||||||
|
require("heatshrink").decompress(atob("mEwwhC/ACcikQXpCQUCC4MgBAgqMCQIXEAgQXNBwIDCAggXOABAXLHwQAHMYQXmmczI5oiCBwUjCwIABmQXDEgJ0KCwMwCwMDDAgyGLYoWBgAXBgAYBMZIXEkYWBC4YYBGAh7FFwgHCC4YEBPRIwCFwYXFGAaqHC56oIIwgXFJAbUJLwpgHI4qPDIwpIFR4wWDLwa6BAAQHDVIYYCC/gYCC453MPIR3HU5gADd5bXHC4rvJMAYAECwJeCd5MjGAjVDC4ZHGNARIFGAgNDFw5IJUogwFC4gwBDAhGBBghIFBQhhBbYguEPAweCDAgACCwZACNg5LFXQYsIC5QAFdg4XcCxJHNBwYTEC6A+BJYQEEC5YYBMYhbCCxo0GCaIXbAHgA="))
|
After Width: | Height: | Size: 11 KiB |
|
@ -0,0 +1,20 @@
|
||||||
|
{
|
||||||
|
"id": "cogclock",
|
||||||
|
"name": "Cog Clock",
|
||||||
|
"version": "0.02",
|
||||||
|
"description": "A cross-shaped clock inside a cog",
|
||||||
|
"icon": "icon.png",
|
||||||
|
"screenshots": [{"url":"screenshot.png"}],
|
||||||
|
"type": "clock",
|
||||||
|
"tags": "clock",
|
||||||
|
"supports": ["BANGLEJS"],
|
||||||
|
"allow_emulator": true,
|
||||||
|
"storage": [
|
||||||
|
{"name":"cogclock.app.js","url":"app.js"},
|
||||||
|
{"name":"cogclock.settings.js","url":"settings.js"},
|
||||||
|
{"name":"cogclock.img","url":"icon.js","evaluate":true}
|
||||||
|
],
|
||||||
|
"data": [
|
||||||
|
{"name": "cogclock.settings.json"}
|
||||||
|
]
|
||||||
|
}
|
After Width: | Height: | Size: 5.7 KiB |
|
@ -0,0 +1,19 @@
|
||||||
|
(function(back) {
|
||||||
|
let s = require('Storage').readJSON("cogclock.settings.json", true) || {};
|
||||||
|
|
||||||
|
function saver(key) {
|
||||||
|
return value => {
|
||||||
|
s[key] = value;
|
||||||
|
require('Storage').writeJSON("cogclock.settings.json", s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const menu = {
|
||||||
|
"": {"title": /*LANG*/"Cog Clock"},
|
||||||
|
/*LANG*/"< Back": back,
|
||||||
|
/*LANG*/"Show date": require("ClockFace_menu").showDate(s.showDate, saver('showDate')),
|
||||||
|
/*LANG*/"Load widgets": require("ClockFace_menu").loadWidgets(s.loadWidgets, saver('loadWidgets')),
|
||||||
|
};
|
||||||
|
|
||||||
|
E.showMenu(menu);
|
||||||
|
});
|
|
@ -4,3 +4,4 @@
|
||||||
0.04: Fix for Bangle.js 2 and themes
|
0.04: Fix for Bangle.js 2 and themes
|
||||||
0.05: Fix bearing not clearing correctly (visible in single or double digit bearings)
|
0.05: Fix bearing not clearing correctly (visible in single or double digit bearings)
|
||||||
0.06: Add button for force compass calibration
|
0.06: Add button for force compass calibration
|
||||||
|
0.07: Use 360-heading to output the correct heading value (fix #1866)
|
||||||
|
|
|
@ -49,7 +49,7 @@ Bangle.on('mag', function(m) {
|
||||||
g.setFontAlign(0,0).setFont("6x8",3);
|
g.setFontAlign(0,0).setFont("6x8",3);
|
||||||
var y = 36;
|
var y = 36;
|
||||||
g.clearRect(M-40,24,M+40,48);
|
g.clearRect(M-40,24,M+40,48);
|
||||||
g.drawString(Math.round(m.heading),M,y,true);
|
g.drawString(Math.round(360-m.heading),M,y,true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"id": "compass",
|
"id": "compass",
|
||||||
"name": "Compass",
|
"name": "Compass",
|
||||||
"version": "0.06",
|
"version": "0.07",
|
||||||
"description": "Simple compass that points North",
|
"description": "Simple compass that points North",
|
||||||
"icon": "compass.png",
|
"icon": "compass.png",
|
||||||
"screenshots": [{"url":"screenshot_compass.png"}],
|
"screenshots": [{"url":"screenshot_compass.png"}],
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
1.00: Initial implementation
|
|
@ -0,0 +1,3 @@
|
||||||
|
# Classic Football Chronometer Game
|
||||||
|
|
||||||
|
Context: https://www.anaitgames.com/analisis/analisis-casio-football-14
|
|
@ -0,0 +1 @@
|
||||||
|
atob("MDABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/wAAAAAA/wAAAAAA/wAAAAAA/wAAAAAA/wAAAAAA/wAAAAAA/wAAAAAA/wAAAAAADwAAAAAADwAAAAAADwAAAAAADwAAAAAA//AAAAAA//AAAAAA//AAAAAA//AAAAAADw8AD/AADw8AD/AADw8AD/AADw8AD/AP/wAAD/AP/wAAD/AP/wAAD/AP/wAAD/AA8PAAAAAA8PAAAAAA8PAAAAAA8PAAAAAAAA8AAAAAAA8AAAAAAA8AAAAAAA8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA")
|
|
@ -0,0 +1,440 @@
|
||||||
|
const digit = [];
|
||||||
|
|
||||||
|
const dash = {
|
||||||
|
width: 75,
|
||||||
|
height: 128,
|
||||||
|
bpp: 1,
|
||||||
|
buffer: require('heatshrink').decompress(atob('AH4A/AH4A/AH4A/AH4A/AB0D/4AB+AJEBAX/BAk/CQ8PCQ4kDCQoIDCQgkDCQgkECQgIE4ASHFxH8JRgSEEgYSEPJAkEAH4A/AH4A/AH4A/AH4A/ACg='))
|
||||||
|
};
|
||||||
|
function loadDigits () {
|
||||||
|
digit[0] = {
|
||||||
|
width: 80,
|
||||||
|
height: 128,
|
||||||
|
bpp: 1,
|
||||||
|
buffer: require('heatshrink').decompress(atob('AH4AGn//AAngBIMfBIvABIMPBIuABIMHBIoIBg0DBAn+gYSBgIJE/kHBIOABIn4h4JB4F/BIfwj4JB8BQEAoIJBBoJOEv4JBEIJOEIwMHGoIJDIIIJBJIJOEBIQOCJwYJDOIR9DBISFCSIYJCTISlDBIXwBIZoBBP4J/BP4J/BNX+gED//gBIc/BIMB//ABIcf/gDB/+ABIcP/AhCBAYuBFoU+BIkDFoUcBIkBFoUIBIkAFogA/AAZPJMZJ3JRZKfIWZLHJbZL5bBP4J/BP4J/BKPgBIc/BIfABIcfBIeA/4AB/EPBIcBBIX8AwIJB/0DBIQECBIIOCAAQYBBIIiCAAQsBBIPwGwIAC4F/BIPgJQIACAoIJBBoIJDDIIJBJwZQDBIJODKAcAgxODKAZxBJwgABPYROEKASFDAAiRCJwhQCTYYAkA'))
|
||||||
|
};
|
||||||
|
|
||||||
|
digit[1] = {
|
||||||
|
width: 80,
|
||||||
|
height: 128,
|
||||||
|
bpp: 1,
|
||||||
|
buffer: require('heatshrink').decompress(atob('AH4A2wAIHgIJIgYJIg4JIh4JIj4JIn4JIv4JI/4JHgIJIgYJIg4JIh4JIj4JIn4J/BP4J/BP4Jqj//BA0Ah/+BI8H/gJHgf4BI8B+AJHgHgBJFABJAA/J55jIO5KLJT5KzJY5L5nBP4J/BP4J/AAcfBJEPBJEHBJEDBJEBBJEABJN/BJE/BJEfBJEPBJEHBJEDBJEBBJEABJIA/AAwA='))
|
||||||
|
};
|
||||||
|
|
||||||
|
digit[2] = {
|
||||||
|
width: 80,
|
||||||
|
height: 128,
|
||||||
|
bpp: 1,
|
||||||
|
buffer: require('heatshrink').decompress(atob('AH4AGj//AAnwBIMPBIvgBIMHBIvABIMDBIuABIMBBIsBGQQIE/0DBIV/BIf8g4JCn4JD/EPKA/wj4JCKAngn4JCKAnAv4JCKAmA/4JCKAgEBQYZOEBIgADFgIJHIAKlJBI5oBBP4J/BP4J/BOcfBJEP/wJHg/8Aof/AAP+gf4BAUBBIX/gPwBIUDBIeA8AiDBIfAoA2DBIYSDJQQACEwZeCAAQ6DgF/BJATJE5I7IghPFBIUOMYomDO4g6EwCLDJwgiDAAhyFTohKEToheEBP4J/BP4J/BOHwBJHgBJHAv////8BImABAP//wJEAIIACBIf+BImABIX8g4JD4AJC/EPBIZACgfwj4JDKgUD8E/BIZoCgZODKAkDJwZQEgcBBIhQCgROEKAhOEKAhOEKAhOEKAgAm'))
|
||||||
|
};
|
||||||
|
|
||||||
|
digit[3] = {
|
||||||
|
width: 80,
|
||||||
|
height: 128,
|
||||||
|
bpp: 1,
|
||||||
|
buffer: require('heatshrink').decompress(atob('AH4AGj//AAnwBIMPBIvgBIMHBIvABIMDBIuABIMBBIsBGQQIE/0DBIV/BIf8g4JCn4JD/EPKA/wj4JCKAngn4JCKAnAv4JCKAmA/4JCKAgEBQYZOEBIgADFgIJHIAKlJBI5oBBI58BBP4J/BP4J/BL8/BJEf/wJHh/8BI8H/AFD/4AB/0D+AICgIJDgPgBIUDBIQ5B4AiDBIeAwA2DBIYSDJQIJDEwZeCAAQ6DOQQACJwgTJE5I7JJ5JjEgIUDO4kDFAgJC/kDIwipNj4JIn7HIbZL5TBP4J/BP4J/BJs/BJEfBJEPBIgjB//8g4JDgIIB//+gYJDAgIACBwIJCDAIACwAJDFgIAC4F/IAgAC8E/KggAC+EfIgoAB/EPBIQIDKAROFKAZOGKAROGKAQJI4BOGKAQJI+CfHAEAA=='))
|
||||||
|
};
|
||||||
|
digit[4] = {
|
||||||
|
width: 80,
|
||||||
|
height: 128,
|
||||||
|
bpp: 1,
|
||||||
|
buffer: require('heatshrink').decompress(atob('AH4AswEBBJOABAoHBgPABIsDBIPgBIsHBIPwBIsPBIP4BIsfBIP8BIs/BIP+BIt/BIP/BIv/BIRQEAwQCBKAkDBIZQEg4JDKAkPBIZQEj4JIn4J/BP4J/BP4JjgAJFj//AYN/8AJDh/+C4QJEg/8C4XAv////+gYjCh+ABAIABgPwC4Q9BAAWAEYUCgYJD4FAFgYJDIAoJDEwRUDAARoGAAROCCZYnJHZJPJMZAABO46hCRYwAFT4YAFWYYAFY4YAFbYYJ/BP4J/BP4Jnj4JIh4JIg4JIgYJIgIJIgAJJv4JIn4JIj4JIh4JIg4JIgYJIgIJIgAJJAH4AGA='))
|
||||||
|
};
|
||||||
|
|
||||||
|
digit[5] = {
|
||||||
|
width: 80,
|
||||||
|
height: 128,
|
||||||
|
bpp: 1,
|
||||||
|
buffer: require('heatshrink').decompress(atob('AGUP/4AE/gJBg4JF/AJBgYJF+AJBgIJF8AJBwAJF4AJB4F/BImABIPgn4JEIoXwj4ID/wJC/BQEJwUA/hQEJwUA/xQEJwUA/5QEJwQJBKAhOCBIJQEJwQJBKAiVDFggAEIAgJFKgYJFNAYJ/BP4J/BP4Jmv/8BI8//AJHj/wBI8P8E//4ABBIcH4F/BIWABIUDwAIC//ABIUBgIJD8AeDgYJDGwkHBIZKEh4JDLwkfBIZyECZInJHZJPFkChEMYdwUIh3DFAiLDgKvIgbDIJQKvIUIgJFUIZ8FBP4J/BP4J/BL8PBJEHBJEDBJEBBIl//4ABwAJEBAQHBv4JCDAIAC8E/BIQsBAAXwj4JCIAIAC/EPBIRUBAAX8g4JCNAIAC/0DBI//gIJCJwZQCBIQIEKANAJwpQCJwxQCJwxQCJwxQCBJYAwA='))
|
||||||
|
};
|
||||||
|
|
||||||
|
digit[6] = {
|
||||||
|
width: 80,
|
||||||
|
height: 128,
|
||||||
|
bpp: 1,
|
||||||
|
buffer: require('heatshrink').decompress(atob('AGU//4AE8AJBj4JF4AJBh4JFwAJBg4JFBAMGgYIE/wSCgIJE/gJCwAJE/AJC4F/BIfwBIXgKAhOCg/wKAhOCg/4KAhOD/hQEOwUH/xQDJwRiCKAZOCBIRQDJwQJCGwQAEBIJKCBIxeCBP4J/BP4J/BOED//gBI0B//ABI0A/+ABI9/CoIAB/gJDnwpBAAP+BIccHoIACBIcIh4JDFgkfBIZAEBIhUEv4JDNAgJE/ATNn4nIHZBPGKARjFgIUCO4sDFASLFg48COQsPKARyGUILHGn6hBBIJyGco4J/BP4J/BP4Jm8AJDn4JD4AJDj4JDwAJDh4JDgP/AAP8AwIJB/0DBIQECBIIOCAAQYBBIP4EQIACwAJC+A2BAAXAv4JB8BKBAAQFBBIINBBIYZBBIIhBAAYtBBIJODKAcAgxODKAZnBJwhQCOIYAEPoROEKASZDAAilCJwhQCTYYAuA=='))
|
||||||
|
};
|
||||||
|
|
||||||
|
digit[7] = {
|
||||||
|
width: 80,
|
||||||
|
height: 128,
|
||||||
|
bpp: 1,
|
||||||
|
buffer: require('heatshrink').decompress(atob('AGUH/4AE/wJBgYJF/gJBgIJF+AeCBJN/BIngsAJBn4JE4HgBIMfBImBBIUPBIkDBIRQE/0HBIRQE/kPBIRQE/EfBIRQE+E/BIZQD8AJEKAfABYIJCKAYsBBIYADIAIJHKgIJHNAIJ/BP4J/BP4Jzg//4AJGgf/wAJGgP/BAwAB/wJIvgJInAJIiAJIAH5PPMZJ3JRZCfJWZLHJfM4J/BP4J/BP4JNg4JIgYJIgIJIgAJJv4JIn4JIj4JIh4JIeg4JIgYJIgIJIgAJJsAJIkAJIAH4AQA='))
|
||||||
|
};
|
||||||
|
|
||||||
|
digit[8] = {
|
||||||
|
width: 80,
|
||||||
|
height: 128,
|
||||||
|
bpp: 1,
|
||||||
|
buffer: require('heatshrink').decompress(atob('AGUf/4AE+AJBh4JF8AJBg4JF4AJBgYJFwAIBgIJFgOAgeABAn+A4MD4F/BIf8g4JB8E/BIf4h4JB+BQEAoIJBBoJOEn4JBEIJOEv4JBGoJOEAIIHBKAgEBBIRQDDAQJCKAYsCBISFCSIYJCTISlDBIX4BIZoBBP4J/BP4J/BNkB//wBIcf/4DB//gBIcP/wDBv/ABIcH/ghCwH/AAP+gYtCj4pBAAUBFoUOHoIACwAtCgkHBIfAoA2DBIZAEJQIACKgheBAARoGBKInJHZBPJMZJ3JRZKfJWZDHJfM4J/BP4J/BP4JP+AJDj4JD8AJDh4JD4AJDg4JDwH/AAP+AwQCBgIJCAgQJBBwQACDAIJB/giBAAXAv4JB/A2BAAXgn4JB+BKBAAQFBBIINBBIYZBBIIhBBIYtBBIJODKAYJBJwhQCwECJwhQCwBxCAAh9CJwhQCTIYAEUoROEKASbDAFwA='))
|
||||||
|
};
|
||||||
|
|
||||||
|
digit[9] = {
|
||||||
|
width: 80,
|
||||||
|
height: 128,
|
||||||
|
bpp: 1,
|
||||||
|
buffer: require('heatshrink').decompress(atob('AGUP/4AE/gJBg4JF/AJBgYJF+AJBgIJF8AJBwAJF4FAgHAv4JEwHAgHgn4JEgIJB+EfBAf+gYJB/BQE/kHBIIDBJwkPBIIXBJwkfBIIrBJwk/BIRQEJYIJCKAgOBBIXgIwYiBBIR7CQ4YJCR4SbDBISjCV4YJC/wJDFYIJ/BP4J/BP4Jjv/8BIcP/+AgE//AJDg//C4XwBIcDEYUP8E//4ABgIjCg/Av4JCwAjCgeABAQ5BuAJBgMBBIfgkAsDBIY2EIAIACJQhUBAAReENAIACOQgTJE5I7JJ5KhBMYwABO44ABRY4AFT4YAFWYYAFY4YAFbYYJ/BP4J/BP4Jnh4JIg4JIgYJIgIJEv//AAOABIgICA4N/BIQYBAAXgn4JCFgIAC+EfBIRABAAX4h4JCKgIAC/kHBIRoBAAX+gYJCn4JD/8BBIRODKAQJCBAhQBoBOFKAROGKAROGKAROGKAQJLAGA='))
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// sprites
|
||||||
|
|
||||||
|
const left0 = {
|
||||||
|
width: 8,
|
||||||
|
height: 10,
|
||||||
|
bpp: 1,
|
||||||
|
transparent: 0,
|
||||||
|
buffer: atob('ADAwEDgUcCgEAA==')
|
||||||
|
};
|
||||||
|
|
||||||
|
const left1 = {
|
||||||
|
width: 8,
|
||||||
|
height: 10,
|
||||||
|
bpp: 1,
|
||||||
|
transparent: 0,
|
||||||
|
buffer: atob('ADAwEDh0ECAoAA==')
|
||||||
|
};
|
||||||
|
|
||||||
|
const left2 = {
|
||||||
|
width: 8,
|
||||||
|
height: 10,
|
||||||
|
bpp: 1,
|
||||||
|
transparent: 0,
|
||||||
|
buffer: atob('ADAwEBg4EBg0AA==')
|
||||||
|
};
|
||||||
|
|
||||||
|
const left4 = {
|
||||||
|
width: 8,
|
||||||
|
height: 10,
|
||||||
|
bpp: 1,
|
||||||
|
transparent: 0,
|
||||||
|
buffer: atob('ABgYVDgQEChEAA==')
|
||||||
|
};
|
||||||
|
|
||||||
|
const right0 = {
|
||||||
|
width: 8,
|
||||||
|
height: 10,
|
||||||
|
bpp: 1,
|
||||||
|
transparent: 0,
|
||||||
|
buffer: atob('AAwMCBwoDhQgAA==')
|
||||||
|
};
|
||||||
|
|
||||||
|
const right1 = {
|
||||||
|
width: 8,
|
||||||
|
height: 10,
|
||||||
|
bpp: 1,
|
||||||
|
transparent: 0,
|
||||||
|
buffer: atob('AAwMCBwuCAQUAA==')
|
||||||
|
};
|
||||||
|
|
||||||
|
const right2 = {
|
||||||
|
width: 8,
|
||||||
|
height: 10,
|
||||||
|
bpp: 1,
|
||||||
|
transparent: 0,
|
||||||
|
buffer: atob('AAwMCBgcCBgsAA==')
|
||||||
|
};
|
||||||
|
|
||||||
|
const right4 = left4;
|
||||||
|
|
||||||
|
const ball0 = {
|
||||||
|
width: 8,
|
||||||
|
height: 10,
|
||||||
|
bpp: 1,
|
||||||
|
transparent: 0,
|
||||||
|
buffer: atob('AAAAAAAwMAAAAA==')
|
||||||
|
};
|
||||||
|
|
||||||
|
const ball1 = {
|
||||||
|
width: 8,
|
||||||
|
height: 10,
|
||||||
|
bpp: 1,
|
||||||
|
transparent: 0,
|
||||||
|
buffer: atob('AAAAAAAAGBgAAA==')
|
||||||
|
};
|
||||||
|
const gol01 = {
|
||||||
|
width: 8,
|
||||||
|
height: 10,
|
||||||
|
bpp: 1,
|
||||||
|
transparent: 0,
|
||||||
|
buffer: atob('ABhkhIS0sIAAAA==')
|
||||||
|
};
|
||||||
|
|
||||||
|
const gol11 = {
|
||||||
|
width: 8,
|
||||||
|
height: 10,
|
||||||
|
bpp: 1,
|
||||||
|
buffer: require('heatshrink').decompress(atob('gEYk0hkMthsBBAI='))
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
loadDigits();
|
||||||
|
|
||||||
|
let goalFrame = 0;
|
||||||
|
let score0 = 0;
|
||||||
|
let score1 = 0;
|
||||||
|
|
||||||
|
function printNumber (n, x, y, options) {
|
||||||
|
if (n > 9 || n < -1) {
|
||||||
|
console.log(n);
|
||||||
|
return; // error
|
||||||
|
}
|
||||||
|
if (digit.length === 0) {
|
||||||
|
g.setColor(1, 1, 1);
|
||||||
|
if (options.scale == 0.2) {
|
||||||
|
g.setFont12x20(1);
|
||||||
|
} else {
|
||||||
|
g.setFont12x20(2.5);
|
||||||
|
}
|
||||||
|
g.drawString('' + n, x, y);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const img = (n == -1) ? dash : digit[n];
|
||||||
|
if (img) {
|
||||||
|
// g.setColor(0,0,0);
|
||||||
|
// g.fillRect(x,y,x+32*options.scale,64*options.scale);
|
||||||
|
g.setColor(1, 1, 1);
|
||||||
|
g.drawImage(img, x, y, options);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let inc = 0;
|
||||||
|
let msinc = 0;
|
||||||
|
let seq0 = 0;
|
||||||
|
let seq1 = 0;
|
||||||
|
let goaler = -1;
|
||||||
|
const w = g.getWidth();
|
||||||
|
let owner = -1;
|
||||||
|
g.setBgColor(0, 0, 0);
|
||||||
|
g.clear();
|
||||||
|
g.setColor(1, 1, 1);
|
||||||
|
function onStop () {
|
||||||
|
if (goalFrame > 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
stopped = !stopped;
|
||||||
|
if (stopped) {
|
||||||
|
// Bangle.beep();
|
||||||
|
if (msinc == 0) {
|
||||||
|
// GOOL
|
||||||
|
if (owner == 0) {
|
||||||
|
score0++;
|
||||||
|
goaler = 0;
|
||||||
|
} else if (owner == 1) {
|
||||||
|
score1++;
|
||||||
|
goaler = 1;
|
||||||
|
}
|
||||||
|
goalFrame = 5;
|
||||||
|
}
|
||||||
|
let newOwner = 0;
|
||||||
|
if (msinc % 2) {
|
||||||
|
newOwner = 1;
|
||||||
|
} else {
|
||||||
|
newOwner = 0;
|
||||||
|
}
|
||||||
|
if (newOwner) {
|
||||||
|
seq0--;
|
||||||
|
seq1++;
|
||||||
|
} else {
|
||||||
|
seq0++;
|
||||||
|
seq1--;
|
||||||
|
}
|
||||||
|
if (seq0 < 0) seq0 = 0;
|
||||||
|
if (seq0 > 3) seq0 = 3;
|
||||||
|
if (seq1 < 0) seq1 = 0;
|
||||||
|
if (seq1 > 3) seq1 = 3;
|
||||||
|
owner = newOwner;
|
||||||
|
}
|
||||||
|
refresh();
|
||||||
|
refresh_ms();
|
||||||
|
}
|
||||||
|
var stopped = true;
|
||||||
|
Bangle.on('tap', function (pos) {
|
||||||
|
console.log('touch', pos);
|
||||||
|
if (endGame) {
|
||||||
|
Bangle.beep();
|
||||||
|
score0 = 0;
|
||||||
|
score1 = 0;
|
||||||
|
seq0 = 0;
|
||||||
|
seq1 = 0;
|
||||||
|
inc = 0;
|
||||||
|
msinc = 0;
|
||||||
|
stopped = true;
|
||||||
|
endGame = false;
|
||||||
|
} else {
|
||||||
|
if (inc == 0) {
|
||||||
|
autogame();
|
||||||
|
} else {
|
||||||
|
onStop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
g.setFont12x20(3);
|
||||||
|
let part = 0;
|
||||||
|
let endInc = 0;
|
||||||
|
var endGame = false;
|
||||||
|
function refresh () {
|
||||||
|
g.clear();
|
||||||
|
if (inc > 59) {
|
||||||
|
inc = 0;
|
||||||
|
part++;
|
||||||
|
}
|
||||||
|
if (inc > 44) {
|
||||||
|
if (part < 2) {
|
||||||
|
part++;
|
||||||
|
}
|
||||||
|
if (part >= 2) {
|
||||||
|
if (score0 != score1) {
|
||||||
|
endGame = true;
|
||||||
|
endInc = inc;
|
||||||
|
inc = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// end of 1st or 2nd part of the game?
|
||||||
|
}
|
||||||
|
let two = (inc < 10) ? '0' + inc : '' + inc;
|
||||||
|
if (endGame) {
|
||||||
|
g.setColor(0, 0, 0);
|
||||||
|
g.fillRect(0, 64, w, h);
|
||||||
|
if (inc % 2) {
|
||||||
|
two = (endInc < 10) ? '0' + endInc : '' + endInc;
|
||||||
|
printNumber(-1, 2, 64 + 16, { scale: 0.4 });
|
||||||
|
printNumber(part, 34, 64 + 16, { scale: 0.4 });
|
||||||
|
printNumber(two[0], 74, 64 + 16, { scale: 0.4 });
|
||||||
|
printNumber(two[1], 74 + 32, 64 + 16, { scale: 0.4 });
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// seconds
|
||||||
|
printNumber(0, 2, 64 + 16, { scale: 0.4 });
|
||||||
|
printNumber(part, 34, 64 + 16, { scale: 0.4 });
|
||||||
|
printNumber(two[0], 74, 64 + 16, { scale: 0.4 });
|
||||||
|
printNumber(two[1], 74 + 32, 64 + 16, { scale: 0.4 });
|
||||||
|
}
|
||||||
|
refresh_ms();
|
||||||
|
refresh_score();
|
||||||
|
refresh_pixels();
|
||||||
|
}
|
||||||
|
|
||||||
|
function refresh_pixels () {
|
||||||
|
let frame4 = inc % 2;
|
||||||
|
if (goalFrame > 0) {
|
||||||
|
frame4 = goalFrame % 2;
|
||||||
|
if (goaler == 0) {
|
||||||
|
g.drawImage(frame4 ? right4 : right0, 20, 10, { scale: 5 });
|
||||||
|
g.setColor(1, 1, 1);
|
||||||
|
g.drawImage(gol11, w - 50, 10, { scale: 5 });
|
||||||
|
} else if (goaler == 1) {
|
||||||
|
g.drawImage(frame4 ? left0 : left4, w - 50, 10, { scale: 5 });
|
||||||
|
g.setColor(1, 1, 1);
|
||||||
|
g.drawImage(gol01, 30, 10, { scale: 5 });
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (endGame) {
|
||||||
|
if (score0 > score1) {
|
||||||
|
g.drawImage(frame4 ? right1 : right0, 5 + (seq0 * 10), 10, { scale: 5 });
|
||||||
|
} else if (score0 < score1) {
|
||||||
|
g.drawImage(frame4 ? left0 : left1, w - 30 - (seq1 * 10), 10, { scale: 5 });
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
g.drawImage(frame4 ? right1 : right0, 5 + (seq0 * 10), 10, { scale: 5 });
|
||||||
|
g.drawImage(frame4 ? left0 : left1, w - 30 - (seq1 * 10), 10, { scale: 5 });
|
||||||
|
let bx = (owner == 0) ? w / 3 : w / 2;
|
||||||
|
bx += 2;
|
||||||
|
g.drawImage(frame4 ? ball0 : ball1, bx, 10, { scale: 5 });
|
||||||
|
}
|
||||||
|
let dots = 0;
|
||||||
|
function refresh_dots () {
|
||||||
|
if (endGame) {
|
||||||
|
dots = 0;
|
||||||
|
} else {
|
||||||
|
dots++;
|
||||||
|
}
|
||||||
|
if (dots % 2) {
|
||||||
|
g.setColor(1, 1, 1);
|
||||||
|
} else {
|
||||||
|
g.setColor(0, 0, 0);
|
||||||
|
}
|
||||||
|
const x = 67;
|
||||||
|
let y = 100;
|
||||||
|
g.fillRect(x, y, x + 4, y + 4);
|
||||||
|
y += 16;
|
||||||
|
g.fillRect(x, y, x + 4, y + 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
const h = g.getHeight();
|
||||||
|
|
||||||
|
function refresh_ms () {
|
||||||
|
if (endGame) {
|
||||||
|
if (inc % 2) {
|
||||||
|
printNumber(-1, 80 + 64 - 4, 64 + 16 + 8 + 16, { scale: 0.2 });
|
||||||
|
printNumber(-1, 80 + 64 + 16 - 4, 64 + 32 + 8, { scale: 0.2 });
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// nanoseconds
|
||||||
|
if (msinc > 59) {
|
||||||
|
msinc = 0;
|
||||||
|
}
|
||||||
|
g.setColor(0, 0, 0);
|
||||||
|
g.fillRect(80 + 64, h / 2, 80 + 64 + 32, g.getHeight());
|
||||||
|
const two = (msinc < 10) ? '0' + msinc : '' + msinc;
|
||||||
|
printNumber(two[0], 80 + 64 - 4, 64 + 16 + 8 + 16, { scale: 0.2 });
|
||||||
|
printNumber(two[1], 80 + 64 + 16 - 4, 64 + 32 + 8, { scale: 0.2 });
|
||||||
|
}
|
||||||
|
|
||||||
|
function refresh_score () {
|
||||||
|
g.setColor(0, 0, 0);
|
||||||
|
g.fillRect(0, h - 32, w, h);
|
||||||
|
let two = (score0 < 10) ? '0' + score0 : '' + score0;
|
||||||
|
printNumber(two[0], 64 - 16, 32 + 64 + 16 + 8 + 16, { scale: 0.2 });
|
||||||
|
printNumber(two[1], 64, 32 + 64 + 32 + 8, { scale: 0.2 });
|
||||||
|
two = (score1 < 10) ? '0' + score1 : '' + score1;
|
||||||
|
printNumber(two[0], 32 + 64, 32 + 64 + 16 + 8 + 16, { scale: 0.2 });
|
||||||
|
printNumber(two[1], 32 + 64 + 16, 32 + 64 + 32 + 8, { scale: 0.2 });
|
||||||
|
}
|
||||||
|
refresh();
|
||||||
|
|
||||||
|
setInterval(function () {
|
||||||
|
if (!stopped || endGame) {
|
||||||
|
inc++;
|
||||||
|
}
|
||||||
|
if (goalFrame > 0) {
|
||||||
|
goalFrame--;
|
||||||
|
}
|
||||||
|
refresh();
|
||||||
|
}, 1000);
|
||||||
|
|
||||||
|
setInterval(function () {
|
||||||
|
refresh_dots();
|
||||||
|
}, 500);
|
||||||
|
|
||||||
|
setInterval(function () {
|
||||||
|
if (!stopped) {
|
||||||
|
msinc++;
|
||||||
|
if (msinc > 59) {
|
||||||
|
msinc = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, 10);
|
||||||
|
|
||||||
|
setInterval(function () {
|
||||||
|
if (!stopped) {
|
||||||
|
refresh_ms();
|
||||||
|
}
|
||||||
|
}, 250);
|
||||||
|
|
||||||
|
function autogame () {
|
||||||
|
if (endGame) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
onStop();
|
||||||
|
if (stopped) {
|
||||||
|
setTimeout(autogame, 500);
|
||||||
|
} else {
|
||||||
|
setTimeout(autogame, 315 + 10 * (Math.random() * 5));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Bangle.setOptions({ lockTimeout: 0, backlightTimeout: 0 });
|
||||||
|
autogame();
|
After Width: | Height: | Size: 232 B |
After Width: | Height: | Size: 96 B |
After Width: | Height: | Size: 95 B |
After Width: | Height: | Size: 463 B |
After Width: | Height: | Size: 671 B |
After Width: | Height: | Size: 386 B |
After Width: | Height: | Size: 606 B |
After Width: | Height: | Size: 620 B |
After Width: | Height: | Size: 535 B |
After Width: | Height: | Size: 656 B |
After Width: | Height: | Size: 726 B |
After Width: | Height: | Size: 516 B |
After Width: | Height: | Size: 709 B |
After Width: | Height: | Size: 741 B |
After Width: | Height: | Size: 69 KiB |
After Width: | Height: | Size: 9.4 KiB |
After Width: | Height: | Size: 7.0 KiB |
After Width: | Height: | Size: 115 B |
After Width: | Height: | Size: 115 B |
After Width: | Height: | Size: 112 B |
After Width: | Height: | Size: 120 B |
After Width: | Height: | Size: 116 B |
After Width: | Height: | Size: 121 B |
After Width: | Height: | Size: 112 B |
After Width: | Height: | Size: 125 B |
After Width: | Height: | Size: 116 B |
After Width: | Height: | Size: 125 B |
After Width: | Height: | Size: 113 B |
After Width: | Height: | Size: 125 B |
|
@ -0,0 +1,31 @@
|
||||||
|
{
|
||||||
|
"id": "football",
|
||||||
|
"name": "football",
|
||||||
|
"shortName": "football",
|
||||||
|
"version": "1.00",
|
||||||
|
"type": "app",
|
||||||
|
"description": "Classic football game of the CASIO chronometer",
|
||||||
|
"icon": "app.png",
|
||||||
|
"allow_emulator": true,
|
||||||
|
"tags": "games",
|
||||||
|
"supports": [
|
||||||
|
"BANGLEJS2"
|
||||||
|
],
|
||||||
|
"readme": "README.md",
|
||||||
|
"storage": [
|
||||||
|
{
|
||||||
|
"name": "football.app.js",
|
||||||
|
"url": "app.js"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "football.img",
|
||||||
|
"url": "app-icon.js",
|
||||||
|
"evaluate": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"screenshots": [
|
||||||
|
{
|
||||||
|
"url": "screenshot.png"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
After Width: | Height: | Size: 2.5 KiB |
|
@ -81,6 +81,7 @@ function onInit(device) {
|
||||||
if (crc==3435933210) version = "2v11.52";
|
if (crc==3435933210) version = "2v11.52";
|
||||||
if (crc==46757280) version = "2v11.58";
|
if (crc==46757280) version = "2v11.58";
|
||||||
if (crc==3508163280 || crc==1418074094) version = "2v12";
|
if (crc==3508163280 || crc==1418074094) version = "2v12";
|
||||||
|
if (crc==4056371285) version = "2v13";
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
version += `(⚠ update required)`;
|
version += `(⚠ update required)`;
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ var nhwmn = { // New homework Menu
|
||||||
|
|
||||||
function newHomeworkMenu() {
|
function newHomeworkMenu() {
|
||||||
E.showMessage("Getting subjects...");
|
E.showMessage("Getting subjects...");
|
||||||
var rawsubjects = require("Storage").read("subjects.txt"); // This code reads out the subjects list and removes the newline character at the end
|
var rawsubjects = require("Storage").read("homework.subjects.txt"); // This code reads out the subjects list and removes the newline character at the end
|
||||||
var splitsubjects = rawsubjects.split(",");
|
var splitsubjects = rawsubjects.split(",");
|
||||||
var lastItem = splitsubjects[splitsubjects.length - 1];
|
var lastItem = splitsubjects[splitsubjects.length - 1];
|
||||||
var thiscurrentsubject;
|
var thiscurrentsubject;
|
||||||
|
|
|
@ -9,6 +9,10 @@
|
||||||
"supports" : ["BANGLEJS2"],
|
"supports" : ["BANGLEJS2"],
|
||||||
"readme": "README.md",
|
"readme": "README.md",
|
||||||
"custom": "subjects.html",
|
"custom": "subjects.html",
|
||||||
|
"data": [
|
||||||
|
{"name":"homework.txt" },
|
||||||
|
{"name":"homework.subjects.txt" }
|
||||||
|
],
|
||||||
"storage": [
|
"storage": [
|
||||||
{"name":"homework.app.js","url":"app.js"},
|
{"name":"homework.app.js","url":"app.js"},
|
||||||
{"name":"homework.img","url":"app-icon.js","evaluate":true}
|
{"name":"homework.img","url":"app-icon.js","evaluate":true}
|
||||||
|
|
|
@ -20,9 +20,10 @@
|
||||||
// send finished app (in addition to contents of app.json)
|
// send finished app (in addition to contents of app.json)
|
||||||
sendCustomizedApp({
|
sendCustomizedApp({
|
||||||
storage:[
|
storage:[
|
||||||
{name:"subjects.txt"},
|
{name:"homework.subjects.txt", url:"subjects.txt", content:app},
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
|
console.log("Sent homework.subjects.txt!");
|
||||||
});
|
});
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -158,6 +158,8 @@ const itemsN = Math.ceil(apps.length / appsN);
|
||||||
Bangle.setUI({
|
Bangle.setUI({
|
||||||
mode: "custom",
|
mode: "custom",
|
||||||
drag: (e) => {
|
drag: (e) => {
|
||||||
|
g.setColor(g.theme.fg);
|
||||||
|
g.setBgColor(g.theme.bg);
|
||||||
let dy = e.dy;
|
let dy = e.dy;
|
||||||
if (scroll + R.h - dy > itemsN * itemSize) {
|
if (scroll + R.h - dy > itemsN * itemSize) {
|
||||||
dy = scroll + R.h - itemsN * itemSize;
|
dy = scroll + R.h - itemsN * itemSize;
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
0.01: New App
|
||||||
|
0.02: Allow drawing polys
|
||||||
|
0.03: Allow partly importing Amazfit decompiler formatted watchfaces
|
||||||
|
0.04: Allow writing all image data to separate file to save some RAM
|
||||||
|
Allow hiding elements on lock
|
||||||
|
0.05: Add precompilation to js for performance
|
||||||
|
0.06: Watchfaces can be refreshed partly
|
||||||
|
0.07: Allow wrapping drawing in timeouts to get faster reactions
|
||||||
|
Show/Hide widgets with swipe up or down
|
|
@ -0,0 +1,297 @@
|
||||||
|
# Imageclock
|
||||||
|
|
||||||
|
This app is a highly customizable watchface. To use it, you need to select
|
||||||
|
a watchface from another source. There is a native format as described here. You can also load decompiled watchfaces for Amazfit BIP fitness trackers.
|
||||||
|
|
||||||
|
# Usage
|
||||||
|
|
||||||
|
## Install a watchface
|
||||||
|
|
||||||
|
Choose the folder which contains the watchface, then clock "Upload to watch".
|
||||||
|
|
||||||
|
## Usage on the watch
|
||||||
|
|
||||||
|
Slide up/down to hide/show widgets.
|
||||||
|
Press button to start launcher.
|
||||||
|
|
||||||
|
# Design watch faces
|
||||||
|
|
||||||
|
## Folder structure
|
||||||
|
|
||||||
|
* watchfacename
|
||||||
|
* resources/
|
||||||
|
* face.json
|
||||||
|
* info.json
|
||||||
|
|
||||||
|
|
||||||
|
### resources
|
||||||
|
|
||||||
|
This folder contains image files. It can have subfolders. These files will
|
||||||
|
be read and converted into a resource bundle used by the clock
|
||||||
|
|
||||||
|
Folder types:
|
||||||
|
|
||||||
|
* Number
|
||||||
|
* Contains files named 0.ext to 9.ext and minus.ext
|
||||||
|
* CodedImage
|
||||||
|
* Contains files named with only digits for codes, i.e. 721.ext
|
||||||
|
* Contains a file named fallback.ext in case no code matches
|
||||||
|
* Codes are evaluated as follows: 721 -> if not found check 720 -> if not found check 700 -> if found use
|
||||||
|
* MultiState
|
||||||
|
* Notifications: sound.ext, silent.ext, vibrate.ext
|
||||||
|
* other status icons: on.ext, off.ext
|
||||||
|
* Scale
|
||||||
|
* Contains the components of the scale, named 0.ext to y.ext, y beeing the last element of the scale
|
||||||
|
|
||||||
|
### face.json
|
||||||
|
|
||||||
|
This file contains the description of the watch face elements.
|
||||||
|
|
||||||
|
#### Object types:
|
||||||
|
|
||||||
|
##### Properties
|
||||||
|
```
|
||||||
|
Properties: {
|
||||||
|
"Redraw": {
|
||||||
|
"Unlocked": 5000,
|
||||||
|
"Locked": 60000,
|
||||||
|
"Default": "Always",
|
||||||
|
"Events": ["HRM"],
|
||||||
|
"Clear": true
|
||||||
|
},
|
||||||
|
"Events": ["lock","HRM"]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Possible values for `Default` are `Always`, `Change`.
|
||||||
|
|
||||||
|
##### Images
|
||||||
|
|
||||||
|
```
|
||||||
|
"Image": {
|
||||||
|
"X": 0,
|
||||||
|
"Y": 0,
|
||||||
|
"Scale": 1,
|
||||||
|
"RotationValue": "Seconds",
|
||||||
|
"MinRotationValue": 0,
|
||||||
|
"MaxRotationValue": 60,
|
||||||
|
"ImagePath": [ "path", "in", "resources", "file" ]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
`RotationValue` references one of the implemented numerical values.
|
||||||
|
Mandatory:
|
||||||
|
* `ImagePath`
|
||||||
|
|
||||||
|
```
|
||||||
|
"Image": {
|
||||||
|
"X": 0,
|
||||||
|
"Y": 0,
|
||||||
|
"Value": "BatteryPercentage",
|
||||||
|
"Steps": 7,
|
||||||
|
"ImagePath": [ "path", "in", "resources", "file" ]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
If `Value` and `Steps`are given, the value is scaled and `Steps` number of images starting at 0 are used to display the value.
|
||||||
|
|
||||||
|
##### Coded Images
|
||||||
|
```
|
||||||
|
"CodedImage": {
|
||||||
|
"X": 0,
|
||||||
|
"Y": 0,
|
||||||
|
"Value": "WeatherCode",
|
||||||
|
"ImagePath": [ "path", "in", "resources", "file" ]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
The `Value` field is one of the implemented numerical values.
|
||||||
|
|
||||||
|
##### Number
|
||||||
|
|
||||||
|
Can be aligned to bottom left, top left, bottom right, top right and center. Will currently force all numbers to
|
||||||
|
be integer.
|
||||||
|
|
||||||
|
```
|
||||||
|
"Number": {
|
||||||
|
"X": 123,
|
||||||
|
"Y": 123,
|
||||||
|
"Alignment": "BottomRight",
|
||||||
|
"Value": "Temperature",
|
||||||
|
"Spacing": 1,
|
||||||
|
"ImagePath": [ "path", "to", "numbers", "folder" ]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
The `Value` field is one of the implemented numerical values.
|
||||||
|
`Alignment` is either `BottomRight` or `TopLeft`
|
||||||
|
|
||||||
|
Mandatory:
|
||||||
|
* `ImagePath`
|
||||||
|
* `Value`
|
||||||
|
|
||||||
|
##### Scale
|
||||||
|
|
||||||
|
```
|
||||||
|
"Scale": {
|
||||||
|
"X": 123,
|
||||||
|
"Y": 123,
|
||||||
|
"Value": "Temperature",
|
||||||
|
"MinValue": "-20",
|
||||||
|
"MaxValue": "50",
|
||||||
|
"ImagePath": [ "path", "to", "scale", "folder" ],
|
||||||
|
"Segments": [
|
||||||
|
{ "X": 5, "Y": 5},
|
||||||
|
{ "X": 10, "Y": 10 }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
The `Value` field is one of the implemented numerical values.
|
||||||
|
`MaxValue` and `MinValue` set the start and endpoints of the scale.
|
||||||
|
|
||||||
|
Mandatory:
|
||||||
|
* `ImagePath`
|
||||||
|
* `Value`
|
||||||
|
|
||||||
|
##### MultiState
|
||||||
|
|
||||||
|
```
|
||||||
|
"MultiState": {
|
||||||
|
"X": 0,
|
||||||
|
"Y": 0,
|
||||||
|
"Value": "Lock",
|
||||||
|
"ImagePath": ["icons", "status", "lock"]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
The `Value` field is one of the implemented multi state values.
|
||||||
|
|
||||||
|
Mandatory:
|
||||||
|
* `ImagePath`
|
||||||
|
* `Value`
|
||||||
|
|
||||||
|
##### Poly
|
||||||
|
|
||||||
|
```
|
||||||
|
"Poly":{
|
||||||
|
"Filled": true,
|
||||||
|
"RotationValue": "Second",
|
||||||
|
"MinRotationValue": "0",
|
||||||
|
"MaxRotationValue": "60",
|
||||||
|
"ForegroundColor": "#00f",
|
||||||
|
"BackgroundColor": "#008",
|
||||||
|
"Vertices":[
|
||||||
|
{"X":-1, "Y":13},
|
||||||
|
{"X":0, "Y":15},
|
||||||
|
{"X":1, "Y":13},
|
||||||
|
{"X":2, "Y":0},
|
||||||
|
{"X":1, "Y":-75},
|
||||||
|
{"X":0, "Y":-80},
|
||||||
|
{"X":-1, "Y":-75},
|
||||||
|
{"X":-2, "Y":0}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
The `RotationValue` field is one of the implemented numeric values.
|
||||||
|
|
||||||
|
##### Rect
|
||||||
|
|
||||||
|
```
|
||||||
|
"Rect":{
|
||||||
|
"X": 10,
|
||||||
|
"Y": 20,
|
||||||
|
"Width": 30,
|
||||||
|
"Height": 40,
|
||||||
|
"Filled": true,
|
||||||
|
"ForegroundColor": "#00f",
|
||||||
|
"BackgroundColor": "#008"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
The `RotationValue` field is one of the implemented numeric values.
|
||||||
|
|
||||||
|
##### Nesting
|
||||||
|
```
|
||||||
|
"Container": {
|
||||||
|
"X": 10,
|
||||||
|
"Y": 10,
|
||||||
|
"OtherContainer": {
|
||||||
|
"X": 5,
|
||||||
|
"Y": 5,
|
||||||
|
"SomeElement": {
|
||||||
|
"X": 2,
|
||||||
|
"Y": 2,
|
||||||
|
<Content>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
`SomeElement` will be drawn at X- and Y-position 2+5+10=17, because positions are relative to parent element.
|
||||||
|
Container names can be everything but other object names.
|
||||||
|
|
||||||
|
#### Implemented data sources
|
||||||
|
|
||||||
|
##### Numerical
|
||||||
|
|
||||||
|
* Hour
|
||||||
|
* Hour12Analog
|
||||||
|
* Hour12
|
||||||
|
* HourTens
|
||||||
|
* HourOnes
|
||||||
|
* Minute
|
||||||
|
* MinuteAnalog
|
||||||
|
* MinuteTens
|
||||||
|
* MinuteOnes
|
||||||
|
* Second
|
||||||
|
* SecondAnalog
|
||||||
|
* SecondTens
|
||||||
|
* SecondOnes
|
||||||
|
* WeekDay
|
||||||
|
* WeekDayMondayFirst
|
||||||
|
* Day
|
||||||
|
* DayTens
|
||||||
|
* DayOnes
|
||||||
|
* Month
|
||||||
|
* MonthTens
|
||||||
|
* MonthOnes
|
||||||
|
* Pulse
|
||||||
|
* Steps
|
||||||
|
* Temperature
|
||||||
|
* Pressure
|
||||||
|
* Altitude
|
||||||
|
* BatteryPercentage
|
||||||
|
* BatteryVoltage
|
||||||
|
* StepsGoal
|
||||||
|
* WeatherCode
|
||||||
|
* WeatherTemperature
|
||||||
|
|
||||||
|
##### Multistate
|
||||||
|
|
||||||
|
* on/off
|
||||||
|
* Lock
|
||||||
|
* Charge
|
||||||
|
* Alarm
|
||||||
|
* Bluetooth
|
||||||
|
* BluetoothPeripheral
|
||||||
|
* HRM
|
||||||
|
* Barometer
|
||||||
|
* Compass
|
||||||
|
* GPS
|
||||||
|
* StepsGoal
|
||||||
|
* WeatherTemperatureNegative
|
||||||
|
* on/off/vibrate
|
||||||
|
* Notifications
|
||||||
|
* celsius/fahrenheit/unknown
|
||||||
|
* WeatherTemperatureUnit
|
||||||
|
|
||||||
|
### info.json
|
||||||
|
|
||||||
|
This file contains information for the conversion process, it will not be
|
||||||
|
stored on the watch
|
||||||
|
|
||||||
|
# TODO
|
||||||
|
|
||||||
|
* Handle events and redraws better
|
||||||
|
* Performance improvements
|
||||||
|
* Mark elements with how often they need to be redrawn
|
||||||
|
* Finalize the file format
|
||||||
|
* Localization
|
||||||
|
|
||||||
|
# Creator
|
||||||
|
|
||||||
|
[halemmerich](https://github.com/halemmerich)
|
|
@ -0,0 +1 @@
|
||||||
|
require("heatshrink").decompress(atob("mEwwIdah/wAof//4ECgYFB4AFBg4FB8AFBj/wh/4AoM/wEB/gFBvwCEBAU/AQP4gfAj8AgPwAoMPwED8AFBg/AAYIBDA4ngg4TB4EBApkPKgJSBJQIFTMgIFCJIIFDKoIFEvgFBGoMAnw7DP4IFEh+BAoItBg+DNIQwBMIaeCKoKxCPoIzCEgKVHUIqtFXIrFFaIrdFdIwAV"))
|