diff --git a/android.html b/android.html
index 9f75c4507..a0bc6075a 100644
--- a/android.html
+++ b/android.html
@@ -22,7 +22,7 @@
diff --git a/apps/.eslintrc.json b/apps/.eslintrc.json
index d5a4bf2a3..a2973e931 100644
--- a/apps/.eslintrc.json
+++ b/apps/.eslintrc.json
@@ -144,7 +144,7 @@
],
"no-constant-condition": "off",
"no-delete-var": "off",
- "no-empty": "off",
+ "no-empty": ["warn", { "allowEmptyCatch": true }],
"no-global-assign": "off",
"no-inner-declarations": "off",
"no-prototype-builtins": "off",
diff --git a/apps/a_dndtoggle/ChangeLog b/apps/a_dndtoggle/ChangeLog
index ec66c5568..2d760f914 100644
--- a/apps/a_dndtoggle/ChangeLog
+++ b/apps/a_dndtoggle/ChangeLog
@@ -1 +1,2 @@
0.01: Initial version
+0.02: Add settings page; Add line break to update message
\ No newline at end of file
diff --git a/apps/a_dndtoggle/README.md b/apps/a_dndtoggle/README.md
index bd0981c5b..c373bc872 100644
--- a/apps/a_dndtoggle/README.md
+++ b/apps/a_dndtoggle/README.md
@@ -1,10 +1,13 @@
# a_dndtoggle - Toggle Quiet Mode of the watch
When Quiet mode is off, just start this app to set quiet mode. Start it again to turn off quiet mode.
+
+Use the app settings to choose which quiet mode you prefer ("Alarms" or "Silent"). Default is "Silent".
+
Work in progress.
#ToDo
-Settings page, current status indicator.
+Current status indicator
## Creator
diff --git a/apps/a_dndtoggle/a_dndtoggle.app.js b/apps/a_dndtoggle/a_dndtoggle.app.js
index c0b968f2c..207034209 100644
--- a/apps/a_dndtoggle/a_dndtoggle.app.js
+++ b/apps/a_dndtoggle/a_dndtoggle.app.js
@@ -6,11 +6,14 @@ let current = 0|bSettings.quiet;
//1 alarms
//2 silent
+const dndSettings =
+ require('Storage').readJSON("a_dndtoggle.settings.json", true) || {};
+
console.log("old: " + current);
switch (current) {
case 0:
- bSettings.quiet = 2;
+ bSettings.quiet = dndSettings.mode || 2;
Bangle.buzz();
setTimeout('Bangle.buzz();',500);
break;
@@ -29,7 +32,7 @@ switch (current) {
console.log("new: " + bSettings.quiet);
-E.showMessage(modeNames[current] + " -> " + modeNames[bSettings.quiet]);
+E.showMessage(modeNames[current] + " -> \n" + modeNames[bSettings.quiet]);
setTimeout('exitApp();', 2000);
diff --git a/apps/a_dndtoggle/metadata.json b/apps/a_dndtoggle/metadata.json
index f5ae9cc31..62f0edae9 100644
--- a/apps/a_dndtoggle/metadata.json
+++ b/apps/a_dndtoggle/metadata.json
@@ -2,14 +2,18 @@
"id": "a_dndtoggle",
"name": "a_dndtoggle - Toggle Quiet Mode of the watch",
"shortName": "A_DND Toggle",
- "version": "0.01",
+ "version": "0.02",
"description": "Toggle Quiet Mode of the watch just by starting this app.",
"icon": "a_dndtoggle.png",
"type": "app",
"tags": "tool",
"supports": ["BANGLEJS","BANGLEJS2"],
+ "data" : [
+ {"name":"a_dndtoggle.settings.json"}
+ ],
"storage": [
{"name":"a_dndtoggle.app.js","url":"a_dndtoggle.app.js"},
+ {"name":"a_dndtoggle.settings.js","url":"settings.js"},
{"name":"a_dndtoggle.img","url":"app-icon.js","evaluate":true}
],
"readme": "README.md"
diff --git a/apps/a_dndtoggle/settings.js b/apps/a_dndtoggle/settings.js
new file mode 100644
index 000000000..5316525b3
--- /dev/null
+++ b/apps/a_dndtoggle/settings.js
@@ -0,0 +1,33 @@
+(function(back) {
+
+ const settings =
+ require('Storage').readJSON("a_dndtoggle.settings.json", true) || {};
+
+ function updateSettings() {
+ require('Storage').writeJSON("a_dndtoggle.settings.json", settings);
+ }
+
+ function buildMainMenu(){
+ // 0-Noisy is only a placeholder so that the other values map to the Bangle quiet mode options
+ const modes = [/*LANG*/"Noisy",/*LANG*/"Alarms",/*LANG*/"Silent"];
+ let mainmenu = {
+ '': { 'title': 'A_DND Toggle' },
+ '< Back': back,
+ /*LANG*/"Quiet Mode": {
+ value: settings.mode || 2,
+ min: 1, // don't allow choosing 0-Noisy
+ max: modes.length - 1,
+ format: v => modes[v],
+ onchange: v => {
+ settings.mode = v;
+ updateSettings();
+ }
+ }
+ };
+
+ return mainmenu;
+ }
+
+ E.showMenu(buildMainMenu());
+ });
+
\ No newline at end of file
diff --git a/apps/andark/app.js b/apps/andark/app.js
index efa00ce6f..865e3e708 100644
--- a/apps/andark/app.js
+++ b/apps/andark/app.js
@@ -104,7 +104,6 @@ Bangle.on('lcdPower',on=>{
if (on) {
secondInterval = setInterval(draw, 1000);
draw(); // draw immediately
- }else{
}
});
Bangle.on('lock',on=>{
diff --git a/apps/aptsciclk/ChangeLog b/apps/aptsciclk/ChangeLog
index ed32a45a2..19e7c9469 100644
--- a/apps/aptsciclk/ChangeLog
+++ b/apps/aptsciclk/ChangeLog
@@ -6,3 +6,4 @@
0.06: Formatting
0.07: Added potato GLaDOS and quote functionality when you tap her
0.08: Fixed drawing issues with the quotes and added more
+0.09: Minor code improvements
diff --git a/apps/aptsciclk/app.js b/apps/aptsciclk/app.js
index c2903cf37..f32a52870 100644
--- a/apps/aptsciclk/app.js
+++ b/apps/aptsciclk/app.js
@@ -270,8 +270,7 @@ function queueDraw() {
function draw() {
- if (pause){}
- else{
+ if (!pause){
// get date
var d = new Date();
var da = d.toString().split(" ");
diff --git a/apps/aptsciclk/metadata.json b/apps/aptsciclk/metadata.json
index 77e40f843..edc9704d2 100644
--- a/apps/aptsciclk/metadata.json
+++ b/apps/aptsciclk/metadata.json
@@ -2,7 +2,7 @@
"id": "aptsciclk",
"name": "Apeture Science Clock",
"shortName":"AptSci Clock",
- "version": "0.08",
+ "version": "0.09",
"description": "A clock based on the portal series",
"icon": "app.png",
"screenshots": [{"url":"screenshot.png"}],
diff --git a/apps/autoreset/ChangeLog b/apps/autoreset/ChangeLog
new file mode 100644
index 000000000..5560f00bc
--- /dev/null
+++ b/apps/autoreset/ChangeLog
@@ -0,0 +1 @@
+0.01: New App!
diff --git a/apps/autoreset/README.md b/apps/autoreset/README.md
new file mode 100644
index 000000000..965b2e291
--- /dev/null
+++ b/apps/autoreset/README.md
@@ -0,0 +1,21 @@
+# Auto Reset
+
+Sets a timeout to load the clock face. The timeout is stopped and started again upon user input.
+
+## Usage
+
+Install with app loader and Auto Reset will run in background. If you don't interact with the watch it will time out to the clock face after 10 minutes.
+
+## TODO
+
+- Add settings page
+ - set how many minutes the timeout should count down.
+ - whitelist/blacklist for apps.
+
+## Requests
+
+Mention @thyttan in an issue on the espruino/BangleApps repo for bug reports and feature requests.
+
+## Creator
+
+thyttan
diff --git a/apps/autoreset/app.png b/apps/autoreset/app.png
new file mode 100644
index 000000000..695c49931
Binary files /dev/null and b/apps/autoreset/app.png differ
diff --git a/apps/autoreset/boot.js b/apps/autoreset/boot.js
new file mode 100644
index 000000000..3302eca08
--- /dev/null
+++ b/apps/autoreset/boot.js
@@ -0,0 +1,20 @@
+{
+let timeoutAutoreset;
+let resetTimeoutAutoreset = (force)=>{
+ if (timeoutAutoreset) clearTimeout(timeoutAutoreset);
+ setTimeout(()=>{ // Short outer timeout to make sure we have time to leave clock face before checking `Bangle.CLOCK!=1`.
+ if (Bangle.CLOCK!=1) { // Only add timeout if not already on clock face.
+ timeoutAutoreset = setTimeout(()=>{
+ if (Bangle.CLOCK!=1) Bangle.showClock();
+ }, 10*60*1000);
+ }
+ },200);
+};
+
+Bangle.on('touch', resetTimeoutAutoreset);
+Bangle.on('swipe', resetTimeoutAutoreset);
+Bangle.on('message', resetTimeoutAutoreset);
+setWatch(resetTimeoutAutoreset, BTN, {repeat:true, edge:'rising'});
+
+if (Bangle.CLOCK!=1) resetTimeoutAutoreset();
+}
diff --git a/apps/autoreset/metadata.json b/apps/autoreset/metadata.json
new file mode 100644
index 000000000..ca35b4d7a
--- /dev/null
+++ b/apps/autoreset/metadata.json
@@ -0,0 +1,13 @@
+{ "id": "autoreset",
+ "name": "Auto Reset",
+ "version":"0.01",
+ "description": "Sets a timeout to load the clock face. The timeout is stopped and started again upon user input.",
+ "icon": "app.png",
+ "type": "bootloader",
+ "tags": "system",
+ "supports" : ["BANGLEJS2"],
+ "readme": "README.md",
+ "storage": [
+ {"name":"autoreset.boot.js","url":"boot.js"}
+ ]
+}
diff --git a/apps/binaryclk/ChangeLog b/apps/binaryclk/ChangeLog
index 7b6810faa..dd35cb918 100644
--- a/apps/binaryclk/ChangeLog
+++ b/apps/binaryclk/ChangeLog
@@ -1,3 +1,4 @@
0.01: Added app
0.02: Removed unneeded squares
-0.03: Added settings with fullscreen option
+0.03: Added setting for fullscreen option
+0.04: Added settings to hide unused squares and show date
diff --git a/apps/binaryclk/app.js b/apps/binaryclk/app.js
index 94c906104..7969fe301 100644
--- a/apps/binaryclk/app.js
+++ b/apps/binaryclk/app.js
@@ -1,11 +1,15 @@
var settings = Object.assign({
- fullscreen: false,
+ fullscreen: false,
+ hidesq: false,
+ showdate: false,
}, require('Storage').readJSON("binaryclk.json", true) || {});
function draw() {
+
var dt = new Date();
- var h = dt.getHours(), m = dt.getMinutes();
+ var h = dt.getHours(), m = dt.getMinutes(), d = dt.getDate();
const t = [];
+
t[0] = Math.floor(h/10);
t[1] = Math.floor(h%10);
t[2] = Math.floor(m/10);
@@ -17,25 +21,44 @@ function draw() {
let i = 0;
var gap = 8;
var mgn = 20;
+
if (settings.fullscreen) {
gap = 12;
mgn = 0;
}
+
const sq = 29;
var pos = sq + gap;
for (let r = 3; r >= 0; r--) {
for (let c = 0; c < 4; c++) {
if (t[c] & Math.pow(2, r)) {
- g.fillRect(mgn/2 + gap + c * pos, mgn + gap + i * pos, mgn/2 + gap + c * pos + sq, mgn + gap + i * pos + sq);
+ g.fillRect(Math.floor(mgn/2) + gap + c * pos, mgn + gap + i * pos, Math.floor(mgn/2) + gap + c * pos + sq, mgn + gap + i * pos + sq);
} else {
- g.drawRect(mgn/2 + gap + c * pos, mgn + gap + i * pos, mgn/2 + gap + c * pos + sq, mgn + gap + i * pos + sq);
+ g.drawRect(Math.floor(mgn/2) + gap + c * pos, mgn + gap + i * pos, Math.floor(mgn/2) + gap + c * pos + sq, mgn + gap + i * pos + sq);
}
}
i++;
}
- g.clearRect(mgn/2 + gap, mgn + gap, mgn/2 + gap + sq, mgn + 2 * gap + 2 * sq);
- g.clearRect(mgn/2 + 3 * gap + 2 * sq, mgn + gap, mgn/2 + 3 * gap + 3 * sq, mgn + gap + sq);
+
+ var c1sqhide = 0;
+ var c3sqhide = 0;
+
+ if (settings.hidesq) {
+ c1sqhide = 2;
+ c3sqhide = 1;
+ }
+
+ if (settings.hidesq) {
+ g.clearRect(Math.floor(mgn/2), mgn, Math.floor(mgn/2) + pos, mgn + c1sqhide * pos);
+ g.clearRect(Math.floor(mgn/2) + 2 * pos + gap, mgn, Math.floor(mgn/2) + 3 * pos, mgn + c3sqhide * pos);
+ }
+ if (settings.showdate) {
+ g.setFontAlign(0, 0);
+ g.setFont("Vector",20);
+ g.drawRect(Math.floor(mgn/2) + gap, mgn + gap, Math.floor(mgn/2) + gap + sq, mgn + gap + sq);
+ g.drawString(d, Math.ceil(mgn/2) + gap + Math.ceil(sq/2) + 1, mgn + gap + Math.ceil(sq/2) + 1);
+ }
}
g.clear();
diff --git a/apps/binaryclk/metadata.json b/apps/binaryclk/metadata.json
index b4ddc6544..b8489885a 100644
--- a/apps/binaryclk/metadata.json
+++ b/apps/binaryclk/metadata.json
@@ -1,8 +1,8 @@
{
"id": "binaryclk",
"name": "Bin Clock",
- "version": "0.03",
- "description": "Clock face to show binary time in 24 hr format",
+ "version": "0.04",
+ "description": "Clock face to show binary time in 24 hour format",
"icon": "app-icon.png",
"screenshots": [{"url":"screenshot.png"}],
"type": "clock",
diff --git a/apps/binaryclk/screenshot.png b/apps/binaryclk/screenshot.png
index 8b54ed66f..504a1926f 100644
Binary files a/apps/binaryclk/screenshot.png and b/apps/binaryclk/screenshot.png differ
diff --git a/apps/binaryclk/settings.js b/apps/binaryclk/settings.js
index 0ef30e19d..f7e8620de 100644
--- a/apps/binaryclk/settings.js
+++ b/apps/binaryclk/settings.js
@@ -2,6 +2,8 @@
var FILE = "binaryclk.json";
var settings = Object.assign({
fullscreen: false,
+ hidesq: false,
+ showdate: false,
}, require('Storage').readJSON(FILE, true) || {});
function writeSettings() {
@@ -16,7 +18,21 @@
onchange: v => {
settings.fullscreen = v;
writeSettings();
- }
+ },
+ },
+ 'Hide Squares': {
+ value: settings.hidesq,
+ onchange: v => {
+ settings.hidesq = v;
+ writeSettings();
+ },
+ },
+ 'Show Date': {
+ value: settings.showdate,
+ onchange: v => {
+ settings.showdate = v;
+ writeSettings();
+ },
},
});
})
diff --git a/apps/c25k/ChangeLog b/apps/c25k/ChangeLog
new file mode 100644
index 000000000..0e7594334
--- /dev/null
+++ b/apps/c25k/ChangeLog
@@ -0,0 +1,4 @@
+0.01: New App!
+0.02: Add rep info to time screen
+0.03: Add option to pause/resume workout (Bangle.js 1 only)
+0.04: Add possibility of creating a custom exercise
diff --git a/apps/c25k/README.md b/apps/c25k/README.md
new file mode 100644
index 000000000..8237199d5
--- /dev/null
+++ b/apps/c25k/README.md
@@ -0,0 +1,96 @@
+# C25K
+
+Unofficial app for the Couch to 5k training plan.
+From being a couch-potato to running 5k in 8 weeks!
+
+Each week has 3 training days, ideally with rest days between them.
+
+Each day's programme consists of running for a certain time with occasional walking/resting phases.
+When walking is part of the programme, the (run+walk) stages are repeated a number of times.
+
+
+
+
+
+## Features
+
+- Show remaining time in seconds for each phase
+- Vibrates on phase changes
+- Keeps screen on to allow quickly glancing at the time while running
+- Shows time on button press
+
+## Usage
+
+If you know the week and day of the programme you'd like to start, set `Week` and `Day` to the appropriate values in the main menu and press `Start`.
+
+**Example**:
+To start the programme of the **second day** of **week 4**:
+
+
+---
+
+Alternatively, you can go to the `View plan` menu to look at all the programmes and select the one you'd like to start.
+
+**Example**:
+Go to the `View plan` menu:
+
+
+Select the programme to start it:
+
+
+---
+
+The format of the `View menu` is `w{week}d{day}(r:{run mins}|w:{walk mins}|x{number of reps})`.
+
+For example `w6d1(r:6|w:3|x2)` means:
+`it's the programme of day 1 on week 6`,
+`it consists of running for 6 minutes`,
+`followed by walking for 3`,
+`done 2 times back to back`.
+
+---
+
+### Create a custom excercise
+
+Under the `Custom run` menu, it's possible to create a custom excercise.
+
+
+Some important details/limitations:
+
+- To disable walking: set `walk` to `0`
+- When walking is set to `0`, the repetition count is set to `1`.
+- When repetition is set to `2` or higher, `walk` is set to `1`.
+
+**Unfortunately, the value in the menu do not update to reflect the changes, so I recommend setting the values with the rules above in mind.**
+
+---
+
+### Show extra info:
+
+If you ever need to peek at the time, just press the middle (or only) physical button on the watch:
+
+
+This view also shows `current rep / total reps` at the top.
+
+---
+
+### Pause/resume workout:
+
+**This is currently only available on Bangle.js 1.**
+
+Press the top button to pause or to resume the active programme:
+
+
+---
+
+## Disclaimer
+
+This app was hacked together in a day with no JS knowledge.
+It's probably inefficient and buggy, but it does what I needed it to do: allow me to follow the C25K programme without a phone.
+
+The app was designed with a Bangle.js 1 in mind, as that's the one I have.
+It *should* work fine on the Bangle.js 2, but I couldn't test it on real hardware.
+
+---
+
+Made with <3 by [Erovia](https://github.com/Erovia/BangleApps/tree/c25k)
diff --git a/apps/c25k/app-icon.js b/apps/c25k/app-icon.js
new file mode 100644
index 000000000..6b85dbf29
--- /dev/null
+++ b/apps/c25k/app-icon.js
@@ -0,0 +1 @@
+require("heatshrink").decompress(atob("mEw4X/AoPk9G9gsj14lZhWq0AEBgtVqALmhQJBAQMFBIICCBc4ADBQYLnAQQKEBcibETQIABHggLiAEQqEh/wgACCBcpXDBAIKDBcqJDh//BQYLkHwg7GBcY7FU5ALgAEQA="))
diff --git a/apps/c25k/app.js b/apps/c25k/app.js
new file mode 100644
index 000000000..eed918e46
--- /dev/null
+++ b/apps/c25k/app.js
@@ -0,0 +1,290 @@
+var week = 1; // Stock plan: programme week
+var day = 1; // Stock plan: programe day
+var run = 1; // Custom plan: running time
+var walk = 0; // Custom plan: walking time
+var reps = 1; // Custom plan: repetition count
+
+var time; // To store the date
+
+var loop; // To store how many times we will have to do a countdown
+var rep; // The current rep counter
+var counter; // The seconds counter
+var currentMode; // Either "run" or "walk"
+var mainInterval; // Ticks every second, checking if a new countdown is needed
+var activityInterval; // Ticks every second, doing the countdown
+var extraInfoWatch; // Watch for button presses to show additional info
+var paused = false; // Track pause state
+var pauseOrResumeWatch; // Watch for button presses to pause/resume countdown
+var defaultFontSize = (process.env.HWVERSION == 2) ? 7 : 9; // Default font size, Banglejs 2 has smaller
+var activityBgColour; // Background colour of current activity
+var currentActivity; // To store the current activity
+
+function outOfTime() {
+ buzz();
+
+ // Once we're done
+ if (loop == 0) {
+ clearWatch(extraInfoWatch); // Don't watch for button presses anymore
+ if (pauseOrResumeWatch) clearWatch(pauseOrResumeWatch); // Don't watch for button presses anymore
+ g.setBgColor("#75C0E0"); // Blue background for the "Done" text
+ drawText("Done", defaultFontSize); // Write "Done" to screen
+ g.reset();
+ setTimeout(E.showMenu, 5000, mainmenu); // Show the main menu again after 5secs
+ clearInterval(mainInterval); // Stop the main interval from starting a new activity
+ mainInterval = undefined;
+ currentMode = undefined;
+ }
+}
+
+// Buzz 3 times on state transitions
+function buzz() {
+ Bangle.buzz(500)
+ .then(() => new Promise(resolve => setTimeout(resolve, 200)))
+ .then(() => Bangle.buzz(500))
+ .then(() => new Promise(resolve => setTimeout(resolve, 200)))
+ .then(() => Bangle.buzz(500));
+}
+
+function drawText(text, size){
+ g.clear();
+ g.setFontAlign(0, 0); // center font
+ g.setFont("6x8", size);
+ g.drawString(text, g.getWidth() / 2, g.getHeight() / 2);
+}
+
+function countDown() {
+ if (!paused) {
+ var text = "";
+ var size = defaultFontSize;
+ if (time) {
+ var total = ("walk" in currentActivity) ? currentActivity.repetition : 1;
+ text += rep + "/" + total + "\n"; // Show the current/total rep count when time is shown
+ size -= 2; // Use smaller font size to fit everything nicely on the screen
+ }
+ text += (currentMode === "run") ? "Run\n" + counter : "Walk\n" + counter; // Switches output text
+ if (time) text += "\n" + time;
+ drawText(text, size); // draw the current mode and seconds
+ Bangle.setLCDPower(1); // keep the watch LCD lit up
+
+ counter--; // Reduce the seconds
+
+ // If the current activity is done
+ if (counter < 0) {
+ clearInterval(activityInterval);
+ activityInterval = undefined;
+ outOfTime();
+ return;
+ }
+ }
+}
+
+function startTimer() {
+ // If something is already running, do nothing
+ if (activityInterval) return;
+
+ // Switches between the two modes
+ if (!currentMode || currentMode === "walk") {
+ currentMode = "run";
+ rep++; // Increase the rep counter every time a "run" activity starts
+ counter = currentActivity.run * 60;
+ activityBgColour = "#ff5733"; // Red background for running
+ }
+ else {
+ currentMode = "walk";
+ counter = currentActivity.walk * 60;
+ activityBgColour = "#4da80a"; // Green background for walking
+
+ }
+
+ g.setBgColor(activityBgColour);
+ countDown();
+ if (!activityInterval) {
+ loop--; // Reduce the number of iterations
+ activityInterval = setInterval(countDown, 1000); // Start a new activity
+ }
+}
+
+function showTime() {
+ if (time) return; // If clock is already shown, don't do anything even if the button was pressed again
+ // Get the time and format it with a leading 0 if necessary
+ var d = new Date();
+ var h = d.getHours();
+ var m = d.getMinutes();
+ time = h + ":" + m.toString().padStart(2, 0);
+ setTimeout(function() { time = undefined; }, 5000); // Hide clock after 5secs
+}
+
+// Populate the PLAN menu
+function populatePlan() {
+ for (var i = 0; i < PLAN.length; i++) {
+ for (var j = 0; j < PLAN[i].length; j++) {
+ // Ever line will have the following format:
+ // w{week}d{day}(r:{run mins}|w:{walk mins}|x{number of reps})
+ var name = "w" + (i + 1) + "d" + (j + 1);
+ if (process.env.HWVERSION == 2) name += "\n"; // Print in 2 lines to accomodate the Bangle.js 2 screen
+ name += "(r:" + PLAN[i][j].run;
+ if ("walk" in PLAN[i][j]) name += "|w:" + PLAN[i][j].walk;
+ if ("repetition" in PLAN[i][j]) name += "|x" + PLAN[i][j].repetition;
+ name += ")";
+ // Each menu item will have a function that start the program at the selected day
+ planmenu[name] = getFunc(i, j);
+ }
+ }
+}
+
+// Helper function to generate functions for the activePlan menu
+function getFunc(i, j) {
+ return function() {
+ currentActivity = PLAN[i][j];
+ startActivity();
+ };
+}
+
+function startActivity() {
+ loop = ("walk" in currentActivity) ? currentActivity.repetition * 2 : 1;
+ rep = 0;
+
+ E.showMenu(); // Hide the main menu
+ extraInfoWatch = setWatch(showTime, (process.env.HWVERSION == 2) ? BTN1 : BTN2, {repeat: true}); // Show the clock on button press
+ if (process.env.HWVERSION == 1) pauseOrResumeWatch = setWatch(pauseOrResumeActivity, BTN1, {repeat: true}); // Pause or resume on button press (Bangle.js 1 only)
+ buzz();
+ mainInterval = setInterval(function() {startTimer();}, 1000); // Check every second if we need to do something
+}
+
+// Pause or resume current activity
+function pauseOrResumeActivity() {
+ paused = !paused;
+ buzz();
+ if (paused) {
+ g.setBgColor("#fdd835"); // Yellow background for pause screen
+ drawText("Paused", (process.env.HWVERSION == 2) ? defaultFontSize - 3 : defaultFontSize - 2); // Although the font size is configured here, this feature does not work on Bangle.js 2 as the only physical button is tied to the extra info screen already
+ }
+ else {
+ g.setBgColor(activityBgColour);
+ }
+}
+
+const PLAN = [
+ [
+ {"run": 1, "walk": 1.5, "repetition": 8},
+ {"run": 1, "walk": 1.5, "repetition": 8},
+ {"run": 1, "walk": 1.5, "repetition": 8},
+ ],
+ [
+ {"run": 1.5, "walk": 2, "repetition": 6},
+ {"run": 1.5, "walk": 2, "repetition": 6},
+ {"run": 1.5, "walk": 2, "repetition": 6},
+ ],
+ [
+ {"run": 2, "walk": 2, "repetition": 5},
+ {"run": 2.5, "walk": 2.5, "repetition": 4},
+ {"run": 2.5, "walk": 2.5, "repetition": 4},
+ ],
+ [
+ {"run": 3, "walk": 2, "repetition": 5},
+ {"run": 3, "walk": 2, "repetition": 5},
+ {"run": 4, "walk": 2.5, "repetition": 3},
+ ],
+ [
+ {"run": 5, "walk": 2, "repetition": 3},
+ {"run": 8, "walk": 5, "repetition": 2},
+ {"run": 20},
+ ],
+ [
+ {"run": 6, "walk": 3, "repetition": 2},
+ {"run": 10, "walk": 3, "repetition": 2},
+ {"run": 25},
+ ],
+ [
+ {"run": 25},
+ {"run": 25},
+ {"run": 25},
+ ],
+ [
+ {"run": 30},
+ {"run": 30},
+ {"run": 30},
+ ],
+];
+
+var customRun = {"run": 1};
+
+// Main menu
+var mainmenu = {
+ "": { "title": "-- C25K --" },
+ "Week": {
+ value: week,
+ min: 1, max: PLAN.length, step: 1,
+ onchange : v => { week = v; }
+ },
+ "Day": {
+ value: day,
+ min: 1, max: 3, step: 1,
+ onchange: v => { day = v; }
+ },
+ "View plan": function() { E.showMenu(planmenu); },
+ "Custom run": function() { E.showMenu(custommenu); },
+ "Start": function() {
+ currentActivity = PLAN[week - 1][day -1];
+ startActivity();
+ },
+ "Exit": function() { load(); },
+};
+
+// Plan view
+var planmenu = {
+ "": { title: "-- Plan --" },
+ "< Back": function() { E.showMenu(mainmenu);},
+};
+
+// Custom view
+var custommenu = {
+ "": { title : "-- Cust. run --" },
+ "< Back": function() { E.showMenu(mainmenu);},
+ "Run (mins)": {
+ value: run,
+ min: 1, max: 150, step: 1,
+ wrap: true,
+ onchange: v => { customRun.run = v; }
+ },
+ "Walk (mins)": {
+ value: walk,
+ min: 0, max: 10, step: 1,
+ onchange: v => {
+ if (v > 0) {
+ if (reps == 1) { reps = 2; } // Walking only makes sense with multiple reps
+ customRun.repetition = reps;
+ customRun.walk = v;
+ }
+ else {
+ // If no walking, delete both the reps and walk data
+ delete customRun.repetition;
+ delete customRun.walk;
+ }
+ walk = v;
+ }
+ },
+ "Reps": {
+ value: reps,
+ min: 1, max: 10, step: 1,
+ onchange: v => {
+ if (v > 1) {
+ if (walk == 0) { walk = 1; } // Multiple reps only make sense with walking phases
+ customRun.walk = walk;
+ customRun.repetition = v;
+ }
+ else {
+ // If no multiple reps, delete both the reps and walk data
+ delete customRun.repetition;
+ delete customRun.walk;
+ }
+ reps = v;
+ }
+ },
+ "Start": function() { currentActivity = customRun; startActivity(); }
+};
+
+// Populate the activePlan menu view
+populatePlan();
+// Actually display the menu
+E.showMenu(mainmenu);
diff --git a/apps/c25k/app.png b/apps/c25k/app.png
new file mode 100644
index 000000000..6b3a9ba95
Binary files /dev/null and b/apps/c25k/app.png differ
diff --git a/apps/c25k/c25k-scrn1.png b/apps/c25k/c25k-scrn1.png
new file mode 100644
index 000000000..c4d9ea24b
Binary files /dev/null and b/apps/c25k/c25k-scrn1.png differ
diff --git a/apps/c25k/c25k-scrn2.png b/apps/c25k/c25k-scrn2.png
new file mode 100644
index 000000000..ba064200e
Binary files /dev/null and b/apps/c25k/c25k-scrn2.png differ
diff --git a/apps/c25k/c25k-scrn3.png b/apps/c25k/c25k-scrn3.png
new file mode 100644
index 000000000..6901abf31
Binary files /dev/null and b/apps/c25k/c25k-scrn3.png differ
diff --git a/apps/c25k/c25k-scrn4.png b/apps/c25k/c25k-scrn4.png
new file mode 100644
index 000000000..ad64da947
Binary files /dev/null and b/apps/c25k/c25k-scrn4.png differ
diff --git a/apps/c25k/c25k-scrn5.png b/apps/c25k/c25k-scrn5.png
new file mode 100644
index 000000000..ca32abdfa
Binary files /dev/null and b/apps/c25k/c25k-scrn5.png differ
diff --git a/apps/c25k/c25k-scrn6.png b/apps/c25k/c25k-scrn6.png
new file mode 100644
index 000000000..53f5221d7
Binary files /dev/null and b/apps/c25k/c25k-scrn6.png differ
diff --git a/apps/c25k/c25k-scrn7.png b/apps/c25k/c25k-scrn7.png
new file mode 100644
index 000000000..407afd48b
Binary files /dev/null and b/apps/c25k/c25k-scrn7.png differ
diff --git a/apps/c25k/c25k-scrn8.png b/apps/c25k/c25k-scrn8.png
new file mode 100644
index 000000000..1cd92d876
Binary files /dev/null and b/apps/c25k/c25k-scrn8.png differ
diff --git a/apps/c25k/c25k-scrn9.png b/apps/c25k/c25k-scrn9.png
new file mode 100644
index 000000000..53dbaad1f
Binary files /dev/null and b/apps/c25k/c25k-scrn9.png differ
diff --git a/apps/c25k/metadata.json b/apps/c25k/metadata.json
new file mode 100644
index 000000000..876926a0c
--- /dev/null
+++ b/apps/c25k/metadata.json
@@ -0,0 +1,30 @@
+{
+ "id": "c25k",
+ "name": "C25K",
+ "icon": "app.png",
+ "version":"0.04",
+ "description": "Unofficial app for the Couch to 5k training plan",
+ "readme": "README.md",
+ "type": "app",
+ "tags": "running,c25k,tool,outdoors,exercise",
+ "allow_emulator": true,
+ "supports": [
+ "BANGLEJS",
+ "BANGLEJS2"
+ ],
+ "storage": [
+ {"name": "c25k.app.js", "url": "app.js"},
+ {"name": "c25k.img", "url": "app-icon.js", "evaluate": true}
+ ],
+ "screenshots": [
+ {"url": "c25k-scrn1.png"},
+ {"url": "c25k-scrn2.png"},
+ {"url": "c25k-scrn3.png"},
+ {"url": "c25k-scrn4.png"},
+ {"url": "c25k-scrn5.png"},
+ {"url": "c25k-scrn6.png"},
+ {"url": "c25k-scrn7.png"},
+ {"url": "c25k-scrn8.png"},
+ {"url": "c25k-scrn9.png"}
+ ]
+}
diff --git a/apps/carcrazy/ChangeLog b/apps/carcrazy/ChangeLog
index f697617b4..f4fd9ab7b 100644
--- a/apps/carcrazy/ChangeLog
+++ b/apps/carcrazy/ChangeLog
@@ -1,3 +1,4 @@
0.01: Car Crazy is now avialable for testing in beta!
0.02: 10 Levels are now added making the game harder as it goes along. Some of the levels include multiple cars and faster cars. More levels coming soon.
0.03: Settings are now added so that you can reset your high score.
+0.04: Minor code improvements.
diff --git a/apps/carcrazy/app.js b/apps/carcrazy/app.js
index 0fb765871..2bb9932a7 100644
--- a/apps/carcrazy/app.js
+++ b/apps/carcrazy/app.js
@@ -66,10 +66,8 @@ function moveEnemyPosition(){
enemyPositonCenterX2 = 120;
}else if((randomRoadPositionIndicator2 == 3)){
enemyPositonCenterX2 = 155;
- }else if(level == 7||level == 8){
-
}
- }
+ } // TODO: else if(level == 7)
}
function collision(){
diff --git a/apps/carcrazy/metadata.json b/apps/carcrazy/metadata.json
index 3898de962..4a1b359c8 100644
--- a/apps/carcrazy/metadata.json
+++ b/apps/carcrazy/metadata.json
@@ -2,7 +2,7 @@
"id": "carcrazy",
"name": "Car Crazy",
"shortName": "Car Crazy",
- "version": "0.03",
+ "version": "0.04",
"description": "A simple car game where you try to avoid the other cars by tilting your wrist left and right. Hold down button 2 to start.",
"icon": "carcrash.png",
"tags": "game",
diff --git a/apps/cards/ChangeLog b/apps/cards/ChangeLog
index 24c1bf8ff..84dc1e8c7 100644
--- a/apps/cards/ChangeLog
+++ b/apps/cards/ChangeLog
@@ -1,2 +1,3 @@
0.01: Simple app to display loyalty cards
0.02: Hiding widgets while showing the code
+0.03: Added option to use max brightness when showing code
diff --git a/apps/cards/app.js b/apps/cards/app.js
index 33b4c9e15..79b6cc497 100644
--- a/apps/cards/app.js
+++ b/apps/cards/app.js
@@ -14,6 +14,14 @@
Bangle.loadWidgets();
Bangle.drawWidgets();
+// get brightness
+let brightness;
+
+function loadBrightness() {
+ const getBrightness = require('Storage').readJSON("setting.json", 1) || {};
+ brightness = getBrightness.brightness || 0.1;
+}
+
//may make it configurable in the future
const WHITE=-1
const BLACK=0
@@ -89,6 +97,10 @@ function printLinearCode(binary) {
}
function showCode(card) {
+ // set to full bright when the setting is true
+ if(settings.fullBrightness) {
+ Bangle.setLCDBrightness(1);
+ }
widget_utils.hide();
E.showScroller();
// keeping it on rising edge would come back twice..
@@ -129,6 +141,10 @@ function showCode(card) {
}
function showCard(card) {
+ // reset brightness to old value after maxing it out
+ if(settings.fullBrightness) {
+ Bangle.setLCDBrightness(brightness);
+ }
var lines = [];
var bodyFont = fontBig;
if(!card) return;
@@ -208,4 +224,7 @@ function showList() {
back : () => load()
});
}
+if(settings.fullBrightness) {
+ loadBrightness();
+}
showList();
diff --git a/apps/cards/metadata.json b/apps/cards/metadata.json
index 810741d5f..74bfaa2b3 100644
--- a/apps/cards/metadata.json
+++ b/apps/cards/metadata.json
@@ -1,7 +1,7 @@
{
"id": "cards",
"name": "Cards",
- "version": "0.02",
+ "version": "0.03",
"description": "Display loyalty cards",
"icon": "app.png",
"screenshots": [{"url":"screenshot_cards_overview.png"}, {"url":"screenshot_cards_card1.png"}, {"url":"screenshot_cards_card2.png"}, {"url":"screenshot_cards_barcode.png"}, {"url":"screenshot_cards_qrcode.png"}],
diff --git a/apps/cards/settings.js b/apps/cards/settings.js
index db0ab56de..451b02204 100644
--- a/apps/cards/settings.js
+++ b/apps/cards/settings.js
@@ -14,6 +14,13 @@
updateSettings();
}
},
+ /*LANG*/"Full Brightness" : {
+ value : !!settings.fullBrightness,
+ onchange: v => {
+ settings.fullBrightness = v;
+ updateSettings();
+ }
+ }
};
E.showMenu(mainmenu);
})
diff --git a/apps/cscsensor/ChangeLog b/apps/cscsensor/ChangeLog
index 5264e8d42..c01b35503 100644
--- a/apps/cscsensor/ChangeLog
+++ b/apps/cscsensor/ChangeLog
@@ -7,3 +7,4 @@
Improve connection code
0.07: Make Bangle.js 2 compatible
0.08: Convert Yes/No On/Off in settings to checkboxes
+0.09: Automatically reconnect on error
diff --git a/apps/cscsensor/cscsensor.app.js b/apps/cscsensor/cscsensor.app.js
index 4ebe7d57e..1ad7a9e98 100644
--- a/apps/cscsensor/cscsensor.app.js
+++ b/apps/cscsensor/cscsensor.app.js
@@ -226,7 +226,7 @@ function getSensorBatteryLevel(gatt) {
function connection_setup() {
mySensor.screenInit = true;
E.showMessage("Scanning for CSC sensor...");
- NRF.requestDevice({ filters: [{services:["1816"]}]}).then(function(d) {
+ NRF.requestDevice({ filters: [{services:["1816"]}], maxInterval: 100}).then(function(d) {
device = d;
E.showMessage("Found device");
return device.gatt.connect();
@@ -249,6 +249,7 @@ function connection_setup() {
}).catch(function(e) {
E.showMessage(e.toString(), "ERROR");
console.log(e);
+ setTimeout(connection_setup, 1000);
});
}
diff --git a/apps/cscsensor/metadata.json b/apps/cscsensor/metadata.json
index d7c3add53..5d70251da 100644
--- a/apps/cscsensor/metadata.json
+++ b/apps/cscsensor/metadata.json
@@ -2,7 +2,7 @@
"id": "cscsensor",
"name": "Cycling speed sensor",
"shortName": "CSCSensor",
- "version": "0.08",
+ "version": "0.09",
"description": "Read BLE enabled cycling speed and cadence sensor and display readings on watch",
"icon": "icons8-cycling-48.png",
"tags": "outdoors,exercise,ble,bluetooth,bike,cycle,bicycle",
diff --git a/apps/doztime/ChangeLog b/apps/doztime/ChangeLog
index 77d82eff9..c3701b6d8 100644
--- a/apps/doztime/ChangeLog
+++ b/apps/doztime/ChangeLog
@@ -5,3 +5,4 @@
0.05: extraneous comments and code removed
display improved
now supports Adjust Clock widget, if installed
+0.06: minor code improvements
diff --git a/apps/doztime/app-bangle1.js b/apps/doztime/app-bangle1.js
index 38c5acbac..3042e9367 100644
--- a/apps/doztime/app-bangle1.js
+++ b/apps/doztime/app-bangle1.js
@@ -223,9 +223,8 @@ function fixTime() {
Bangle.on("GPS",function cb(g) {
Bangle.setGPSPower(0,"time");
Bangle.removeListener("GPS",cb);
- if (!g.time || (g.time.getFullYear()<2000) ||
- (g.time.getFullYear()>2200)) {
- } else {
+ if (g.time && (g.time.getFullYear()>=2000) &&
+ (g.time.getFullYear()<=2200)) {
// We have a GPS time. Set time
setTime(g.time.getTime()/1000);
}
diff --git a/apps/doztime/metadata.json b/apps/doztime/metadata.json
index a05bf1470..83be15724 100644
--- a/apps/doztime/metadata.json
+++ b/apps/doztime/metadata.json
@@ -2,7 +2,7 @@
"id": "doztime",
"name": "Dozenal Digital Time",
"shortName": "Dozenal Digital",
- "version": "0.05",
+ "version": "0.06",
"description": "A dozenal Holocene calendar and dozenal diurnal digital clock",
"icon": "app.png",
"type": "clock",
diff --git a/apps/fallout_clock/.gitignore b/apps/fallout_clock/.gitignore
new file mode 100644
index 000000000..e5f9ba937
--- /dev/null
+++ b/apps/fallout_clock/.gitignore
@@ -0,0 +1,7 @@
+node_modules/
+res/
+
+fallout_clock.code-workspace
+
+package.json
+package-lock.json
diff --git a/apps/fallout_clock/ChangeLog b/apps/fallout_clock/ChangeLog
new file mode 100644
index 000000000..ee9876b1a
--- /dev/null
+++ b/apps/fallout_clock/ChangeLog
@@ -0,0 +1,5 @@
+0.10: (20240125) Basic Working Clock.
+0.11: (20240125) Widgets Added. Improved Interval Loop.
+0.12: (20240221) Fix: Month Reporting Wrong.
+0.20: (20240223) Created as a Package.
+0.21: (20240223) Added StandardJS and NPM.
diff --git a/apps/fallout_clock/LICENSE b/apps/fallout_clock/LICENSE
new file mode 100644
index 000000000..d9d472761
--- /dev/null
+++ b/apps/fallout_clock/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2024 Zachary D. Skelton
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/apps/fallout_clock/README.md b/apps/fallout_clock/README.md
new file mode 100644
index 000000000..b48e7e762
--- /dev/null
+++ b/apps/fallout_clock/README.md
@@ -0,0 +1,29 @@
+# Fallout Clock
+
+Inspired by the aesthetic of the Fallout series, this clock face looks to emulate the color and feel of a PipBoy.
+
+
+
+## Usage
+
+You can also go into Settings, and choose it as the default clock under **Select Clock**.
+
+## Planned Features:
+- Display Steps as Health
+- Display Heartrate
+- Brighter Color when the backlight is not on.
+- Configurable Settings
+
+## Controls
+
+Zero Settings, Zero Configuration. Install and add as your clockface.
+
+## Requests
+
+To request new features, add [an issue](https://github.com/zskelton/fallout_clock/issues).
+
+## Creator
+
+Zachary D. Skelton \
+[Skelton Networks](https://skeltonnetworks.com)\
+[Github](https://github.com/zskelton)
\ No newline at end of file
diff --git a/apps/fallout_clock/app-icon.js b/apps/fallout_clock/app-icon.js
new file mode 100644
index 000000000..c84c6fb48
--- /dev/null
+++ b/apps/fallout_clock/app-icon.js
@@ -0,0 +1 @@
+atob("MDDDAb88//9u/1r/1/YZrgAAit4kkkkkkkkkkAAVIkkkkkkkkkkkkkkkkkkAAAARJJIkkkkkkkkkkkkkkkAAAACJJJJUkkkkkkkkkkkkkAAAAARJJJJAAkkkkkkkkkkkAAAAACpJJJKgAAkkkkkkkkkgAAAAAVJJJJIAAAEkkkkkkkkAAAAACpJfpJUAAAAkkkkkkkgAAAAABJf/9JAAAAAEkkkkkkAAAAAARJdf/+gAAAAAkkkkkgAAAAAC//dL//gAAAAAEkkkkAAAAYADpJJL//8AAAAAAkkkkAAAD8AdJJJL///gAAAAAkkkgAAADr/pJJL////0AAAAAEkkgAAABJJL/pfb////gAAAAAkkAAAADpJeu22X////4AAAAAkkAAAADpL1tttuf/7f8AAAAAkgAAAAb/+ttttuSSS7/AAAAAEgAAAAdeyttttySSSb/gAAAAEgAAAC9eWtttuaySSf/2SSSSkgAAAVfxtttttyySX//9JJJQAAAAAJetttttttyST//9JJJUAAAABJeOaNyNutySW//9JJKgAAAARJdu6N1tvRySS3/JJJUAAAACJJVuVu1tzRyST2/JJKAAAAAVJL1ttyttuNuSWW7pJKgAAACpJLxtt6NtttuSS27pJUAAAAVJJLxtt6ttttuSWT9JKgAAAAJJJLxttzNtttuSST9JIAAAAiJJJL1ttttt2NuSSS9JUAAAA2222212xtty3RySSS9KgAAAEgAAAAZ6OW2tu1ySST9QAAAAEgAAAAaW1ttu2VySSXKAAAAAEkAAAACtu221ttySbdKgAAAAEkAAAADNty1ttuST9JUAAAAAkkAAAAAVty1ttuSXpKAAAAAAkkgAAAACtttttyT9JIAAAAAEkkkAAAAARttttyfdJUAAAAAEkkkAAAAACtttuSzJKgAAAAAkkkkgAAAAAWtuSSfpQAAAAAEkkkkkAAAAADa2yT9JAAAAAAkkkkkkgAAAAD7e3/pKgAAAAAkkkkkkkAAAAVL/9JJUAAAAAEkkkkkkkgAAARJJJJKAAAAAEkkkkkkkkkAAAJJJJJIAAAAAkkkkkkkkkkkACpJJJJUAAAAEkkkkkkkkkkkgCJJJJKgAAAEkkkkkkkkkkkkklJJJJQAAAEkkkkkkkkkkkkkkkkpJJAAEkkkkkkkkk=")
diff --git a/apps/fallout_clock/clock.js b/apps/fallout_clock/clock.js
new file mode 100644
index 000000000..56bb68a3a
--- /dev/null
+++ b/apps/fallout_clock/clock.js
@@ -0,0 +1,141 @@
+/* global Bangle, Graphics, g */
+
+// NAME: Fallout Clock (Bangle.js 2)
+// DOCS: https://www.espruino.com/ReferenceBANGLEJS2
+// AUTHOR: Zachary D. Skelton
+// VERSION: 0.1.0 (24JAN2024) - Creating [ Maj.Min.Bug ] REF: https://semver.org/
+// LICENSE: MIT License (2024) [ https://opensource.org/licenses/MIT ]
+
+/* THEME COLORS */
+// Dark Full - #000000 - (0,0.00,0)
+// Dark Half - #002f00 - (0,0.18,0)
+// Dark Zero - #005f00 - (0,0.37,0)
+// Light Zero - #008e00 - (0,0.55,0)
+// Light Half - #00bf00 - (0,0.75,0)
+// Light Full - #00ee00 - (0,0.93,0)
+
+/* FONTS */
+// Font: Good Time Rg - https://www.dafont.com/good-times.font
+// Large = 50px
+Graphics.prototype.setLargeFont = function () {
+ this.setFontCustom(
+ atob('AAAAAAAAAAAAAAAAAAAAAABAAAAAAAB8AAAAAAA/gAAAAAAP4AAAAAAD+AAAAAAA/gAAAAAAP4AAAAAAB8AAAAAAAGAAAAAAAAAAAAAAAAAAAAAAAADAAAAAAADwAAAAAAD8AAAAAAD/AAAAAAD/wAAAAAD/8AAAAAH/8AAAAAH/8AAAAAH/4AAAAAH/4AAAAAH/4AAAAAH/4AAAAAP/4AAAAAP/wAAAAAP/wAAAAAP/wAAAAAP/wAAAAAH/wAAAAAB/wAAAAAAfgAAAAAAHgAAAAAABgAAAAAAAAAAAAAAAAAAOAAAAAAB//AAAAAB//8AAAAB///wAAAA////AAAAf///4AAAP////AAAH////4AAD/+B//AAB/8AD/wAAf8AAP+AAP+AAB/gAD/AAAP8AA/gAAB/AAf4AAAf4AH8AAAD+AB/AAAA/gAfwAAAP4AH8AAAD+AB/AAAA/gAfwAAAP4AH8AAAD+AB/AAAA/gAfwAAAP4AH8AAAD+AB/gAAB/gAP4AAAfwAD/AAAP8AA/4AAH+AAH/AAD/gAB/8AD/wAAP/4H/8AAB////+AAAP////AAAB////gAAAP///wAAAB///wAAAAH//wAAAAAf/wAAAAAAOAAAAAAAAAAAAAfgAAAAAAH8AAAAAAB/AAAAAAAfwAAAAAAH8AAAAAAB/AAAAAAAfwAAAAAAH+AAAAAAB/wAAAAAAf/////wAD/////8AA//////AAH/////wAA/////8AAH/////AAAf////wAAA////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP/wAH8AA//8AB/AA///AAfwAf//wAH8AH//8AB/AD///AAfwA///wAH8Af//8AB/AH8B/AAfwB+AfwAH8AfgH8AB/AH4B/AAfwB+AfwAH8AfgH8AB/AH4B/AAfwB+AfwAH8AfgH8AB/AH4B/AAfwB+AfwAH8AfgH8AB/AH4B/AAfwB+AfwAH8AfgH8AB/AH4B/AAfwB+AfwAH8AfgH8AB/AH4B/AAfwD+AfwAH+B/AH8AB///wB/AAf//8AfwAD///AH8AA///gB/AAH//wAfwAA//4AH8AAH/8AB/AAAf8AAPwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD8AB/AAAB/AAfwAAAfwAH8AAAH8AB/AAAB/AAfwAAAfwAH8AAAH8AB/AAAB/AAfwAAAfwAH8AfAH8AB/AH4B/AAfwB+AfwAH8AfgH8AB/AH4B/AAfwB+AfwAH8AfgH8AB/AH4B/AAfwB+AfwAH8AfgH8AB/AH4B/AAfwB+AfwAH8AfgH8AB/AH4B/AAfwB+AfwAH8AfgH8AB/AH4B/AAfwB+AfwAH8A/gH8AB/gP4D/AAf8H/A/wAH///8/8AA/////+AAP/////gAB/////4AAf/8//8AAD/+P/+AAAf/B//AAAA/AH/AAAAAAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAH///AAAAB///8AAAAf///gAAAH///8AAAB////gAAAf///4AAAH////AAAAAAD/wAAAAAAP8AAAAAAB/AAAAAAAfwAAAAAAD+AAAAAAA/gAAAAAAP4AAAAAAD+AAAAAAA/gAAAAAAP4AAAAAAD+AAAAAAA/gAAAAAAP4AAAAAAD+AAAAAAA/gAAAAAAP4AAAAAAD+AAAAAAA/gAAAAAAP4AAAAAAD+AAAH/////8AB//////AAf/////wAH/////8AB//////AAf/////wAH/////8AAAAAP4AAAAAAD+AAAAAAA/gAAAAAAP4AAAAAAD+AAAAAAA/AAAAAAAAAAAAAAAAAAAAH///AD8AB///4B/AAf//+AfwAH///gH8AB///4B/AAf//+AfwAH///gH8AB///4B/AAfwB+AfwAH8AfgH8AB/AH4B/AAfwB+AfwAH8AfgH8AB/AH4B/AAfwB+AfwAH8AfgH8AB/AH4B/AAfwB+AfwAH8AfgH8AB/AH4B/AAfwB+AfwAH8AfgH8AB/AH4B/AAfwB+AfwAH8AfgH8AB/AH4B/AAfwB+AfwAH8AfgH8AB/AH4B/AAfwB+AfwAH8AfgH8AB/AH8D/AAfwB/h/wAH8Af//8AB/AD//+AAfwA///gAH8AH//wAB/AA//4AAfgAH/8AAAAAAf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHwAAAAAB//4AAAAB///wAAAB////AAAA////4AAAf////AAAP////4AAH/////AAB//fv/wAA/8H4f+AAP+B+D/gAH/AfgP8AB/gH4D/AAfwB+AfwAH8AfgH8AB/AH4B/AAfwB+AfwAH8AfgH8AB/AH4B/AAfwB+AfwAH8AfgH8AB/AH4B/AAfwB+AfwAH8AfgH8AB/AH4B/AAfwB+AfwAH8AfgH8AB/AH4B/AAfwB+AfwAH8AfgH8AB/AH4B/AAfwB+A/wAH8Afwf8AB/AH///AAfwA///gAH8AP//4AB/AD//8AAfwAf/+AAH8AD//AAAAAAP/gAAAAAAeAAAAAAAAAAAAAAAAAAAAAAAAAAAAH4AAAAAAB/AAAABAAfwAAAAwAH8AAAAcAB/AAAAfAAfwAAAPwAH8AAAH8AB/AAAD/AAfwAAD/wAH8AAB/8AB/AAA//AAfwAAf/gAH8AAP/gAB/AAP/wAAfwAH/4AAH8AD/8AAB/AB/8AAAfwB/+AAAH8A//AAAB/Af/gAAAfwP/gAAAH8P/wAAAB/H/4AAAAfz/8AAAAH9/8AAAAB//+AAAAAf//AAAAAH//gAAAAB//gAAAAAf/wAAAAAH/4AAAAAB/8AAAAAAf8AAAAAAH+AAAAAAB/AAAAAAAPgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP4AAAD/gP/gAAB/+H/8AAA//z//gAAf////8AAP/////gAD/////4AB//////AAf+P/B/wAH+A/gP8AB/AP4B/AAfwB+AfwAH8AfgH8AB/AH4B/AAfwB+AfwAH8AfgH8AB/AH4B/AAfwB+AfwAH8AfgH8AB/AH4B/AAfwB+AfwAH8AfgH8AB/AH4B/AAfwB+AfwAH8AfgH8AB/AH4B/AAfwB+AfwAH8AfgH8AB/AH4B/AAfwB+AfwAH8A/gH8AB/gP8D/AAf+P/h/wAH/////8AA/////+AAP/////gAB/////wAAP/8//4AAB/+H/8AAAH+A/+AAAAAAD+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAAAAAAH/4AAAAAH//gAAAAD//8AAAAB///AD8AA///4B/AAP///AfwAH///wH8AB/4f8B/AAf4B/AfwAH8APwH8AB/AD8B/AAfwA/AfwAH8APwH8AB/AD8B/AAfwA/AfwAH8APwH8AB/AD8B/AAfwA/AfwAH8APwH8AB/AD8B/AAfwA/AfwAH8APwH8AB/AD8B/AAfwA/AfwAH8APwH8AB/AD8B/AAfwA/AfwAH+APwP8AB/wD8D/AAP+A/B/gAD/wPx/4AAf/j9/+AAH/////AAA/////gAAH////4AAA////8AAAH///8AAAAf//+AAAAA//8AAAAAAfwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAEAAAAD4AHwAAAB/AD+AAAAfwA/gAAAH8AP4AAAB/AD+AAAAfwA/gAAAD4AHwAAAAMAAYAAAAAAAAAAAAAAAAA'),
+ 46,
+ atob('DRYqEykpKiwsJi0rDQ=='),
+ 50 | 65536
+ )
+ return this
+}
+
+// Medium = 16px ()
+Graphics.prototype.setMediumFont = function () {
+ this.setFontCustom(
+ atob('AAAAAAAADwAAAB8AAAAPAAAAGwAAAb8AAB/9AAH/kAAv+QAA/4AAAPQAAAACvkAAH//wAD///AC/Qf4A/AA/APQAHwDwAA8A9AAfAPwAPwC+Qf4AP//8AB//9AAG/4AAoAAAAPAAAAD4AAAA////AL///wAv//8AAAAAAPAL/wDwH/8A8D//APA9DwDwPA8A8DwPAPA8DwDwPA8A9DwPAP78DwD/+A8AL+APAPAADwDwAA8A8BQPAPA8DwDwPA8A8DwPAPA8DwDwPA8A9DwfAP7/vwD///8AP+v8AAUBUACqqQAA//9AAP//wABVW8AAAAPAAAADwAAAA8AAAAPAAAADwAD///8A////AP///wAAA8AAAAKAAAAAAAD//A8A//wPAP/8DwDwPA8A8DwPAPA8DwDwPA8A8DwPAPA8DwDwPR8A8D+/APAv/gCgC/gAC//gAD///AC///4A/Tx/APg8LwDwPA8A8DwPAPA8DwDwPA8A8D0fAPA/vwDwL/4AoAv4AAAAQABQAAAA8AAHAPAAHwDwAL8A8AP/APAf+ADwf9AA8v9AAP/4AAD/4AAA/0AAAP0AAAAAAEAAL9v4AL///gD//78A+H0vAPA8DwDwPA8A8DwPAPA8DwDwPA8A9D0fAP7/vwD///8AP9v8AC/4AAC//g8A/r8PAPQfDwDwDw8A8A8PAPAPDwDwDw8A+A8fAP5PfwC///4AL//8AAb/4AAAAAAAAAAAAAA8DwAAfB8AADwPAA=='),
+ 46,
+ atob('BAcNBg0NDg4ODA4OBA=='),
+ 16 | 131072
+ )
+ return this
+}
+
+/* VARIABLES */
+// Const
+const H = g.getHeight()
+const W = g.getWidth()
+// Mutable
+let timer = null
+
+/* UTILITY FUNCTIONS */
+// Return String of Current Time
+function getCurrentTime () {
+ try {
+ const d = new Date()
+ const h = d.getHours()
+ const m = d.getMinutes()
+ return `${h}:${m.toString().padStart(2, 0)}`
+ } catch (e) {
+ console.log(e)
+ return '0:00'
+ }
+}
+
+// Return String of Current Date
+function getCurrentDate () {
+ try {
+ const d = new Date()
+ const year = d.getFullYear()
+ const month = d.getMonth()
+ const day = d.getDate()
+ const display = `${month + 1}.${day.toString().padStart(2, 0)}.${year}`
+ return display
+ } catch (e) {
+ console.log(e)
+ return '0.0.0000'
+ }
+}
+
+// Set A New Draw for the Next Minute
+function setNextDraw () {
+ console.log('tick')
+ // Clear Timeout
+ if (timer) {
+ clearInterval(timer)
+ }
+ // Calculate time until next minute
+ const d = new Date()
+ const s = d.getSeconds()
+ const ms = d.getMilliseconds()
+ const delay = 60000 - (s * 1000) - ms
+ // Set Timeout
+ timer = setInterval(draw, delay)
+}
+
+function draw () {
+ // Reset Variables
+ g.reset()
+ // Set Background Color
+ g.setBgColor(0, 0, 0)
+ // Draw Background
+ g.setColor(0, 0, 0)
+ g.fillRect(0, 0, W, H)
+ // Set Font for Time
+ g.setColor(0, 0.93, 0)
+ g.setLargeFont()
+ g.setFontAlign(0, 0)
+ // Draw Time
+ const time = getCurrentTime()
+ g.drawString(time, W / 2, H / 2, true /* clear background */)
+ // Set Font for Date
+ g.setColor(0, 0.75, 0)
+ g.setMediumFont()
+ g.setFontAlign(0, 1)
+ // Draw Date
+ const dateStr = getCurrentDate()
+ g.drawString(dateStr, W / 2, H - 45, true)
+ // Draw Border
+ g.setColor(0, 0.93, 0)
+ g.drawLine(5, 36, W - 5, 36)
+ g.drawLine(5, H - 9, W - 5, H - 9)
+ g.setColor(0, 0.18, 0)
+ g.fillRect(0, 27, W, 32)
+ g.fillRect(0, H, W, H - 5)
+ // Draw Widgets
+ Bangle.drawWidgets()
+ // Schedule Next Draw
+ setNextDraw()
+}
+
+/* MAIN LOOP */
+function main () {
+ // Clear Screen
+ g.clear()
+ // Set as Clock to Enable Launcher Screen on BTN1
+ Bangle.setUI('clock')
+ // Load Widgets
+ Bangle.loadWidgets()
+ // Draw Clock
+ draw()
+}
+
+/* BOOT CODE */
+main()
diff --git a/apps/fallout_clock/icon.png b/apps/fallout_clock/icon.png
new file mode 100644
index 000000000..fc9bc1fdc
Binary files /dev/null and b/apps/fallout_clock/icon.png differ
diff --git a/apps/fallout_clock/metadata.json b/apps/fallout_clock/metadata.json
new file mode 100644
index 000000000..20861411a
--- /dev/null
+++ b/apps/fallout_clock/metadata.json
@@ -0,0 +1,18 @@
+{
+ "id":"fallout_clock",
+ "name":"Fallout Clock",
+ "version":"0.21",
+ "description":"A simple clock for the Fallout fan",
+ "icon":"icon.png",
+ "type":"clock",
+ "tags": "clock,fallout,green,retro",
+ "supports": ["BANGLEJS2"],
+ "readme": "README.md",
+ "storage": [
+ {"name":"fallout_clock.app.js", "url":"clock.js"},
+ {"name":"fallout_clock.img", "url":"app-icon.js", "evaluate":true}
+ ],
+ "screenshots": [
+ {"url":"./screenshot.png", "name":"Fallout Clock Screenshot"}
+ ]
+}
diff --git a/apps/fallout_clock/res/fallout_icon.png b/apps/fallout_clock/res/fallout_icon.png
new file mode 100644
index 000000000..fc9bc1fdc
Binary files /dev/null and b/apps/fallout_clock/res/fallout_icon.png differ
diff --git a/apps/fallout_clock/res/good times rg.otf b/apps/fallout_clock/res/good times rg.otf
new file mode 100644
index 000000000..53c181cca
Binary files /dev/null and b/apps/fallout_clock/res/good times rg.otf differ
diff --git a/apps/fallout_clock/res/screenshot.png b/apps/fallout_clock/res/screenshot.png
new file mode 100644
index 000000000..253554b72
Binary files /dev/null and b/apps/fallout_clock/res/screenshot.png differ
diff --git a/apps/fallout_clock/screenshot.png b/apps/fallout_clock/screenshot.png
new file mode 100644
index 000000000..253554b72
Binary files /dev/null and b/apps/fallout_clock/screenshot.png differ
diff --git a/apps/gipy/ChangeLog b/apps/gipy/ChangeLog
index d46d24c69..a80cd42ea 100644
--- a/apps/gipy/ChangeLog
+++ b/apps/gipy/ChangeLog
@@ -127,4 +127,11 @@
* Interface: disable/enable waypoints detection and elevation
* Touching the screen when sleeping will wake up but not change screen
* Removing footways (if bicycles not allowed) to reduce resource usage
- * Switching screen will clear the screen immediately so you can know your screen touch has been received
\ No newline at end of file
+ * Switching screen will clear the screen immediately so you can know your screen touch has been received
+
+0.24:
+ * Fix for loading very large files (> 65kb)
+ * New menu on file selection : reverse path without waiting for file to load
+ * Fix for files converted from maps2gpx : path was not reduced in size correctly
+ * Experimental ski mode : have a ski slopes map
+ * Fix for path projection display when lost and zoomed out
diff --git a/apps/gipy/README.md b/apps/gipy/README.md
index e247e954b..e9444769f 100644
--- a/apps/gipy/README.md
+++ b/apps/gipy/README.md
@@ -33,7 +33,7 @@ It provides the following features :
### Preparing the file
-You first need to have a trace file in *gpx* format.
+You typically want to use a trace file in *gpx* format.
Usually I download from [komoot](https://www.komoot.com/) or I export
from google maps using [mapstogpx](https://mapstogpx.com/). [Brouter](https://brouter.damsy.net) is
also a nice open source option.
@@ -48,6 +48,11 @@ Just click the disk icon and select your gpx file.
This will request additional information from openstreetmap.
Your path will be displayed in svg.
+Note that it is also possible to just hit the shift key and drag the mouse on the map
+to download a map (with no trace). If you want a map, hitting the "ski" checkbox
+before selecting the area will parse openstreetmap data in order to get the pistes and
+the lifts. Colors will correspond to difficulty levels.
+
### Starting Gipy
At start you will have a menu for selecting your trace (if more than one).
diff --git a/apps/gipy/TODO b/apps/gipy/TODO
index e5fe68240..a433b9465 100644
--- a/apps/gipy/TODO
+++ b/apps/gipy/TODO
@@ -1,5 +1,7 @@
-urgent TODO:
+- is path projection wrong for high res ?
+
+medium TODO:
- prefetch tiles ?
- update documentation to reflect new display ?
diff --git a/apps/gipy/app.js b/apps/gipy/app.js
index 0a631613b..83ce0757a 100644
--- a/apps/gipy/app.js
+++ b/apps/gipy/app.js
@@ -95,26 +95,30 @@ function compute_eta(hour, minutes, approximate_speed, remaining_distance) {
}
class TilesOffsets {
- constructor(buffer, offset) {
- let type_size = Uint8Array(buffer, offset, 1)[0];
+ constructor(filename, offset) {
+ let header = E.toArrayBuffer(s.read(filename, offset, 4));
+ let type_size = Uint8Array(header, 0, 1)[0];
offset += 1;
- this.entry_size = Uint8Array(buffer, offset, 1)[0];
+ this.entry_size = Uint8Array(header, 1, 1)[0];
offset += 1;
- let non_empty_tiles_number = Uint16Array(buffer, offset, 1)[0];
+ let non_empty_tiles_number = Uint16Array(header, 2, 1)[0];
offset += 2;
- this.non_empty_tiles = Uint16Array(buffer, offset, non_empty_tiles_number);
+
+ let bytes = (type_size==24)?3:2;
+ let buffer = E.toArrayBuffer(s.read(filename, offset, 2*non_empty_tiles_number+bytes*non_empty_tiles_number));
+ this.non_empty_tiles = Uint16Array(buffer, 0, non_empty_tiles_number);
offset += 2 * non_empty_tiles_number;
if (type_size == 24) {
this.non_empty_tiles_ends = Uint24Array(
buffer,
- offset,
+ 2*non_empty_tiles_number,
non_empty_tiles_number
);
offset += 3 * non_empty_tiles_number;
} else if (type_size == 16) {
this.non_empty_tiles_ends = Uint16Array(
buffer,
- offset,
+ 2*non_empty_tiles_number,
non_empty_tiles_number
);
offset += 2 * non_empty_tiles_number;
@@ -153,27 +157,29 @@ class TilesOffsets {
}
class Map {
- constructor(buffer, offset, filename) {
+ constructor(filename, offset) {
// header
- let color_array = Uint8Array(buffer, offset, 3);
+
+ let header = E.toArrayBuffer(s.read(filename, offset, 43));
+ let color_array = Uint8Array(header, 0, 3);
this.color = [
color_array[0] / 255,
color_array[1] / 255,
color_array[2] / 255,
];
offset += 3;
- this.first_tile = Int32Array(buffer, offset, 2); // absolute tile id of first tile
+ this.first_tile = Int32Array(header, 3, 2); // absolute tile id of first tile
offset += 2 * 4;
- this.grid_size = Uint32Array(buffer, offset, 2); // tiles width and height
+ this.grid_size = Uint32Array(header, 11, 2); // tiles width and height
offset += 2 * 4;
- this.start_coordinates = Float64Array(buffer, offset, 2); // min x and y coordinates
+ this.start_coordinates = Float64Array(header, 19, 2); // min x and y coordinates
offset += 2 * 8;
- let side_array = Float64Array(buffer, offset, 1); // side of a tile
+ let side_array = Float64Array(header, 35, 1); // side of a tile
this.side = side_array[0];
offset += 8;
// tiles offsets
- let res = new TilesOffsets(buffer, offset);
+ let res = new TilesOffsets(filename, offset);
this.tiles_offsets = res[0];
offset = res[1];
@@ -246,7 +252,7 @@ class Map {
let tile_y = absolute_tile_y - this.first_tile[1];
let side = img.getWidth() - 6;
- let thick = this.color[0] != 0;
+ let thick = this.color[0] == 1;
img.setColor(this.color[0], this.color[1], this.color[2]);
let tile_num = tile_x + tile_y * this.grid_size[0];
@@ -296,26 +302,25 @@ class Map {
}
class Interests {
- constructor(buffer, offset) {
- this.first_tile = Int32Array(buffer, offset, 2); // absolute tile id of first tile
+ constructor(filename, offset) {
+ let header = E.toArrayBuffer(s.read(filename, offset, 40));
+ this.first_tile = Int32Array(header, 0, 2); // absolute tile id of first tile
offset += 2 * 4;
- this.grid_size = Uint32Array(buffer, offset, 2); // tiles width and height
+ this.grid_size = Uint32Array(header, 8, 2); // tiles width and height
offset += 2 * 4;
- this.start_coordinates = Float64Array(buffer, offset, 2); // min x and y coordinates
+ this.start_coordinates = Float64Array(header, 16, 2); // min x and y coordinates
offset += 2 * 8;
- let side_array = Float64Array(buffer, offset, 1); // side of a tile
+ let side_array = Float64Array(header, 32, 1); // side of a tile
this.side = side_array[0];
offset += 8;
- let res = new TilesOffsets(buffer, offset);
+ let res = new TilesOffsets(filename, offset);
offset = res[1];
this.offsets = res[0];
let end = this.offsets.end_offset();
this.binary_interests = new Uint8Array(end);
- let binary_interests = Uint8Array(buffer, offset, end);
- for (let i = 0; i < end; i++) {
- this.binary_interests[i] = binary_interests[i];
- }
+ let buffer = E.toArrayBuffer(s.read(filename, offset, end));
+ this.binary_interests = Uint8Array(buffer);
offset += end;
return [this, offset];
}
@@ -374,14 +379,15 @@ class Status {
this.scale_factor = diagonal_third / maps[0].side; // multiply geo coordinates by this to get pixels coordinates
if (this.path !== null) {
- let r = [0];
+ //TODO: float32 ??
+ let r = new Float64Array(this.path.len);
// let's do a reversed prefix computations on all distances:
// loop on all segments in reversed order
let previous_point = null;
for (let i = this.path.len - 1; i >= 0; i--) {
let point = this.path.point(i);
if (previous_point !== null) {
- r.unshift(r[0] + point.distance(previous_point));
+ r[i] = r[i+1] + point.distance(previous_point);
}
previous_point = point;
}
@@ -634,6 +640,10 @@ class Status {
this.display();
}
display_direction() {
+ let scale_factor = this.scale_factor;
+ if (!this.zoomed_in) {
+ scale_factor *= 3/5;
+ }
//TODO: go towards point on path at 20 meter
if (this.current_segment === null) {
return;
@@ -658,7 +668,7 @@ class Status {
this.displayed_position,
this.adjusted_cos_direction,
this.adjusted_sin_direction,
- this.scale_factor
+ scale_factor
);
let cos1 = Math.cos(full_angle + 0.6 + Math.PI / 2);
@@ -1076,6 +1086,9 @@ class Status {
let half_width = width / 2;
let half_height = height / 2 + Y_OFFSET;
let scale_factor = this.scale_factor;
+ if (!this.zoomed_in) {
+ scale_factor *= 3/5;
+ }
if (this.path !== null) {
// compute coordinate for projection on path
@@ -1141,8 +1154,11 @@ function load_gps(filename) {
.drawString(filename, 0, g.getHeight() - 30);
g.flip();
- let buffer = s.readArrayBuffer(filename);
- let file_size = buffer.length;
+ let file_size;
+ {
+ let buffer = s.readArrayBuffer(filename);
+ file_size = buffer.length;
+ }
let offset = 0;
let path = null;
@@ -1150,60 +1166,51 @@ function load_gps(filename) {
let maps = [];
let interests = null;
while (offset < file_size) {
- let block_type = Uint8Array(buffer, offset, 1)[0];
+ let block_type = Uint8Array(E.toArrayBuffer(s.read(filename, offset, 1)))[0];
offset += 1;
if (block_type == 0) {
// it's a map
console.log("loading map");
- let res = new Map(buffer, offset, filename);
+ let res = new Map(filename, offset);
let map = res[0];
offset = res[1];
maps.push(map);
} else if (block_type == 2) {
console.log("loading path");
- let res = new Path(buffer, offset);
+ let res = new Path(filename, offset);
path = res[0];
offset = res[1];
} else if (block_type == 3) {
console.log("loading interests");
- let res = new Interests(buffer, offset);
+ let res = new Interests(filename, offset);
interests = res[0];
offset = res[1];
} else if (block_type == 4) {
- console.log("loading heights");
let heights_number = path.points.length / 2;
- heights = Int16Array(buffer, offset, heights_number);
+ let buffer = E.toArrayBuffer(s.read(filename, offset, heights_number*2));
+ heights = Int16Array(buffer);
offset += 2 * heights_number;
} else {
console.log("todo : block type", block_type);
}
}
- // checksum file size
- if (offset != file_size) {
- console.log("invalid file size", file_size, "expected", offset);
- let msg = "invalid file\nsize " + file_size + "\ninstead of" + offset;
- E.showAlert(msg).then(function () {
- E.showAlert();
- start_gipy(path, maps, interests, heights);
- });
- } else {
- start_gipy(path, maps, interests, heights);
- }
+ start_gipy(path, maps, interests, heights);
}
class Path {
- constructor(buffer, offset) {
- let points_number = Uint16Array(buffer, offset, 1)[0];
+ constructor(filename, offset) {
+ let points_number = Uint16Array(E.toArrayBuffer(s.read(filename, offset, 2)))[0];
offset += 2;
+ let waypoints_len = Math.ceil(points_number / 8.0);
+ let buffer = E.toArrayBuffer(s.read(filename, offset, points_number * 16 + waypoints_len));
// path points
- this.points = Float64Array(buffer, offset, points_number * 2);
+ this.points = Float64Array(buffer, 0, 2 * points_number);
offset += 8 * points_number * 2;
// path waypoints
- let waypoints_len = Math.ceil(points_number / 8.0);
- this.waypoints = Uint8Array(buffer, offset, waypoints_len);
+ this.waypoints = Uint8Array(buffer, points_number * 2, waypoints_len);
offset += waypoints_len;
return [this, offset];
@@ -1370,14 +1377,47 @@ function drawMenu() {
menu["Exit"] = function () {
load();
};
+ Bangle.setLCDBrightness(settings.brightness);
+ Bangle.setLocked(false);
E.showMenu(menu);
}
+
+function ask_options(fn) {
+ g.clear();
+ let height = g.getHeight();
+ let width = g.getWidth();
+ g.drawRect(10, 10, width - 10, height / 2 - 10);
+ g.drawRect(10, height/2 + 10, width - 10, height - 10);
+ g.setFont("Vector:30").setFontAlign(0,0).drawString("Forward", width/2, height/4);
+ g.drawString("Backward", width/2, 3*height/4);
+ g.flip();
+
+ function options_select(b, xy) {
+ end = false;
+ if (xy.y < height / 2 - 10) {
+ g.setColor(0, 0, 0).fillRect(10, 10, width - 10, height / 2 - 10);
+ g.setColor(1, 1, 1).setFont("Vector:30").setFontAlign(0,0).drawString("Forward", width/2, height/4);
+ end = true;
+ } else if (xy.y > height/2 + 10) {
+ g.setColor(0, 0, 0).fillRect(10, height/2 + 10, width - 10, height - 10);
+ g.setColor(1, 1, 1).setFont("Vector:30").setFontAlign(0,0).drawString("Backward", width/2, 3*height/4);
+ go_backwards = true;
+ end = true;
+ }
+ if (end) {
+ g.flip();
+ Bangle.removeListener("touch", options_select);
+ console.log("loading", fn);
+ load_gps(fn);
+ }
+ }
+ Bangle.on("touch", options_select);
+}
+
function start(fn) {
E.showMenu();
- console.log("loading", fn);
-
- load_gps(fn);
+ ask_options(fn);
}
function start_gipy(path, maps, interests, heights) {
@@ -1387,7 +1427,9 @@ function start_gipy(path, maps, interests, heights) {
NRF.sleep(); // disable bluetooth completely
}
+ console.log("creating status");
status = new Status(path, maps, interests, heights);
+ console.log("done creating status");
setWatch(
function () {
@@ -1491,6 +1533,7 @@ function start_gipy(path, maps, interests, heights) {
});
if (simulated) {
+ console.log("un-comment simulator to use it");
// status.starting_time = getTime();
// // let's keep the screen on in simulations
// Bangle.setLCDTimeout(0);
@@ -1518,8 +1561,8 @@ function start_gipy(path, maps, interests, heights) {
// if (point_index >= status.path.len / 2 - 1) {
// return;
// }
- // let p1 = status.path.point(2 * point_index); // use these to approximately follow path
- // let p2 = status.path.point(2 * (point_index + 1));
+ // let p1 = status.path.point(8 * point_index); // use these to approximately follow path
+ // let p2 = status.path.point(8 * (point_index + 1));
// //let p1 = status.path.point(point_index); // use these to strictly follow path
// //let p2 = status.path.point(point_index + 1);
diff --git a/apps/gipy/interface.html b/apps/gipy/interface.html
index f8eebabe6..0fb60778f 100644
--- a/apps/gipy/interface.html
+++ b/apps/gipy/interface.html
@@ -55,6 +55,9 @@
+
+
+
@@ -140,7 +143,9 @@ if ((e.which !== 1) && (e.button !== 1)) { return; }
this._map.containerPointToLatLng(this._point));
let south_west = bounds.getSouthWest();
let north_east = bounds.getNorthEast();
- gps_data = gps_from_area(south_west.lng, south_west.lat, north_east.lng, north_east.lat);
+ let ski = document.getElementById("ski").checked;
+ console.log("ski", ski);
+ gps_data = gps_from_area(south_west.lng, south_west.lat, north_east.lng, north_east.lat, ski);
document.getElementById('gps_file').value = "";
display_polygon(this._map);
diff --git a/apps/gipy/metadata.json b/apps/gipy/metadata.json
index 636bbe865..5b416bced 100644
--- a/apps/gipy/metadata.json
+++ b/apps/gipy/metadata.json
@@ -2,7 +2,7 @@
"id": "gipy",
"name": "Gipy",
"shortName": "Gipy",
- "version": "0.23",
+ "version": "0.24",
"description": "Follow gpx files using the gps. Don't get lost in your bike trips and hikes.",
"allow_emulator":false,
"icon": "gipy.png",
diff --git a/apps/gipy/pkg/gps.d.ts b/apps/gipy/pkg/gps.d.ts
index 11cdf371b..9ad646068 100644
--- a/apps/gipy/pkg/gps.d.ts
+++ b/apps/gipy/pkg/gps.d.ts
@@ -53,9 +53,10 @@ export function load_gps_from_string(input: string, autodetect_waypoints: boolea
* @param {number} ymin
* @param {number} xmax
* @param {number} ymax
+* @param {boolean} ski
* @returns {Gps}
*/
-export function gps_from_area(xmin: number, ymin: number, xmax: number, ymax: number): Gps;
+export function gps_from_area(xmin: number, ymin: number, xmax: number, ymax: number, ski: boolean): Gps;
/**
*/
export class Gps {
@@ -75,15 +76,15 @@ export interface InitOutput {
readonly get_gps_content: (a: number, b: number) => void;
readonly request_map: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number, i: number, j: number, k: number, l: number, m: number, n: number, o: number, p: number, q: number) => number;
readonly load_gps_from_string: (a: number, b: number, c: number) => number;
- readonly gps_from_area: (a: number, b: number, c: number, d: number) => number;
+ readonly gps_from_area: (a: number, b: number, c: number, d: number, e: number) => number;
readonly __wbindgen_malloc: (a: number) => number;
readonly __wbindgen_realloc: (a: number, b: number, c: number) => number;
readonly __wbindgen_export_2: WebAssembly.Table;
- readonly wasm_bindgen__convert__closures__invoke1_mut__hef038f7a61abd0f6: (a: number, b: number, c: number) => void;
+ readonly wasm_bindgen__convert__closures__invoke1_mut__hc18aa489d857d6a0: (a: number, b: number, c: number) => void;
readonly __wbindgen_add_to_stack_pointer: (a: number) => number;
readonly __wbindgen_free: (a: number, b: number) => void;
readonly __wbindgen_exn_store: (a: number) => void;
- readonly wasm_bindgen__convert__closures__invoke2_mut__h545ed49cfafdda52: (a: number, b: number, c: number, d: number) => void;
+ readonly wasm_bindgen__convert__closures__invoke2_mut__h41c3b5af183df3b2: (a: number, b: number, c: number, d: number) => void;
}
export type SyncInitInput = BufferSource | WebAssembly.Module;
diff --git a/apps/gipy/pkg/gps.js b/apps/gipy/pkg/gps.js
index 9057a5aa0..0f8b74804 100644
--- a/apps/gipy/pkg/gps.js
+++ b/apps/gipy/pkg/gps.js
@@ -205,7 +205,7 @@ function makeMutClosure(arg0, arg1, dtor, f) {
return real;
}
function __wbg_adapter_24(arg0, arg1, arg2) {
- wasm.wasm_bindgen__convert__closures__invoke1_mut__hef038f7a61abd0f6(arg0, arg1, addHeapObject(arg2));
+ wasm.wasm_bindgen__convert__closures__invoke1_mut__hc18aa489d857d6a0(arg0, arg1, addHeapObject(arg2));
}
function _assertClass(instance, klass) {
@@ -373,10 +373,11 @@ export function load_gps_from_string(input, autodetect_waypoints) {
* @param {number} ymin
* @param {number} xmax
* @param {number} ymax
+* @param {boolean} ski
* @returns {Gps}
*/
-export function gps_from_area(xmin, ymin, xmax, ymax) {
- const ret = wasm.gps_from_area(xmin, ymin, xmax, ymax);
+export function gps_from_area(xmin, ymin, xmax, ymax, ski) {
+ const ret = wasm.gps_from_area(xmin, ymin, xmax, ymax, ski);
return Gps.__wrap(ret);
}
@@ -388,7 +389,7 @@ function handleError(f, args) {
}
}
function __wbg_adapter_86(arg0, arg1, arg2, arg3) {
- wasm.wasm_bindgen__convert__closures__invoke2_mut__h545ed49cfafdda52(arg0, arg1, addHeapObject(arg2), addHeapObject(arg3));
+ wasm.wasm_bindgen__convert__closures__invoke2_mut__h41c3b5af183df3b2(arg0, arg1, addHeapObject(arg2), addHeapObject(arg3));
}
/**
@@ -475,6 +476,17 @@ function getImports() {
const ret = fetch(getObject(arg0));
return addHeapObject(ret);
};
+ imports.wbg.__wbg_signal_31753ac644b25fbb = function(arg0) {
+ const ret = getObject(arg0).signal;
+ return addHeapObject(ret);
+ };
+ imports.wbg.__wbg_new_6396e586b56e1dff = function() { return handleError(function () {
+ const ret = new AbortController();
+ return addHeapObject(ret);
+ }, arguments) };
+ imports.wbg.__wbg_abort_064ae59cda5cd244 = function(arg0) {
+ getObject(arg0).abort();
+ };
imports.wbg.__wbg_new_2d0053ee81e4dd2a = function() { return handleError(function () {
const ret = new Headers();
return addHeapObject(ret);
@@ -515,17 +527,6 @@ function getImports() {
const ret = getObject(arg0).fetch(getObject(arg1));
return addHeapObject(ret);
};
- imports.wbg.__wbg_signal_31753ac644b25fbb = function(arg0) {
- const ret = getObject(arg0).signal;
- return addHeapObject(ret);
- };
- imports.wbg.__wbg_new_6396e586b56e1dff = function() { return handleError(function () {
- const ret = new AbortController();
- return addHeapObject(ret);
- }, arguments) };
- imports.wbg.__wbg_abort_064ae59cda5cd244 = function(arg0) {
- getObject(arg0).abort();
- };
imports.wbg.__wbg_newwithstrandinit_05d7180788420c40 = function() { return handleError(function (arg0, arg1, arg2) {
const ret = new Request(getStringFromWasm0(arg0, arg1), getObject(arg2));
return addHeapObject(ret);
@@ -694,8 +695,8 @@ function getImports() {
const ret = wasm.memory;
return addHeapObject(ret);
};
- imports.wbg.__wbindgen_closure_wrapper2354 = function(arg0, arg1, arg2) {
- const ret = makeMutClosure(arg0, arg1, 299, __wbg_adapter_24);
+ imports.wbg.__wbindgen_closure_wrapper2356 = function(arg0, arg1, arg2) {
+ const ret = makeMutClosure(arg0, arg1, 293, __wbg_adapter_24);
return addHeapObject(ret);
};
diff --git a/apps/gipy/pkg/gps_bg.wasm b/apps/gipy/pkg/gps_bg.wasm
index 47d190458..c9e212a13 100644
Binary files a/apps/gipy/pkg/gps_bg.wasm and b/apps/gipy/pkg/gps_bg.wasm differ
diff --git a/apps/gipy/pkg/gps_bg.wasm.d.ts b/apps/gipy/pkg/gps_bg.wasm.d.ts
index dbf30308b..251d9c3b1 100644
--- a/apps/gipy/pkg/gps_bg.wasm.d.ts
+++ b/apps/gipy/pkg/gps_bg.wasm.d.ts
@@ -10,12 +10,12 @@ export function get_polyline(a: number, b: number): void;
export function get_gps_content(a: number, b: number): void;
export function request_map(a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number, i: number, j: number, k: number, l: number, m: number, n: number, o: number, p: number, q: number): number;
export function load_gps_from_string(a: number, b: number, c: number): number;
-export function gps_from_area(a: number, b: number, c: number, d: number): number;
+export function gps_from_area(a: number, b: number, c: number, d: number, e: number): number;
export function __wbindgen_malloc(a: number): number;
export function __wbindgen_realloc(a: number, b: number, c: number): number;
export const __wbindgen_export_2: WebAssembly.Table;
-export function wasm_bindgen__convert__closures__invoke1_mut__hef038f7a61abd0f6(a: number, b: number, c: number): void;
+export function wasm_bindgen__convert__closures__invoke1_mut__hc18aa489d857d6a0(a: number, b: number, c: number): void;
export function __wbindgen_add_to_stack_pointer(a: number): number;
export function __wbindgen_free(a: number, b: number): void;
export function __wbindgen_exn_store(a: number): void;
-export function wasm_bindgen__convert__closures__invoke2_mut__h545ed49cfafdda52(a: number, b: number, c: number, d: number): void;
+export function wasm_bindgen__convert__closures__invoke2_mut__h41c3b5af183df3b2(a: number, b: number, c: number, d: number): void;
diff --git a/apps/hwid_a_battery_widget/ChangeLog b/apps/hwid_a_battery_widget/ChangeLog
index e7cdd2b4b..99601c31b 100644
--- a/apps/hwid_a_battery_widget/ChangeLog
+++ b/apps/hwid_a_battery_widget/ChangeLog
@@ -8,3 +8,4 @@
0.08: Handling exceptions
0.09: Add option for showing battery high mark
0.10: Fix background color
+0.11: Minor code improvements
diff --git a/apps/hwid_a_battery_widget/metadata.json b/apps/hwid_a_battery_widget/metadata.json
index 98d7ce2d5..2abc57a9b 100644
--- a/apps/hwid_a_battery_widget/metadata.json
+++ b/apps/hwid_a_battery_widget/metadata.json
@@ -3,7 +3,7 @@
"name": "A Battery Widget (with percentage) - Hanks Mod",
"shortName":"H Battery Widget",
"icon": "widget.png",
- "version":"0.10",
+ "version":"0.11",
"type": "widget",
"supports": ["BANGLEJS", "BANGLEJS2"],
"readme": "README.md",
diff --git a/apps/hwid_a_battery_widget/widget.js b/apps/hwid_a_battery_widget/widget.js
index 79ce9a5ad..7c76364a0 100644
--- a/apps/hwid_a_battery_widget/widget.js
+++ b/apps/hwid_a_battery_widget/widget.js
@@ -24,8 +24,7 @@
var s = width - 1;
var x = this.x;
var y = this.y;
- if ((typeof x === 'undefined') || (typeof y === 'undefined')) {
- } else {
+ if (x !== undefined && y !== undefined) {
g.setBgColor(COLORS.white);
g.clearRect(old_x, old_y, old_x + width, old_y + height);
diff --git a/apps/linuxclock/ChangeLog b/apps/linuxclock/ChangeLog
index 5529034be..d4ae7213e 100644
--- a/apps/linuxclock/ChangeLog
+++ b/apps/linuxclock/ChangeLog
@@ -3,3 +3,4 @@
0.03: Update clock_info to avoid a redraw
0.04: Fix clkinfo -- use .get instead of .show
0.05: Use clock_info module as an app
+0.06: Fix month in date (jan 0 -> 1, etc)
\ No newline at end of file
diff --git a/apps/linuxclock/app.js b/apps/linuxclock/app.js
index cea33fe3a..67202dac1 100644
--- a/apps/linuxclock/app.js
+++ b/apps/linuxclock/app.js
@@ -112,7 +112,7 @@ function getTime(){
function getDate(){
var date = new Date();
- return twoD(date.getDate()) + "." + twoD(date.getMonth());
+ return twoD(date.getDate()) + "." + twoD(date.getMonth() + 1);
}
function getDay(){
diff --git a/apps/linuxclock/metadata.json b/apps/linuxclock/metadata.json
index ccd9db5e7..422306977 100644
--- a/apps/linuxclock/metadata.json
+++ b/apps/linuxclock/metadata.json
@@ -1,7 +1,7 @@
{
"id": "linuxclock",
"name": "Linux Clock",
- "version": "0.05",
+ "version": "0.06",
"description": "A Linux inspired clock.",
"readme": "README.md",
"icon": "app.png",
diff --git a/apps/locale/locales.js b/apps/locale/locales.js
index c307c405f..a0d5ea031 100644
--- a/apps/locale/locales.js
+++ b/apps/locale/locales.js
@@ -790,7 +790,8 @@ var locales = {
trans: { yes: "ja", Yes: "Ja", no: "nei", No: "Nei", ok: "ok", on: "på", off: "av", "< Back": "< Tilbake", "Delete": "Slett", "Mark Unread": "Merk som ulest" }
},
"ca_ES": {
- lang: "es_ES",
+ lang: "ca_ES",
+ icon: "🇪🇺",
decimal_point: ",",
thousands_sep: ".",
currency_symbol: "€",
@@ -800,7 +801,7 @@ var locales = {
temperature: "°C",
ampm: { 0: "", 1: "" },
timePattern: { 0: "%HH:%MM:%SS", 1: "%HH:%MM" },
- datePattern: { 0: "%A, %d de %B %Y", "1": "%d/%m/%y" },
+ datePattern: { 0: "%d %B %Y", "1": "%d/%m/%y" },
abmonth: "gen.,febr.,març,abr.,maig,juny,jul.,ag.,set.,oct.,nov.,des.",
month: "gener,febrer,març,abril,maig,juny,juliol,agost,setembre,octobre,novembre,desembre",
abday: "dg.,dl.,dt.,dc.,dj.,dv.,ds.",
diff --git a/apps/messagegui/ChangeLog b/apps/messagegui/ChangeLog
index ea6b0fe43..cbf38af45 100644
--- a/apps/messagegui/ChangeLog
+++ b/apps/messagegui/ChangeLog
@@ -101,4 +101,6 @@
0.72: Nav message updastes don't automatically launch navigation menu unless they're new
0.73: Add sharp left+right nav icons
0.74: Add option for driving on left (affects roundabout icons in navigation)
-0.75: Handle text with images in messages list by just displaying the first line
\ No newline at end of file
+0.75: Handle text with images in messages list by just displaying the first line
+0.76: Swipe up/down on a shown message to show the next newer/older message.
+
diff --git a/apps/messagegui/README.md b/apps/messagegui/README.md
index 699588e1b..801ebfb2a 100644
--- a/apps/messagegui/README.md
+++ b/apps/messagegui/README.md
@@ -38,6 +38,7 @@ When a message is shown, you'll see a screen showing the message title and text.
* The 'back-arrow' button (or physical button on Bangle.js 2) goes back to Messages, marking the current message as read.
* The top-left icon shows more options, for instance deleting the message of marking unread
* On Bangle.js 2 you can tap on the message body to view a scrollable version of the title and text (or can use the top-left icon + `View Message`)
+- On Bangle.js 2 swipe up/down to show newer/older message
* If shown, the 'tick' button:
* **Android** opens the notification on the phone
* **iOS** responds positively to the notification (accept call/etc)
diff --git a/apps/messagegui/app.js b/apps/messagegui/app.js
index 5596510c5..330c9677f 100644
--- a/apps/messagegui/app.js
+++ b/apps/messagegui/app.js
@@ -289,7 +289,8 @@ function showMessageSettings(msg) {
}
function showMessage(msgid) {
- var msg = MESSAGES.find(m=>m.id==msgid);
+ let idx = MESSAGES.findIndex(m=>m.id==msgid);
+ var msg = MESSAGES[idx];
if (updateLabelsInterval) {
clearInterval(updateLabelsInterval);
updateLabelsInterval=undefined;
@@ -389,9 +390,11 @@ function showMessage(msgid) {
{type:"h",fillx:1, c: footer}
]},{back:goBack});
- Bangle.swipeHandler = lr => {
+ Bangle.swipeHandler = (lr,ud) => {
if (lr>0 && posHandler) posHandler();
if (lr<0 && negHandler) negHandler();
+ if (ud>0 && idx0) showMessage(MESSAGES[idx-1].id);
};
Bangle.on("swipe", Bangle.swipeHandler);
g.reset().clearRect(Bangle.appRect);
diff --git a/apps/messagegui/metadata.json b/apps/messagegui/metadata.json
index 6f2cb5d2e..1bf9b84d9 100644
--- a/apps/messagegui/metadata.json
+++ b/apps/messagegui/metadata.json
@@ -2,7 +2,7 @@
"id": "messagegui",
"name": "Message UI",
"shortName": "Messages",
- "version": "0.75",
+ "version": "0.76",
"description": "Default app to display notifications from iOS and Gadgetbridge/Android",
"icon": "app.png",
"type": "app",
diff --git a/apps/multitimer/ChangeLog b/apps/multitimer/ChangeLog
index 67b0cc014..fff0d3d23 100644
--- a/apps/multitimer/ChangeLog
+++ b/apps/multitimer/ChangeLog
@@ -6,3 +6,4 @@
0.06: Support fastloading
0.07: Fix fastloading support - ensure drag handler's restored after
menu display/fastload removes it
+0.08: Add setting for initial page to display
diff --git a/apps/multitimer/app.js b/apps/multitimer/app.js
index 965a12d26..31da18796 100644
--- a/apps/multitimer/app.js
+++ b/apps/multitimer/app.js
@@ -78,7 +78,7 @@ function drawTimers() {
}, 1000 - (timers[idx].t % 1000));
}
- E.showScroller({
+ const s = E.showScroller({
h : 40, c : timers.length+2,
back : function() {load();},
draw : (idx, r) => {
@@ -138,7 +138,7 @@ function timerMenu(idx) {
}, 1000 - (a.t % 1000));
}
- E.showScroller({
+ const s = E.showScroller({
h : 40, c : 5,
back : function() {
clearInt();
@@ -328,9 +328,22 @@ function editTimer(idx, a) {
setUI();
}
+function readJson() {
+ let json = require("Storage").readJSON("multitimer.json", true) || {};
+
+ if (Array.isArray(json)) {
+ // old format, convert
+ json = { sw: json };
+ require("Storage").writeJSON("multitimer.json", json);
+ }
+ if (!json.sw) json.sw = [];
+
+ return json;
+}
+
function drawSw() {
layer = 1;
- const sw = require("Storage").readJSON("multitimer.json", true) || [];
+ const sw = readJson().sw;
function updateTimers(idx) {
if (!timerInt1[idx]) timerInt1[idx] = setTimeout(function() {
@@ -341,7 +354,7 @@ function drawSw() {
}, 1000 - (sw[idx].t % 1000));
}
- E.showScroller({
+ const s = E.showScroller({
h : 40, c : sw.length+2,
back : function() {load();},
draw : (idx, r) => {
@@ -382,12 +395,13 @@ function drawSw() {
function swMenu(idx, a) {
layer = -1;
- const sw = require("Storage").readJSON("multitimer.json", true) || [];
+ const json = readJson();
+ const sw = json.sw;
if (sw[idx]) a = sw[idx];
else {
a = {"t" : 0, "on" : false, "msg" : ""};
sw[idx] = a;
- require("Storage").writeJSON("multitimer.json", sw);
+ require("Storage").writeJSON("multitimer.json", json);
}
function updateTimer() {
@@ -408,7 +422,7 @@ function swMenu(idx, a) {
}
else delete a.msg;
sw[idx] = a;
- require("Storage").writeJSON("multitimer.json", sw);
+ require("Storage").writeJSON("multitimer.json", json);
swMenu(idx, a);
});
}
@@ -420,7 +434,7 @@ function swMenu(idx, a) {
setUI();
}
- E.showScroller({
+ const s = E.showScroller({
h : 40, c : 5,
back : function() {
clearInt();
@@ -458,7 +472,7 @@ function swMenu(idx, a) {
select : (i) => {
function saveAndReload() {
- require("Storage").writeJSON("multitimer.json", sw);
+ require("Storage").writeJSON("multitimer.json", json);
s.draw();
}
@@ -707,5 +721,17 @@ function onDrag(e) {
}
}
-drawTimers();
+switch (readJson().initialScreen) {
+ case 1:
+ drawSw();
+ break;
+ case 2:
+ drawAlarms();
+ break;
+ case 0:
+ case undefined:
+ default:
+ drawTimers();
+ break;
+}
}
diff --git a/apps/multitimer/metadata.json b/apps/multitimer/metadata.json
index e753d0581..8ba946520 100644
--- a/apps/multitimer/metadata.json
+++ b/apps/multitimer/metadata.json
@@ -1,7 +1,7 @@
{
"id": "multitimer",
"name": "Multi Timer",
- "version": "0.07",
+ "version": "0.08",
"description": "Set timers and chronographs (stopwatches) and watch them count down in real time. Pause, create, edit, and delete timers and chronos, and add custom labels/messages. Also sets alarms.",
"icon": "app.png",
"screenshots": [
@@ -16,6 +16,7 @@
{"name":"multitimer.app.js","url":"app.js"},
{"name":"multitimer.boot.js","url":"boot.js"},
{"name":"multitimer.alarm.js","url":"alarm.js"},
+ {"name":"multitimer.settings.js","url":"settings.js"},
{"name":"multitimer.img","url":"app-icon.js","evaluate":true}
],
"data": [{"name":"multitimer.json"}],
diff --git a/apps/multitimer/settings.js b/apps/multitimer/settings.js
new file mode 100644
index 000000000..4faeb2573
--- /dev/null
+++ b/apps/multitimer/settings.js
@@ -0,0 +1,32 @@
+(function(back) {
+ const file = "multitimer.json";
+ let json = require('Storage').readJSON(file, true) || {};
+ if (Array.isArray(json)) {
+ // old format, convert
+ json = { sw: json };
+ }
+ if (!json.sw) json.sw = [];
+
+ function writeSettings() {
+ require('Storage').writeJSON(file, json);
+ }
+
+ const screens = ["Timers", "Chronos", "Alarms"];
+
+ E.showMenu({
+ "": {
+ "title": "multitimer"
+ },
+ "< Back": back,
+ "Initial screen": {
+ value: json.initialScreen || 0,
+ min: 0,
+ max: screens.length - 1,
+ format: v => screens[v],
+ onchange: v => {
+ json.initialScreen = v;
+ writeSettings();
+ }
+ },
+ });
+});
diff --git a/apps/novaclock/app.js b/apps/novaclock/app.js
index 52bee0dbd..13cf3bfb3 100644
--- a/apps/novaclock/app.js
+++ b/apps/novaclock/app.js
@@ -85,7 +85,7 @@ function novaOpenEyes(speed, white, animation) {
scale: 2.2
});
}, speed * 5);
- } else {}
+ }
} else {
g.drawImage(novaEyesStage4(), -10, -10, {
@@ -126,7 +126,7 @@ function novaOpenEyes(speed, white, animation) {
});
open = true;
}, speed * 5);
- } else {}
+ }
}
}
@@ -136,7 +136,7 @@ function novaCloseEyes(speed, white, animation) {
g.drawImage(novaEyesStage0(), -10, -10, {
scale: 2.2
});
- } else {}
+ }
setTimeout(function() {
g.drawImage(novaEyesStage1(), -10, -10, {
scale: 2.2
@@ -164,7 +164,7 @@ function novaCloseEyes(speed, white, animation) {
g.drawImage(novaEyesWhiteStage0(), -10, -10, {
scale: 2.2
});
- } else {}
+ }
setTimeout(function() {
timedraw(true);
g.drawImage(novaEyesTransStage1(), -10, -10, {
diff --git a/apps/red7game/ChangeLog b/apps/red7game/ChangeLog
index ffe131874..fffef63d5 100644
--- a/apps/red7game/ChangeLog
+++ b/apps/red7game/ChangeLog
@@ -4,3 +4,4 @@
0.04: Update cards to draw rounded on newer firmware. Make sure in-game menu can't be pulled up during end of game.
0.05: add confirmation prompt to new game to prevent fat fingering new game during existing one.
0.06: fix AI logic typo and add prompt to show what AI played each turn.
+0.07: Minor code improvements.
diff --git a/apps/red7game/metadata.json b/apps/red7game/metadata.json
index eeb1cfcb8..5f41740ed 100644
--- a/apps/red7game/metadata.json
+++ b/apps/red7game/metadata.json
@@ -2,7 +2,7 @@
"name": "Red 7 Card Game",
"shortName" : "Red 7",
"icon": "icon.png",
- "version":"0.06",
+ "version":"0.07",
"description": "An implementation of the card game Red 7 for your watch. Play against the AI and be the last player still in the game to win!",
"tags": "game",
"supports":["BANGLEJS2"],
diff --git a/apps/red7game/red7.js b/apps/red7game/red7.js
index 697d36f97..fc8116cb8 100644
--- a/apps/red7game/red7.js
+++ b/apps/red7game/red7.js
@@ -486,8 +486,7 @@ function canPlay(hand, palette, otherPalette) {
} else {
//Check if any palette play can win with rule.
for(let h of hand.handCards) {
- if(h === c) {}
- else {
+ if(h !== c) {
clonePalette.addCard(c);
if(isWinningCombo(c, clonePalette, otherPalette)) {
return true;
@@ -531,8 +530,7 @@ class AI {
} else {
//Check if any palette play can win with rule.
for(let h of this.hand.handCards) {
- if(h === c) {}
- else {
+ if(h !== c) {
clonePalette.addCard(h);
if(isWinningCombo(c, clonePalette, otherPalette)) {
ruleStack.addCard(c);
diff --git a/apps/rep/interface.html b/apps/rep/interface.html
index e14fea4c9..5356b091f 100644
--- a/apps/rep/interface.html
+++ b/apps/rep/interface.html
@@ -101,7 +101,8 @@ function getData() {
uploadBtn.disabled = true;
Util.showModal("Loading...");
- Util.readStorageJSON(repJson, reps => {
+ Util.readStorageJSON(repJson, reps_ => {
+ reps = reps_;
Util.hideModal();
for(const rep of reps){
renderRep(rep);
diff --git a/apps/sched/ChangeLog b/apps/sched/ChangeLog
index 92b04fb32..98cedd5ad 100644
--- a/apps/sched/ChangeLog
+++ b/apps/sched/ChangeLog
@@ -23,3 +23,5 @@
0.20: Alarm dismiss and snooze events
0.21: Fix crash in clock_info
0.22: Dated event repeat option
+0.23: Allow buzzing forever when an alarm fires
+0.24: Emit alarmReload when alarms change (used by widalarm)
diff --git a/apps/sched/README.md b/apps/sched/README.md
index 2fb201cee..1216a1a11 100644
--- a/apps/sched/README.md
+++ b/apps/sched/README.md
@@ -14,10 +14,10 @@ Global Settings
---------------
- `Unlock at Buzz` - If `Yes` the alarm/timer will unlock the watch
+- `Delete Expired Timers` - Default for whether expired timers are removed after firing.
- `Default Auto Snooze` - Default _Auto Snooze_ value for newly created alarms (_Alarms_ only)
- `Default Snooze` - Default _Snooze_ value for newly created alarms/timers
-- `Default Repeat` - Default _Repeat_ value for newly created alarms (_Alarms_ only)
-- `Buzz Count` - The number of buzzes before the watch goes silent
+- `Buzz Count` - The number of buzzes before the watch goes silent, or "forever" to buzz until stopped.
- `Buzz Interval` - The interval between one buzz and the next
- `Default Alarm/Timer Pattern` - Default vibration pattern for newly created alarms/timers
diff --git a/apps/sched/interface.html b/apps/sched/interface.html
index 62e45676b..73ceff3c1 100644
--- a/apps/sched/interface.html
+++ b/apps/sched/interface.html
@@ -2,6 +2,26 @@
+