diff --git a/apps/90sclk/ChangeLog b/apps/90sclk/ChangeLog
new file mode 100644
index 000000000..feb008f5f
--- /dev/null
+++ b/apps/90sclk/ChangeLog
@@ -0,0 +1,2 @@
+0.01: New App!
+0.02: Fullscreen settings.
\ No newline at end of file
diff --git a/apps/90sclk/README.md b/apps/90sclk/README.md
new file mode 100644
index 000000000..c09c6fe23
--- /dev/null
+++ b/apps/90sclk/README.md
@@ -0,0 +1,13 @@
+# 90s Clock
+
+A watch face in 90s style:
+
+
+
+Fullscreen mode can be enabled in the settings:
+
+
+
+
+## Creator
+- [David Peer](https://github.com/peerdavid)
diff --git a/apps/90sclk/app-icon.js b/apps/90sclk/app-icon.js
new file mode 100644
index 000000000..28f75c4e6
--- /dev/null
+++ b/apps/90sclk/app-icon.js
@@ -0,0 +1 @@
+require("heatshrink").decompress(atob("mEwgc8+fAgEgwAMDvPnz99BYdl2weHtu27ft2AGBiEcuEAhAPDg4jGgECIRMN23fthUNgP374vBAB3gAgc/gAXNjlx4EDxwJEpAjG/6IBjkBL4UAjVgBAJuCgPHBQMFEIkkyQjFhwEClgXBEYNBwkQJoibCBwNFBAUCEAVAQZAjC/8euPHDon//hKB//xEYMP//jBYP/+ARDNYM///+EYIgBj1B/8fCIUhEYQRB//FUIM/EZU4EYMkEYP/8VhEYUH/gRBWAUfI4MD+AjBoAsBwEH8EB/EDwE4HwYjCuEHWAOHgExEYKbBCIZNB8fAEYQHByE/EwPABAY+BgRHDBANyJQXHNwIjD8CSBj/+BwMSTwOOBYK2D/4CCNYZQB/iJBQwYjCCIcAgeBSoOAWYQjEVoIRCNAIjKAQKJBgAFC8ZoCWwJbDABMHGQPAAoMQB5EDx/4A4gqBZwIGCWwIABuBWC4EBZwPgv/AcwS/EAAcIU4IRBVQIRKEwIjBv0ARIUDCJIjD//x/ARK/5HC/+BCJkcI45uDgECUgQjCWAM4WwUBWYanEAA8cTARWBEYUC5RAHw1YgEOFQXADQPHIIkAhgICuARBh0A23blhHBagIKBsOGjNswhHDEYUUAoTUBhkxEYMwKwU503bvuwXILmCEYMYsumWYYjB85lDEYovBEYXm7fs25EBI4kYtOWNwIjD4+8NYsw4YjGz9/2hrEoOGjVBwE4NYdzNYSwBuEDEYcxaIUA8+atugGogjBiVgWAI"))
diff --git a/apps/90sclk/app.js b/apps/90sclk/app.js
new file mode 100644
index 000000000..6babbfec2
--- /dev/null
+++ b/apps/90sclk/app.js
@@ -0,0 +1,144 @@
+const SETTINGS_FILE = "90sclk.setting.json";
+const locale = require('locale');
+const storage = require('Storage');
+
+
+/*
+ * Load settings
+ */
+let settings = {
+ fullscreen: false,
+};
+
+let saved_settings = storage.readJSON(SETTINGS_FILE, 1) || settings;
+for (const key in saved_settings) {
+ settings[key] = saved_settings[key]
+}
+
+
+function getImg() {
+ return require("heatshrink").decompress(atob("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"));
+}
+
+Graphics.prototype.setFontTime = function(scale) {
+ // Actual height 54 (56 - 3)
+ this.setFontCustom(atob("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA4AAAAAAAAPwAAAAAAAA/gAAAAAAAF/AAAAAAAA/8AAAAAAAD/wAAAAAAAP/AAAAAAAA/wAAAAAAAB/AAAAAAAAB4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAAAAAB+AAAAAAAAf4AAAAAAAH/wAAAAAAB//AAAAAAAf/+AAAAAAH//8AAAAAB///wAAAAAf///gAAAAH///+AAAAB////4AAAAf///+AAAAH////gAAAB////8AAAA/////AAAAP////wAAAD////8AAAA/////AAAAP////gAAAD////4AAAA////+AAAAD////gAAAAP///4AAAAAf//+AAAAAB///gAAAAAD//4AAAAAAP/+AAAAAAAf/gAAAAAAB/wAAAAAAAH8AAAAAAAAPAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB/wAAAAAAAf/wAAAAAAH//gAAAAAD///gAAAAAf///AAAAAB///+AAAAgP///8AAAHg////wAAAfn////gAAD/t////AAAP/j///8AAA//D///4AAH//D///gAAf//H//+AAB///H//4AAH//+P//gAAP//+P/+AAA///8f/4AAD///8f/gAAP///8f+AAAf///8/wAAB////w/AAAD////A4AAAH///4BgAAAP///gAAAAAf//8AAAAAA///AAAAAAA//wAAAAAAA/+AAAAAAAAcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAfgAAAAAAAD+AAAAAAAAP4AAAAAAAB/gAAAAAAAP+AAAAAAAA/5//////4D/v//////gP+//////+A/7//////4D/v//////gP+//////+A/7//////4D/v//////gP+//////+Af7//////4A/v//////gA+//////+AA7///hAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB8AAAD/4AAfwAAAf/gAD/AAAH/+AA/8AAA//4AH/wAAP//gA//AAD//+AH/8AA///4Af/wAP///gD//AD///+AP/8Af///4A//wH////gD//B////+AP/8f//7/4A//3///P/gD/////w/+AP////8D/4A/////AP/gD////4A/+AP///+AD/4Af///gAH/gB///4AAf/AD///AAB/8AH//wAAH/wAP/8AAAf/AAf/gAAB/4AA/4AAAAAAAAfAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//gAAAf/wD/+AAAB//AP/4AAAH/8A//gAAAf/wD/+AAAB//AP/4AAAH/8A//gAAAf/wB/+AAAAAAAAAB/4A//8A////////wH////////Af///////8A////////wD///+////AP///7///8A////P///wB///8f//+AH///h///4AP//+D///AAf//wH//4AA//+AP//AAB//wAf/4AAD/+AAf/AAAD/gAAfwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAf+AAAAAAAH//AAAAAAA//+AAAAAAP//8AAAAAB///4AAAAAP///wAAAAA////gAAAAH////AAAAA////8AAAAD////4AAAAf////j//gB////+//+AP///////4A////////gD///////+Af///////4B////////gH///////+Af///////gB//////AAAH8AAAHAAAAAAA//wAAAAAAD//4AAAAAAP//gAAAAAA//+AAAAAAD//4AAAAAAP//gAAAAAA//+AAAAAAD//4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH////AB/AAf///+AP/+B////4A//4H////AD//gf///8AP/+B////4A//4H////gD//gf/////+AAAAAAAP///wP//gA////A//+AD///8D//4AP///wP//gAf//+A//+AB///4D//4AD///gAB/gAH//8AAAAAAP//gAAAAAAf/8AAAAAAA//gAAAAAAA/4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAfwAAAAAAAP/8AAAAAAB//8AAAAAAf//8AAAAAD///4AAAAAf///wAAAAD////wAAAAf////AAAAD////+AAAAP////8AAAB/////wAAAP/////gAAA/////+AAAH/////8AAAf/////wAAB//////gAAP/////+AAA//////4AAD//////gAAP/////+AAA//////4AAD//////gAAP//////AAA//////8AAAAf////wAAAAAAP//gAAAAB///+AAAAAH///4AAAAAf///gAAAAB///+AAAAAH///wAAAAAf///AAAAAA///8AAAAAD///gAAAAAH//+AAAAAAP//wAAAAAAf/+AAAAAAA//wAAAAAAB/+AAAAAAAB/gAAAAAAAB4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB/wAAAAAH///AAAAAAf//8AAAAAB///wAAAAAH///AAAAAAf//8AAAAAB///wAAAAAH///AAAAAAf//8AAAAAA//AAAAAAAAAAAAAAAAwAAP//////A////////8D////////wP////////A////////8D////////wP////////A////////8D////////wP////////A////////8D////////wP////////A////0cAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAf/AAAD/gAH//AAA//gA//+AAP//AH//8AB//+A///4AP//8H///wA///4f///AH///j///+Af///P///4D///9////wP////////A////////8D////////wP///3///+AAAAAAAAAAB/wAAAAAAAP///x4AAAA////P///4D///8////gH///z///+Af///H///4B///8f///gD///g///8AH//8D///wAf//wH//+AA//+AP//wAA//gA//+AAA/4AA//gAAAEAAB/4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP4AAAAAAAH/8AAAAAAB//8AAAAAAP//4AAAAAB///wAAAAAP///gAAAAB////AAAAAP///8AAAAA////4AAAAH////gAAAAf////AAAAD////8AAAAP////wAAAA/////AAAAD////8AAAAH////wAAAAAAAAAAAAAD///+AAAAAP///////AA///////8AD///////wAP///////AA///////8AB///////wAH//////+AAf//////4AA///////gAD//////8AAH//////wAAf/////+AAA//////4AAB//////AAAH/////4AAAP/////AAAAf////4AAAA////+AAAAB////wAAAAB///8AAAAAB///AAAAAAB//wAAAAAAAcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+AB8AAAAAH8AP4AAAAA/4B/wAAAAH/gO/AAAAAf+A/8AAAAB/4D/wAAAAH/AP/AAAAAP4AfwAAAAAfAA+AAAAAAQAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="), 46, atob("FionHyIiJiIyJScyFA=="), 58+(scale<<8)+(1<<16));
+ return this;
+};
+
+
+Graphics.prototype.setFontDate = function(scale) {
+ // Actual height 28 (27 - 0)
+ this.setFontCustom(atob("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH///wf///B///8H///wf//+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH4AAAfwAAB+AAAAAAAAfwAAB/AAAH8AAAYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPAADg8AAfH+AB//4A///gD//+AP//AA/w/gBPf+AB//4A///wB//8AH//AAfw8AAPDwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYAAAD4AAAfwAAD/h4B/+HwH/4/Af//+AP5/4A/n/gB8f8ADg/gAAD8AAADgAAAAAAAAAAAAAAAAAAAAAAAAB8AAAP4CAB/gcAH+D4Af4/wB/n+AH9/wAHv+AAB/wAAf8AAD/gAA/54AH/PwAf5/gB+H+ADw/4AEB/gAAH8AAAPgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAAAP4AB9/wAP//gB///AP//8A///4D///gH//+Af3/wAfP/AAAf8AAB/gAAP/AAB/8AAP/wAAfOAAAQQAAAAAAAAAAAAAAAAAAAAAAAAAAAAD+AAAP4AAA/gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYBgAH///g////n////f///9/////8AB/fgAH8AAAPAAAAAAAAAAAAAAAAAAAAAAD9/AAf38AB/f///9////z///+H///wP//8AAAAAAAAAAAAAAAAAAAAAAAAFAAAA+AAAH8AAAfwAAB/AAAD8AAAEAAAAAAAAAAAAAAAAAAAAAAAAfAAAB8AAAHwAAAfAAA//wAD//AAP/8AA//wAD//AAAfAAAB8AAAHwAAAfAAAAAAAAAAAAAAAAAAAAAAABkAAAPwAAA/AAAB4AAACAAAAAAAAAAAAAAAAAAAAAD4AAAPgAAA+AAAD4AAAPgAAA+AAAD4AAAPgAAA+AAAD4AAAPgAAA+AAAAAAAAAAAAAAAAAAAAAAACAAAAeAAAD4AAAPgAAA8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAAAPAAAD+AAA/4AAP/wAD//AB//wAf/8AH//AB//wAf/8AA//AAD/wAAH8AAAeAAAAgAAAAAAAAAAAAAAAAAAAAAAAA8AAAP8AAD/4AEP/wAd//gD9//AP9/8A/9/wD/7/AP/78Af/7wA//CAB/8AAD/AAADwAAAAAAAAAAAAAAAAAAAABwAAAPAAAB8AAAH3//+ff//59///n3//+Pf//4d///gAAAAAAAAAAAAAAAAAAAAAAAAAAAAOAD8B4AfwfgH/B+A/8P4P/w/j//D+//8P//vw//4/D/+B8H/gHwf8AfAfAA8AAAAAAAAAAAAAAfgAPx/AB/H8AH8fwAPwH/f/H///8f///x/+//H/7/8P/H/gf8P8A/APgAAAAAAAAAAAAAAAAAAAAAAAAD8AAA/8AAH/4AA//gAD//AAf/9/h///+H///4f///h//8AAD/gAAP+AAA/4AAD/gAAAAAAAAAAAAAAAAAAAAAAAAf/4PB//g/n/+D+f/4P5/gf/n/B/+f8H/5/wP/AAAf4AAA/AAAAAAAAAAAAAAAAAAAAAAAAAA8AAAP8AAD/8AAf/4AD//wAP//gB//+AH//8A///wD///AP//8A///wAAP/AAD/+AAH/4AAf/AAB/8AAD/gAAH+AAAPgAAAAAAAAAAAAAAAAAAAAeAAD/4AAP/gAA/+AAB/4AAAAAM+f///5////n///+f///5////n///+f5AAAAAAAAAAAAAAAAAAAAAAAAAAAAA+AP4H+B/w/8P/n/4////n///+f///4AAAAH/9/+P///4/+f/j/5/+H/D/wH4H+AAAHgAAAAAAAAAAAAAAAAAAAA/AAAP/AAB/+AAP/4AA//wAH//AAf/8AB//wAH///wf///B///8H///wP//+A///4B///gD//8AP//gAP/4AAf+AAAPAAAAAAAAAAAAAAAAAAAAAAGAwAA8HgAH4+AAfD4AA4HAAAAAAAAAAAAAAAAAAAAAAAAAAcAAAB4+AAPn4AA+PgABwcAAAAAAAAAAAAAAAAAAAAABgAAAOAAAB8AAAf4AAD/wAAf/AAD/+AAfz8AA8HwADgfgAEA+AAABgAAAAAAAAAAAAAAAAAAAAHj4AAfPgAB8+AAHz4AAfPgAB8+AAHz4AAfPgAB8+AAHz4AAfPgAB8+AAHj4AAAAAAAAAAAAAAAAAAAAAAAAAAAYAAQDwADgfgAfD8AB/fgAD/8AAH/wAAP+AAAfwAAA+AAABwAAAAAAAAAAAAAAAAAAAAAAAAAD8AAAf8AAD/wAAf/gAB/+AAH/4AgA//3B///cH//9wf//3A//8YD/+AAH/4AAP+AAAPgAAAAAAAAAAAAAAAAAD8AAA/8AAH/4AA//wAH8fgAfu+AAf98AOf7wA///ADn/8AO//wA///AD//YAP/8AA/gMAB//wAD//AAH/4AAP/AAAPwAAAAAAAAAAAAAAAAAAAAP///h///+P///5////n///+f//AB+D8AH///+f///4////h///+B///4AAAAAAAAAAAAAAAAAAAAAAAf///j////P///8////z////P///8////z///AP///+f///5////D/5/8H/H/gPwH8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/gAA//gAH//AA//+AH//8A///4D///gf///B///8H///wf///B/gH8H+Afwf4B/BwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH//8A////D///8P///w////B///8H///gP//+A///wB//+AD//wAD/8AAD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAB////n///+f///5////n///+f///5////n/fP+f9+/5/37/n/AP+AAAAAAAAAAAAAAAAAAAAAAAAAAAAf///5////n///+f///5////n///+f///5/z8AH/PwAf8AAAAAAAAAAAAAAAAAAAAAAA/gAAP/wAD//wAf//gD///Af//+B///4P///w////H///8f///x////H///8f4H/x/gf/D+B/8AAHAAAAcAAABwAAAHAAAAAAAAAAAAAAAAAAAAAAABgH///gf//+B///4H///gf//+B///4AB+AAf/9+B///4H///gf//+B///4H///gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8P///w////D///8P///w////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHgAAAfAAAB+AAAH4AAAfgAAB+f///5////n///+f///x///8AAAAAAAAAAAAAAAAAAAAAAAAAAANH///8f///x////H///8f///x////H//+AAH/8AA//4AH//wA///gD//+Af//8B///wH///Af//8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAX5////n///+f///5////v///+////5//7/gAAP+AAA/4AAD/gAAAAAAAAAAAAAAAAAAAAAAAAAAvh///+P///5////n///+f///5/wAAD+AAAP8AAAfwAAD/AAAP4AAB////n///+f///5////j///+H///4AAAAAAAAAAAAAAAAAAAAAAAH///gf//+B///4H///gf//+B///4B//4AB//4B///4H///gf//+B///4H///gf//+B///4AAAAAAAAAAAAAAAD/AAA//gAH//AA//+AH//8Af//wD///gf//+B///8H///wf///B/z/8H//wAf///B///8H///wf///A///8D///gH//8AP//wAf/+AA//gAA/4AAAAAAAAAAAAAAAAAA/x////H///8f///x////H///8f///x//gAH/+AAf/4AA//gAB/8AAD/gAAH8AAAAAAAAAAAAAAAAAAAAAAAcAAAP8AAD/8AA//8AH//4Af//wD///AP//+B///4H///wf///B///8H//+Af///B///8H///wf///A///8D///gH//+Af//4A///gB//+AB//4AB/PgAAAYAAAAAAAAAAAAAAAAAAAP///5////n///+f///5////n///+P///4////D///+P///4////h/9/+D/gAAD4AAAAAAAAAAAAAAAAAAAAAAAAAADwAAA/wAAH/gAA//AfH/8D8f/4f5////n+P/+f4P/5/g//j8D/8DgH/wAAP8AAAHgAAAAAAAAAAAAAAAAAAAAAAAAAAAAHwAAAfAAAB8//8H///wf///B///8H///wf//AB8AAAHwAAAeAAAAAAAAAAAAAAAAAAAAAAAAAAB///8H///8f///5////n///+AAAH5////n///+f///x////H///wf/gAAAAAAAAAAAAAAAAQAAAD8AAAP/AAA//wAH//8Af//+B////gf//+AP//4AP//gP//+P///5////n///gP//gA//AAD/gAAPgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA///+D///8P///4////j///+PAAfwAAB/AAAH4AAAfw////j//++P//74///vj///8AAB7AAAAAAAAAAAAAAAAAAAAAAAAAAABgeAA+B/AP8P/n/w////j///+H///gH//4D///8P///4////h/4/8H8AfwPAAOAgAAAAAAAAAAAAAAAAAAAAAAAAAABwAAAHwAAAfgAAB/AAAH8H/wf///B///8H///wf///B///8H/8cAfwAAB+AAAHwAAAcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAcAAABwAAAHAAD8cAD/xwD//HH//+f///5////n///+P//w4f/wDh/gAOHgAA4AAADgAAAOAAAAAAAAAAAAAA///+////////////////////////+AAA/wAAD/gAAP+AAA/wAAAAAAAAAAAAAAAAAAAAAAAAAAAHAAAA/AAAD/AAAf/AAB//gAD//gAD//gAD//gAD//gAD//gAD//AAD/4AAB/AAAB8AAABgAAAAAAAAAAAAAAAAAAOAAAe4AAB7gAAHuAAAe////7////v///+////7////v///YwAAAAAAAA="), 32, atob("HA4NFhEaFwoNDQsRCRALFBMPEBESEBgSExgKCRARERIXEhQVExEPGBMOERYRFhQaExwUExARFRYTFhMPFA4="), 28+(scale<<8)+(1<<16));
+ return this;
+}
+
+
+// timeout used to update every minute
+var drawTimeout;
+
+// schedule a draw for the next minute
+function queueDraw() {
+ if (drawTimeout) clearTimeout(drawTimeout);
+ drawTimeout = setTimeout(function() {
+ drawTimeout = undefined;
+ draw();
+ }, 60000 - (Date.now() % 60000));
+}
+
+
+function drawBorderString(str, x, y, b, fc){
+ g.setColor("#000");
+ g.drawString(str, x, y+b);
+ g.drawString(str, x, y-b);
+ g.drawString(str, x+b, y);
+ g.drawString(str, x-b, y);
+
+ g.setColor(fc);
+ g.drawString(str,x+1,y);
+}
+
+
+function getSteps() {
+ try{
+ if (WIDGETS.wpedom !== undefined) {
+ return WIDGETS.wpedom.getSteps();
+ } else if (WIDGETS.activepedom !== undefined) {
+ return WIDGETS.activepedom.getSteps();
+ }
+ } catch(ex) {
+ // In case we failed, we can only show 0 steps.
+ }
+
+ return 0;
+}
+
+
+function draw() {
+ // queue draw in one minute
+ queueDraw();
+
+ var x = g.getWidth()/2;
+ var y_offset = settings.fullscreen ? 0 : 10;
+ var y = g.getHeight()/2-20 + y_offset;
+
+ g.reset().clearRect(0,24,g.getWidth(),g.getHeight());
+ g.drawImage(getImg(),0,0);
+
+ // Draw time
+ var date = new Date();
+ var timeStr = locale.time(date,1);
+ g.setFontAlign(0,0);
+ g.setFontTime();
+ drawBorderString(timeStr, x, y, 5, "#fff");
+
+ // Draw date
+ y += 50;
+ x = x - g.stringWidth(timeStr) / 2 + 5;
+ g.setFontDate();
+ g.setFontAlign(-1,0);
+ var dateStr = locale.dow(date, true).toUpperCase() + date.getDate();
+ var fc = Bangle.isLocked() ? "#0ff" :"#fff";
+ fc = E.getBattery() < 50 ? "#f00" : fc;
+ drawBorderString(dateStr, x, y, 3, fc);
+
+ // Draw steps
+ g.setFontAlign(1,1);
+ var steps = parseInt(getSteps() / 1000);
+ drawBorderString(steps, g.getWidth()-10, g.getHeight()-10, 3, "#f0f");
+
+ // Draw widgets if not fullscreen
+ if(settings.fullscreen){
+ for (let wd of WIDGETS) {wd.draw=()=>{};wd.area="";}
+ } else {
+ Bangle.drawWidgets();
+ }
+}
+
+Bangle.loadWidgets();
+
+// Clear the screen once, at startup
+g.setTheme({bg:"#000",fg:"#fff",dark:false}).clear();
+// draw immediately at first, queue update
+draw();
+// Stop updates when LCD is off, restart when on
+Bangle.on('lcdPower',on=>{
+ if (on) {
+ draw(); // draw immediately, queue redraw
+ } else { // stop draw timer
+ if (drawTimeout) clearTimeout(drawTimeout);
+ drawTimeout = undefined;
+ }
+});
+
+
+Bangle.on('lock', function(isLocked) {
+ print("LOCK");
+ if (drawTimeout) clearTimeout(drawTimeout);
+ drawTimeout = undefined;
+ draw();
+});
+
+
+// Show launcher when middle button pressed
+Bangle.setUI("clock");
diff --git a/apps/90sclk/app.png b/apps/90sclk/app.png
new file mode 100644
index 000000000..29875b1dc
Binary files /dev/null and b/apps/90sclk/app.png differ
diff --git a/apps/90sclk/bg.png b/apps/90sclk/bg.png
new file mode 100644
index 000000000..4ebf755ad
Binary files /dev/null and b/apps/90sclk/bg.png differ
diff --git a/apps/90sclk/metadata.json b/apps/90sclk/metadata.json
new file mode 100644
index 000000000..fb2824a6f
--- /dev/null
+++ b/apps/90sclk/metadata.json
@@ -0,0 +1,18 @@
+{
+ "id": "90sclk",
+ "name": "90s Clock",
+ "version": "0.02",
+ "description": "A 90s style watch-face",
+ "readme": "README.md",
+ "icon": "app.png",
+ "screenshots": [{"url":"screenshot.png"},{"url":"screenshot_2.png"}],
+ "type": "clock",
+ "tags": "clock",
+ "supports": ["BANGLEJS2"],
+ "allow_emulator": true,
+ "storage": [
+ {"name":"90sclk.app.js","url":"app.js"},
+ {"name":"90sclk.img","url":"app-icon.js","evaluate":true},
+ {"name":"90sclk.settings.js","url":"settings.js"}
+ ]
+}
diff --git a/apps/90sclk/screenshot.png b/apps/90sclk/screenshot.png
new file mode 100644
index 000000000..182a85321
Binary files /dev/null and b/apps/90sclk/screenshot.png differ
diff --git a/apps/90sclk/screenshot_2.png b/apps/90sclk/screenshot_2.png
new file mode 100644
index 000000000..9646b1168
Binary files /dev/null and b/apps/90sclk/screenshot_2.png differ
diff --git a/apps/90sclk/settings.js b/apps/90sclk/settings.js
new file mode 100644
index 000000000..8f97cd317
--- /dev/null
+++ b/apps/90sclk/settings.js
@@ -0,0 +1,31 @@
+(function(back) {
+ const SETTINGS_FILE = "90sclk.setting.json";
+
+ // initialize with default settings...
+ const storage = require('Storage')
+ let settings = {
+ fullscreen: false,
+ };
+ let saved_settings = storage.readJSON(SETTINGS_FILE, 1) || settings;
+ for (const key in saved_settings) {
+ settings[key] = saved_settings[key]
+ }
+
+ function save() {
+ storage.write(SETTINGS_FILE, settings)
+ }
+
+
+ E.showMenu({
+ '': { 'title': '90s Clock' },
+ '< Back': back,
+ 'Full Screen': {
+ value: settings.fullscreen,
+ format: () => (settings.fullscreen ? 'Yes' : 'No'),
+ onchange: () => {
+ settings.fullscreen = !settings.fullscreen;
+ save();
+ },
+ }
+ });
+ })
diff --git a/apps/altimeter/ChangeLog b/apps/altimeter/ChangeLog
new file mode 100644
index 000000000..29388520e
--- /dev/null
+++ b/apps/altimeter/ChangeLog
@@ -0,0 +1,2 @@
+0.01: New App!
+0.02: Actually upload correct code
diff --git a/apps/altimeter/app-icon.js b/apps/altimeter/app-icon.js
new file mode 100644
index 000000000..1f8dfb637
--- /dev/null
+++ b/apps/altimeter/app-icon.js
@@ -0,0 +1 @@
+require("heatshrink").decompress(atob("mEw4UA///t9TmuV3+GJf4AN+ALVgf8BasP/4LVn//4ALUWgJUJBZUDBYJUIBZcP3/nKhEOt/WBZE5r+VKg0KgEVr9V3wLHqtaqt9sALElWAqoABt1QBZNeBYuq0ILCrVUBYulBYVWBYkCBYgABBZ8K1WVBYlABZegKQWqBQlVqALKqWoKQWpBYtWBZeqKRAAB1WABZZSHAANq0ALLKQ6qC1ALLKQ5UEAH4AG"))
diff --git a/apps/altimeter/app.js b/apps/altimeter/app.js
new file mode 100644
index 000000000..cac4e80fd
--- /dev/null
+++ b/apps/altimeter/app.js
@@ -0,0 +1,30 @@
+Bangle.setBarometerPower(true, "app");
+
+g.clear(1);
+Bangle.loadWidgets();
+Bangle.drawWidgets();
+var zero = 0;
+var R = Bangle.appRect;
+var y = R.y + R.h/2;
+var MEDIANLENGTH = 20;
+var avr = [], median;
+var value = 0;
+
+Bangle.on('pressure', function(e) {
+ while (avr.length>MEDIANLENGTH) avr.pop();
+ avr.unshift(e.altitude);
+ median = avr.slice().sort();
+ g.reset().clearRect(0,y-30,g.getWidth()-10,y+30);
+ if (median.length>10) {
+ var mid = median.length>>1;
+ value = E.sum(median.slice(mid-4,mid+5)) / 9;
+ g.setFont("Vector",50).setFontAlign(0,0).drawString((value-zero).toFixed(1), g.getWidth()/2, y);
+ }
+});
+
+g.reset();
+g.setFont("6x8").setFontAlign(0,0).drawString(/*LANG*/"ALTITUDE (m)", g.getWidth()/2, y-40);
+g.setFont("6x8").setFontAlign(0,0,3).drawString(/*LANG*/"ZERO", g.getWidth()-5, g.getHeight()/2);
+setWatch(function() {
+ zero = value;
+}, (process.env.HWVERSION==2) ? BTN1 : BTN2, {repeat:true});
diff --git a/apps/altimeter/app.png b/apps/altimeter/app.png
new file mode 100644
index 000000000..9c9d69077
Binary files /dev/null and b/apps/altimeter/app.png differ
diff --git a/apps/altimeter/metadata.json b/apps/altimeter/metadata.json
new file mode 100644
index 000000000..8bdbf3022
--- /dev/null
+++ b/apps/altimeter/metadata.json
@@ -0,0 +1,12 @@
+{ "id": "altimeter",
+ "name": "Altimeter",
+ "version":"0.02",
+ "description": "Simple altimeter that can display height changed using Bangle.js 2's built in pressure sensor.",
+ "icon": "app.png",
+ "tags": "tool,outdoors",
+ "supports" : ["BANGLEJS2"],
+ "storage": [
+ {"name":"altimeter.app.js","url":"app.js"},
+ {"name":"altimeter.img","url":"app-icon.js","evaluate":true}
+ ]
+}
diff --git a/apps/bwclk/ChangeLog b/apps/bwclk/ChangeLog
new file mode 100644
index 000000000..05a22774f
--- /dev/null
+++ b/apps/bwclk/ChangeLog
@@ -0,0 +1,5 @@
+0.01: New App.
+0.02: Use build in function for steps and other improvements.
+0.03: Adapt colors based on the theme of the user.
+0.04: Steps can be hidden now such that the time is even larger.
+0.05: Included icons for information.
\ No newline at end of file
diff --git a/apps/bwclk/README.md b/apps/bwclk/README.md
new file mode 100644
index 000000000..a5b66df71
--- /dev/null
+++ b/apps/bwclk/README.md
@@ -0,0 +1,16 @@
+# Black & White clock
+
+
+
+## Features
+- Fullscreen on/off
+- The design is adapted to the theme of your bangle.
+- Tab left/right of screen to show steps, temperature etc.
+- Enable / disable lock icon in the settings.
+- If the "sched" app is installed tab top / bottom of the screen to set the timer.
+
+## Thanks to
+Icons created by Flaticon
+
+## Creator
+- [David Peer](https://github.com/peerdavid)
diff --git a/apps/bwclk/app-icon.js b/apps/bwclk/app-icon.js
new file mode 100644
index 000000000..1df0fa6a5
--- /dev/null
+++ b/apps/bwclk/app-icon.js
@@ -0,0 +1 @@
+require("heatshrink").decompress(atob("mEwgIcah0EgEB/H8iFsAoOY4kMBYMDhmGgXkAoUGiWkAoQQBoAFCjgnCAoM4hgFDuEI+wpC8EKyg1C/0eAoMAsEAiQvBAAeAApQAB/4Ao+P4v/wn0P8Pgn/wnkH4Pjv/j/nn9PH//n/nj/IFF4F88AXBAoM88EcAoPHj//jlDAoOf/+Y+YFHjnnjAjBEIIjD+BHDO9IALA=="))
diff --git a/apps/bwclk/app.js b/apps/bwclk/app.js
new file mode 100644
index 000000000..d4e6c50ab
--- /dev/null
+++ b/apps/bwclk/app.js
@@ -0,0 +1,412 @@
+/*
+ * Includes
+ */
+const locale = require('locale');
+const storage = require('Storage');
+
+/*
+ * Statics
+ */
+const SETTINGS_FILE = "bwclk.setting.json";
+const TIMER_IDX = "bwclk";
+const W = g.getWidth();
+const H = g.getHeight();
+
+/*
+ * Settings
+ */
+let settings = {
+ fullscreen: false,
+ showLock: true,
+ showInfo: 0,
+};
+
+let saved_settings = storage.readJSON(SETTINGS_FILE, 1) || settings;
+for (const key in saved_settings) {
+ settings[key] = saved_settings[key]
+}
+
+
+/*
+ * Assets
+ */
+
+// Manrope font
+Graphics.prototype.setLargeFont = function(scale) {
+ // Actual height 49 (50 - 2)
+ this.setFontCustom(atob("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/wAAAAAAAAD/AAAAAAAAAP8AAAAAAAAA/wAAAAAAAAD/AAAAAAAAAP8AAAAAAAAA/wAAAAAAAAD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAcAAAAAAAAAfwAAAAAAAAf/AAAAAAAAf/8AAAAAAAf//wAAAAAAP///AAAAAAP///8AAAAAP////wAAAAP////4AAAAP////8AAAAH////8AAAAH////8AAAAB////8AAAAAH///+AAAAAAf//+AAAAAAB//+AAAAAAAH/+AAAAAAAAf+AAAAAAAAB/AAAAAAAAAHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///gAAAAAD////4AAAAA/////4AAAAH/////4AAAA//////wAAAH//////gAAA///////AAAH//////+AAA///////4AAD/4AAAH/wAAP+AAAAP/AAB/wAAAAf8AAH/AAAAA/4AAf4AAAAB/gAB/gAAAAH+AAP8AAAAAf4AA/wAAAAB/gAD/AAAAAH+AAP8AAAAAf4AAf4AAAAB/gAB/gAAAAH+AAH+AAAAA/4AAf8AAAAH/AAB/4AAAA/8AAD/4AAAH/wAAP/8AAH/+AAAf//////4AAA///////AAAB//////4AAAD//////AAAAH/////4AAAAP////+AAAAAP////gAAAAAD///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP+AAAAAAAAB/wAAAAAAAAH/AAAAAAAAA/4AAAAAAAAH/gAAAAAAAAf8AAAAAAAAD/gAAAAAAAAP+AAAAAAAAB///////8AAH///////wAAf///////AAB///////8AAH///////wAAf///////AAB///////8AAH///////wAAP///////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPAAAAfwAAAH8AAAD/AAAB/wAAAf8AAAP/AAAD/wAAB/8AAAf/AAAP/wAAD/8AAB//AAAf/wAAH/8AAD//AAA//gAAf/8AAD/wAAB//wAAf+AAAP//AAB/wAAB//8AAH+AAAP//wAAf4AAB///AAD/AAAP/v8AAP8AAB/8/wAA/wAAP/j/AAD/AAB/8P8AAH+AAH/g/wAAf4AA/8D/AAB/wAH/gP8AAH/AA/+A/wAAf/AP/wD/AAA//D/+AP8AAD////wA/wAAH///+AD/AAAP///wAP8AAAf//+AA/wAAA///wAD/AAAB//+AAP8AAAB//gAA/wAAAB/4AAD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB4AAAD+AAAAHwAAAf4AAAAfwAAB/gAAAB/gAAH+AAAAP/AAAf4AAAA/8AAB/gAAAD/4AAH+ADAAH/wAAf4AeAAP/AAB/gD+AAP8AAH+Af+AA/4AAf4D/4AB/gAB/gP/AAH+AAH+B/8AAf4AAf4P/wAB/gAB/h//AAH+AAH+P/8AAf4AAf5//wAB/gAB/v//gAP+AAH+//+AA/4AAf//f8AH/AAB//5/8B/8AAH//D////gAAf/4P///+AAB//Af///wAAH/4A///+AAAf/AB///wAAB/4AD//+AAAH/AAH//gAAAP4AAD/4AAAAAAAAA4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AAAAAAAAA/+AAAAAAAAP/4AAAAAAAH//gAAAAAAB//+AAAAAAAf//4AAAAAAH///gAAAAAB///+AAAAAAf///4AAAAAH//9/gAAAAD///H+AAAAA///wf4AAAAP//8B/gAAAD///AH+AAAA///wAf4AAAH//8AB/gAAAf//AAH+AAAB//gAAf4AAAH/4AAB/gAAAf+AAAH+AAAB/gAf///8AAH4AB////wAAeAAH////AABgAAf///8AAAAAB////wAAAAAH////AAAAAAf///8AAAAAB////wAAAAAH////AAAAAAAAf4AAAAAAAAB/gAAAAAAAAH+AAAAAAAAAfwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGAAAAAAAAAAeAAAAAf//AB+AAAH///+AP8AAAf///4A/4AAB////gD/wAAH////Af/gAAf///8B/+AAB////wB/8AAH///+AB/wAAf4Af4AD/gAB/gB/AAP+AAH+AP8AAf4AAf4A/wAB/gAB/gD+AAH+AAH+AP4AAf4AAf4A/gAB/gAB/gD/AAH+AAH+AP8AAf4AAf4A/wAD/gAB/gD/gAf8AAH+AH/AD/wAAf4Af/Af+AAB/gB////4AAH+AD////AAAf4AH///8AAB/gAP///gAAH+AA///8AAAAAAA///AAAAAAAB//4AAAAAAAB/+AAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB///gAAAAAB////4AAAAAf////4AAAAH/////4AAAA//////wAAAH//////gAAA///////AAAH//////+AAAf//////4AAD/4D/wH/wAAP+AP8AP/AAB/wB/gAf8AAH/AH8AA/4AAf4A/wAB/gAB/gD/AAH+AAH8AP4AAf4AA/wA/gAB/gAD/AD+AAH+AAH8AP8AAf4AAf4A/wAB/gAB/gD/AAP+AAH+AP+AB/wAAf8Af8AP/AAA/4B/8B/8AAD/gH////gAAP8AP///8AAAfgAf///wAAA8AB///+AAADgAD///wAAAAAAD//+AAAAAAAH//gAAAAAAAH/4AAAAAAAAB4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/gAAAAAAAAH+AAAAAAAAAf4AAAAAAAAB/gAAAAAAAAH+AAAAAAAAAf4AAAAADgAB/gAAAAA+AAH+AAAAAf4AAf4AAAAH/gAB/gAAAD/+AAH+AAAA//4AAf4AAAf//gAB/gAAH//+AAH+AAD///wAAf4AA///8AAB/gAf//+AAAH+AH///gAAAf4D///wAAAB/g///8AAAAH+f//+AAAAAf////gAAAAB////wAAAAAH///8AAAAAAf//+AAAAAAB///gAAAAAAH//wAAAAAAAf/8AAAAAAAB/+AAAAAAAAH/gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH/wAAAAB/wB//wAAAAf/wf//gAAAD//z///AAAAf/////+AAAD//////8AAAf//////4AAD///////gAAP////w//AAB/+f/8Af8AAH/Af/gA/4AAf4A/8AD/gAB/gB/wAH+AAP8AH+AAf4AA/wAf4AB/gAD/AB/gAH+AAP8AH+AAf4AA/wAf4AB/gAB/gB/wAH+AAH+AP/AAf4AAf8A/+AD/gAB/8f/8Af8AAD////4H/wAAP//////+AAAf//////4AAA///////AAAD//////8AAAH//z///gAAAH/+H//4AAAAH/gH//AAAAAAAAH/wAAAAAAAABwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAfgAAAAAAAAP/wAAAAAAAD//wAAAAAAAf//wAAAAAAH///gABgAAA////AAPAAAD///+AB+AAAf///4AP4AAD////wB/wAAP/AP/AH/AAB/4Af+AP+AAH/AA/4A/4AAf4AB/gB/gAB/gAH+AH+AAP8AAP4Af4AA/wAA/gB/gAD/AAD+AH+AAP8AAP4Af4AA/4AB/gB/gAB/gAH+AH+AAH+AAfwA/4AAf8AD/AH/AAB/4Af4A/8AAD/4H/gP/wAAP//////+AAAf//////wAAA///////AAAB//////4AAAD//////AAAAH/////wAAAAH////+AAAAAH////AAAAAAAf/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAf4AP8AAAAAB/gA/wAAAAAH+AD/AAAAAAf4AP8AAAAAB/gA/wAAAAAH+AD/AAAAAAf4AP8AAAAAB/gA/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"), 46, atob("ExwqHCYlJyYoIicoFg=="), 64+(scale<<8)+(1<<16));
+ return this;
+};
+
+
+Graphics.prototype.setMediumFont = function(scale) {
+ // Actual height 41 (42 - 2)
+ this.setFontCustom(atob("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/AAAAAAAA/AAAAAAAA/AAAAAAAA/AAAAAAAA/AAAAAAAA/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHAAAAAAAB/AAAAAAAP/AAAAAAD//AAAAAA///AAAAAP///AAAAB///8AAAAf///AAAAH///wAAAB///+AAAAH///gAAAAH//4AAAAAH/+AAAAAAH/wAAAAAAH8AAAAAAAHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA///8AAAAH////AAAAP////wAAAf////4AAA/////8AAB/////+AAD/gAAH+AAD+AAAD/AAH8AAAB/AAH4AAAA/gAH4AAAAfgAH4AAAAfgAPwAAAAfgAPwAAAAfgAPwAAAAfgAHwAAAAfgAH4AAAAfgAH4AAAA/gAH8AAAA/AAD+AAAD/AAD/gAAH/AAB/////+AAB/////8AAA/////4AAAf////wAAAH////gAAAB///+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPgAAAAAAAfwAAAAAAA/gAAAAAAA/AAAAAAAB/AAAAAAAD+AAAAAAAD8AAAAAAAH8AAAAAAAH//////AAH//////AAH//////AAH//////AAH//////AAH//////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD4AAA/AAAP4AAB/AAAf4AAD/AAA/4AAD/AAB/4AAH/AAD/4AAP/AAH/AAAf/AAH8AAA//AAH4AAB//AAP4AAD//AAPwAAH+/AAPwAAP8/AAPwAAf4/AAPwAA/4/AAPwAA/w/AAPwAB/g/AAPwAD/A/AAP4AH+A/AAH8AP8A/AAH/A/4A/AAD///wA/AAD///gA/AAB///AA/AAA//+AA/AAAP/8AA/AAAD/wAA/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADgAAH4AAAHwAAH4AAAH4AAH4AAAH8AAH4AAAP+AAH4AAAH+AAH4A4AB/AAH4A+AA/AAH4B/AA/gAH4D/AAfgAH4H+AAfgAH4P+AAfgAH4f+AAfgAH4/+AAfgAH5/+AAfgAH5//AAfgAH7+/AA/gAH/8/gB/AAH/4f4H/AAH/wf//+AAH/gP//8AAH/AH//8AAH+AD//wAAH8AB//gAAD4AAf+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+AAAAAAAD/AAAAAAAP/AAAAAAB//AAAAAAH//AAAAAAf//AAAAAB///AAAAAH///AAAAAf/8/AAAAB//w/AAAAH/+A/AAAA//4A/AAAD//gA/AAAH/+AA/AAAH/4AA/AAAH/gAA/AAAH+AAA/AAAHwAAA/AAAHAAf///AAEAAf///AAAAAf///AAAAAf///AAAAAf///AAAAAf///AAAAAAA/AAAAAAAA/AAAAAAAA/AAAAAAAA/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGAAAAAP/AHgAAH///AP4AAH///gP8AAH///gP8AAH///gP+AAH///gD/AAH/A/AB/AAH4A/AA/gAH4A+AAfgAH4B+AAfgAH4B+AAfgAH4B8AAfgAH4B8AAfgAH4B+AAfgAH4B+AAfgAH4B+AA/gAH4B/AA/AAH4A/gD/AAH4A/4H+AAH4Af//+AAH4AP//8AAH4AP//4AAHwAD//wAAAAAB//AAAAAAAf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA///8AAAAD////AAAAP////wAAAf////4AAA/////8AAB/////+AAD/gP4H+AAD/AfgD/AAH8A/AB/AAH8A/AA/gAH4B+AAfgAH4B+AAfgAPwB8AAfgAPwB8AAfgAPwB+AAfgAPwB+AAfgAH4B+AAfgAH4B/AA/gAH8B/AB/AAH+A/wD/AAD+A/8P+AAB8Af//+AAB4AP//8AAAwAH//4AAAAAD//gAAAAAA//AAAAAAAP4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPwAAAAAAAPwAAAAAAAPwAAAAAAAPwAAAAAAAPwAAAAHAAPwAAAA/AAPwAAAD/AAPwAAAf/AAPwAAB//AAPwAAP//AAPwAA//8AAPwAH//wAAPwAf/+AAAPwB//4AAAPwP//AAAAPw//8AAAAP3//gAAAAP//+AAAAAP//wAAAAAP//AAAAAAP/4AAAAAAP/gAAAAAAP+AAAAAAAHwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP+AAAAH+A//gAAAf/h//4AAA//z//8AAB/////+AAD/////+AAD///+H/AAH+H/4B/AAH8B/wA/gAH4A/gAfgAH4A/gAfgAPwA/AAfgAPwA/AAfgAPwA/AAfgAPwA/AAfgAH4A/gAfgAH4A/gAfgAH8B/wA/gAH/H/4B/AAD///+H/AAD/////+AAB/////+AAA//z//8AAAf/h//4AAAH+A//gAAAAAAH+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/gAAAAAAD/8AAAAAAP/+AAAAAAf//AAcAAA///gA8AAB///wB+AAD/x/4B/AAD+AP4B/AAH8AH8A/gAH4AH8A/gAH4AD8AfgAP4AD8AfgAPwAB8AfgAPwAB8AfgAPwAB8AfgAPwAB8AfgAH4AD8AfgAH4AD4A/gAH8AH4B/AAD+APwD/AAD/g/wP+AAB/////+AAA/////8AAAf////4AAAP////wAAAH////AAAAA///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD8APwAAAAD8APwAAAAD8APwAAAAD8APwAAAAD8APwAAAAD8APwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=="), 46, atob("DxcjFyAfISAiHCAiEg=="), 54+(scale<<8)+(1<<16));
+ return this;
+};
+
+Graphics.prototype.setSmallFont = function(scale) {
+ // Actual height 28 (27 - 0)
+ this.setFontCustom(atob("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//84D//zgP/+GAAAAAAAAAAAAAAAAAAAD4AAAPgAAA+AAAAAAAAAAAAA+AAAD4AAAPgAAAAAAAAAAAAAAAAAAAAAAAAAAAAOAAAg4AAHDgAAcOCABw54AHD/gAf/8AD/8AB//gAP8OAA9w4YCHD/gAcf+AB//gAf/gAP/uAA/w4ADnDgAAcOAABw4AAHAAAAcAAAAAAAAAAAAAAAIAA+A4AH8HwA/4PgHjgOAcHAcBwcBw/BwH78DgfvwOB8HA4HAOBw8A+HngB4P8ADgfgAAAYAAAAAAAAAAB4AAAf4AQB/gDgOHAeA4cDwDhweAOHDwA88eAB/nwAD88AAAHgAAA8AAAHn4AA8/wAHnvgA8cOAHhg4A8GDgHgcOA8B74BgD/AAAH4AAAAAAAAAAAAAAAAAMAAAH8AD8/4Af/3wB/8HgODwOA4HA4DgODgOAcOA4A44DwDzgHAH8AMAPwAQP+AAA/8AAAB4AAADAAAAAA+AAAD4AAAPgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH/8AD//+A/+/+H4AD98AAB3gAADIAAAAAAAAAAAAAIAAABwAAAXwAAHPwAB8P8D/gP//4AH/8AAAAAAAAAAAAAAAAAAAAAAAAGAAAA4gAAB/AAAH8AAD/AAAP8AAAH4AAAfwAADiAAAOAAAAAAAAAAAAAAGAAAAYAAABgAAAGAAAAYAAABgAAD/+AAP/4AABgAAAGAAAAYAAABgAAAGAAAAYAAAAAAAAAAAAAADkAAAPwAAA/AAAAAAAAAAAAAAAAAAAAAAAAABgAAAGAAAAYAAABgAAAGAAAAYAAABgAAAGAAAAYAAAAAAAAAAAAAAAAAAAAAAADgAAAOAAAA4AAAAAAAAAAAAAAAAAAAAAAAAAAA4AAA/gAA/+AA//AA//AAP/AAA/AAADAAAAAAAAAAAAAAAAAAA//gAP//gB///AHgA8A8AB4DgADgOAAOA4AA4DgADgPAAeAeADwB///AD//4AD/+AAAAAAAAAAAAAAAA4AAAHgAAAcAAADwAAAP//+A///4D///gAAAAAAAAAAAAAAAAAAAAAAYAeADgD4AeAfAD4DwAfgOAD+A4Ae4DgDzgOAeOA4Dw4DweDgH/wOAP+A4AfwDgAAAAAAAAAAAAIAOAA4A4ADwDggHAOHgOA48A4DnwDgO/AOA7uA4D84HgPh/8A8H/gDgH8AAACAAAAAAAAAAAAAHgAAB+AAA/4AAP7gAD+OAA/g4AP4DgA+AOADAA4AAB/+AAH/4AAf/gAADgAAAOAAAAAAAAAAAAAAAAD4cAP/h4A/+HwDw4HgOHAOA4cA4DhwDgOHAOA4cA4Dh4HAOD58A4H/gAAP8AAAGAAAAAAAAAAAAAAAAD/+AAf/8AD//4AePDwDw4HgOHAOA4cA4DhwDgOHAOA4cB4Bw8PAHD/8AIH/gAAH4AAAAAAAAAADgAAAOAAAA4AAYDgAHgOAD+A4B/wDgf4AOP+AA7/AAD/gAAP4AAA8AAAAAAAAAAAAAAAAAAeH8AD+/4Af//wDz8HgOHgOA4OA4Dg4DgODgOA4eA4Dz8HgH//8AP7/gAeH8AAAAAAAAAAAAAAAA+AAAH+AgB/8HAHh4cA8Dg4DgODgOAcOA4Bw4DgODgPA4eAeHDwB///AD//4AD/+AAAAAAAAAAAAAAAAAAAAAAAAAAODgAA4OAADg4AAAAAAAAAAAAAAAAAAAAAAAAAAAAABwA5AHAD8AcAPgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGAAAB8AAAP4AAB5wAAPDgAB4HAAHAOAAIAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGMAAAYwAABjAAAGMAAAYwAABjAAAGMAAAYwAABjAAAGMAAAYwAABjAAAGMAAAYwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAEAAcA4AB4HAADw4AADnAAAH4AAAPAAAAYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPAAAB8AAAHgAAA4AAADgDzgOA/OA4D84DgeAAPHwAAf+AAA/wAAB8AAAAAAAAAAAAAAAAAAD+AAB/+AAP/8AB4B4AOABwBwADgHB8OA4P4cDhxxwMGDDAwYMMDBgwwOHHHA4f4cDh/xwHAHCAcAMAA8AwAB8PAAD/4AAD/AAAAAAAAAAAAAACAAAB4AAB/gAA/8AAf+AAP/wAH/nAA/gcADwBwAPwHAA/4cAA/9wAAf/AAAP/AAAD/gAAB+AAAA4AAAAAAAAAAAAAAD///gP//+A///4DgcDgOBwOA4HA4DgcDgOBwOA4HA4Dg8DgPHwOAf/h4A///AB8f4AAAfAAAAAAAP+AAD/+AAf/8AD4D4AeADwBwAHAOAAOA4AA4DgADgOAAOA4AA4DgADgOAAOAcABwB4APAD4D4AHgPAAOA4AAAAAAAAAAAAAAAP//+A///4D///gOAAOA4AA4DgADgOAAOA4AA4DgADgOAAOA8AB4BwAHAHwB8AP//gAP/4AAP+AAAAAAAAAAAAAAAA///4D///gP//+A4HA4DgcDgOBwOA4HA4DgcDgOBwOA4HA4DgcDgOBgOA4AA4AAAAAAAAAAAAAAD///gP//+A///4DgcAAOBwAA4HAADgcAAOBwAA4HAADgcAAOAwAA4AAAAAAAAAf+AAD/+AA//+ADwB4AeADwDwAHgOAAOA4AA4DgADgOAAOA4AA4DgMDgPAweAcDBwB8MfADw/4AHD/AAAPwAAAAAAAAAAAAAAAP//+A///4D///gABwAAAHAAAAcAAABwAAAHAAAAcAAABwAAAHAAAAcAAABwAA///4D///gP//+AAAAAAAAAAAAAAAAAAAD///gP//+A///4AAAAAAAAAAAADgAAAPAAAA+AAAA4AAADgAAAOAAAA4AAAHgP//8A///wD//8AAAAAAAAAAAAAAAAAAAA///4D///gP//+AAHAAAA+AAAP8AAB54AAPDwAB4HgAPAPAB4AfAPAA+A4AA4DAABgAAACAAAAAAAAAAP//+A///4D///gAAAOAAAA4AAADgAAAOAAAA4AAADgAAAOAAAA4AAADgAAAAAAAAAAAAAAP//+A///4D///gD+AAAD+AAAB+AAAB/AAAB/AAAB/AAAB+AAAH4AAB+AAA/gAAP4AAD+AAA/AAAfwAAD///gP//+A///4AAAAAAAAAAAAAAAAAAAP//+A///4D///gHwAAAPwAAAPgAAAfgAAAfAAAAfAAAA/AAAA+AAAB+AAAB8A///4D///gP//+AAAAAAAAAAAP+AAD/+AAf/8AD4D4AeADwBwAHAOAAOA4AA4DgADgOAAOA4AA4DgADgOAAOAcABwB4APAD4D4AH//AAP/4AAP+AAAAAAAAAAAP//+A///4D///gOAcAA4BwADgHAAOAcAA4BwADgHAAOAcAA4DgAD4eAAH/wAAP+AAAPgAAAAAAAA/4AAP/4AB//wAPgPgB4APAHAAcA4AA4DgADgOAAOA4AA4DgADgOAAOA4AO4BwA/AHgB8APgPwAf//gA//uAA/4QAAAAAAAAAA///4D///gP//+A4BwADgHAAOAcAA4BwADgHAAOAcAA4B8ADgP8APh/8Af/H4A/4HgA+AGAAAAAAAAAAAABgAHwHAA/g+AH/A8A8cBwDg4DgODgOA4OA4DgcDgOBwOA4HA4DwODgHg4cAPh/wAcH+AAwPwAAAAADgAAAOAAAA4AAADgAAAOAAAA4AAAD///gP//+A///4DgAAAOAAAA4AAADgAAAOAAAA4AAADgAAAAAAAAAAAAAAAAAP//AA///AD//+AAAB8AAABwAAADgAAAOAAAA4AAADgAAAOAAAA4AAAHgAAA8A///gD//8AP//gAAAAAAAAAAIAAAA8AAAD+AAAH/AAAD/wAAB/4AAA/8AAAf4AAAPgAAB+AAA/4AAf+AAP/AAH/gAD/wAAP4AAA4AAAAAAAAPAAAA/gAAD/4AAA/+AAAf/AAAH/gAAB+AAAf4AAf/AAf/AAP/gAD/gAAPwAAA/4AAA/+AAAf/AAAH/wAAB/gAAB+AAB/4AA/+AA/+AA/+AAD/AAAPAAAAgAAAAAAAAMAAGA4AA4D4APgHwB8APwfAAPn4AAf+AAAfwAAB/AAAf+AAD4+AA/B8AHwB8A+AD4DgADgMAAGAwAAADwAAAPwAAAPwAAAfgAAAfgAAAf/4AAf/gAH/+AB+AAAPwAAD8AAA/AAADwAAAMAAAAgAAAAAAAAMAACA4AA4DgAPgOAD+A4Af4DgH7gOB+OA4Pw4Dj8DgO/AOA/4A4D+ADgPgAOA4AA4DAADgAAAAAAAAAAAAAAAAAAAAAAAAAAAAP/////////gAAAOAAAA4AAADAAAAAAAAAAAAAAAAAAAAAAA4AAAD+AAAP/gAAH/4AAB/+AAAf+AAAH4AAABgAAAAAAAAADAAAAOAAAA4AAADgAAAP////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAADgAAAcAAADgAAAcAAADgAAAcAAAB4AAADwAAADgAAAHAAAAOAAAAYAAAAAAAAAAAAAAAAAAAAMAAAAwAAADAAAAMAAAAwAAADAAAAMAAAAwAAADAAAAMAAAAwAAADAAAAMAAAAwAAADAAAAMAAAAwAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+AAHH8AA8/4AHzjgAcMOABxwYAHHBgAccOABxwwAHGHAAP/4AA//4AA//gAAAAAAAAAAAAAAAAAAA///4D///gP//+AA4BwAHADgAcAOABwA4AHADgAcAOAB4B4ADwPAAP/8AAf/AAAf4AAAAAAAAAAAAPwAAD/wAAf/gADwPAAeAeABwA4AHADgAcAOABwA4AHADgAeAeAA8DwABwOAADAwAAAAAAAAAAAA/AAAP/AAD//AAPA8AB4B4AHADgAcAOABwA4AHADgAcAOAA4BwD///gP//+A///4AAAAAAAAAAAAAAAAPwAAD/wAAf/gAD2PAAeYeABxg4AHGDgAcYOABxg4AHGDgAeYeAA/jwAB+OAAD4wAABgAAAAAAAAAAABgAAAGAAAB//+Af//4D///gPcAAA5gAADGAAAMYAAAAAAAAAPwAAD/wMA//w4DwPHgeAePBwA4cHADhwcAOHBwA4cHADhwOAcPB///4H///Af//wAAAAAAAAAAAAAAAAAAD///gP//+AA//4ADgAAAcAAABwAAAHAAAAcAAABwAAAHgAAAP/+AAf/4AA//gAAAAAAAAAAAAAAMf/+A5//4Dn//gAAAAAAAAAAAAAAAAAAHAAAAfn///+f//+5///wAAAAAAAAAAAAAAAAAAP//+A///4D///gAAcAAAD8AAAf4AADzwAAeHgAHwPAAeAeABgA4AEABgAAAAAAAAAD///gP//+A///4AAAAAAAAAAAAAAAAAAAAf/+AB//4AH//gAOAAABwAAAHAAAAcAAABwAAAHgAAAP/+AA//4AB//gAOAAABwAAAHAAAAcAAABwAAAHgAAAf/+AA//4AA//gAAAAAAAAAAAAAAAf/+AB//4AD//gAOAAABwAAAHAAAAcAAABwAAAHAAAAeAAAA//4AB//gAD/+AAAAAAAAAAAAAAAAD8AAA/8AAH/4AA8DwAHgHgAcAOABwA4AHADgAcAOABwA4AHgHgAPh8AAf/gAA/8AAA/AAAAAAAAAAAAAAAAB///8H///wf///A4BwAHADgAcAOABwA4AHADgAcAOAB4B4ADwPAAP/8AAf/AAAf4AAAAAAAAAAAAPwAAD/wAA//wADwPAAeAeABwA4AHADgAcAOABwA4AHADgAOAcAB///8H///wf///AAAAAAAAAAAAAAAAAAAH//gAf/+AB//4ADwAAAcAAABwAAAHAAAAcAAAAAAAAAAMAAHw4AA/jwAH+HgAcYOABxw4AHHDgAcMOABw44AHjjgAPH+AA8fwAAw+AAAAAABgAAAGAAAAcAAAf//wB///AH//+ABgA4AGADgAYAOABgA4AAAAAAAAAAAAAAAH/AAAf/wAB//wAAB/AAAAeAAAA4AAADgAAAOAAAA4AAADgAAAcAB//4AH//gAf/+AAAAAAAAAAAAAAABwAAAH4AAAf8AAAP8AAAH+AAAD+AAAD4AAA/gAAf8AAP+AAH/AAAfgAABwAAAAAAAAAAAABwAAAH8AAAf+AAAP/gAAD/gAAB+AAAf4AAP8AAP+AAB/AAAH4AAAf8AAAP+AAAD/gAAB+AAAf4AAf/AAP/AAB/gAAHgAAAQAAABAAIAHADgAeAeAA8HwAB8+AAD/gAAD8AAAPwAAD/gAAfPgADwfAAeAeABwA4AEAAgAAAAABAAAAHgAAAfwAAA/wAAAf4BwAP4/AAP/8AAP+AAD/AAB/wAA/4AAP8AAB+AAAHAAAAQAAAAAAIAHADgAcAeABwD4AHA/gAcHuABx84AHPDgAf4OAB/A4AHwDgAeAOABgA4AEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYAAAH4Af//////n//AAAA4AAADgAAAAAAAAAAAAAAAAAP//+A///4D///gAAAAAAAAAAAAAAAAAAA4AAADgAAAOAAAA//5/9////wAH4AAAGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAeAAAD4AAAOAAAA4AAADgAAAHAAAAcAAAA4AAADgAAAOAAAD4AAAPAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"), 32, atob("BgkMGhEZEgYMDAwQCAwICxILEBAREBEOEREJCREVEQ8ZEhEUExAOFBQHDREPGBMUERQSEhEUERsREBIMCwwTEg4QERAREQoREQcHDgcYEREREQoPDBEPFg8PDwwIDBMc"), 28+(scale<<8)+(1<<16));
+ return this;
+};
+
+var imgLock = {
+ width : 16, height : 16, bpp : 1,
+ transparent : 0,
+ buffer : E.toArrayBuffer(atob("A8AH4A5wDDAYGBgYP/w//D/8Pnw+fD58Pnw//D/8P/w="))
+};
+
+var imgSteps = {
+ width : 24, height : 24, bpp : 1,
+ transparent : 1,
+ buffer : require("heatshrink").decompress(atob("/H///wv4CBn4CD8ACCj4IBj8f+Eeh/wjgCBngCCg/4nEH//4h/+jEP/gRBAQX+jkf/wgB//8GwP4FoICDHgICCBwIA=="))
+};
+
+var imgBattery = {
+ width : 24, height : 24, bpp : 1,
+ transparent : 1,
+ buffer : require("heatshrink").decompress(atob("/4AN4EAg4TBgd///9oEAAQv8ARQRDDQQgCEwQ4OA"))
+};
+
+var imgBpm = {
+ width : 24, height : 24, bpp : 1,
+ transparent : 1,
+ buffer : require("heatshrink").decompress(atob("/4AOn4CD/wCCjgCCv/8jF/wGYgOA5MB//BC4PDAQnjAQPnAQgANA"))
+};
+
+var imgTemperature = {
+ width : 24, height : 24, bpp : 1,
+ transparent : 1,
+ buffer : require("heatshrink").decompress(atob("//D///wICBjACBngCNkgCP/0kv/+s1//nDn/8wICEBAIOC/08v//IYJECA=="))
+};
+
+var imgWind = {
+ width : 24, height : 24, bpp : 1,
+ transparent : 1,
+ buffer : require("heatshrink").decompress(atob("/0f//8h///Pn//zAQXzwf/88B//mvGAh18gEevn/DIICB/PwgEBAQMHBAIADFwM/wEAGAP/54CD84CE+eP//wIQU/A=="))
+};
+
+var imgTimer = {
+ width : 24, height : 24, bpp : 1,
+ transparent : 1,
+ buffer : require("heatshrink").decompress(atob("/+B/4CD84CEBAPygFP+F+h/x/+P+fz5/n+HnAQNn5/wuYCBmYCC5kAAQfOgFz80As/ngHn+fD54mC/F+j/+gF/HAQA=="))
+};
+
+var imgCharging = {
+ width : 24, height : 24, bpp : 1,
+ transparent : 1,
+ buffer : require("heatshrink").decompress(atob("//+v///k///4AQPwBANgBoMxBoMb/P+h/w/kH8H4gfB+EBwfggHH4EAt4CBn4CBj4CBh4FCCIO/8EB//Agf/wEH/8Gh//x////fAQIA="))
+};
+
+
+
+/*
+ * Draw timeout
+ */
+// timeout used to update every minute
+var drawTimeout;
+
+// schedule a draw for the next minute
+function queueDraw() {
+ if (drawTimeout) clearTimeout(drawTimeout);
+ drawTimeout = setTimeout(function() {
+ drawTimeout = undefined;
+ draw();
+ }, 60000 - (Date.now() % 60000));
+}
+
+
+/*
+ * Helper
+ */
+function getSteps() {
+ try{
+ if (WIDGETS.wpedom !== undefined) {
+ return WIDGETS.wpedom.getSteps();
+ } else if (WIDGETS.activepedom !== undefined) {
+ return WIDGETS.activepedom.getSteps();
+ } else {
+ return Bangle.getHealthStatus("day").steps;
+ }
+ } catch(ex) {
+ // In case we failed, we can only show 0 steps.
+ }
+
+ return 0;
+}
+
+
+function getWeather(){
+ var weatherJson;
+
+ try {
+ weatherJson = storage.readJSON('weather.json');
+ var weather = weatherJson.weather;
+
+ // Temperature
+ weather.temp = locale.temp(weather.temp-273.15);
+
+ // Humidity
+ weather.hum = weather.hum + "%";
+
+ // Wind
+ const wind = locale.speed(weather.wind).match(/^(\D*\d*)(.*)$/);
+ weather.wind = Math.round(wind[1]) + " km/h";
+
+ return weather
+
+ } catch(ex) {
+ // Return default
+ }
+
+ return {
+ temp: "? °C",
+ hum: "-",
+ txt: "-",
+ wind: "? km/h",
+ wdir: "-",
+ wrose: "-"
+ };
+}
+
+function isAlarmEnabled(){
+ try{
+ var alarm = require('sched');
+ var alarmObj = alarm.getAlarm(TIMER_IDX);
+ if(alarmObj===undefined || !alarmObj.on){
+ return false;
+ }
+
+ return true;
+
+ } catch(ex){ }
+ return false;
+}
+
+function getAlarmMinutes(){
+ if(!isAlarmEnabled()){
+ return -1;
+ }
+
+ var alarm = require('sched');
+ var alarmObj = alarm.getAlarm(TIMER_IDX);
+ return Math.round(alarm.getTimeToAlarm(alarmObj)/(60*1000));
+}
+
+function increaseAlarm(){
+ try{
+ var minutes = isAlarmEnabled() ? getAlarmMinutes() : 0;
+ var alarm = require('sched')
+ alarm.setAlarm(TIMER_IDX, {
+ timer : (minutes+5)*60*1000,
+ });
+ alarm.reload();
+ } catch(ex){ }
+}
+
+function decreaseAlarm(){
+ try{
+ var minutes = getAlarmMinutes();
+ minutes -= 5;
+
+ var alarm = require('sched')
+ alarm.setAlarm(TIMER_IDX, undefined);
+
+ if(minutes > 0){
+ alarm.setAlarm(TIMER_IDX, {
+ timer : minutes*60*1000,
+ });
+ }
+
+ alarm.reload();
+ } catch(ex){ }
+}
+
+
+/*
+ * D R A W
+ */
+function draw() {
+ // queue draw in one minute
+ queueDraw();
+
+ // Set info
+ var showInfo = settings.showInfo;
+ if(isAlarmEnabled()){
+ showInfo = 100;
+ }
+
+ if(Bangle.isCharging()){
+ showInfo = 101;
+ }
+
+
+ // Draw background
+ var yOffset = settings.fullscreen ? 0 : 10;
+ var y = H/5*2 + yOffset;
+ g.reset().clearRect(0,0,W,W);
+ g.setColor(g.theme.fg);
+ g.fillRect(0,y,W,H);
+
+ // Draw date
+ y -= settings.fullscreen ? 5 : 0;
+ var date = new Date();
+ g.setColor(g.theme.fg);
+ g.setFontAlign(1,1);
+ g.setMediumFont();
+ var dateStr = date.getDate();
+ dateStr = ("0" + dateStr).substr(-2);
+ g.drawString(dateStr, W/2-1, y+4);
+
+ g.setSmallFont();
+ g.setFontAlign(-1,1);
+ g.drawString(locale.dow(date, true), W/2 + 10, y-23);
+ g.drawString(locale.month(date, 1), W/2 + 10, y+1);
+
+ // Draw time
+ g.setColor(g.theme.bg);
+ g.setFontAlign(0,-1);
+ var timeStr = locale.time(date,1);
+ y += settings.fullscreen ? 20 : 10;
+
+ if(showInfo == 0){
+ y += 8;
+ g.setLargeFont();
+ } else {
+ g.setMediumFont();
+ }
+
+ g.drawString(timeStr, W/2, y);
+
+ // Draw info or timer
+ y += H/5*2-5;
+ g.setFontAlign(0,0);
+ if(showInfo > 0){
+ g.setSmallFont();
+
+ var infoStr = "";
+ var infoImg;
+ if(showInfo == 100){
+ infoStr = getAlarmMinutes() + " min.";
+ infoImg = imgTimer;
+ } else if(showInfo == 101){
+ infoStr = E.getBattery() + "%";
+ infoImg = imgCharging;
+ } else if (showInfo == 1){
+ infoStr = E.getBattery() + "%";
+ infoImg = imgBattery;
+ } else if (showInfo == 2){
+ infoStr = getSteps()
+ infoStr = Math.round(infoStr/100) / 10; // This ensures that we do not show e.g. 15.0k and 15k instead
+ infoStr = infoStr + "k";
+ infoImg = imgSteps;
+ } else if (showInfo == 3){
+ infoStr = Math.round(Bangle.getHealthStatus("day").bpm) + " bpm";
+ infoImg = imgBpm;
+ } else if (showInfo == 4){
+ var weather = getWeather();
+ infoStr = weather.temp;
+ infoImg = imgTemperature;
+ } else if (showInfo == 5){
+ var weather = getWeather();
+ infoStr = weather.wind;
+ infoImg = imgWind;
+ }
+
+ var imgWidth = 0;
+ if(infoImg !== undefined){
+ imgWidth = infoImg.width;
+ var strWidth = g.stringWidth(infoStr);
+ g.drawImage(infoImg, W/2 - strWidth/2 - infoImg.width/2 - 5, y - infoImg.height/2);
+ }
+ g.drawString(infoStr, W/2 + imgWidth/2, y+3);
+ }
+
+ // Draw lock
+ if(settings.showLock && Bangle.isLocked()){
+ g.setColor(g.theme.fg);
+ g.drawImage(imgLock, W-16, 2);
+ }
+
+ // Draw widgets if not fullscreen
+ if(settings.fullscreen){
+ for (let wd of WIDGETS) {wd.draw=()=>{};wd.area="";}
+ } else {
+ Bangle.drawWidgets();
+ }
+}
+
+Bangle.loadWidgets();
+
+// Clear the screen once, at startup and set the correct theme.
+var bgOrig = g.theme.bg
+var fgOrig = g.theme.fg
+g.setTheme({bg:fgOrig,fg:bgOrig}).clear();
+draw();
+
+// Stop updates when LCD is off, restart when on
+Bangle.on('lcdPower',on=>{
+ if (on) {
+ draw(); // draw immediately, queue redraw
+ } else { // stop draw timer
+ if (drawTimeout) clearTimeout(drawTimeout);
+ drawTimeout = undefined;
+ }
+});
+
+Bangle.on('lock', function(isLocked) {
+ if (drawTimeout) clearTimeout(drawTimeout);
+ drawTimeout = undefined;
+ draw();
+});
+
+Bangle.on('charging',function(charging) {
+ if (drawTimeout) clearTimeout(drawTimeout);
+ drawTimeout = undefined;
+ draw();
+});
+
+Bangle.on('touch', function(btn, e){
+ var left = parseInt(g.getWidth() * 0.2);
+ var right = g.getWidth() - left;
+ var upper = parseInt(g.getHeight() * 0.2);
+ var lower = g.getHeight() - upper;
+
+ var is_left = e.x < left;
+ var is_right = e.x > right;
+ var is_upper = e.y < upper;
+ var is_lower = e.y > lower;
+
+ if(is_upper){
+ Bangle.buzz(40, 0.6);
+ increaseAlarm();
+ draw();
+ }
+
+ if(is_lower){
+ Bangle.buzz(40, 0.6);
+ decreaseAlarm();
+ draw();
+ }
+
+ var maxInfo = 6;
+ if(is_right){
+ Bangle.buzz(40, 0.6);
+ settings.showInfo = (settings.showInfo+1) % maxInfo;
+ storage.write(SETTINGS_FILE, settings);
+ draw();
+ }
+
+ if(is_left){
+ Bangle.buzz(40, 0.6);
+ settings.showInfo = settings.showInfo-1;
+ settings.showInfo = settings.showInfo < 0 ? maxInfo-1 : settings.showInfo;
+ storage.write(SETTINGS_FILE, settings);
+ draw();
+ }
+});
+
+
+// Show launcher when middle button pressed
+Bangle.setUI("clock");
diff --git a/apps/bwclk/app.png b/apps/bwclk/app.png
new file mode 100644
index 000000000..5073f0ed0
Binary files /dev/null and b/apps/bwclk/app.png differ
diff --git a/apps/bwclk/metadata.json b/apps/bwclk/metadata.json
new file mode 100644
index 000000000..babaa37bf
--- /dev/null
+++ b/apps/bwclk/metadata.json
@@ -0,0 +1,18 @@
+{
+ "id": "bwclk",
+ "name": "BlackWhite Clock",
+ "version": "0.05",
+ "description": "Black and white clock.",
+ "readme": "README.md",
+ "icon": "app.png",
+ "screenshots": [{"url":"screenshot.png"}, {"url":"screenshot_2.png"}],
+ "type": "clock",
+ "tags": "clock",
+ "supports": ["BANGLEJS2"],
+ "allow_emulator": true,
+ "storage": [
+ {"name":"bwclk.app.js","url":"app.js"},
+ {"name":"bwclk.img","url":"app-icon.js","evaluate":true},
+ {"name":"bwclk.settings.js","url":"settings.js"}
+ ]
+}
diff --git a/apps/bwclk/screenshot.png b/apps/bwclk/screenshot.png
new file mode 100644
index 000000000..02ef7a704
Binary files /dev/null and b/apps/bwclk/screenshot.png differ
diff --git a/apps/bwclk/screenshot_2.png b/apps/bwclk/screenshot_2.png
new file mode 100644
index 000000000..2f31c8b3c
Binary files /dev/null and b/apps/bwclk/screenshot_2.png differ
diff --git a/apps/bwclk/settings.js b/apps/bwclk/settings.js
new file mode 100644
index 000000000..82d1cad0b
--- /dev/null
+++ b/apps/bwclk/settings.js
@@ -0,0 +1,40 @@
+(function(back) {
+ const SETTINGS_FILE = "bwclk.setting.json";
+
+ // initialize with default settings...
+ const storage = require('Storage')
+ let settings = {
+ fullscreen: false,
+ showLock: true,
+ };
+ let saved_settings = storage.readJSON(SETTINGS_FILE, 1) || settings;
+ for (const key in saved_settings) {
+ settings[key] = saved_settings[key]
+ }
+
+ function save() {
+ storage.write(SETTINGS_FILE, settings)
+ }
+
+
+ E.showMenu({
+ '': { 'title': 'BlackWhite Clock' },
+ '< Back': back,
+ 'Fullscreen': {
+ value: settings.fullscreen,
+ format: () => (settings.fullscreen ? 'Yes' : 'No'),
+ onchange: () => {
+ settings.fullscreen = !settings.fullscreen;
+ save();
+ },
+ },
+ 'Show Lock': {
+ value: settings.showLock,
+ format: () => (settings.showLock ? 'Yes' : 'No'),
+ onchange: () => {
+ settings.showLock = !settings.showLock;
+ save();
+ },
+ }
+ });
+ })
diff --git a/apps/compass/ChangeLog b/apps/compass/ChangeLog
index 4bb7838ac..d1adafc4c 100644
--- a/apps/compass/ChangeLog
+++ b/apps/compass/ChangeLog
@@ -3,3 +3,4 @@
0.03: Eliminate flickering
0.04: Fix for Bangle.js 2 and themes
0.05: Fix bearing not clearing correctly (visible in single or double digit bearings)
+0.06: Add button for force compass calibration
diff --git a/apps/compass/README.md b/apps/compass/README.md
new file mode 100644
index 000000000..d60192f73
--- /dev/null
+++ b/apps/compass/README.md
@@ -0,0 +1,29 @@
+# Compass
+
+This app uses Bangle.js's built-in magnetometer as a compass.
+
+## Usage
+
+Hold your Bangle.js **face up** (so the display is parallel to the ground),
+and the red arrow will point north, with the heading in degrees printed at
+the top of the screen.
+
+This compass app does not include tilt compensation - so much like a real
+compass you should always keep it face up when taking a reading.
+
+The first time you run the compass after your Bangle has booted (or if
+you move to an area with a substantially different magnetic field) you will
+need to recalibrate your compass (even if a heading is shown).
+
+## Calibration
+
+Press the button next to the `RESET` label on the screen. The North/South marker
+will disappear and a message will appear asking you to rotate the watch 360 degrees.
+
+* Hold the watch face up, so the display is parallel to the ground
+* Rotate it around slowly, all 360 degrees (with the display still parallel to the ground)
+* The `Uncalibrated` message will disappear before you have finished rotating the full 360 degrees - but you should still complete the full rotation in order for the compass to work properly.
+
+Once you've rotated the full 360 degrees your compass should now work fine,
+and calibration is stored between runs of the app. However if you go near
+to a strong magnet you may still need to recalibrate.
diff --git a/apps/compass/compass.js b/apps/compass/compass.js
index 65ad83c4f..4730111ac 100644
--- a/apps/compass/compass.js
+++ b/apps/compass/compass.js
@@ -38,7 +38,7 @@ Bangle.on('mag', function(m) {
if (!wasUncalibrated) {
g.clearRect(0,24,W,48);
g.setFontAlign(0,-1).setFont("6x8");
- g.drawString("Uncalibrated\nturn 360° around",M,24+4);
+ g.drawString(/*LANG*/"Uncalibrated\nturn 360° around",M,24+4);
wasUncalibrated = true;
}
} else {
@@ -64,7 +64,12 @@ Bangle.on('mag', function(m) {
oldHeading = m.heading;
});
-g.clear();
+g.clear(1);
+g.setFont("6x8").setFontAlign(0,0,3).drawString(/*LANG*/"RESET", g.getWidth()-5, g.getHeight()/2);
+setWatch(function() {
+ Bangle.resetCompass();
+}, (process.env.HWVERSION==2) ? BTN1 : BTN2, {repeat:true});
+
Bangle.loadWidgets();
Bangle.drawWidgets();
Bangle.setCompassPower(1);
diff --git a/apps/compass/metadata.json b/apps/compass/metadata.json
index 318d90c86..3e3b37f72 100644
--- a/apps/compass/metadata.json
+++ b/apps/compass/metadata.json
@@ -1,12 +1,13 @@
{
"id": "compass",
"name": "Compass",
- "version": "0.05",
+ "version": "0.06",
"description": "Simple compass that points North",
"icon": "compass.png",
"screenshots": [{"url":"screenshot_compass.png"}],
"tags": "tool,outdoors",
"supports": ["BANGLEJS","BANGLEJS2"],
+ "readme": "README.md",
"storage": [
{"name":"compass.app.js","url":"compass.js"},
{"name":"compass.img","url":"compass-icon.js","evaluate":true}
diff --git a/apps/fuzzyw/ChangeLog b/apps/fuzzyw/ChangeLog
new file mode 100644
index 000000000..7b83706bf
--- /dev/null
+++ b/apps/fuzzyw/ChangeLog
@@ -0,0 +1 @@
+0.01: First release
diff --git a/apps/fuzzyw/README.md b/apps/fuzzyw/README.md
new file mode 100644
index 000000000..906eb167b
--- /dev/null
+++ b/apps/fuzzyw/README.md
@@ -0,0 +1,26 @@
+# Fuzzy Text Clock
+
+An imprecise clock for when you're not in a rush.
+
+This clock is a remake of one of my favourite Pebble watchfaces, Fuzzy Text International. I use this watch for weekends and holidays, when 'within 5 minutes of the actual time' is close enough!
+
+By default it will use the language set on the watch, go to settings to pick:
+* en_GB - English
+* en_US - American
+* es_ES - Spanish
+* fr_FR - French
+* no_NO - Norwegian
+* sv_SE - Swedish
+* de_DE - German
+
+Most translations are taken from the original Fuzzy Text International code.
+
+## TODO
+* Bold hour word (as the pebble version has)
+* Animation when changing time?
+
+## References
+Based on Pebble app Fuzzy Text International: https://github.com/hallettj/Fuzzy-Text-International
+
+
+
diff --git a/apps/fuzzyw/fuzzy_strings.json b/apps/fuzzyw/fuzzy_strings.json
new file mode 100644
index 000000000..8594ad554
--- /dev/null
+++ b/apps/fuzzyw/fuzzy_strings.json
@@ -0,0 +1,163 @@
+{
+ "en_GB":{
+ "hours":[
+ "midnight", "one", "two", "three", "four", "five",
+ "six", "seven", "eight", "nine", "ten", "eleven",
+ "twelve", "one", "two", "three", "four", "five",
+ "six", "seven", "eight", "nine", "ten", "eleven"
+ ],
+ "minutes":[
+ "*$1 o'clock",
+ "five past *$1",
+ "ten past *$1",
+ "quarter past *$1",
+ "twenty past *$1",
+ "twenty five past *$1",
+ "half past *$1",
+ "twenty five to *$2",
+ "twenty to *$2",
+ "quarter to *$2",
+ "ten to *$2",
+ "five to *$2"
+ ],
+ "text_scale":3.5
+ },
+ "en_US":{
+ "hours":[
+ "midnight", "one", "two", "three", "four", "five",
+ "six", "seven", "eight", "nine", "ten", "eleven",
+ "twelve", "one", "two", "three", "four", "five",
+ "six", "seven", "eight", "nine", "ten", "eleven"
+ ],
+ "minutes":[
+ "*$1 o'clock",
+ "five after *$1",
+ "ten after *$1",
+ "quarter after *$1",
+ "twenty after *$1",
+ "twenty five after *$1",
+ "half past *$1",
+ "twenty five to *$2",
+ "twenty to *$2",
+ "quarter to *$2",
+ "ten to *$2",
+ "five to *$2"
+ ],
+ "text_scale":3.5
+ },
+ "es_ES":{
+ "hours":[
+ "doce", "una", "dos", "tres", "cuatro", "cinco",
+ "seis", "siete", "ocho", "nueve", "diez", "once",
+ "doce", "una", "dos", "tres", "cuatro", "cinco",
+ "seis", "siete", "ocho", "nueve", "diez", "once"
+ ],
+ "minutes":[
+ "*$1 en punto",
+ "*$1 y cinco",
+ "*$1 y diez",
+ "*$1 y cuarto",
+ "*$1 y veinte",
+ "*$1 y veinti- cinco",
+ "*$1 y media",
+ "*$2 menos veinti- cinco",
+ "*$2 menos veinte",
+ "*$2 menos cuarto",
+ "*$2 menos diez",
+ "*$2 menos cinco"
+ ],
+ "text_scale":3.5
+ },
+ "fr_FR":{
+ "hours":[
+ "douze", "une", "deux", "trois", "quatre", "cinq",
+ "six", "sept", "huit", "neuf", "dix", "onze",
+ "douze", "une", "deux", "trois", "quatre", "cinq",
+ "six", "sept", "huit", "neuf", "dix", "onze"
+ ],
+ "minutes":[
+ "*$1 heures",
+ "*$1 heures cinq",
+ "*$1 heures dix",
+ "*$1 heures et quart",
+ "*$1 heures vingt",
+ "*$1 heures vingt- cinq",
+ "*$1 heures et demie",
+ "*$2 moins vingt- cinq",
+ "*$2 heures moins vingt",
+ "*$2 moins le quart",
+ "*$2 heures moins dix",
+ "*$2 heures moins cinq"
+ ],
+ "text_scale":3.5
+ },
+ "no_NB":{
+ "hours":[
+ "tolv", "ett", "to", "tre", "fire", "fem",
+ "seks", "sju", "åtte", "ni", "ti", "elleve",
+ "tolv", "ett", "to", "tre", "fire", "fem",
+ "seks", "sju", "åtte", "ni", "ti", "elleve"
+ ],
+ "minutes":[
+ "klokka er *$1",
+ "fem over *$1",
+ "ti over *$1",
+ "kvart over *$1",
+ "ti på halv *$2",
+ "fem på halv *$2",
+ "halv *$2",
+ "fem over halv *$2",
+ "ti over halv *$2",
+ "kvart på *$2",
+ "ti på *$2",
+ "fem på *$2"
+ ],
+ "text_scale":3.5
+ },
+ "sv_SE":{
+ "hours":[
+ "tolv", "ett", "två", "tre", "fyra", "fem",
+ "sex", "sju", "åtta", "nio", "tio", "elva",
+ "tolv", "ett", "två", "tre", "fyra", "fem",
+ "sex", "sju", "åtta", "nio", "tio", "elva"
+ ],
+ "minutes":[
+ "*$1",
+ "fem över *$1",
+ "tio över *$1",
+ "kvart över *$1",
+ "tjugo över *$1",
+ "fem i halv *$2",
+ "halv *$2",
+ "fem över halv *$2",
+ "tjugo i *$2",
+ "kvart i *$2",
+ "tio i *$2",
+ "fem i *$2"
+ ],
+ "text_scale":3.5
+ },
+ "de_DE":{
+ "hours":[
+ "zwölf", "eins", "zwei", "drei", "vier", "fünf",
+ "sechs", "sieben", "acht", "neun", "zehn", "elf",
+ "zwölf", "eins", "zwei", "drei", "vier", "fünf",
+ "sechs", "sieben", "acht", "neun", "zehn", "elf"
+ ],
+ "minutes":[
+ "*$1 uhr",
+ "fünf nach *$1",
+ "zehn nach *$1",
+ "viertel nach *$1",
+ "zwanzig nach *$1",
+ "fünf for halb *$2",
+ "halb *$2",
+ "fünf nach halb *$2",
+ "zwanzig vor *$2",
+ "viertel vor *$2",
+ "zehn vor *$2",
+ "fünf vor *$2"
+ ],
+ "text_scale":3.5
+ }
+}
diff --git a/apps/fuzzyw/fuzzyw-dark.png b/apps/fuzzyw/fuzzyw-dark.png
new file mode 100644
index 000000000..88220e5c7
Binary files /dev/null and b/apps/fuzzyw/fuzzyw-dark.png differ
diff --git a/apps/fuzzyw/fuzzyw-light.png b/apps/fuzzyw/fuzzyw-light.png
new file mode 100644
index 000000000..5383e08a4
Binary files /dev/null and b/apps/fuzzyw/fuzzyw-light.png differ
diff --git a/apps/fuzzyw/fuzzyw.app.js b/apps/fuzzyw/fuzzyw.app.js
new file mode 100644
index 000000000..07b5c4068
--- /dev/null
+++ b/apps/fuzzyw/fuzzyw.app.js
@@ -0,0 +1,75 @@
+// adapted from https://github.com/hallettj/Fuzzy-Text-International/
+const fuzzy_strings = require("Storage").readJSON("fuzzy_strings.json");
+
+const SETTINGS_FILE = "fuzzyw.settings.json";
+let settings = require("Storage").readJSON(SETTINGS_FILE,1)|| {'language': 'System', 'alignment':'Centre'};
+
+if (settings.language == 'System') {
+ settings.language = require('locale').name;
+}
+
+let fuzzy_string = fuzzy_strings[settings.language];
+
+let timeout = 2.5*60;
+let drawTimeout;
+
+function queueDraw(seconds) {
+ let millisecs = seconds * 1000;
+ if (drawTimeout) clearTimeout(drawTimeout);
+ drawTimeout = setTimeout(function() {
+ drawTimeout = undefined;
+ draw();
+ }, millisecs - (Date.now() % millisecs));
+}
+
+const h = g.getHeight();
+const w = g.getWidth();
+let align_mode = 0;
+let align_pos = w/2;
+if (settings.alignment =='Left') {
+ align_mode = -1;
+ align_pos = 0;
+} else if (settings.alignment == 'Right') {
+ align_mode = 1;
+ align_pos = w;
+}
+
+function getTimeString(date) {
+ let segment = Math.round((date.getMinutes()*60 + date.getSeconds() + 1)/300);
+ let hour = date.getHours() + Math.floor(segment/12);
+ f_string = fuzzy_string.minutes[segment % 12];
+ if (f_string.includes('$1')) {
+ f_string = f_string.replace('$1', fuzzy_string.hours[(hour) % 24]);
+ } else {
+ f_string = f_string.replace('$2', fuzzy_string.hours[(hour + 1) % 24]);
+ }
+ return f_string;
+}
+
+function draw() {
+ let time_string = getTimeString(new Date()).replace('*', '');
+ // print(time_string);
+ g.setFont('Vector', (h-24*2)/fuzzy_string.text_scale);
+ g.setFontAlign(align_mode, 0);
+ g.clearRect(0, 24, w, h-24);
+ g.setColor(g.theme.fg);
+ g.drawString(g.wrapString(time_string, w).join("\n"), align_pos, h/2);
+ queueDraw(timeout);
+}
+
+g.clear();
+draw();
+
+// Stop updates when LCD is off, restart when on
+Bangle.on('lcdPower',on=>{
+ if (on) {
+ draw(); // draw immediately, queue redraw
+ } else { // stop draw timer
+ if (drawTimeout) clearTimeout(drawTimeout);
+ drawTimeout = undefined;
+ }
+});
+
+Bangle.setUI('clock');
+Bangle.loadWidgets();
+Bangle.drawWidgets();
diff --git a/apps/fuzzyw/fuzzyw.icon.js b/apps/fuzzyw/fuzzyw.icon.js
new file mode 100644
index 000000000..acc7e2fcf
--- /dev/null
+++ b/apps/fuzzyw/fuzzyw.icon.js
@@ -0,0 +1 @@
+require("heatshrink").decompress(atob("mEwgP/ABX8oYFD+AFE8AFE8IXE8YFKwFCj08h4FBocenEHCIPDjk4CoIFBhlwAoeMuIFEuBSBAoOI+AFD4HxGoQFB+AFD4P4uYFC8P4gYFD/w7BAFEfApfEj+B/Ecg/Ah8A+EMg/Dw0YseHj/Dw/8sfHAoPH/lhDoIFBwFwj4FB40AvkPAoU8v4dCAoIdDw04FIMP4EOgFwh47Bj8EvEfw/DJwgFXABY"))
diff --git a/apps/fuzzyw/fuzzyw.png b/apps/fuzzyw/fuzzyw.png
new file mode 100644
index 000000000..afd0b0f76
Binary files /dev/null and b/apps/fuzzyw/fuzzyw.png differ
diff --git a/apps/fuzzyw/fuzzyw.settings.js b/apps/fuzzyw/fuzzyw.settings.js
new file mode 100644
index 000000000..00219accf
--- /dev/null
+++ b/apps/fuzzyw/fuzzyw.settings.js
@@ -0,0 +1,46 @@
+(function(back) {
+ const SETTINGS_FILE = "fuzzyw.settings.json";
+
+ var align_options = ['Left','Centre','Right'];
+ var language_options = ['System', 'en_GB', 'en_US', 'es_ES', 'fr_FR', 'no_NO', 'sv_SE', 'de_DE'];
+
+ // initialize with default settings...
+ let s = {'language': 'System', 'alignment': 'Centre'};
+
+ // ...and overwrite them with any saved values
+ // This way saved values are preserved if a new version adds more settings
+ const storage = require('Storage')
+ let settings = storage.readJSON(SETTINGS_FILE, 1) || s;
+ const saved = settings || {}
+ for (const key in saved) {
+ s[key] = saved[key]
+ }
+
+ function save() {
+ settings = s
+ storage.write(SETTINGS_FILE, settings)
+ }
+
+ E.showMenu({
+ '': { 'title': 'Fuzzy Text Clock' },
+ '< Back': back,
+ 'Language': {
+ value: 0 | language_options.indexOf(s.language),
+ min: 0, max: language_options.length - 1,
+ format: v => language_options[v],
+ onchange: v => {
+ s.language = language_options[v];
+ save();
+ }
+ },
+ 'Alignment': {
+ value: 0 | align_options.indexOf(s.alignment),
+ min: 0, max: align_options.length - 1,
+ format: v => align_options[v],
+ onchange: v => {
+ s.alignment = align_options[v];
+ save();
+ }
+ },
+ });
+})
diff --git a/apps/fuzzyw/metadata.json b/apps/fuzzyw/metadata.json
new file mode 100644
index 000000000..ebd20e49f
--- /dev/null
+++ b/apps/fuzzyw/metadata.json
@@ -0,0 +1,20 @@
+{
+ "id":"fuzzyw",
+ "name":"Fuzzy Text Clock",
+ "shortName": "Fuzzy Text",
+ "version": "0.01",
+ "description": "An imprecise clock for when you're not in a rush",
+ "readme": "README.md",
+ "icon":"fuzzyw.png",
+ "screenshots": [{"url":"fuzzyw-light.png"},{"url":"fuzzyw-dark.png"}],
+ "type": "clock",
+ "tags": "clock",
+ "supports": ["BANGLEJS", "BANGLEJS2"],
+ "allow_emulator": true,
+ "storage": [
+ {"name":"fuzzyw.app.js","url":"fuzzyw.app.js"},
+ {"name":"fuzzyw.settings.js","url":"fuzzyw.settings.js"},
+ {"name":"fuzzyw.img","url":"fuzzyw.icon.js","evaluate":true},
+ {"name":"fuzzy_strings.json","url":"fuzzy_strings.json"}
+ ]
+}
diff --git a/apps/lcars/ChangeLog b/apps/lcars/ChangeLog
index 9d43f6575..4935fe714 100644
--- a/apps/lcars/ChangeLog
+++ b/apps/lcars/ChangeLog
@@ -17,3 +17,4 @@
0.17: Settings for mph/kph and other minor improvements.
0.18: Fullscreen mode can now be enabled or disabled in the settings.
0.19: Alarms can not go bigger than 100.
+0.20: Use alarm for alarm functionality instead of own implementation.
\ No newline at end of file
diff --git a/apps/lcars/README.md b/apps/lcars/README.md
index f979b2304..7024e8edf 100644
--- a/apps/lcars/README.md
+++ b/apps/lcars/README.md
@@ -3,7 +3,8 @@
A simple LCARS inspired clock.
Note: To display the steps, the wpedom app is required. To show weather data
such as temperature, humidity or window you BangleJS must be connected
-with Gadgetbride and the weather app must be installed.
+with Gadgetbride and the weather app must be installed. To use the timer
+the "sched" app must be installed on your device.
## Control
* Tap left / right to change between screens.
@@ -15,7 +16,7 @@ with Gadgetbride and the weather app must be installed.
* Tab on left/right to switch between different screens.
* Cusomizable data that is shown on screen 1 (steps, weather etc.)
* Shows random and real images of planets.
- * Tap on top/bottom of screen 1 to activate an alarm.
+ * Tap on top/bottom of screen 1 to activate an alarm. Depends on widtmr.
* The lower orange line indicates the battery level.
* Display graphs (day or month) for steps + hrm on the second screen.
@@ -36,8 +37,9 @@ Access different screens via tap on the left/ right side of the screen


+## Creator
+- [David Peer](https://github.com/peerdavid)
## Contributors
-- [David Peer](https://github.com/peerdavid).
-- [Adam Schmalhofer](https://github.com/adamschmalhofer).
-- [Jon Warrington](https://github.com/BartokW).
+- [Adam Schmalhofer](https://github.com/adamschmalhofer)
+- [Jon Warrington](https://github.com/BartokW)
diff --git a/apps/lcars/lcars.app.js b/apps/lcars/lcars.app.js
index 433d33427..577955d2e 100644
--- a/apps/lcars/lcars.app.js
+++ b/apps/lcars/lcars.app.js
@@ -1,6 +1,7 @@
+const TIMER_IDX = "lcars";
const SETTINGS_FILE = "lcars.setting.json";
const locale = require('locale');
-const storage = require('Storage')
+const storage = require('Storage');
let settings = {
alarm: -1,
dataRow1: "Steps",
@@ -124,11 +125,16 @@ Graphics.prototype.setFontAntonioLarge = function(scale) {
*/
var drawTimeout;
function queueDraw() {
+
+ // Faster updates during alarm to ensure that it is
+ // shown correctly...
+ var timeout = isAlarmEnabled() ? 10000 : 60000;
+
if (drawTimeout) clearTimeout(drawTimeout);
drawTimeout = setTimeout(function() {
drawTimeout = undefined;
draw();
- }, 60000 - (Date.now() % 60000));
+ }, timeout - (Date.now() % timeout));
}
/**
@@ -238,6 +244,7 @@ function drawInfo(){
return;
}
+ g.setFontAlign(-1, -1, 0);
g.setFontAntonioMedium();
g.setColor(cOrange);
g.clearRect(120, 10, g.getWidth(), 75);
@@ -480,9 +487,6 @@ function draw(){
// Queue draw first to ensure that its called in one minute again.
queueDraw();
- // First handle alarm to show this correctly afterwards
- handleAlarm();
-
// Next draw the watch face
g.reset();
g.clearRect(0, 0, g.getWidth(), g.getHeight());
@@ -561,43 +565,57 @@ function getWeather(){
/*
* Handle alarm
*/
-function getCurrentTimeInMinutes(){
- return Math.floor(Date.now() / (1000*60));
-}
-
function isAlarmEnabled(){
- return settings.alarm >= 0;
+ try{
+ var alarm = require('sched');
+ var alarmObj = alarm.getAlarm(TIMER_IDX);
+ if(alarmObj===undefined || !alarmObj.on){
+ return false;
+ }
+
+ return true;
+
+ } catch(ex){ }
+ return false;
}
function getAlarmMinutes(){
- var currentTime = getCurrentTimeInMinutes();
- return settings.alarm - currentTime;
+ if(!isAlarmEnabled()){
+ return -1;
+ }
+
+ var alarm = require('sched');
+ var alarmObj = alarm.getAlarm(TIMER_IDX);
+ return Math.round(alarm.getTimeToAlarm(alarmObj)/(60*1000));
}
-function handleAlarm(){
- if(!isAlarmEnabled()){
- return;
- }
+function increaseAlarm(){
+ try{
+ var minutes = isAlarmEnabled() ? getAlarmMinutes() : 0;
+ var alarm = require('sched')
+ alarm.setAlarm(TIMER_IDX, {
+ timer : (minutes+5)*60*1000,
+ });
+ alarm.reload();
+ } catch(ex){ }
+}
- if(getAlarmMinutes() > 0){
- return;
- }
+function decreaseAlarm(){
+ try{
+ var minutes = getAlarmMinutes();
+ minutes -= 5;
- // Alarm
- var t = 300;
- Bangle.buzz(t, 1)
- .then(() => new Promise(resolve => setTimeout(resolve, t)))
- .then(() => Bangle.buzz(t, 1))
- .then(() => new Promise(resolve => setTimeout(resolve, t)))
- .then(() => Bangle.buzz(t, 1))
- .then(() => new Promise(resolve => setTimeout(resolve, t)))
- .then(() => Bangle.buzz(t, 1))
- .then(() => new Promise(resolve => setTimeout(resolve, 5E3)))
- .then(() => {
- // Update alarm state to disabled
- settings.alarm = -1;
- storage.writeJSON(SETTINGS_FILE, settings);
- });
+ var alarm = require('sched')
+ alarm.setAlarm(TIMER_IDX, undefined);
+
+ if(minutes > 0){
+ alarm.setAlarm(TIMER_IDX, {
+ timer : minutes*60*1000,
+ });
+ }
+
+ alarm.reload();
+ } catch(ex){ }
}
@@ -625,27 +643,6 @@ Bangle.on('charging',function(charging) {
});
-function increaseAlarm(){
- if(isAlarmEnabled() && getAlarmMinutes() < 95){
- settings.alarm += 5;
- } else {
- settings.alarm = getCurrentTimeInMinutes() + 5;
- }
-
- storage.writeJSON(SETTINGS_FILE, settings);
-}
-
-
-function decreaseAlarm(){
- if(isAlarmEnabled() && (settings.alarm-5 > getCurrentTimeInMinutes())){
- settings.alarm -= 5;
- } else {
- settings.alarm = -1;
- }
-
- storage.writeJSON(SETTINGS_FILE, settings);
-}
-
function feedback(){
Bangle.buzz(40, 0.3);
}
diff --git a/apps/lcars/metadata.json b/apps/lcars/metadata.json
index 1335b8e1d..7155442f8 100644
--- a/apps/lcars/metadata.json
+++ b/apps/lcars/metadata.json
@@ -3,7 +3,7 @@
"name": "LCARS Clock",
"shortName":"LCARS",
"icon": "lcars.png",
- "version":"0.19",
+ "version":"0.20",
"readme": "README.md",
"supports": ["BANGLEJS2"],
"description": "Library Computer Access Retrieval System (LCARS) clock.",
diff --git a/apps/notanalog/ChangeLog b/apps/notanalog/ChangeLog
index 574d46609..6515f787c 100644
--- a/apps/notanalog/ChangeLog
+++ b/apps/notanalog/ChangeLog
@@ -1,3 +1,4 @@
0.01: Launch app.
0.02: 12k steps are 360 degrees - improves readability of steps.
-0.03: Battery improvements through sleep (no minute updates) and partial updates of drawing.
\ No newline at end of file
+0.03: Battery improvements through sleep (no minute updates) and partial updates of drawing.
+0.04: Use alarm for timer instead of own alarm implementation.
\ No newline at end of file
diff --git a/apps/notanalog/README.md b/apps/notanalog/README.md
index 2928fd959..e368f75d2 100644
--- a/apps/notanalog/README.md
+++ b/apps/notanalog/README.md
@@ -8,8 +8,8 @@ black one the battery level (100% = 360 degrees).
The selected theme is also respected. Note that this watch face is in fullscreen
mode, but widgets are still loaded in background.
-## Other features
-- Set a timer - simply touch top (+5min.) or bottom (-5 min.).
+## Other Features
+- Set a timer - simply touch top (+5min.) or bottom (-5 min.). This only works if "sched" is installed.
- If the weather is available through the weather app, the outside temp. will be shown.
- Sleep modus at midnight to save more battery (no minute updates).
- Icons for charging and GPS.
@@ -29,5 +29,5 @@ which helped a lot for this development.
Icons from by Freepik - Flaticon
-## Contributors
+## Creator
- [David Peer](https://github.com/peerdavid).
\ No newline at end of file
diff --git a/apps/notanalog/metadata.json b/apps/notanalog/metadata.json
index 5efb6bccf..0a291b180 100644
--- a/apps/notanalog/metadata.json
+++ b/apps/notanalog/metadata.json
@@ -3,7 +3,7 @@
"name": "Not Analog",
"shortName":"Not Analog",
"icon": "notanalog.png",
- "version":"0.03",
+ "version":"0.04",
"readme": "README.md",
"supports": ["BANGLEJS2"],
"description": "An analog watch face for people that can not read analog watch faces.",
diff --git a/apps/notanalog/notanalog.app.js b/apps/notanalog/notanalog.app.js
index cea8072b8..c3dc9308f 100644
--- a/apps/notanalog/notanalog.app.js
+++ b/apps/notanalog/notanalog.app.js
@@ -1,7 +1,7 @@
/**
* NOT ANALOG CLOCK
*/
-
+const TIMER_IDX = "notanalog";
const locale = require('locale');
const storage = require('Storage')
const SETTINGS_FILE = "notanalog.setting.json";
@@ -291,7 +291,6 @@ function drawSleep(){
function draw(fastUpdate){
// Execute handlers
handleState(fastUpdate);
- handleAlarm();
if(state.sleep){
drawSleep();
@@ -377,82 +376,80 @@ Bangle.on('touch', function(btn, e){
* Some helpers
*/
function queueDraw() {
+
+ // Faster updates during alarm to ensure that it is
+ // shown correctly...
+ var timeout = isAlarmEnabled() ? 10000 : 60000;
+
if (drawTimeout) clearTimeout(drawTimeout);
drawTimeout = setTimeout(function() {
drawTimeout = undefined;
- draw(true);
- }, 60000 - (Date.now() % 60000));
+ draw();
+ }, timeout - (Date.now() % timeout));
}
/*
* Handle alarm
*/
-function getCurrentTimeInMinutes(){
- return Math.floor(Date.now() / (1000*60));
-}
-
function isAlarmEnabled(){
- return settings.alarm >= 0;
-}
+ try{
+ var alarm = require('sched');
+ var alarmObj = alarm.getAlarm(TIMER_IDX);
+ if(alarmObj===undefined || !alarmObj.on){
+ return false;
+ }
+
+ return true;
+
+ } catch(ex){ }
+ return false;
+ }
function getAlarmMinutes(){
- var currentTime = getCurrentTimeInMinutes();
- return settings.alarm - currentTime;
-}
-
-function handleAlarm(){
if(!isAlarmEnabled()){
- return;
+ return -1;
}
- if(getAlarmMinutes() > 0){
- return;
- }
-
- // Alarm
- var t = 300;
- Bangle.buzz(t, 1)
- .then(() => new Promise(resolve => setTimeout(resolve, t)))
- .then(() => Bangle.buzz(t, 1))
- .then(() => new Promise(resolve => setTimeout(resolve, t)))
- .then(() => Bangle.buzz(t, 1))
- .then(() => new Promise(resolve => setTimeout(resolve, t)))
- .then(() => Bangle.buzz(t, 1))
- .then(() => new Promise(resolve => setTimeout(resolve, 5E3)))
- .then(() => {
- // Update alarm state to disabled
- settings.alarm = -1;
- storage.writeJSON(SETTINGS_FILE, settings);
- });
+ var alarm = require('sched');
+ var alarmObj = alarm.getAlarm(TIMER_IDX);
+ return Math.round(alarm.getTimeToAlarm(alarmObj)/(60*1000));
}
-
function increaseAlarm(){
- if(isAlarmEnabled()){
- settings.alarm += 5;
- } else {
- settings.alarm = getCurrentTimeInMinutes() + 5;
- }
-
- storage.writeJSON(SETTINGS_FILE, settings);
+ try{
+ var minutes = isAlarmEnabled() ? getAlarmMinutes() : 0;
+ var alarm = require('sched')
+ alarm.setAlarm(TIMER_IDX, {
+ timer : (minutes+5)*60*1000,
+ });
+ alarm.reload();
+ } catch(ex){ }
}
-
function decreaseAlarm(){
- if(isAlarmEnabled() && (settings.alarm-5 > getCurrentTimeInMinutes())){
- settings.alarm -= 5;
- } else {
- settings.alarm = -1;
- }
+ try{
+ var minutes = getAlarmMinutes();
+ minutes -= 5;
- storage.writeJSON(SETTINGS_FILE, settings);
+ var alarm = require('sched')
+ alarm.setAlarm(TIMER_IDX, undefined);
+
+ if(minutes > 0){
+ alarm.setAlarm(TIMER_IDX, {
+ timer : minutes*60*1000,
+ });
+ }
+
+ alarm.reload();
+ } catch(ex){ }
}
function feedback(){
Bangle.buzz(40, 0.6);
}
+
/*
* Lets start widgets, listen for btn etc.
*/
diff --git a/apps/smpltmr/ChangeLog b/apps/smpltmr/ChangeLog
new file mode 100644
index 000000000..07afedd21
--- /dev/null
+++ b/apps/smpltmr/ChangeLog
@@ -0,0 +1 @@
+0.01: Release
\ No newline at end of file
diff --git a/apps/smpltmr/README.md b/apps/smpltmr/README.md
new file mode 100644
index 000000000..1296166e2
--- /dev/null
+++ b/apps/smpltmr/README.md
@@ -0,0 +1,21 @@
+# Simple Timer
+
+A simple app to set a timer quickly. Simply tab on top/bottom/left/right
+to select the minutes and tab in the middle of the screen to start/stop
+the timer. Note that this timer depends on qalarm.
+
+# Overview
+If you open the app, you can simply control the timer
+by clicking on top, bottom, left or right of the screen.
+If you tab at the middle of the screen, the timer is
+started / stopped.
+
+
+
+
+# Creator
+[David Peer](https://github.com/peerdavid)
+
+
+# Thanks to...
+Time icon created by CreativeCons - Flaticon
\ No newline at end of file
diff --git a/apps/smpltmr/app-icon.js b/apps/smpltmr/app-icon.js
new file mode 100644
index 000000000..bc4261459
--- /dev/null
+++ b/apps/smpltmr/app-icon.js
@@ -0,0 +1 @@
+require("heatshrink").decompress(atob("mEwwMAg//AAXgApcAvAZBhwCBuAFuGoUeAQM4AQM8AQl8Bwn4AQMPgEB+AFBg+AgZYBgED4AHBAoIPBCYIAC/AfCGwQrCGAQ3CAAMcIYQFCJ4QABnoREvIdE/eeAgUB+fPAoUD8/nIIUHz/zJoUPn/5LIUev/8MoU8//+OIU5XwO8AoN7AoPeAoNzAoPOAsrFKg4QBAAPgApYA=="))
\ No newline at end of file
diff --git a/apps/smpltmr/app.js b/apps/smpltmr/app.js
new file mode 100644
index 000000000..eb01e27d0
--- /dev/null
+++ b/apps/smpltmr/app.js
@@ -0,0 +1,124 @@
+/*
+ * SIMPLE TIMER
+ *
+ * Creator: David Peer
+ * Date: 02/2022
+ */
+
+Bangle.loadWidgets();
+
+
+const alarm = require("sched");
+
+const TIMER_IDX = "smpltmr";
+const screenWidth = g.getWidth();
+const screenHeight = g.getHeight();
+const cx = parseInt(screenWidth/2);
+const cy = parseInt(screenHeight/2)-12;
+var minutes = 5;
+var interval; //used for the 1 second interval timer
+
+
+function isTimerEnabled(){
+ var alarmObj = alarm.getAlarm(TIMER_IDX);
+ if(alarmObj===undefined || !alarmObj.on){
+ return false;
+ }
+
+ return true;
+}
+
+function getTimerMin(){
+ var alarmObj = alarm.getAlarm(TIMER_IDX);
+ return Math.round(alarm.getTimeToAlarm(alarmObj)/(60*1000));
+}
+
+function setTimer(minutes){
+ alarm.setAlarm(TIMER_IDX, {
+ // msg : "Simple Timer",
+ timer : minutes*60*1000,
+ });
+ alarm.reload();
+}
+
+function deleteTimer(){
+ alarm.setAlarm(TIMER_IDX, undefined);
+ alarm.reload();
+}
+
+setWatch(_=>load(), BTN1);
+function draw(){
+ g.clear(1);
+ Bangle.drawWidgets();
+
+ if (interval) {
+ clearInterval(interval);
+ }
+ interval = undefined;
+
+ // Write time
+ g.setFontAlign(0, 0, 0);
+ g.setFont("Vector", 32).setFontAlign(0,-1);
+
+ var started = isTimerEnabled();
+ var text = minutes + " min.";
+ if(started){
+ var min = getTimerMin();
+ text = min + " min.";
+ }
+
+ var rectWidth = parseInt(g.stringWidth(text) / 2);
+
+ if(started){
+ interval = setInterval(draw, 1000);
+ g.setColor("#ff0000");
+ } else {
+ g.setColor(g.theme.fg);
+ }
+ g.fillRect(cx-rectWidth-5, cy-5, cx+rectWidth, cy+30);
+
+ g.setColor(g.theme.bg);
+ g.drawString(text, cx, cy);
+}
+
+
+Bangle.on('touch', function(btn, e){
+ var left = parseInt(g.getWidth() * 0.25);
+ var right = g.getWidth() - left;
+ var upper = parseInt(g.getHeight() * 0.25);
+ var lower = g.getHeight() - upper;
+
+ var isLeft = e.x < left;
+ var isRight = e.x > right;
+ var isUpper = e.y < upper;
+ var isLower = e.y > lower;
+ var isMiddle = !isLeft && !isRight && !isUpper && !isLower;
+ var started = isTimerEnabled();
+
+ if(isRight && !started){
+ minutes += 1;
+ Bangle.buzz(40, 0.3);
+ } else if(isLeft && !started){
+ minutes -= 1;
+ Bangle.buzz(40, 0.3);
+ } else if(isUpper && !started){
+ minutes += 5;
+ Bangle.buzz(40, 0.3);
+ } else if(isLower && !started){
+ minutes -= 5;
+ Bangle.buzz(40, 0.3);
+ } else if(isMiddle) {
+ if(!started){
+ setTimer(minutes);
+ } else {
+ deleteTimer();
+ }
+ Bangle.buzz(80, 0.6);
+ }
+ minutes = Math.max(0, minutes);
+
+ draw();
+});
+
+g.reset();
+draw();
\ No newline at end of file
diff --git a/apps/smpltmr/app.png b/apps/smpltmr/app.png
new file mode 100644
index 000000000..04ed03751
Binary files /dev/null and b/apps/smpltmr/app.png differ
diff --git a/apps/smpltmr/description.png b/apps/smpltmr/description.png
new file mode 100644
index 000000000..1286d1ab9
Binary files /dev/null and b/apps/smpltmr/description.png differ
diff --git a/apps/smpltmr/metadata.json b/apps/smpltmr/metadata.json
new file mode 100644
index 000000000..06bad962d
--- /dev/null
+++ b/apps/smpltmr/metadata.json
@@ -0,0 +1,17 @@
+{
+ "id": "smpltmr",
+ "name": "Simple Timer",
+ "shortName": "Simple Timer",
+ "version": "0.01",
+ "description": "A very simple app to start a timer.",
+ "icon": "app.png",
+ "tags": "tool",
+ "dependencies": {"scheduler":"type"},
+ "supports": ["BANGLEJS2"],
+ "screenshots": [{"url":"screenshot.png"}, {"url": "screenshot_2.png"}],
+ "readme": "README.md",
+ "storage": [
+ {"name":"smpltmr.app.js","url":"app.js"},
+ {"name":"smpltmr.img","url":"app-icon.js","evaluate":true}
+ ]
+}
diff --git a/apps/smpltmr/screenshot.png b/apps/smpltmr/screenshot.png
new file mode 100644
index 000000000..eff94475c
Binary files /dev/null and b/apps/smpltmr/screenshot.png differ
diff --git a/apps/smpltmr/screenshot_2.png b/apps/smpltmr/screenshot_2.png
new file mode 100644
index 000000000..7b5dc9a3d
Binary files /dev/null and b/apps/smpltmr/screenshot_2.png differ