diff --git a/apps.json b/apps.json
index 6866ee2b0..960951dc0 100644
--- a/apps.json
+++ b/apps.json
@@ -3,7 +3,7 @@
"id": "fwupdate",
"name": "Firmware Update",
"version": "0.02",
- "description": "Uploads new Espruino firmwares to Bangle.js 2",
+ "description": "[BETA] Uploads new Espruino firmwares to Bangle.js 2. For now, please use the instructions under https://www.espruino.com/Bangle.js2#firmware-updates",
"icon": "app.png",
"type": "RAM",
"tags": "tools,system",
@@ -11,7 +11,7 @@
"custom": "custom.html",
"customConnect": true,
"storage": [],
- "sortorder": -20
+ "sortorder": 20
},
{
"id": "boot",
@@ -33,10 +33,11 @@
"id": "hebrew_calendar",
"name": "Hebrew Calendar",
"shortName": "HebCal",
- "version": "0.03",
+ "version": "0.04",
"description": "lists the date according to the hebrew calendar",
"icon": "app.png",
- "tags": "",
+ "allow_emulator": false,
+ "tags": "tool,locale",
"supports": [
"BANGLEJS",
"BANGLEJS2"
@@ -47,6 +48,10 @@
"name": "hebrew_calendar.app.js",
"url": "app.js"
},
+ {
+ "name": "hebrewDate",
+ "url": "hebrewDate.js"
+ },
{
"name": "hebrew_calendar.img",
"url": "app-icon.js",
@@ -54,6 +59,21 @@
}
]
},
+ { "id": "golfscore",
+ "name": "Golf Score",
+ "shortName":"golfscore",
+ "version":"0.02",
+ "description": "keeps track of strokes during a golf game",
+ "icon": "app.png",
+ "tags": "outdoors",
+ "allow_emulator": true,
+ "supports" : ["BANGLEJS","BANGLEJS2"],
+ "readme": "README.md",
+ "storage": [
+ {"name":"golfscore.app.js","url":"app.js"},
+ {"name":"golfscore.img","url":"app-icon.js","evaluate":true}
+ ]
+ },
{
"id": "messages",
"name": "Messages",
@@ -282,7 +302,7 @@
{
"id": "gbridge",
"name": "Gadgetbridge",
- "version": "0.24",
+ "version": "0.25",
"description": "(NOT RECOMMENDED) Handles Gadgetbridge notifications from Android. This is now replaced by the 'Android' app.",
"icon": "app.png",
"type": "widget",
@@ -538,7 +558,7 @@
"icon": "clock-impword.png",
"type": "clock",
"tags": "clock",
- "supports": ["BANGLEJS"],
+ "supports": ["BANGLEJS","BANGLEJS2"],
"screenshots": [{"url":"bangle1-impercise-word-clock-screenshot.png"}],
"allow_emulator": true,
"storage": [
@@ -824,7 +844,7 @@
{
"id": "weather",
"name": "Weather",
- "version": "0.12",
+ "version": "0.13",
"description": "Show Gadgetbridge weather report",
"icon": "icon.png",
"screenshots": [{"url":"screenshot.png"}],
@@ -1127,7 +1147,7 @@
{
"id": "qrcode",
"name": "Custom QR Code",
- "version": "0.03",
+ "version": "0.04",
"description": "Use this to upload a customised QR code to Bangle.js",
"icon": "app.png",
"tags": "qrcode",
@@ -3871,7 +3891,7 @@
"id": "qmsched",
"name": "Quiet Mode Schedule and Widget",
"shortName": "Quiet Mode",
- "version": "0.04",
+ "version": "0.05",
"description": "Automatically turn Quiet Mode on or off at set times, and change LCD options while Quiet Mode is active.",
"icon": "app.png",
"screenshots": [{"url":"screenshot_b1_main.png"},{"url":"screenshot_b1_edit.png"},{"url":"screenshot_b1_lcd.png"},
@@ -4118,14 +4138,17 @@
{
"id": "vectorclock",
"name": "Vector Clock",
- "version": "0.02",
+ "version": "0.03",
"description": "A digital clock that uses the built-in vector font.",
"icon": "app.png",
"type": "clock",
"tags": "clock",
- "supports": ["BANGLEJS"],
+ "supports": ["BANGLEJS", "BANGLEJS2"],
"allow_emulator": true,
- "screenshots": [{"url":"bangle1-vector-clock-screenshot.png"}],
+ "screenshots": [
+ {"url":"bangle2-vector-clock-screenshot.png"},
+ {"url":"bangle1-vector-clock-screenshot.png"}
+ ],
"storage": [
{"name":"vectorclock.app.js","url":"app.js"},
{"name":"vectorclock.img","url":"app-icon.js","evaluate":true}
@@ -4443,9 +4466,9 @@
"name": "A Battery Widget (with percentage)",
"shortName":"A Battery Widget",
"icon": "widget.png",
- "version":"1.01",
+ "version":"1.02",
"type": "widget",
- "supports": ["BANGLEJS2"],
+ "supports": ["BANGLEJS", "BANGLEJS2"],
"readme": "README.md",
"description": "Simple and slim battery widget with charge status and percentage",
"tags": "widget,battery",
@@ -4712,7 +4735,7 @@
{ "id": "pooqroman",
"name": "pooq Roman watch face",
"shortName":"pooq Roman",
- "version":"0.0.0",
+ "version":"0.02",
"description": "A classic watch face with a certain dynamicity. Most amusing in 24h mode. Slide up to show more hands, down for less(!). By design does not support standard widgets, sorry!",
"icon": "app.png",
"type": "clock",
@@ -4747,7 +4770,7 @@
{
"id": "weatherClock",
"name": "Weather Clock",
- "version": "0.03",
+ "version": "0.04",
"description": "A clock which displays current weather conditions (requires Gadgetbridge and Weather apps).",
"icon": "app.png",
"screenshots": [{"url":"screens/screen1.png"}],
@@ -4830,9 +4853,10 @@
"id": "ptlaunch",
"name": "Pattern Launcher",
"shortName": "Pattern Launcher",
- "version": "0.02",
+ "version": "0.10",
"description": "Directly launch apps from the clock screen with custom patterns.",
"icon": "app.png",
+ "screenshots": [{"url":"main_menu_add.png"}, {"url":"add_pattern.png"}, {"url":"select_app.png"}, {"url":"main_menu_manage.png"}, {"url":"manage_patterns.png"}],
"tags": "tools",
"supports": ["BANGLEJS2"],
"readme": "README.md",
@@ -4843,22 +4867,6 @@
],
"data": [{"name":"ptlaunch.patterns.json"}]
},
- { "id": "clicompleteclk",
- "name": "CLI complete clock",
- "shortName":"CLI cmplt clock",
- "version":"0.02",
- "description": "Command line styled clock with lots of information",
- "icon": "app.png",
- "allow_emulator": true,
- "type": "clock",
- "tags": "clock,cli,command,bash,shell,weather,hrt",
- "supports" : ["BANGLEJS", "BANGLEJS2"],
- "readme": "README.md",
- "storage": [
- {"name":"clicompleteclk.app.js","url":"app.js"},
- {"name":"clicompleteclk.img","url":"app-icon.js","evaluate":true}
- ]
- },
{
"id": "rebble",
"name": "Rebble Clock",
@@ -4877,5 +4885,52 @@
{"name":"rebble.settings.js","url":"rebble.settings.js"},
{"name":"rebble.img","url":"rebble.icon.js","evaluate":true}
]
+ },
+ { "id": "snaky",
+ "name": "Snaky",
+ "shortName":"Snaky",
+ "version":"0.01",
+ "description": "The classic snake game. Eat apples and don't bite your tail. Control the snake with the touch screen.",
+ "tags": "game,fun",
+ "icon": "snaky.png",
+ "supports" : ["BANGLEJS2"],
+ "readme": "README.md",
+ "storage": [
+ {"name":"snaky.app.js","url":"snaky.js"},
+ {"name":"snaky.img","url":"snaky-icon.js","evaluate":true}
+ ]
+ },
+ {
+ "id": "clicompleteclk",
+ "name": "CLI complete clock",
+ "shortName":"CLI cmplt clock",
+ "version":"0.03",
+ "description": "Command line styled clock with lots of information",
+ "icon": "app.png",
+ "allow_emulator": true,
+ "type": "clock",
+ "tags": "clock,cli,command,bash,shell,weather,hrt",
+ "supports" : ["BANGLEJS", "BANGLEJS2"],
+ "readme": "README.md",
+ "storage": [
+ {"name":"clicompleteclk.img","url":"app-icon.js","evaluate":true},
+ {"name":"clicompleteclk.settings.js","url":"settings.js"}
+ ],
+ "data": [{"name":"clicompleteclk.json"}]
+ },
+ {
+ "id":"awairmonitor",
+ "name":"Awair Monitor",
+ "icon": "app.png",
+ "allow_emulator": true,
+ "version":"0.01",
+ "description": "Displays the level of CO2, VOC, PM 2.5, Humidity and Temperature, from your Awair device.",
+ "tags": "tool,health",
+ "readme":"README.md",
+ "supports":["BANGLEJS2"],
+ "storage": [
+ {"name":"awairmonitor.app.js","url":"app.js"},
+ {"name":"awairmonitor.img","url":"app-icon.js","evaluate":true}
+ ]
}
]
diff --git a/apps/awairmonitor/ChangeLog b/apps/awairmonitor/ChangeLog
new file mode 100644
index 000000000..0cc9a42b0
--- /dev/null
+++ b/apps/awairmonitor/ChangeLog
@@ -0,0 +1 @@
+0.01: Beta version for Bangle 2 paired with Chrome (2021/12/11)
diff --git a/apps/awairmonitor/README.md b/apps/awairmonitor/README.md
new file mode 100644
index 000000000..8d6e25633
--- /dev/null
+++ b/apps/awairmonitor/README.md
@@ -0,0 +1,20 @@
+# Awair Monitor
+
+Displays the level of CO2, VOC, PM 2.5, Humidity and Temperature, from your Awair device.
+
+* What you need:
+ * A BangleJS 2
+ * An Awair device [with local API enabled](https://support.getawair.com/hc/en-us/articles/360049221014-Awair-Local-API-Feature)
+ * The web app [awair_to_bangle.html](awair_to_bangle.html) that will retrive the data from your Awair device and sent it to your BangleJS 2 through Chrome's Bluetooth LE connection
+* How to get started
+ * Open awair_to_bangle.html with a text/code editor and input the IP address of your Awair on top (const awair_ip_1 = "192.168.xx.xx")
+ * Launch the Awair Monitor app on your BangleJS
+ * Open awair_to_bangle.html on Chrome and click "Connect BangleJS" - it connects to your watch the same way as the Bangle app store
+ * Once connected to the watch with the app running, the watch app is updated once per second
+
+
+
+## Creator
+[@alainsaas](https://github.com/alainsaas)
+
+Contributions are welcome, send me your Pull Requests!
diff --git a/apps/awairmonitor/app-icon.js b/apps/awairmonitor/app-icon.js
new file mode 100644
index 000000000..9d4dcf4a3
--- /dev/null
+++ b/apps/awairmonitor/app-icon.js
@@ -0,0 +1 @@
+require("heatshrink").decompress(atob("mEwgP/AD38g4FD8EAAoeAgE/AoUD/EfAgP+AYMPDgQPBw4FB/F///DAoPwAQPjAQPBAQPxDgJVCAoP4gYaCCwIcBAoM/8P8h0HjEP8f4h0Gp0H4/44lj5+H4/54lzj/jx/5/lyDgIFDh/xAoQRBAoXsuY8Bx4jCAoeEkYFB447CAoRxBOAPxM4RmC8IFD4ZZD/8H/DHDh/+AoaSBUAIABCoYATVwS2Ct4FE84REXQQLCk4RJAo0XGxY="))
diff --git a/apps/awairmonitor/app.js b/apps/awairmonitor/app.js
new file mode 100644
index 000000000..a5a1d1a72
--- /dev/null
+++ b/apps/awairmonitor/app.js
@@ -0,0 +1,98 @@
+Graphics.prototype.setFontMichroma36 = function() {
+g.setFontCustom(atob("AAAAAAAAAAAAAAAAeAAAAAeAAAAAeAAAAAeAAAAAAAAAAAAAAAAAAAAAAAGAAAAA+AAAAD+AAAAP+AAAA/8AAAD/wAAAf/AAAB/4AAAH/gAAAf+AAAB/4AAAH/gAAAf+AAAAfwAAAAfAAAAAcAAAAAAAAAAAAAAAAAAAAAAAA///AAD///wAH///4AP///8APwAD+APAAAeAeAAAeAeAAAPAeAAAPAeAAAPAeAAAPAeAAAPAeAAAPAeAAAPAeAAAPAeAAAPAeAAAPAeAAAPAeAAAPAeAAAPAeAAAPAeAAAPAeAAAPAeAAAPAeAAAPAeAAAeAPAAAeAPwAD+AP///8AH///4AD///wAA///AAAAAAAAAAAAAAAAAAAAAEAAAAAOAAAAAfAAAAA+AAAAB8AAAAD8AAAAH4AAAAPwAAAAPgAAAAfAAAAAf///+Af///+Af///+Af///+AAAAAAAAAAAAAAAAAAAAAAAAAA/Af+AD/A/+AH/B/+AP/D/+APwD4eAPADweAfADweAeADweAeADweAeADweAeAHgeAeAHgeAeAHgeAeAHgeAeAHgeAeAHgeAeAHgeAeAHgeAeAHgeAeAHgeAeAPgeAeAPAeAeAPAeAeAPAeAeAPAeAfAPAeAPw/AeAP/+AeAH/+AeAD/8AeAB/wAOAAAAAAAAAAAAAAAAAAAAAAAAAB8APgAD8AP4AH8AP8AP8AP8APgAB+AfAAAeAeAAAeAeAAAPAeAAAPAeAAAPAeAAAPAeAeAPAeAeAPAeAeAPAeAeAPAeAeAPAeAeAPAeAeAPAeAeAPAeAeAPAeAeAPAeAeAPAeAeAPAeAeAPAeAeAeAfAeAeAPx/h+AP///+AH///8AD///4AB/h/gAAAAAAAAAAAAAAAAAAAAAAeAAAAA/AAAAA/AAAAB/AAAAD/AAAAH/AAAAPvAAAAPPAAAAfPAAAA+PAAAB8PAAAD4PAAADwPAAAHwPAAAPgPAAAfAPAAA+APAAA8APAAB8APAAD4APAAHwAPAAPgAPAAPAAPAAfAAPAAf///+Af///+Af///+Af///+AAAAPAAAAAPAAAAAPAAAAAPAAAAAOAAAAAAAAAAAAAAAAAAAAAAAAAAf/8PgAf/8P4Af/8P8Af/8P8AeB4A+AeB4AeAeDwAeAeDwAPAeDwAPAeDwAPAeDwAPAeDwAPAeDwAPAeDwAPAeDwAPAeDwAPAeDwAPAeDwAPAeDwAPAeDwAPAeDwAPAeDwAPAeDwAPAeDwAfAeDwAeAeD4A+AeD+D+AeB//8AeB//4AeA//4AAAP/AAAAAAAAAAAAAAAAAAAAAAAAAAA///AAD///wAH///4AH///8AP4fB+APAeAeAfA8AeAeA8APAeA8APAeA8APAeA8APAeA8APAeA8APAeA8APAeA8APAeA8APAeA8APAeA8APAeA8APAeA8APAeA8APAeA8APAeA8APAfA8APAPA+AeAPgeAeAP8fh+AH8f/8AD8P/8AA8H/4AAAB/gAAAAAAAAAAAAAAAAAAAAAAAAAeAAAAAeAAAAAeAAAAAeAAAAAeAAAAAeAAACAeAAAGAeAAAOAeAAAeAeAAA+AeAAD+AeAAH8AeAAP4AeAAfwAeAA/gAeAB/AAeAD+AAeAP4AAeAfwAAeA/gAAeB/AAAeD+AAAeH8AAAefwAAAe/gAAAf/AAAAf+AAAAf8AAAAf4AAAAfgAAAAfAAAAAAAAAAAAAAAAAAAAAAAAAAMAAB+B/wAD/j/4AH/3/8AP///+AP//A+AfB+AeAeA+AeAeA+APAeA+APAeA+APAeA8APAeA8APAeA8APAeA8APAeA8APAeA8APAeA8APAeA8APAeA8APAeA8APAeA+APAeA+APAeA+APAeA+AOAeA+AeAPh/A+AP///+AP/3/8AH/3/8AB/D/wAAAA/AAAAAAAAAAAAAAAAAAAAAAAAAAA/wAAAD/4HAAH/8HwAP/+H4AP5/H8AfAfA8AeAPAeAeAPAeAeAPAeAeAHgfAeAHgPAeAHgPAeAHgPAeAHgPAeAHgPAeAHgPAeAHgPAeAHgPAeAHgPAeAHgPAeAHgPAeAHgPAeAHAPAeAPAOAeAPAeAPAPAeAPwfB+AP///8AH///4AD///wAA///AAAAAAAAAAAAAAAAAAAAAAAAAAAB8DwAAB8HwAAB8HwAAB8DwAAAAAAAAAAAAA"), 46, atob("CBIkESMjJCMjIyMjCA=="), 36+(1<<8)+(1<<16));
+};
+
+var drawTimeout;
+
+function queueNextDraw() {
+ if (drawTimeout) clearTimeout(drawTimeout);
+ drawTimeout = setTimeout(function() {
+ drawTimeout = undefined;
+ draw();
+ }, 1000 - (Date.now() % 1000));
+}
+
+var locale = require("locale");
+
+var bt_current_co2 = 0;
+var bt_current_voc = 0;
+var bt_current_pm25 = 0;
+var bt_current_humi = 0;
+var bt_current_temp = 0;
+var bt_last_update = 0;
+
+var last_update = 0;
+var bt_co2_history = new Array(10).fill(0);
+var bt_voc_history = new Array(10).fill(0);
+var bt_pm25_history = new Array(10).fill(0);
+var bt_humi_history = new Array(10).fill(0);
+var bt_temp_history = new Array(10).fill(0);
+
+var internal_last_update = -1;
+
+function draw() {
+ g.reset().clearRect(0,24,g.getWidth(),g.getHeight());
+
+ var date = new Date();
+ g.setFontAlign(0,0);
+ g.setFont("Michroma36").drawString(locale.time(date,1), g.getWidth()/2, 56);
+
+ g.setFont("6x8");
+ g.drawString(locale.date(new Date(),1), g.getWidth()/2, 80);
+
+ g.setFont("6x8");
+ g.drawString("CO2", 20, 100);
+ g.drawString("VOC", 55, 100);
+ g.drawString("PM25", 90, 100);
+ g.drawString("Humi", 125, 100);
+ g.drawString("Temp", 160, 100);
+
+ g.setFont("HaxorNarrow7x17");
+ g.drawString(""+bt_current_co2, 18, 110);
+ g.drawString(""+bt_current_voc, 53, 110);
+ g.drawString(""+bt_current_pm25, 88, 110);
+ g.drawString(""+bt_current_humi, 123, 110);
+ g.drawString(""+bt_current_temp, 158, 110);
+
+ if (last_update != bt_last_update) {
+ last_update = bt_last_update;
+ internal_last_update = last_update;
+ if (last_update % 10 == 0) {
+ bt_co2_history.shift(); bt_co2_history.push(bt_current_co2);
+ bt_voc_history.shift(); bt_voc_history.push(bt_current_voc);
+ bt_pm25_history.shift(); bt_pm25_history.push(bt_current_pm25);
+ bt_humi_history.shift(); bt_humi_history.push(bt_current_humi);
+ bt_temp_history.shift(); bt_temp_history.push(bt_current_temp);
+ }
+ }
+
+ if (internal_last_update == -1) {
+ g.drawString("Waiting for connection", 88, 164);
+ } else if (internal_last_update > last_update + 5) {
+ g.drawString("Trying to reconnect since " + (internal_last_update - last_update), 88, 164);
+ }
+
+
+ for (i = 0; i < 10; i++) {
+ // max height = 32
+ g.drawLine(10+i*2, 150-(Math.min(Math.max(bt_co2_history[i],400), 1200)-400)/25, 10+i*2, 150);
+ g.drawLine(45+i*2, 150-(Math.min(Math.max(bt_voc_history[i],0), 1440)-0)/45, 45+i*2, 150);
+ g.drawLine(80+i*2, 150-(Math.min(Math.max(bt_pm25_history[i],0), 32)-0)/1, 80+i*2, 150);
+ g.drawLine(115+i*2, 150-(Math.min(Math.max(bt_humi_history[i],20), 60)-20)/1.25, 115+i*2, 150);
+ g.drawLine(150+i*2, 150-(Math.min(Math.max(bt_temp_history[i],19), 27)-19)*4, 150+i*2, 150);
+
+ // target humidity level
+ g.setColor("#00F").drawLine(115, 150-(40-20)/1.25, 115+18, 150-(40-20)/1.25);
+ g.reset();
+ }
+
+ if (internal_last_update != -1) { internal_last_update++; }
+ queueNextDraw();
+}
+
+// init
+require("FontHaxorNarrow7x17").add(Graphics);
+g.clear();
+Bangle.loadWidgets();
+Bangle.drawWidgets();
+draw();
diff --git a/apps/awairmonitor/app.png b/apps/awairmonitor/app.png
new file mode 100644
index 000000000..26a5d0cff
Binary files /dev/null and b/apps/awairmonitor/app.png differ
diff --git a/apps/awairmonitor/awair_to_bangle.html b/apps/awairmonitor/awair_to_bangle.html
new file mode 100644
index 000000000..2926cca9e
--- /dev/null
+++ b/apps/awairmonitor/awair_to_bangle.html
@@ -0,0 +1,195 @@
+
+
+
+
+
+
+
+
+
+
+
+How to use
+
+Step 1: Enable the Local API on your Awair: https://support.getawair.com/hc/en-us/articles/360049221014-Awair-Local-API-Feature
+
+Step 2: Modify this HTML file to input the IP address of your Awair on top (const awair_ip_1 = "192.168.xx.xx")
+
+Step 3: Launch the Awair Monitor app on your BangleJS
+
+Step 4: Click "Connect BangleJS"
+
+Step 5: Optionally, open the web inspector's console (Right click > Inspector > Console) to read the bluetooth logs
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/apps/awairmonitor/screenshot.png b/apps/awairmonitor/screenshot.png
new file mode 100644
index 000000000..51ca0aa44
Binary files /dev/null and b/apps/awairmonitor/screenshot.png differ
diff --git a/apps/clicompleteclk/README.md b/apps/clicompleteclk/README.md
index 62fdbbc61..8b8094633 100644
--- a/apps/clicompleteclk/README.md
+++ b/apps/clicompleteclk/README.md
@@ -3,12 +3,14 @@
Command line styled clock with lots of information:
It can show the following (depending on availability) information:
-* Time
-* Day of week
-* Date
-* Weather conditions and temperature (requires app [Weather](https://banglejs.com/apps/#weather))
-* Steps (requires app [Health Tracking](https://banglejs.com/apps/#health%20tracking) or a step widget)
-* Heart rate (when screen is on and unlocked)
+* Time data:
+ * Time
+ * Day of week
+ * Date
+* Additional information (can be toggled via settings):
+ * Weather conditions and temperature (requires app [Weather](https://banglejs.com/apps/#weather))
+ * Steps (requires app [Health Tracking](https://banglejs.com/apps/#health%20tracking) or a step widget)
+ * Heart rate (when screen is on and unlocked)
## TODO
* Make time font bigger
diff --git a/apps/clicompleteclk/app.js b/apps/clicompleteclk/app.js
index 7fbdabcc1..a39b37e58 100644
--- a/apps/clicompleteclk/app.js
+++ b/apps/clicompleteclk/app.js
@@ -1,31 +1,60 @@
const storage = require('Storage');
const locale = require("locale");
-const font = "12x20";
-const fontsize = 1;
+const font12 = g.getFonts().includes("12x20");
+const font = font12 ? "12x20" : "6x8";
+const fontsize = font12 ? 1: 2;
const fontheight = 19;
-const marginTop = 10;
+const marginTop = 5;
const marginLeftTopic = 3; // margin of topics
-const marginLeftData = 68; // margin of data values
+const marginLeftData = font12 ? 64 : 75; // margin of data values
const topicColor = g.theme.dark ? "#fff" : "#000";
const textColor = g.theme.dark ? "#0f0" : "#080";
+const textColorRed = g.theme.dark ? "#FF0000" : "#FF0000";
let hrtValue;
let hrtValueIsOld = false;
+
let localTempValue;
let weatherTempString;
let lastHeartRateRowIndex;
+let lastStepsRowIndex;
+let i = 2;
+
+let settings;
+
+function loadSettings() {
+ settings = storage.readJSON('clicompleteclk.json', 1) || {};
+}
+
+function setting(key) {
+ if (!settings) { loadSettings(); }
+ const DEFAULTS = {
+ 'battery': true,
+ 'batteryLvl': 30,
+ 'weather': true,
+ 'steps': true,
+ 'heartrate': true
+ };
+ return (key in settings) ? settings[key] : DEFAULTS[key];
+}
+
+
+let showBattery = setting('battery');
+let batteryWarnLevel = setting('batteryLvl');
+let showWeather = setting('weather');
+let showSteps = setting('steps');
+let showHeartRate = setting('heartrate');
+
-// 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;
- drawAll(false);
+ drawAll(true);
}, 60000 - (Date.now() % 60000));
}
@@ -42,15 +71,13 @@ function updateTime(now){
if (!Bangle.isLCDOn()) return;
writeLineTopic("TIME", 1);
writeLine(locale.time(now,1),1);
- if(now.getMinutes() == 0)
- drawInfo(now);
}
function drawInfo(now) {
- if (now == undefined)
+ if (now == undefined)
now = new Date();
- let i = 2;
+ i = 2;
writeLineTopic("DOWK", i);
writeLine(locale.dow(now),i);
@@ -60,14 +87,28 @@ function drawInfo(now) {
writeLine(locale.date(now,1),i);
i++;
- /*
- writeLineTopic("BAT", i);
- const b = E.getBattery();
- writeLine(b + "%", i); // TODO make bars
- i++;
- */
+ if (showBattery) {
+ writeLineTopic("BATT", i);
+ const b = E.getBattery();
+ writeLine(b + "%", i, b < batteryWarnLevel ? textColorRed : textColor);
+ i++;
+ }
- // weather
+ if (showWeather) {
+ drawWeather();
+ }
+
+ if (showSteps) {
+ drawSteps(i);
+ i++;
+ }
+
+ if (showHeartRate) {
+ drawHeartRate(i);
+ }
+}
+
+function drawWeather() {
const weatherJson = getWeather();
if(weatherJson && weatherJson.weather){
const currentWeather = weatherJson.weather;
@@ -82,19 +123,22 @@ function drawInfo(now) {
writeLine(weatherTempValue,i);
i++;
}
+}
- // steps
+function drawSteps(i) {
+ if (!showSteps) return;
+ if (i == undefined)
+ i = lastStepsRowIndex;
const steps = getSteps();
if (steps != undefined) {
writeLineTopic("STEP", i);
writeLine(steps, i);
- i++;
}
-
- drawHeartRate(i);
+ lastStepsRowIndex = i;
}
function drawHeartRate(i) {
+ if (!showHeartRate) return;
if (i == undefined)
i = lastHeartRateRowIndex;
writeLineTopic("HRTM", i);
@@ -155,15 +199,21 @@ function getWeather() {
// turn on HRM when the LCD is unlocked
Bangle.on('lock', function(isLocked) {
if (!isLocked) {
- Bangle.setHRMPower(1,"clicompleteclk");
- if (hrtValue == undefined)
- hrtValue = "...";
- else
- hrtValueIsOld = true;
+ if (showHeartRate) {
+ Bangle.setHRMPower(1,"clicompleteclk");
+ if (hrtValue == undefined)
+ hrtValue = "...";
+ else
+ hrtValueIsOld = true;
+ }
} else {
- hrtValueIsOld = true;
- Bangle.setHRMPower(0,"clicompleteclk");
+ if (showHeartRate) {
+ hrtValueIsOld = true;
+ Bangle.setHRMPower(0,"clicompleteclk");
+ }
}
+ // Update steps and heart rate
+ drawSteps();
drawHeartRate();
});
@@ -171,25 +221,30 @@ Bangle.on('lcdPower',function(on) {
if (on) {
drawAll(true);
} else {
- hrtValueIsOld = true;
+ if (showHeartRate) {
+ hrtValueIsOld = true;
+ }
if (drawTimeout) clearTimeout(drawTimeout);
drawTimeout = undefined;
}
});
-Bangle.on('HRM', function(hrm) {
- //if(hrm.confidence > 90){
- hrtValueIsOld = false;
- hrtValue = hrm.bpm;
- if (Bangle.isLCDOn())
- drawHeartRate();
- //} else {
- // hrtValue = undefined;
- //}
-});
+if (showHeartRate) {
+ Bangle.on('HRM', function(hrm) {
+ //if(hrm.confidence > 90){
+ hrtValueIsOld = false;
+ hrtValue = hrm.bpm;
+ if (Bangle.isLCDOn())
+ drawHeartRate();
+ //} else {
+ // hrtValue = undefined;
+ //}
+ });
+}
g.clear();
Bangle.setUI("clock");
Bangle.loadWidgets();
Bangle.drawWidgets();
+loadSettings();
drawAll(true);
diff --git a/apps/clicompleteclk/settings.js b/apps/clicompleteclk/settings.js
new file mode 100644
index 000000000..2df20ed3e
--- /dev/null
+++ b/apps/clicompleteclk/settings.js
@@ -0,0 +1,54 @@
+(function(back) {
+ const storage = require('Storage');
+ let settings = storage.readJSON('clicompleteclk.json', 1) || {};
+ function save(key, value) {
+ settings[key] = value;
+ storage.write('clicompleteclk.json', settings);
+ }
+ E.showMenu({
+ '': { 'title': 'CLI complete clk' },
+ 'Show battery': {
+ value: "battery" in settings ? settings.battery : false,
+ format: () => (settings.battery ? 'Yes' : 'No'),
+ onchange: () => {
+ settings.battery = !settings.battery;
+ save('battery', settings.battery);
+ },
+ },
+ 'Battery warn': {
+ value: "batteryLvl" in settings ? settings.batteryLvl : 30,
+ min: 0,
+ max : 100,
+ step: 10,
+ format: x => {
+ return x + "%";
+ },
+ onchange: x => save('batteryLvl', x),
+ },
+ 'Show weather': {
+ value: "weather" in settings ? settings.weather : false,
+ format: () => (settings.weather ? 'Yes' : 'No'),
+ onchange: () => {
+ settings.weather = !settings.weather;
+ save('weather', settings.weather);
+ },
+ },
+ 'Show steps': {
+ value: "steps" in settings ? settings.steps : false,
+ format: () => (settings.steps ? 'Yes' : 'No'),
+ onchange: () => {
+ settings.steps = !settings.steps;
+ save('steps', settings.steps);
+ },
+ },
+ 'Show heartrate': {
+ value: "heartrate" in settings ? settings.heartrate : false,
+ format: () => (settings.heartrate ? 'Yes' : 'No'),
+ onchange: () => {
+ settings.heartrate = !settings.heartrate;
+ save('heartrate', settings.heartrate);
+ },
+ },
+ '< Back': back,
+ });
+});
diff --git a/apps/fwupdate/custom.html b/apps/fwupdate/custom.html
index b5c79a325..8c2008e54 100644
--- a/apps/fwupdate/custom.html
+++ b/apps/fwupdate/custom.html
@@ -3,6 +3,8 @@
+
THIS IS CURRENTLY BETA - PLEASE USE THE NORMAL FIRMWARE UPDATE
+ INSTRUCTIONS FOR BANGLE.JS 1 AND BANGLE.JS 2. For usage on Bangle.js 2 you'll likely need to have an updated bootloader.
Firmware updates using the App Loader are only possible on
Bangle.js 2. For firmware updates on Bangle.js 1 please
diff --git a/apps/gbridge/ChangeLog b/apps/gbridge/ChangeLog
index fddb1eb80..67d421f33 100644
--- a/apps/gbridge/ChangeLog
+++ b/apps/gbridge/ChangeLog
@@ -24,3 +24,5 @@
0.22: Respect Quiet Mode
0.23: Allow notification dismiss to remove from phone too
0.24: tag HRM power requests to allow this to work alongside other widgets/apps (fix #799)
+0.25: workaround call notification
+ Fix inflated step number
diff --git a/apps/gbridge/widget.js b/apps/gbridge/widget.js
index 53f832b07..7cb7147ec 100644
--- a/apps/gbridge/widget.js
+++ b/apps/gbridge/widget.js
@@ -184,7 +184,7 @@
case "call":
var note = { size: 55, title: event.name, id: "call",
body: event.number, icon:require("heatshrink").decompress(atob("jEYwIMJj4CCwACJh4CCCIMOAQMGAQMHAQMDAQMBCIMB4PwgHz/EAn4CBj4CBg4CBgACCAAw="))}
- if (event.cmd === "incoming") {
+ if (event.cmd === "incoming" || event.cmd === "") {
require("notify").show(note);
if (!(require('Storage').readJSON('setting.json',1)||{}).quiet) {
Bangle.buzz();
@@ -262,7 +262,7 @@
// Send a summary of activity to Gadgetbridge
function sendActivity(hrm) {
var steps = currentSteps - lastSentSteps;
- lastSentSteps = 0;
+ lastSentSteps = currentSteps;
gbSend({ t: "act", stp: steps, hrm:hrm });
}
diff --git a/apps/golfscore/ChangeLog b/apps/golfscore/ChangeLog
new file mode 100644
index 000000000..4995dd59a
--- /dev/null
+++ b/apps/golfscore/ChangeLog
@@ -0,0 +1,2 @@
+0.01: New App!
+0.02: multiple player score support
\ No newline at end of file
diff --git a/apps/golfscore/README.md b/apps/golfscore/README.md
new file mode 100644
index 000000000..68552ad4b
--- /dev/null
+++ b/apps/golfscore/README.md
@@ -0,0 +1,37 @@
+# Golf Score
+
+Lets you keep track of strokes during a game of Golf.
+
+
+
+
+
+
+## Usage
+
+1. Open the app,
+1. scroll to setup
+2. set the number of holes (18 by default, but can be configured)
+3. set the number of players (4 by default, but can be 1-20)
+4. click back
+5. scroll to a hole (hole 1)
+6. scroll to a player and set the number of strokes they took (repeat as needed)
+7. click next hole and repeat #6 and #7 as needed; or click back
+8. at any time, check the score card for a sum total of all the strokes for each player
+
+## Features
+
+Track strokes for multiple players (1-20)
+Set number of holes on course
+
+## Controls
+
+N/A
+
+## Requests
+
+Michael Salaverry (github.com/barakplasma)
+
+## Creator
+
+Michael Salaverry
diff --git a/apps/golfscore/app-icon.js b/apps/golfscore/app-icon.js
new file mode 100644
index 000000000..238001688
--- /dev/null
+++ b/apps/golfscore/app-icon.js
@@ -0,0 +1 @@
+require("heatshrink").decompress(atob("mEwwIEBgOABQcD4AFDg1wAokYDokOAokDDwkBDwkADwn4nAFD/geDgP8gYFEDwn8gFgDocA+AFCkE/A4IABg//Aoc//4RDn/+Goc/8AFJj4FLEQYFGh4FLIAYFGg4FKh5sBApEfnhTEAok+Aol8vihEAon4AocB+F4ZQYFF8AFDg/AAocPAouAKYcfXQQFHjzEEhjvDA"))
diff --git a/apps/golfscore/app.js b/apps/golfscore/app.js
new file mode 100644
index 000000000..7c5c2d0e8
--- /dev/null
+++ b/apps/golfscore/app.js
@@ -0,0 +1,113 @@
+// @ts-check
+// @ts-ignore
+const menu = require("graphical_menu");
+/**
+ * @type {{showMenu: (config) => void}}
+ */
+let E;
+/**
+ * @type {{clear: () => void}}
+ */
+let g;
+
+let holes_count = 18;
+let player_count = 4;
+/**
+ * @type {number[][]}
+ */
+let course = new Array(holes_count).map(() => new Array(player_count).fill(0));
+
+const main_menu = {
+ "": {
+ "title": "-- Golf --"
+ },
+ "Setup": function () { E.showMenu(setup_menu); },
+ "Score Card": function () {
+ calculate_score();
+ E.showMenu(score_card);
+ },
+};
+
+function calculate_score() {
+ let scores = course.reduce((acc, hole) => {
+ hole.forEach((stroke_count, player) => {
+ acc[player] = acc[player]+stroke_count;
+ });
+ return acc;
+ }, new Array(player_count).fill(0));
+
+ score_card = {
+ "": {
+ "title": "score card"
+ },
+ "< Back": function () { E.showMenu(main_menu); },
+ };
+
+ for (let player = 0; player < player_count; player++) {
+ score_card["Player - " + (player + 1)] = {
+ value: scores[player]
+ };
+ }
+}
+
+let score_card = {};
+
+const setup_menu = {
+ "": {
+ "title": "-- Golf Setup --"
+ },
+ "Holes": {
+ value: holes_count,
+ min: 1, max: 20, step: 1, wrap: true,
+ onchange: v => { holes_count = v; add_holes(); }
+ },
+ "Players": {
+ value: player_count,
+ min: 1, max: 10, step: 1, wrap: true,
+ onchange: v => { player_count = v; }
+ },
+ "< Back": function () { E.showMenu(main_menu); },
+};
+
+function inc_hole(i, player) { return function (v) { course[i][player] = v; }; }
+
+function add_holes() {
+ for (let j = 0; j < 20; j++) {
+ delete main_menu["Hole - " + (j + 1)];
+ }
+ for (let i = 0; i < holes_count; i++) {
+ course[i] = new Array(player_count).fill(0);
+ main_menu["Hole - " + (i + 1)] = goto_hole_menu(i);
+ }
+ E.showMenu(main_menu);
+}
+
+function goto_hole_menu(i) {
+ return function () {
+ E.showMenu(hole_menu(i));
+ };
+}
+
+function hole_menu(i) {
+ let menu = {
+ "": {
+ "title": `-- Hole ${i + 1}--`
+ },
+ "Next hole": goto_hole_menu(i + 1),
+ "< Back": function () { E.showMenu(main_menu); },
+ };
+
+ for (let player = 0; player < player_count; player++) {
+ menu[`player - ${player + 1}`] = {
+ value: course[i][player],
+ min: 1, max: 20, step: 1, wrap: true,
+ onchange: inc_hole(i, player)
+ };
+ }
+
+ return menu;
+}
+
+// @ts-ignore
+g.clear();
+add_holes();
\ No newline at end of file
diff --git a/apps/golfscore/app.png b/apps/golfscore/app.png
new file mode 100644
index 000000000..fc5d51557
Binary files /dev/null and b/apps/golfscore/app.png differ
diff --git a/apps/golfscore/holemenu.png b/apps/golfscore/holemenu.png
new file mode 100644
index 000000000..ac214f182
Binary files /dev/null and b/apps/golfscore/holemenu.png differ
diff --git a/apps/golfscore/mainmenu.png b/apps/golfscore/mainmenu.png
new file mode 100644
index 000000000..3ebeb0ca7
Binary files /dev/null and b/apps/golfscore/mainmenu.png differ
diff --git a/apps/golfscore/scorecard.png b/apps/golfscore/scorecard.png
new file mode 100644
index 000000000..9e7ff1130
Binary files /dev/null and b/apps/golfscore/scorecard.png differ
diff --git a/apps/golfscore/setupmenu.png b/apps/golfscore/setupmenu.png
new file mode 100644
index 000000000..13158e2e7
Binary files /dev/null and b/apps/golfscore/setupmenu.png differ
diff --git a/apps/hebrew_calendar/ChangeLog b/apps/hebrew_calendar/ChangeLog
index d7dbc19e3..fdd29db66 100644
--- a/apps/hebrew_calendar/ChangeLog
+++ b/apps/hebrew_calendar/ChangeLog
@@ -1,3 +1,4 @@
0.01: New App!
0.02: using TS and rollup to bundle
-0.03: bug fixes and support bangle 1
\ No newline at end of file
+0.03: bug fixes and support bangle 1
+0.04: removing TS
\ No newline at end of file
diff --git a/apps/hebrew_calendar/LICENSE b/apps/hebrew_calendar/LICENSE
index cd6624ad4..bdcdec9e4 100644
--- a/apps/hebrew_calendar/LICENSE
+++ b/apps/hebrew_calendar/LICENSE
@@ -1,5 +1,5 @@
The MIT License (MIT)
-
+Copyright (c) 2021 Michael Salaverry
Copyright (c) 2016-20 Ionică Bizău (https://ionicabizau.net)
Permission is hereby granted, free of charge, to any person obtaining a copy
diff --git a/apps/hebrew_calendar/app.js b/apps/hebrew_calendar/app.js
index 9c21fa89b..399d124f3 100644
--- a/apps/hebrew_calendar/app.js
+++ b/apps/hebrew_calendar/app.js
@@ -1,17 +1,26 @@
-!function(){"use strict";
-/*!
- * This script was taked from this page and ported to Node.js by Ionic Bizu
- * http://www.shamash.org/help/javadate.shtml
- *
- * This script was adapted from C sources written by
- * Scott E. Lee, which contain the following copyright notice:
- *
- * Copyright 1993-1995, Scott E. Lee, all rights reserved.
- * Permission granted to use, copy, modify, distribute and sell so long as
- * the above copyright and this permission statement are retained in all
- * copies. THERE IS NO WARRANTY - USE AT YOUR OWN RISK.
- *
- * Bill Hastings
- * RBI Software Systems
- * bhastings@rbi.com
- */var t="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t};var i=new function(t,i,e,o,r,n,h,a,s,f,u,l,v,c){this[0]=t,this[1]=i,this[2]=e,this[3]=o,this[4]=r,this[5]=n,this[6]=h,this[7]=a,this[8]=s,this[9]=f,this[10]=u,this[11]=l,this[12]=v,this[13]=c}("Tishri","Heshvan","Kislev","Tevet","Shevat","AdarI","AdarII","Nisan","Iyyar","Sivan","Tammuz","Av","Elul"),e=new function(t,i,e,o,r,n,h,a,s,f,u,l,v,c,y,d,m,M,b){this[0]=t,this[1]=i,this[2]=e,this[3]=o,this[4]=r,this[5]=n,this[6]=h,this[7]=a,this[8]=s,this[9]=f,this[10]=u,this[11]=l,this[12]=v,this[13]=c,this[14]=y,this[15]=d,this[16]=m,this[17]=M,this[18]=b}(12,12,13,12,12,13,12,13,12,12,13,12,12,13,12,12,13,12,13);g.clear();let o=new Date,r=function(o){var r,n,h=0,a=0,s=0,f=0,u=0,l=0,v=0;function c(t){var i,o,r,n;for(f=Math.floor((t+310)/6940),r=void 0,n=void 0,r=31524,n=(r+=45971*f)>>16,n+=2744*f,o=Math.floor(n/25920),r=(n-=25920*o)<<16|65535&r,i=Math.floor(r/25920),l=o<<16|i,v=r-=25920*i;lt-74);u++)v+=765433*e[u],l+=Math.floor(v/25920),v%=25920}function y(t,i,e){var o=i,r=o%7;return(e>=19440||!(2==t||5==t||7==t||10==t||13==t||16==t||18==t)&&2==r&&e>=9924||(3==t||6==t||8==t||11==t||14==t||17==t||0==t)&&1==r&&e>=16789)&&(o++,7==++r&&(r=0)),3!=r&&5!=r&&0!=r||o++,o}var d=o;return"object"===(void 0===d?"undefined":t(d))&&(r=o.getMonth()+1,n=o.getDate(),d=o.getFullYear()),function(t){var i,o=0,r=0,n=t-347997;if(c(n),n>=(o=y(u,l,v))){if(s=19*f+u+1,n=o-177)return void(n>o-30?(h=13,a=n-o+30):n>o-60?(h=12,a=n-o+60):n>o-89?(h=11,a=n-o+89):n>o-119?(h=10,a=n-o+119):n>o-148?(h=9,a=n-o+148):(h=8,a=n-o+178));if(13==e[(s-1)%19]){if(h=7,(a=n-o+207)>0)return;if(h--,(a+=30)>0)return;h--,a+=30}else{if(h=6,(a=n-o+207)>0)return;h--,a+=30}if(a>0)return;if(h--,(a+=29)>0)return;r=o,c(l-365),o=y(u,l,v)}if(l=n-o-29,355==(i=r-o)||385==i){if(l<=30)return h=2,void(a=l);l-=30}else{if(l<=29)return h=2,void(a=l);l-=29}h=3,a=l}(function(t,i,e){var o=0,r=0,n=void 0;return o=t<0?t+4801:t+4800,i>2?r=i-3:(r=i+9,o--),n=Math.floor(146097*Math.floor(o/100)/4),n+=Math.floor(o%100*1461/4),n+=Math.floor((153*r+2)/5),n+=e-32045}(d,r,n)),{year:s,month:h,date:a,month_name:i[h-1]}}(o);var n={"":{title:"Hebrew Date"},cal:{value:require("locale").date(o,1),onchange:()=>{}},date:{value:r.date,onchange:()=>{}},month:{value:r.month_name,onchange:()=>{}},year:{value:r.year,onchange:()=>{}}};E.showMenu(n)}();
+g.clear();
+
+let now = new Date();
+
+let today = require('hebrewDate').hebrewDate(now);
+
+var mainmenu = {
+ "": {
+ "title": "Hebrew Date"
+ },
+ greg: {
+ // @ts-ignore
+ value: require('locale').date(now, 1),
+ },
+ date: {
+ value: today.date,
+ },
+ month: {
+ value: today.month_name,
+ },
+ year: {
+ value: today.year,
+ }
+};
+// @ts-ignore
+E.showMenu(mainmenu);
\ No newline at end of file
diff --git a/apps/hebrew_calendar/src/hebrewDate.ts b/apps/hebrew_calendar/hebrewDate.js
similarity index 77%
rename from apps/hebrew_calendar/src/hebrewDate.ts
rename to apps/hebrew_calendar/hebrewDate.js
index cc3a5ed78..da0c9cf50 100644
--- a/apps/hebrew_calendar/src/hebrewDate.ts
+++ b/apps/hebrew_calendar/hebrewDate.js
@@ -1,6 +1,5 @@
/*!
- * This script was taked from this page and ported to Node.js by Ionic Bizu
- * http://www.shamash.org/help/javadate.shtml
+ * This script was taked from this page http://www.shamash.org/help/javadate.shtml and ported to Node.js by Ionică Bizău in https://github.com/IonicaBizau/hebrew-date
*
* This script was adapted from C sources written by
* Scott E. Lee, which contain the following copyright notice:
@@ -14,33 +13,11 @@
* RBI Software Systems
* bhastings@rbi.com
*/
-
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
-
-var GREG_SDN_OFFSET = 32045,
- DAYS_PER_5_MONTHS = 153,
- DAYS_PER_4_YEARS = 1461,
- DAYS_PER_400_YEARS = 146097;
-
-var HALAKIM_PER_HOUR = 1080,
- HALAKIM_PER_DAY = 25920,
- HALAKIM_PER_LUNAR_CYCLE = 29 * HALAKIM_PER_DAY + 13753,
- HALAKIM_PER_METONIC_CYCLE = HALAKIM_PER_LUNAR_CYCLE * (12 * 19 + 7);
-
-var HEB_SDN_OFFSET = 347997,
- NEW_MOON_OF_CREATION = 31524,
- NOON = 18 * HALAKIM_PER_HOUR,
- AM3_11_20 = 9 * HALAKIM_PER_HOUR + 204,
- AM9_32_43 = 15 * HALAKIM_PER_HOUR + 589;
-
-var SUN = 0,
- MON = 1,
- TUES = 2,
- WED = 3,
- THUR = 4,
- FRI = 5,
- SAT = 6;
-
+var GREG_SDN_OFFSET = 32045, DAYS_PER_5_MONTHS = 153, DAYS_PER_4_YEARS = 1461, DAYS_PER_400_YEARS = 146097;
+var HALAKIM_PER_HOUR = 1080, HALAKIM_PER_DAY = 25920, HALAKIM_PER_LUNAR_CYCLE = 29 * HALAKIM_PER_DAY + 13753, HALAKIM_PER_METONIC_CYCLE = HALAKIM_PER_LUNAR_CYCLE * (12 * 19 + 7);
+var HEB_SDN_OFFSET = 347997, NEW_MOON_OF_CREATION = 31524, NOON = 18 * HALAKIM_PER_HOUR, AM3_11_20 = 9 * HALAKIM_PER_HOUR + 204, AM9_32_43 = 15 * HALAKIM_PER_HOUR + 589;
+var SUN = 0, MON = 1, TUES = 2, WED = 3, THUR = 4, FRI = 5, SAT = 6;
function weekdayarr(d0, d1, d2, d3, d4, d5, d6) {
this[0] = d0;
this[1] = d1;
@@ -50,7 +27,6 @@ function weekdayarr(d0, d1, d2, d3, d4, d5, d6) {
this[5] = d5;
this[6] = d6;
}
-
function gregmontharr(m0, m1, m2, m3, m4, m5, m6, m7, m8, m9, m10, m11) {
this[0] = m0;
this[1] = m1;
@@ -65,8 +41,7 @@ function gregmontharr(m0, m1, m2, m3, m4, m5, m6, m7, m8, m9, m10, m11) {
this[10] = m10;
this[11] = m11;
}
-
-function hebrewmontharr(m0, m1, m2, m3, m4, m5, m6, m7, m8, m9, m10, m11, m12, m13?: any) {
+function hebrewmontharr(m0, m1, m2, m3, m4, m5, m6, m7, m8, m9, m10, m11, m12, m13) {
this[0] = m0;
this[1] = m1;
this[2] = m2;
@@ -82,7 +57,6 @@ function hebrewmontharr(m0, m1, m2, m3, m4, m5, m6, m7, m8, m9, m10, m11, m12, m
this[12] = m12;
this[13] = m13;
}
-
function monthsperyeararr(m0, m1, m2, m3, m4, m5, m6, m7, m8, m9, m10, m11, m12, m13, m14, m15, m16, m17, m18) {
this[0] = m0;
this[1] = m1;
@@ -104,12 +78,7 @@ function monthsperyeararr(m0, m1, m2, m3, m4, m5, m6, m7, m8, m9, m10, m11, m12,
this[17] = m17;
this[18] = m18;
}
-
-var gWeekday = new weekdayarr("Sun", "Mon", "Tues", "Wednes", "Thurs", "Fri", "Satur"),
- gMonth = new gregmontharr("January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"),
- hMonth = new hebrewmontharr("Tishri", "Heshvan", "Kislev", "Tevet", "Shevat", "AdarI", "AdarII", "Nisan", "Iyyar", "Sivan", "Tammuz", "Av", "Elul"),
- mpy = new monthsperyeararr(12, 12, 13, 12, 12, 13, 12, 13, 12, 12, 13, 12, 12, 13, 12, 12, 13, 12, 13);
-
+var gWeekday = new weekdayarr("Sun", "Mon", "Tues", "Wednes", "Thurs", "Fri", "Satur"), gMonth = new gregmontharr("January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"), hMonth = new hebrewmontharr("Tishri", "Heshvan", "Kislev", "Tevet", "Shevat", "AdarI", "AdarII", "Nisan", "Iyyar", "Sivan", "Tammuz", "Av", "Elul"), mpy = new monthsperyeararr(12, 12, 13, 12, 12, 13, 12, 13, 12, 12, 13, 12, 12, 13, 12, 12, 13, 12, 13);
/**
* hebrewDate
* Convert the Gregorian dates into Hebrew calendar dates.
@@ -124,55 +93,36 @@ var gWeekday = new weekdayarr("Sun", "Mon", "Tues", "Wednes", "Thurs", "Fri", "S
* - `month_name`: The Hebrew month name.
* - `date`: The Hebrew date.
*/
-export const hebrewDate = function (inputDateOrYear: Date) {
+function hebrewDate(inputDateOrYear) {
var inputMonth, inputDate;
-
- var hebrewMonth = 0,
- hebrewDate = 0,
- hebrewYear = 0,
- metonicCycle = 0,
- metonicYear = 0,
- moladDay = 0,
- moladHalakim = 0;
-
+ var hebrewMonth = 0, hebrewDate = 0, hebrewYear = 0, metonicCycle = 0, metonicYear = 0, moladDay = 0, moladHalakim = 0;
function GregorianToSdn(inputYear, inputMonth, inputDay) {
-
- var year = 0,
- month = 0,
- sdn = void 0;
-
+ var year = 0, month = 0, sdn = void 0;
// Make year a positive number
if (inputYear < 0) {
year = inputYear + 4801;
- } else {
+ }
+ else {
year = inputYear + 4800;
}
-
// Adjust the start of the year
if (inputMonth > 2) {
month = inputMonth - 3;
- } else {
+ }
+ else {
month = inputMonth + 9;
year--;
}
-
sdn = Math.floor(Math.floor(year / 100) * DAYS_PER_400_YEARS / 4);
sdn += Math.floor(year % 100 * DAYS_PER_4_YEARS / 4);
sdn += Math.floor((month * DAYS_PER_5_MONTHS + 2) / 5);
sdn += inputDay - GREG_SDN_OFFSET;
-
return sdn;
}
-
function SdnToHebrew(sdn) {
- var tishri1 = 0,
- tishri1After = 0,
- yearLength = 0,
- inputDay = sdn - HEB_SDN_OFFSET;
-
+ var tishri1 = 0, tishri1After = 0, yearLength = 0, inputDay = sdn - HEB_SDN_OFFSET;
FindTishriMolad(inputDay);
tishri1 = Tishri1(metonicYear, moladDay, moladHalakim);
-
if (inputDay >= tishri1) {
// It found Tishri 1 at the start of the year.
hebrewYear = metonicCycle * 19 + metonicYear + 1;
@@ -180,7 +130,8 @@ export const hebrewDate = function (inputDateOrYear: Date) {
if (inputDay < tishri1 + 30) {
hebrewMonth = 1;
hebrewDate = inputDay - tishri1 + 1;
- } else {
+ }
+ else {
hebrewMonth = 2;
hebrewDate = inputDay - tishri1 - 29;
}
@@ -191,7 +142,8 @@ export const hebrewDate = function (inputDateOrYear: Date) {
moladDay += Math.floor(moladHalakim / HALAKIM_PER_DAY);
moladHalakim = moladHalakim % HALAKIM_PER_DAY;
tishri1After = Tishri1((metonicYear + 1) % 19, moladDay, moladHalakim);
- } else {
+ }
+ else {
// It found Tishri 1 at the end of the year.
hebrewYear = metonicCycle * 19 + metonicYear;
if (inputDay >= tishri1 - 177) {
@@ -199,44 +151,56 @@ export const hebrewDate = function (inputDateOrYear: Date) {
if (inputDay > tishri1 - 30) {
hebrewMonth = 13;
hebrewDate = inputDay - tishri1 + 30;
- } else if (inputDay > tishri1 - 60) {
+ }
+ else if (inputDay > tishri1 - 60) {
hebrewMonth = 12;
hebrewDate = inputDay - tishri1 + 60;
- } else if (inputDay > tishri1 - 89) {
+ }
+ else if (inputDay > tishri1 - 89) {
hebrewMonth = 11;
hebrewDate = inputDay - tishri1 + 89;
- } else if (inputDay > tishri1 - 119) {
+ }
+ else if (inputDay > tishri1 - 119) {
hebrewMonth = 10;
hebrewDate = inputDay - tishri1 + 119;
- } else if (inputDay > tishri1 - 148) {
+ }
+ else if (inputDay > tishri1 - 148) {
hebrewMonth = 9;
hebrewDate = inputDay - tishri1 + 148;
- } else {
+ }
+ else {
hebrewMonth = 8;
hebrewDate = inputDay - tishri1 + 178;
}
return;
- } else {
+ }
+ else {
if (mpy[(hebrewYear - 1) % 19] == 13) {
hebrewMonth = 7;
hebrewDate = inputDay - tishri1 + 207;
- if (hebrewDate > 0) return;
+ if (hebrewDate > 0)
+ return;
hebrewMonth--;
hebrewDate += 30;
- if (hebrewDate > 0) return;
- hebrewMonth--;
- hebrewDate += 30;
- } else {
- hebrewMonth = 6;
- hebrewDate = inputDay - tishri1 + 207;
- if (hebrewDate > 0) return;
+ if (hebrewDate > 0)
+ return;
hebrewMonth--;
hebrewDate += 30;
}
- if (hebrewDate > 0) return;
+ else {
+ hebrewMonth = 6;
+ hebrewDate = inputDay - tishri1 + 207;
+ if (hebrewDate > 0)
+ return;
+ hebrewMonth--;
+ hebrewDate += 30;
+ }
+ if (hebrewDate > 0)
+ return;
hebrewMonth--;
hebrewDate += 29;
- if (hebrewDate > 0) return;
+ if (hebrewDate > 0)
+ return;
// We need the length of the year to figure this out,so find Tishri 1 of this year.
tishri1After = tishri1;
FindTishriMolad(moladDay - 365);
@@ -253,7 +217,8 @@ export const hebrewDate = function (inputDateOrYear: Date) {
return;
}
moladDay -= 30;
- } else {
+ }
+ else {
// Heshvan has 29 days
if (moladDay <= 29) {
hebrewMonth = 2;
@@ -266,7 +231,6 @@ export const hebrewDate = function (inputDateOrYear: Date) {
hebrewMonth = 3;
hebrewDate = moladDay;
}
-
function FindTishriMolad(inputDay) {
// Estimate the metonic cycle number. Note that this may be an under
// estimate because there are 6939.6896 days in a metonic cycle not
@@ -287,18 +251,15 @@ export const hebrewDate = function (inputDateOrYear: Date) {
}
// Find the molad of Tishri closest to this date.
for (metonicYear = 0; metonicYear < 18; metonicYear++) {
- if (moladDay > inputDay - 74) break;
+ if (moladDay > inputDay - 74)
+ break;
moladHalakim += HALAKIM_PER_LUNAR_CYCLE * mpy[metonicYear];
moladDay += Math.floor(moladHalakim / HALAKIM_PER_DAY);
moladHalakim = moladHalakim % HALAKIM_PER_DAY;
}
}
-
function MoladOfMetonicCycle() {
- var r1 = void 0,
- r2 = void 0,
- d1 = void 0,
- d2 = void 0;
+ var r1 = void 0, r2 = void 0, d1 = void 0, d2 = void 0;
// Start with the time of the first molad after creation.
r1 = NEW_MOON_OF_CREATION;
// Calculate gMetonicCycle * HALAKIM_PER_METONIC_CYCLE. The upper 32
@@ -317,42 +278,34 @@ export const hebrewDate = function (inputDateOrYear: Date) {
moladDay = d2 << 16 | d1;
moladHalakim = r1;
}
-
function Tishri1(metonicYear, moladDay, moladHalakim) {
- var tishri1 = moladDay,
- dow = tishri1 % 7,
- leapYear = metonicYear == 2 || metonicYear == 5 || metonicYear == 7 || metonicYear == 10 || metonicYear == 13 || metonicYear == 16 || metonicYear == 18,
- lastWasLeapYear = metonicYear == 3 || metonicYear == 6 || metonicYear == 8 || metonicYear == 11 || metonicYear == 14 || metonicYear == 17 || metonicYear == 0;
-
+ var tishri1 = moladDay, dow = tishri1 % 7, leapYear = metonicYear == 2 || metonicYear == 5 || metonicYear == 7 || metonicYear == 10 || metonicYear == 13 || metonicYear == 16 || metonicYear == 18, lastWasLeapYear = metonicYear == 3 || metonicYear == 6 || metonicYear == 8 || metonicYear == 11 || metonicYear == 14 || metonicYear == 17 || metonicYear == 0;
// Apply rules 2,3 and 4
if (moladHalakim >= NOON || !leapYear && dow == TUES && moladHalakim >= AM3_11_20 || lastWasLeapYear && dow == MON && moladHalakim >= AM9_32_43) {
tishri1++;
dow++;
- if (dow == 7) dow = 0;
+ if (dow == 7)
+ dow = 0;
}
-
// Apply rule 1 after the others because it can cause an additional delay of one day.
if (dow == WED || dow == FRI || dow == SUN) {
tishri1++;
}
-
return tishri1;
}
-
- var inputYear: Date | number = inputDateOrYear;
-
+ var inputYear = inputDateOrYear;
if ((typeof inputYear === "undefined" ? "undefined" : _typeof(inputYear)) === "object") {
inputMonth = inputDateOrYear.getMonth() + 1;
inputDate = inputDateOrYear.getDate();
inputYear = inputDateOrYear.getFullYear();
}
-
SdnToHebrew(GregorianToSdn(inputYear, inputMonth, inputDate));
-
return {
year: hebrewYear,
month: hebrewMonth,
date: hebrewDate,
month_name: hMonth[hebrewMonth - 1]
};
-};
\ No newline at end of file
+}
+
+exports.hebrewDate = hebrewDate;
diff --git a/apps/hebrew_calendar/package.json b/apps/hebrew_calendar/package.json
deleted file mode 100644
index 85e9ebbf0..000000000
--- a/apps/hebrew_calendar/package.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
- "name": "hebrew_calendar",
- "version": "0.0.3",
- "description": "Bangle.js app for seeing hebrew calendar",
- "main": "app.js",
- "types": "app.d.ts",
- "scripts": {
- "build": "rollup -c"
- },
- "author": {
- "name": "Michael Salaverry",
- "url": "https://github.com/barakplasma"
- },
- "license": "MIT",
- "devDependencies": {
- "@rollup/plugin-typescript": "^4.1.1",
- "rollup": "^2.10.2",
- "rollup-plugin-terser": "^5.3.0",
- "terser": "^4.7.0",
- "tslib": "^2.0.0",
- "typescript": "^3.9.2"
- }
-}
diff --git a/apps/hebrew_calendar/rollup.config.mjs b/apps/hebrew_calendar/rollup.config.mjs
deleted file mode 100644
index 5f7f0746f..000000000
--- a/apps/hebrew_calendar/rollup.config.mjs
+++ /dev/null
@@ -1,15 +0,0 @@
-import typescript from '@rollup/plugin-typescript';
-import { terser } from 'rollup-plugin-terser';
-
-export default {
- input: './src/app.ts',
- output: {
- dir: '.',
- format: 'iife',
- name: 'hebrew_calendar'
- },
- plugins: [
- typescript(),
- terser(),
- ]
-};
diff --git a/apps/hebrew_calendar/src/app.ts b/apps/hebrew_calendar/src/app.ts
deleted file mode 100644
index 51314e337..000000000
--- a/apps/hebrew_calendar/src/app.ts
+++ /dev/null
@@ -1,34 +0,0 @@
-declare var Bangle: any;
-declare var g: any;
-declare var E: any;
-declare var require: any;
-
-g.clear();
-
-let now = new Date();
-import { hebrewDate } from "./hebrewDate";
-
-let today = hebrewDate(now);
-
-var mainmenu = {
- "" : {
- "title" : "Hebrew Date"
- },
- cal: {
- value: require('locale').date(now,1),
- onchange : () => {}
- },
- date: {
- value : today.date,
- onchange : () => {}
- },
- month: {
- value : today.month_name,
- onchange : () => {}
- },
- year: {
- value : today.year,
- onchange : () => {}
- }
-};
-E.showMenu(mainmenu);
diff --git a/apps/hebrew_calendar/tsconfig.json b/apps/hebrew_calendar/tsconfig.json
deleted file mode 100644
index 30a9e35f4..000000000
--- a/apps/hebrew_calendar/tsconfig.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
- "compilerOptions": {
- "module": "es2015",
- "noImplicitAny": false,
- "target": "es2015"
- },
- "include": [
- "src"
- ]
-}
diff --git a/apps/impwclock/ChangeLog b/apps/impwclock/ChangeLog
index 0592d4d04..7bc119426 100644
--- a/apps/impwclock/ChangeLog
+++ b/apps/impwclock/ChangeLog
@@ -1,3 +1,4 @@
0.01: New App!
0.02: Stopped watchface from flashing every interval
0.03: Move to Bangle.setUI to launcher support
+0.04: Tweaks for compatibility with BangleJS2
diff --git a/apps/impwclock/README.md b/apps/impwclock/README.md
index 30e42c95e..ac1341097 100644
--- a/apps/impwclock/README.md
+++ b/apps/impwclock/README.md
@@ -1,4 +1,4 @@
# Imprecise Word Clock
-This clock tells time in very rough approximation, as in "Late morning" or "Early afternoon." Good for vacations and weekends. Press button 1 to see the time in accurate, digital form. But do you really need to know the exact time?
+This clock tells time in very rough approximation, as in "Late morning" or "Early afternoon." Good for vacations and weekends. Touch the screen to see the time in accurate, digital form. But do you really need to know the exact time?
diff --git a/apps/impwclock/clock-impword.js b/apps/impwclock/clock-impword.js
index 5492eac15..8bb5da6ba 100644
--- a/apps/impwclock/clock-impword.js
+++ b/apps/impwclock/clock-impword.js
@@ -2,7 +2,7 @@
A remix of word clock
by Gordon Williams https://github.com/gfwilliams
- Changes the representation of time to be more general
-- Shows accurate digital time when button 1 is pressed
+- Toggles showing of accurate digital time when screen touched.
*/
/* jshint esversion: 6 */
@@ -34,14 +34,16 @@ const timeOfDay = {
};
+var big = g.getWidth()>200;
// offsets and increments
-const xs = 35;
-const ys = 31;
-const dy = 22;
-const dx = 25;
+const xs = big ? 35 : 20;
+const ys = big ? 31 : 28;
+const dx = big ? 25 : 20;
+const dy = big ? 22 : 16;
+
// font size and color
-const fontSize = 3; // "6x8"
+const fontSize = big ? 3 : 2; // "6x8"
const passivColor = 0x3186 /*grey*/ ;
const activeColorNight = 0xF800 /*red*/ ;
const activeColorDay = 0xFFFF /* white */;
@@ -115,6 +117,8 @@ function drawWordClock() {
// check whether we need to redraw the watchface
if (hidx !== hidxPrev) {
+ // Turn off showDigitalTime
+ showDigitalTime = false;
// draw allWords
var c;
var y = ys;
@@ -138,15 +142,14 @@ function drawWordClock() {
hidxPrev = hidx;
}
- // Display digital time while button 1 is pressed
- g.clearRect(0, 215, 240, 240);
+ // Display digital time when button is pressed or screen touched
+ g.clearRect(0, big ? 215 : 160, big ? 240 : 176, big ? 240 : 176);
if (showDigitalTime){
g.setColor(activeColor);
- g.drawString(time, 120, 215);
+ g.drawString(time, big ? 120 : 90, big ? 215 : 160);
}
}
-
Bangle.on('lcdPower', function(on) {
if (on) drawWordClock();
});
@@ -157,17 +160,14 @@ Bangle.drawWidgets();
setInterval(drawWordClock, 1E4);
drawWordClock();
-// Show digital time while top button is pressed (if we have physical buttons)
-if (global.BTN3) setWatch(function() {
- showDigitalTime = BTN1.read();
- drawWordClock();
-}, BTN1, {repeat:true,edge:"both"});
-// If LCD pressed (on Bangle.js 2) draw digital time
-Bangle.on('drag',e=>{
- var pressed = e.b!=0;
- if (pressed!=showDigitalTime) {
- showDigitalTime = pressed;
+// If LCD pressed, toggle drawing digital time
+Bangle.on('touch',e=>{
+ if (showDigitalTime){
+ showDigitalTime = false;
+ drawWordClock();
+ } else {
+ showDigitalTime = true;
drawWordClock();
}
});
diff --git a/apps/locale/locales.js b/apps/locale/locales.js
index f4ee1fb43..2e1429ef8 100644
--- a/apps/locale/locales.js
+++ b/apps/locale/locales.js
@@ -40,7 +40,16 @@ const charFallbacks = {
"č":"c",
"ř":"r",
"ő":"o",
- "ě":"e"
+ "ě":"e",
+ "ę":"e",
+ "ą":"a",
+ "ó":"o",
+ "ż":"z",
+ "ź":"z",
+ "ń":"n",
+ "ł":"l",
+ "ś":"s",
+ "ć":"c",
};
/*
@@ -603,6 +612,24 @@ var locales = {
day: "Domingo,Segunda-feira,Terça-feira,Quarta-feira,Quinta-feira,Sexta-feira,Sábado",
trans: { yes: "sim", Yes: "Sim", no: "não", No: "Não", ok: "ok", on: "on", off: "off" }
},
+ "pl_PL": {
+ lang: "pl_PL",
+ decimal_point: ",",
+ thousands_sep: " ",
+ currency_symbol: "zł",
+ int_curr_symbol: "PLN",
+ speed: "kmh",
+ distance: { 0: "m", 1: "km" },
+ temperature: "°C",
+ ampm: { 0: "", 1: "" },
+ timePattern: { 0: "%HH:%MM:%SS", 1: "%HH:%MM" },
+ datePattern: { 0: "%d. %b %Y", "1": "%d.%m.%Y" }, // 1. Mar 2021 // 01.03.2021
+ abmonth: "Sty,Lut,Mar,Kwi,Maj,Cze,Lip,Sie,Wrz,Paź,Lis,Gru",
+ month: "Styczeń,Luty,Marzec,Kwiecień,Maj,Czerwiec,Lipiec,Sierpień,Wrzesień,Październik,Listopad,Grudzień",
+ abday: "Ndz,Pon,Wt,Śr,Czw,Pt,Sob",
+ day: "Niedziela,Poniedziałek,Wtorek,Środa,Czwartek,Piątek,Sobota",
+ trans: { yes: "tak", Yes: "Tak", no: "nie", No: "Nie", ok: "ok", on: "on", off: "off", "< Back": "< Wstecz" }
+ },
/*,
"he_IL": { // This won't work until we get a font - see https://github.com/espruino/BangleApps/issues/399
codePage : "ISO8859-8",
diff --git a/apps/pooqroman/ChangeLog b/apps/pooqroman/ChangeLog
new file mode 100644
index 000000000..9debf0efe
--- /dev/null
+++ b/apps/pooqroman/ChangeLog
@@ -0,0 +1,2 @@
+0.01: New App!
+0.02: Make internal menu time out + small fixes
diff --git a/apps/pooqroman/app.js b/apps/pooqroman/app.js
index d25fcf1a8..d59d4ef6c 100644
--- a/apps/pooqroman/app.js
+++ b/apps/pooqroman/app.js
@@ -1,3 +1,4 @@
+/* -*- mode: Javascript; c-basic-offset: 2; indent-tabs-mode: nil; coding: latin-1 -*- */
// pooqRoman
//
// Copyright (c) 2021 Stephen P Spackman
@@ -54,8 +55,9 @@ class Options {
this.id = this.constructor.id;
this.file = `${this.id}.json`;
this.backing = storage.readJSON(this.file, true) || {};
- this.defaults = this.constructor.defaults;
- Object.keys(this.defaults).forEach(k => this.bless(k));
+ Object.setPrototypeOf(this.backing, this.constructor.defaults);
+ this.reactivator = _ => this.active();
+ Object.keys(this.constructor.defaults).forEach(k => this.bless(k));
}
writeBack(delay) {
@@ -71,29 +73,41 @@ class Options {
bless(k) {
Object.defineProperty(this, k, {
- get: () => this.backing[k] == null ? this.defaults[k] : this.backing[k],
+ get: () => this.backing[k],
set: v => {
this.backing[k] = v;
// Ten second writeback delay, since the user will roll values up and down.
this.writeBack(10000);
}
});
- }
+ }
showMenu(m) {
+ if (m instanceof Function) m = m();
if (m) {
for (const k in m) if ('init' in m[k]) m[k].value = m[k].init();
m[''].selected = -1; // Workaround for self-selection bug.
+ Bangle.on('drag', this.reactivator);
+ this.active();
+ } else {
+ if (this.bored) clearTimeout(this.bored);
+ this.bored = null;
+ Bangle.removeListener('drag', this.reactivator);
+ this.emit('done');
}
+ g.clear(true);
E.showMenu(m);
}
- reset() {
- this.backing = {};
- this.writeBack(0);
+ active() {
+ if (this.bored) clearTimeout(this.bored);
+ this.bored = setTimeout(_ => this.showMenu(), 15000);
}
- interact() {this.showMenu(this.menu);}
+ reset() {
+ this.backing = {__proto__: this.constructor.defaults};
+ this.writeBack(0);
+ }
}
class RomanOptions extends Options {
@@ -101,7 +115,7 @@ class RomanOptions extends Options {
super();
this.menu = {
'': {title: '* face options *'},
- '< Back': _ => {this.showMenu(); this.emit('done');},
+ '< Back': _ => this.showMenu(),
Ticks: {
init: _ => this.resolution,
min: 0, max: 3,
@@ -124,9 +138,11 @@ class RomanOptions extends Options {
onchange: x => this.calendric = x,
format: x => ['none', 'day', 'date'][x]
},
- Defaults: _ => {this.reset();}
+ Defaults: _ => {this.reset(); this.interact();}
};
}
+
+ interact() {this.showMenu(this.menu);}
}
RomanOptions.id = 'pooqroman';
@@ -147,7 +163,7 @@ RomanOptions.defaults = {
hubFg: g.theme.fg,
alarmFg: '#f00',
timerFg: '#0f0',
- active: g.theme.fg2,
+ activeFg: g.theme.fg2,
};
//////////////////////////////////////////////////////////////////////////////
@@ -434,7 +450,7 @@ class Sidebar {
}
static gpsColour(o) {
const fix = Bangle.getGPSFix();
- return fix && fix.fix ? o.active : o.barFg;
+ return fix && fix.fix ? o.activeFg : o.barFg;
}
doPower() {
const c = Bangle.isCharging();
@@ -455,7 +471,7 @@ class Sidebar {
if (Bangle.isCompassOn()) {
const c = Bangle.getCompass();
const a = c && this.rate <= 1000;
- this.g.setColor(a ? this.options.active : this.options.barFg).drawImage(
+ this.g.setColor(a ? this.options.activeFg : this.options.barFg).drawImage(
compassI,
this.x + 4 + imageWidth(compassI) / 2,
this.y + 4 + imageHeight(compassI) / 2,
@@ -470,7 +486,7 @@ class Sidebar {
class Roman {
constructor(g, events) {
this.g = g;
- this.state = {};
+ this.state = null;
const options = this.options = new RomanOptions();
this.events = events.loadFromSystem(this.options);
this.timescales = [1000, [1000, 60000], 60000, 3600000];
@@ -480,7 +496,7 @@ class Roman {
this.seconds = Roman.hand(g, 1, 0.9, 60, _ => options.secondFg);
}
- reset() {this.state = {}; this.g.clear(true);}
+ reset() {this.state = null;}
doIcons(which) {this.state.iconsOk = null;}
@@ -544,7 +560,7 @@ class Roman {
render(d, rate) {
const g = this.g;
- const state = this.state;
+ const state = this.state || (g.clear(true), this.state = {});
const options = this.options;
const events = this.events;
events.clean(d, -39600000); // 11h
@@ -654,8 +670,8 @@ class Clock {
drag: e => {
if (this.t0) {
if (e.b) {
- e.x > this.xN && (this.xN = e.x) || e.x > this.xX && (this.xX = e.x);
- e.y > this.yN && (this.yN = e.y) || e.y > this.yX && (this.xY = e.y);
+ e.x < this.xN && (this.xN = e.x) || e.x > this.xX && (this.xX = e.x);
+ e.y < this.yN && (this.yN = e.y) || e.y > this.yX && (this.yX = e.y);
} else if (this.xX - this.xN < 20) {
if (e.y - this.e0.y < -50) {
this.options.resolution > 0 && this.options.resolution--;
@@ -697,6 +713,7 @@ class Clock {
this.exception && clearTimeout(this.exception);
this.interval && clearInterval(this.interval);
this.timeout = this.exception = this.interval = this.rate = null;
+ this.face.reset(); // Cancel any ongoing background rendering
return this;
}
diff --git a/apps/ptlaunch/ChangeLog b/apps/ptlaunch/ChangeLog
index f50936885..de38d715a 100644
--- a/apps/ptlaunch/ChangeLog
+++ b/apps/ptlaunch/ChangeLog
@@ -1,2 +1,4 @@
0.01: Initial creation of the pattern launch app
0.02: Turn on lcd when launching an app if the lock screen was disabled in the settings
+0.03: Make tap to confirm new pattern more reliable. Also allow for easier creation of single circle patterns.
+0.10: Improve the management of existing patterns: Draw the linked pattern on the left hand side of the app name within a scroller, similar to the default launcher. Slighlty clean up the code to make it less horrible.
\ No newline at end of file
diff --git a/apps/ptlaunch/README.md b/apps/ptlaunch/README.md
index a69492782..8d61afece 100644
--- a/apps/ptlaunch/README.md
+++ b/apps/ptlaunch/README.md
@@ -8,25 +8,32 @@ Create patterns and link them to apps in the Pattern Launcher app.
Then launch the linked apps directly from the clock screen by simply drawing the desired pattern.
-## Screenshots and detailed steps
+## Add Pattern Screenshots
-
+


+## Manage Pattern Screenshots
+
+
+
+
+## Detailed Steps
+
From the main menu you can:
- Add a new pattern and link it to an app (first entry)
- To create a new pattern first select "Add Pattern"
- Now draw any pattern you like, this will later launch the linked app from the clock screen
+ - You can also draw a single-circle pattern (meaning a single tap on one circle) instead of drawing a 'complex' pattern
- If you don't like the pattern, simply re-draw it. The previous pattern will be discarded.
- If you are happy with the pattern tap on screen or press the button to continue
- Now select the app you want to launch with the pattern.
- Note, you can bind multiple patterns to the same app.
-- Remove linked patterns (second entry)
- - To remove a pattern first select "Remove Pattern"
- - You will now see a list of apps that have patterns linked to them
- - Simply select the app that you want to unlink. This will remove the saved pattern, but not the app itself!
- - Note, that you can not actually preview the patterns. This makes removing patterns that are linked to the same app annoying. sorry!
+- Manage created patterns (second entry)
+ - To manage your patterns first select "Manage Patterns"
+ - You will now see a scrollabe list of patterns + linked apps
+ - If you want to deletion a pattern (and unlink the app) simply tap on it, and confirm the deletion
- Disable the lock screen on the clock screen from the settings (third entry)
- To launch the app from the pattern on the clock screen the watch must be unlocked.
- If this annoys you, you can disable the lock on the clock screen from the setting here
diff --git a/apps/ptlaunch/app.js b/apps/ptlaunch/app.js
index 8ba1adf81..b5a3bf610 100644
--- a/apps/ptlaunch/app.js
+++ b/apps/ptlaunch/app.js
@@ -1,26 +1,6 @@
-var storage = require("Storage");
-
var DEBUG = false;
-var log = (message) => {
- if (DEBUG) {
- console.log(JSON.stringify(message));
- }
-};
-var CIRCLE_RADIUS = 25;
-var CIRCLE_RADIUS_2 = CIRCLE_RADIUS * CIRCLE_RADIUS;
-
-var CIRCLES = [
- { x: 25, y: 25, i: 0 },
- { x: 87, y: 25, i: 1 },
- { x: 150, y: 25, i: 2 },
- { x: 25, y: 87, i: 3 },
- { x: 87, y: 87, i: 4 },
- { x: 150, y: 87, i: 5 },
- { x: 25, y: 150, i: 6 },
- { x: 87, y: 150, i: 7 },
- { x: 150, y: 150, i: 8 },
-];
+var storage = require("Storage");
var showMainMenu = () => {
log("loading patterns");
@@ -36,7 +16,7 @@ var showMainMenu = () => {
},
"Add Pattern": () => {
log("creating pattern");
- createPattern().then((pattern) => {
+ recognizeAndDrawPattern().then((pattern) => {
log("got pattern");
log(pattern);
log(pattern.length);
@@ -73,17 +53,32 @@ var showMainMenu = () => {
});
});
},
- "Remove Pattern": () => {
+ "Manage Patterns": () => {
log("selecting pattern through app");
- getStoredPatternViaApp(storedPatterns).then((pattern) => {
- E.showMessage("Deleting...");
- delete storedPatterns[pattern];
- storage.writeJSON("ptlaunch.patterns.json", storedPatterns);
- showMainMenu();
+ showScrollerContainingAppsWithPatterns().then((selected) => {
+ var pattern = selected.pattern;
+ var appName = selected.appName;
+ if (pattern === "back") {
+ showMainMenu();
+ } else {
+ E.showPrompt(appName + "\n\npattern:\n" + pattern, {
+ title: "Delete?",
+ buttons: { Yes: true, No: false },
+ }).then((confirm) => {
+ if (confirm) {
+ E.showMessage("Deleting...");
+ delete storedPatterns[pattern];
+ storage.writeJSON("ptlaunch.patterns.json", storedPatterns);
+ showMainMenu();
+ } else {
+ showMainMenu();
+ }
+ });
+ }
});
},
Settings: () => {
- var settings = storedPatterns["settings"] || {};
+ var settings = storedPatterns.settings || {};
var settingsmenu = {
"": {
@@ -98,7 +93,7 @@ var showMainMenu = () => {
if (settings.lockDisabled) {
settingsmenu["Enable lock"] = () => {
settings.lockDisabled = false;
- storedPatterns["settings"] = settings;
+ storedPatterns.settings = settings;
Bangle.setOptions({ lockTimeout: 1000 * 30 });
storage.writeJSON("ptlaunch.patterns.json", storedPatterns);
showMainMenu();
@@ -106,7 +101,7 @@ var showMainMenu = () => {
} else {
settingsmenu["Disable lock"] = () => {
settings.lockDisabled = true;
- storedPatterns["settings"] = settings;
+ storedPatterns.settings = settings;
storage.writeJSON("ptlaunch.patterns.json", storedPatterns);
Bangle.setOptions({ lockTimeout: 1000 * 60 * 60 * 24 * 365 });
showMainMenu();
@@ -119,12 +114,8 @@ var showMainMenu = () => {
E.showMenu(mainmenu);
};
-var drawCircle = (circle) => {
- g.fillCircle(circle.x, circle.y, CIRCLE_RADIUS);
-};
-
var positions = [];
-var createPattern = () => {
+var recognizeAndDrawPattern = () => {
return new Promise((resolve) => {
E.showMenu();
g.clear();
@@ -147,13 +138,29 @@ var createPattern = () => {
setWatch(() => finishHandler(), BTN);
setTimeout(() => Bangle.on("tap", finishHandler), 250);
+ positions = [];
var dragHandler = (position) => {
+ log(position);
positions.push(position);
debounce().then(() => {
if (isFinished) {
return;
}
+
+ // This might actually be a 'tap' event.
+ // Use this check in addition to the actual tap handler to make it more reliable
+ if (pattern.length > 0 && positions.length === 2) {
+ if (
+ positions[0].x === positions[1].x &&
+ positions[0].y === positions[1].y
+ ) {
+ finishHandler();
+ positions = [];
+ return;
+ }
+ }
+
E.showMessage("Calculating...");
var t0 = Date.now();
@@ -269,18 +276,7 @@ var createPattern = () => {
log("redrawing");
g.clear();
- g.setColor(0, 0, 0);
- CIRCLES.forEach((circle) => drawCircle(circle));
-
- g.setColor(1, 1, 1);
- g.setFontAlign(0, 0);
- g.setFont("6x8", 4);
- pattern.forEach((circleIndex, patternIndex) => {
- var circle = CIRCLES[circleIndex];
- g.drawString(patternIndex + 1, circle.x, circle.y);
- });
- var t2 = Date.now();
- log(t2 - t0);
+ drawCirclesWithPattern(pattern);
});
};
@@ -341,56 +337,256 @@ var getSelectedApp = () => {
});
};
-var getStoredPatternViaApp = (storedPatterns) => {
- E.showMessage("Loading patterns...");
- log("getStoredPatternViaApp");
+//////
+// manage pattern related variables and functions
+// - draws all saved patterns and their linked app names
+// - uses the scroller to allow the user to browse through them
+//////
+
+var scrollerFont = g.getFonts().includes("12x20") ? "12x20" : "6x8:2";
+
+var drawBackButton = (r) => {
+ g.clearRect(r.x, r.y, r.x + r.w - 1, r.y + r.h - 1);
+ g.setFont(scrollerFont)
+ .setFontAlign(-1, 0)
+ .drawString("< Back", 64, r.y + 32);
+};
+
+var drawAppWithPattern = (i, r, storedPatterns) => {
+ log("draw app with pattern");
+ log({ i: i, r: r, storedPatterns: storedPatterns });
+ var storedPattern = storedPatterns[i];
+ var pattern = storedPattern.pattern;
+ var app = storedPattern.app;
+
+ g.clearRect(r.x, r.y, r.x + r.w - 1, r.y + r.h - 1);
+
+ g.drawLine(r.x, r.y, 176, r.y);
+
+ drawCirclesWithPattern(pattern, {
+ enableCaching: true,
+ scale: 0.33,
+ offset: { x: 1, y: 3 + r.y },
+ });
+
+ g.setColor(0, 0, 0);
+ if (!storedPattern.wrappedAppName) {
+ storedPattern.wrappedAppName = g
+ .wrapString(app.name, g.getWidth() - 64)
+ .join("\n");
+ }
+ log(g.getWidth());
+ log(storedPattern.wrappedAppName);
+ g.setFont(scrollerFont)
+ .setFontAlign(-1, 0)
+ .drawString(storedPattern.wrappedAppName, 64, r.y + 32);
+};
+
+var showScrollerContainingAppsWithPatterns = () => {
+ var storedPatternsArray = getStoredPatternsArray();
+ log("drawing scroller for stored patterns");
+ log(storedPatternsArray);
+ log(storedPatternsArray.length);
+
+ g.clear();
+
+ var c = Math.max(storedPatternsArray.length + 1, 3);
+
return new Promise((resolve) => {
- var selectPatternMenu = {
- "": {
- title: "Select App",
- },
- "< Cancel": () => {
- log("cancel");
- showMainMenu();
- },
- };
-
- log(storedPatterns);
- var patterns = Object.keys(storedPatterns);
- log(patterns);
-
- patterns.forEach((pattern) => {
- if (pattern) {
- if (storedPatterns[pattern]) {
- var app = storedPatterns[pattern].app;
- if (!!app && !!app.name) {
- var appName = app.name;
- var i = 0;
- while (appName in selectPatternMenu[app.name]) {
- appName = app.name + i;
- i++;
- }
- selectPatternMenu[appName] = () => {
- log("pattern via app selected");
- log(pattern);
- log(app);
- resolve(pattern);
- };
- }
+ E.showScroller({
+ h: 64,
+ c: c,
+ draw: (i, r) => {
+ log("draw");
+ log({ i: i, r: r });
+ if (i <= 0) {
+ drawBackButton(r);
+ } else if (i <= storedPatternsArray.length) {
+ drawAppWithPattern(i - 1, r, storedPatternsArray);
}
- }
+ },
+ select: (i) => {
+ log("selected: " + i);
+ var pattern = "back";
+ var appName = "";
+ if (i > 0) {
+ var storedPattern = storedPatternsArray[i - 1];
+ pattern = storedPattern.pattern.join("");
+ appName = storedPattern.app.name;
+ }
+ clearCircleDrawingCache();
+ resolve({ pattern: pattern, appName: appName });
+ },
});
-
- E.showMenu(selectPatternMenu);
});
};
-showMainMenu();
+//////
+// storage related functions:
+// - stored patterns
+// - stored settings
+//////
+
+var getStoredPatternsMap = () => {
+ log("loading stored patterns map");
+ var storedPatternsMap = storage.readJSON("ptlaunch.patterns.json", 1) || {};
+ delete storedPatternsMap.settings;
+ log(storedPatternsMap);
+ return storedPatternsMap;
+};
+
+var getStoredPatternsArray = () => {
+ var storedPatternsMap = getStoredPatternsMap();
+ log("converting stored patterns map to array");
+ var patterns = Object.keys(storedPatternsMap);
+ var storedPatternsArray = [];
+ for (var i = 0; i < patterns.length; i++) {
+ var pattern = "" + patterns[i];
+ storedPatternsArray.push({
+ pattern: pattern
+ .split("")
+ .map((circleIndex) => parseInt(circleIndex, 10)),
+ app: storedPatternsMap[pattern].app,
+ });
+ }
+ log(storedPatternsArray);
+ return storedPatternsArray;
+};
//////
-// lib functions
+// circle related variables and functions:
+// - the circle array itself
+// - the radius and the squared radius of the circles
+// - circle draw function
//////
+var CIRCLE_RADIUS = 25;
+var CIRCLE_RADIUS_2 = CIRCLE_RADIUS * CIRCLE_RADIUS;
+
+var CIRCLES = [
+ { x: 25, y: 25, i: 0 },
+ { x: 87, y: 25, i: 1 },
+ { x: 150, y: 25, i: 2 },
+ { x: 25, y: 87, i: 3 },
+ { x: 87, y: 87, i: 4 },
+ { x: 150, y: 87, i: 5 },
+ { x: 25, y: 150, i: 6 },
+ { x: 87, y: 150, i: 7 },
+ { x: 150, y: 150, i: 8 },
+];
+
+var drawCircle = (circle, drawBuffer, scale) => {
+ if (!drawBuffer) {
+ drawBuffer = g;
+ }
+ if (!scale) {
+ scale = 1;
+ }
+
+ var x = circle.x * scale;
+ var y = circle.y * scale;
+ var r = CIRCLE_RADIUS * scale;
+
+ log("drawing circle");
+ log({ x: x, y: y, r: r });
+
+ drawBuffer.fillCircle(x, y, r);
+};
+
+var cachedCirclesDrawings = {};
+
+var clearCircleDrawingCache = () => {
+ cachedCirclesDrawings = {};
+};
+
+var drawCirclesWithPattern = (pattern, options) => {
+ if (!pattern || pattern.length === 0) {
+ pattern = [];
+ }
+ if (!options) {
+ options = {};
+ }
+ var enableCaching = options.enableCaching;
+ var scale = options.scale;
+ var offset = options.offset;
+ if (!enableCaching) {
+ enableCaching = false;
+ }
+ if (!scale) {
+ scale = 1;
+ }
+ if (!offset) {
+ offset = { x: 0, y: 0 };
+ }
+
+ log("drawing circles with pattern, scale and offset");
+ log(pattern);
+ log(scale);
+ log(offset);
+
+ // cache drawn patterns. especially useful for the manage pattern menu
+ var image = cachedCirclesDrawings[pattern.join("")];
+ if (!image) {
+ log("circle image not cached");
+ var drawBuffer = Graphics.createArrayBuffer(
+ g.getWidth() * scale,
+ g.getHeight() * scale,
+ 1,
+ { msb: true }
+ );
+
+ drawBuffer.setColor(1);
+ CIRCLES.forEach((circle) => drawCircle(circle, drawBuffer, scale));
+
+ drawBuffer.setColor(0);
+ drawBuffer.setFontAlign(0, 0);
+ drawBuffer.setFont("6x8", 4 * scale);
+ pattern.forEach((circleIndex, patternIndex) => {
+ var circle = CIRCLES[circleIndex];
+ drawBuffer.drawString(
+ patternIndex + 1,
+ circle.x * scale,
+ circle.y * scale
+ );
+ });
+
+ image = {
+ width: drawBuffer.getWidth(),
+ height: drawBuffer.getHeight(),
+ bpp: 1,
+ buffer: drawBuffer.buffer,
+ };
+
+ if (enableCaching) {
+ cachedCirclesDrawings[pattern.join("")] = image;
+ }
+ } else {
+ log("using cached circle image");
+ }
+
+ g.drawImage(image, offset.x, offset.y);
+};
+
+var cloneCirclesArray = () => {
+ var circlesClone = Array(CIRCLES.length);
+
+ for (var i = 0; i < CIRCLES.length; i++) {
+ circlesClone[i] = CIRCLES[i];
+ }
+
+ return circlesClone;
+};
+
+//////
+// misc lib functions
+//////
+
+var log = (message) => {
+ if (DEBUG) {
+ console.log(JSON.stringify(message));
+ }
+};
+
var debounceTimeoutId;
var debounce = (delay) => {
if (debounceTimeoutId) {
@@ -405,12 +601,8 @@ var debounce = (delay) => {
});
};
-var cloneCirclesArray = () => {
- var circlesClone = Array(CIRCLES.length);
+//////
+// run main function
+//////
- for (var i = 0; i < CIRCLES.length; i++) {
- circlesClone[i] = CIRCLES[i];
- }
-
- return circlesClone;
-};
+showMainMenu();
diff --git a/apps/ptlaunch/boot.js b/apps/ptlaunch/boot.js
index 14d390b13..a23607768 100644
--- a/apps/ptlaunch/boot.js
+++ b/apps/ptlaunch/boot.js
@@ -5,21 +5,6 @@ var log = (message) => {
}
};
-var CIRCLE_RADIUS = 25;
-var CIRCLE_RADIUS_2 = CIRCLE_RADIUS * CIRCLE_RADIUS;
-
-var CIRCLES = [
- { x: 25, y: 25, i: 0 },
- { x: 87, y: 25, i: 1 },
- { x: 150, y: 25, i: 2 },
- { x: 25, y: 87, i: 3 },
- { x: 87, y: 87, i: 4 },
- { x: 150, y: 87, i: 5 },
- { x: 25, y: 150, i: 6 },
- { x: 87, y: 150, i: 7 },
- { x: 150, y: 150, i: 8 },
-];
-
var storedPatterns;
var positions = [];
var dragHandler = (position) => {
@@ -28,7 +13,20 @@ var dragHandler = (position) => {
debounce().then(() => {
log(positions.length);
- var circlesClone = cloneCirclesArray();
+ var CIRCLE_RADIUS = 25;
+ var CIRCLE_RADIUS_2 = CIRCLE_RADIUS * CIRCLE_RADIUS;
+
+ var circles = [
+ { x: 25, y: 25, i: 0 },
+ { x: 87, y: 25, i: 1 },
+ { x: 150, y: 25, i: 2 },
+ { x: 25, y: 87, i: 3 },
+ { x: 87, y: 87, i: 4 },
+ { x: 150, y: 87, i: 5 },
+ { x: 25, y: 150, i: 6 },
+ { x: 87, y: 150, i: 7 },
+ { x: 150, y: 150, i: 8 },
+ ];
var pattern = [];
var step = Math.floor(positions.length / 100) + 1;
@@ -38,92 +36,92 @@ var dragHandler = (position) => {
for (var i = 0; i < positions.length; i += step) {
p = positions[i];
- circle = circlesClone[0];
+ circle = circles[0];
if (circle) {
a = p.x - circle.x;
b = p.y - circle.y;
if (CIRCLE_RADIUS_2 - (a * a + b * b) >= 0) {
pattern.push(circle.i);
- circlesClone.splice(0, 1);
+ circles.splice(0, 1);
}
}
- circle = circlesClone[1];
+ circle = circles[1];
if (circle) {
a = p.x - circle.x;
b = p.y - circle.y;
if (CIRCLE_RADIUS_2 - (a * a + b * b) >= 0) {
pattern.push(circle.i);
- circlesClone.splice(1, 1);
+ circles.splice(1, 1);
}
}
- circle = circlesClone[2];
+ circle = circles[2];
if (circle) {
a = p.x - circle.x;
b = p.y - circle.y;
if (CIRCLE_RADIUS_2 - (a * a + b * b) >= 0) {
pattern.push(circle.i);
- circlesClone.splice(2, 1);
+ circles.splice(2, 1);
}
}
- circle = circlesClone[3];
+ circle = circles[3];
if (circle) {
a = p.x - circle.x;
b = p.y - circle.y;
if (CIRCLE_RADIUS_2 - (a * a + b * b) >= 0) {
pattern.push(circle.i);
- circlesClone.splice(3, 1);
+ circles.splice(3, 1);
}
}
- circle = circlesClone[4];
+ circle = circles[4];
if (circle) {
a = p.x - circle.x;
b = p.y - circle.y;
if (CIRCLE_RADIUS_2 - (a * a + b * b) >= 0) {
pattern.push(circle.i);
- circlesClone.splice(4, 1);
+ circles.splice(4, 1);
}
}
- circle = circlesClone[5];
+ circle = circles[5];
if (circle) {
a = p.x - circle.x;
b = p.y - circle.y;
if (CIRCLE_RADIUS_2 - (a * a + b * b) >= 0) {
pattern.push(circle.i);
- circlesClone.splice(5, 1);
+ circles.splice(5, 1);
}
}
- circle = circlesClone[6];
+ circle = circles[6];
if (circle) {
a = p.x - circle.x;
b = p.y - circle.y;
if (CIRCLE_RADIUS_2 - (a * a + b * b) >= 0) {
pattern.push(circle.i);
- circlesClone.splice(6, 1);
+ circles.splice(6, 1);
}
}
- circle = circlesClone[7];
+ circle = circles[7];
if (circle) {
a = p.x - circle.x;
b = p.y - circle.y;
if (CIRCLE_RADIUS_2 - (a * a + b * b) >= 0) {
pattern.push(circle.i);
- circlesClone.splice(7, 1);
+ circles.splice(7, 1);
}
}
- circle = circlesClone[8];
+ circle = circles[8];
if (circle) {
a = p.x - circle.x;
b = p.y - circle.y;
if (CIRCLE_RADIUS_2 - (a * a + b * b) >= 0) {
pattern.push(circle.i);
- circlesClone.splice(8, 1);
+ circles.splice(8, 1);
}
}
}
@@ -163,16 +161,6 @@ var debounce = (delay) => {
});
};
-var cloneCirclesArray = () => {
- var circlesClone = Array(CIRCLES.length);
-
- for (var i = 0; i < CIRCLES.length; i++) {
- circlesClone[i] = CIRCLES[i];
- }
-
- return circlesClone;
-};
-
(function () {
var sui = Bangle.setUI;
Bangle.setUI = function (mode, cb) {
diff --git a/apps/ptlaunch/main_menu.png b/apps/ptlaunch/main_menu.png
deleted file mode 100644
index a4ecebb0f..000000000
Binary files a/apps/ptlaunch/main_menu.png and /dev/null differ
diff --git a/apps/ptlaunch/main_menu_add.png b/apps/ptlaunch/main_menu_add.png
new file mode 100644
index 000000000..e9a5c52a9
Binary files /dev/null and b/apps/ptlaunch/main_menu_add.png differ
diff --git a/apps/ptlaunch/main_menu_manage.png b/apps/ptlaunch/main_menu_manage.png
new file mode 100644
index 000000000..a6aee1427
Binary files /dev/null and b/apps/ptlaunch/main_menu_manage.png differ
diff --git a/apps/ptlaunch/manage_patterns.png b/apps/ptlaunch/manage_patterns.png
new file mode 100644
index 000000000..82b10ad43
Binary files /dev/null and b/apps/ptlaunch/manage_patterns.png differ
diff --git a/apps/qmsched/ChangeLog b/apps/qmsched/ChangeLog
index 0b8d67e76..f41fe3416 100644
--- a/apps/qmsched/ChangeLog
+++ b/apps/qmsched/ChangeLog
@@ -2,3 +2,4 @@
0.02: Add widget
0.03: Bangle.js 2 support
0.04: Move Quiet Mode LCD options from global settings to this app
+0.05: Avoid immediately redrawing widgets on load
\ No newline at end of file
diff --git a/apps/qmsched/widget.js b/apps/qmsched/widget.js
index 8a8333ba5..b25192b06 100644
--- a/apps/qmsched/widget.js
+++ b/apps/qmsched/widget.js
@@ -1,32 +1,36 @@
-WIDGETS["qmsched"] = {
- area: "tl", width: 24, draw: function() {
- const mode = (require("Storage").readJSON("setting.json", 1) || {}).quiet|0;
- if (mode===0) { // Off
- if (this.width!==0) {
- this.width = 0;
- Bangle.drawWidgets();
+(function() {
+ WIDGETS["qmsched"] = {
+ area: "tl",
+ width: ((require("Storage").readJSON("setting.json", 1) || {}).quiet|0) ? 24 : 0,
+ draw: function() {
+ const mode = (require("Storage").readJSON("setting.json", 1) || {}).quiet|0;
+ if (mode===0) { // Off
+ if (this.width!==0) {
+ this.width = 0;
+ Bangle.drawWidgets();
+ }
+ return;
}
- return;
- }
- // not Off: make sure width is correct
- if (this.width!==24) {
- this.width = 24;
- Bangle.drawWidgets();
- return; // drawWidgets will call draw again
- }
- let x = this.x, y = this.y;
- g.clearRect(x, y, x+23, y+23);
- // quiet mode: draw red one-way-street sign (dim red on Bangle.js 1)
- x = this.x+11;y = this.y+11; // center of widget
- g.setColor(process.env.HWVERSION===2 ? 1 : 0.8, 0, 0).fillCircle(x, y, 8);
- g.setColor(g.theme.bg).fillRect(x-6, y-2, x+6, y+2);
- if (mode>1) {return;} // no alarms
- // alarms still on: draw alarm icon in bottom-right corner
- x = this.x+18;y = this.y+17; // center of alarm
- g.setColor(1, 1, 0)
- .fillCircle(x, y, 3) // alarm body
- .fillRect(x-5, y+2, x+5, y+3) // bottom ridge
- .fillRect(x-1, y-5, x+1, y+5).drawLine(x, y-6, x, y+6) // top+bottom
- .drawLine(x+5, y-3, x+3, y-5).drawLine(x-5, y-3, x-3, y-5); // wriggles
- },
-};
\ No newline at end of file
+ // not Off: make sure width is correct
+ if (this.width!==24) {
+ this.width = 24;
+ Bangle.drawWidgets();
+ return; // drawWidgets will call draw again
+ }
+ let x = this.x, y = this.y;
+ g.clearRect(x, y, x+23, y+23);
+ // quiet mode: draw red one-way-street sign (dim red on Bangle.js 1)
+ x = this.x+11;y = this.y+11; // center of widget
+ g.setColor(process.env.HWVERSION===2 ? 1 : 0.8, 0, 0).fillCircle(x, y, 8);
+ g.setColor(g.theme.bg).fillRect(x-6, y-2, x+6, y+2);
+ if (mode>1) {return;} // no alarms
+ // alarms still on: draw alarm icon in bottom-right corner
+ x = this.x+18;y = this.y+17; // center of alarm
+ g.setColor(1, 1, 0)
+ .fillCircle(x, y, 3) // alarm body
+ .fillRect(x-5, y+2, x+5, y+3) // bottom ridge
+ .fillRect(x-1, y-5, x+1, y+5).drawLine(x, y-6, x, y+6) // top+bottom
+ .drawLine(x+5, y-3, x+3, y-5).drawLine(x-5, y-3, x-3, y-5); // wriggles
+ },
+ };
+})();
\ No newline at end of file
diff --git a/apps/qrcode/ChangeLog b/apps/qrcode/ChangeLog
index 91121ac6e..edcc41cfd 100644
--- a/apps/qrcode/ChangeLog
+++ b/apps/qrcode/ChangeLog
@@ -1,3 +1,4 @@
0.01: New App!
0.02: Add posibillity to generate Wifi code.
0.03: Forces integer scaling and adds more configuration (error correction, description, display)
+0.04: Allow scanning of QR codes from camera or file
diff --git a/apps/qrcode/custom.html b/apps/qrcode/custom.html
index eb9906f57..4920be655 100644
--- a/apps/qrcode/custom.html
+++ b/apps/qrcode/custom.html
@@ -3,34 +3,71 @@
+ Datasource:
-
-
-
-
+
-
-
-