From 42389fd9b41bf28fc717964db9abd7696e03aaf5 Mon Sep 17 00:00:00 2001 From: Erovia Date: Thu, 22 Feb 2024 15:39:13 +0000 Subject: [PATCH] Add option to pause/resume workout (Bangle.js 1 only) --- apps/c25k/ChangeLog | 1 + apps/c25k/README.md | 13 ++++- apps/c25k/app.js | 120 +++++++++++++++++++++++---------------- apps/c25k/c25k-scrn8.png | Bin 0 -> 2334 bytes apps/c25k/metadata.json | 5 +- 5 files changed, 87 insertions(+), 52 deletions(-) create mode 100644 apps/c25k/c25k-scrn8.png diff --git a/apps/c25k/ChangeLog b/apps/c25k/ChangeLog index 4ef344621..3fa68b916 100644 --- a/apps/c25k/ChangeLog +++ b/apps/c25k/ChangeLog @@ -1,2 +1,3 @@ 0.01: New App! 0.02: Add rep info to time screen +0.03: Add option to pause/resume workout (Bangle.js 1 only) diff --git a/apps/c25k/README.md b/apps/c25k/README.md index 8d523700f..5d56fe17c 100644 --- a/apps/c25k/README.md +++ b/apps/c25k/README.md @@ -50,7 +50,7 @@ For example `w6d1(r:6|w:3|x2)` means: --- -### Show the time: +### Show extra info: If you ever need to peek at the time, just press the middle (or only) physical button on the watch: ![](c25k-scrn7.png) @@ -59,6 +59,15 @@ 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: +![](c25k-scrn8.png) + +--- + ## Disclaimer This app was hacked together in a day with no JS knowledge. @@ -69,4 +78,4 @@ It *should* work fine on the Bangle.js 2, but I couldn't test it on real hardwar --- -Made with <3 by [Erovia](https://github.com/Erovia) +Made with <3 by [Erovia](https://github.com/Erovia/BangleApps/tree/c25k) diff --git a/apps/c25k/app.js b/apps/c25k/app.js index 2f80626f3..e7cd2276f 100644 --- a/apps/c25k/app.js +++ b/apps/c25k/app.js @@ -3,27 +3,26 @@ var day = 1; var time; var loop; // To store how many times we will have to do a countdown -var rep = 0; // The current rep counter -var counter = 0; // The seconds counter +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 buttonWatch; // Watch for button presses +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 : 8; // Default font size, Banglejs 2 has smaller +var activityBgColour; // Background colour of current activity function outOfTime() { - // Buzz 3 times on state transitions - 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)); + buzz(); // Once we're done if (loop == 0) { - clearWatch(buttonWatch); // Don't watch for button presses anymore + 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 - g.clear(); - g.drawString("Done", g.getWidth()/2, g.getHeight()/2); // Write "Done" to screen + 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 @@ -31,54 +30,69 @@ function outOfTime() { } } -function countDown() { - var text = ""; - var textsize = (process.env.HWVERSION == 2) ? 7 : 8; // Default font size, Banglejs 2 has smaller screen - if (time) { - var w = week -1; - var d = day - 1; - var total = ("walk" in PLAN[w][d]) ? PLAN[w][d].repetition : 1; - text += rep + "/" + total + "\n"; // Show the current/total rep count when time is shown - textsize -= (process.env.HWVERSION == 2) ? 2 : 1; // 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; +// 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", textsize); - g.drawString(text, g.getWidth() / 2, g.getHeight() / 2); // draw the current mode and seconds - Bangle.setLCDPower(1); // keep the watch LCD lit up + g.setFont("6x8", size); + g.drawString(text, g.getWidth() / 2, g.getHeight() / 2); +} - counter--; // Reduce the seconds +function countDown() { + if (!paused) { + var text = ""; + var size = defaultFontSize; + if (time) { + var w = week -1; + var d = day - 1; + var total = ("walk" in PLAN[w][d]) ? PLAN[w][d].repetition : 1; + text += rep + "/" + total + "\n"; // Show the current/total rep count when time is shown + size -= (process.env.HWVERSION == 2) ? 2 : 1; // 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 - // If the current activity is done - if (counter < 0) { - clearInterval(activityInterval); - activityInterval = undefined; - outOfTime(); - return; + counter--; // Reduce the seconds + + // If the current activity is done + if (counter < 0) { + clearInterval(activityInterval); + activityInterval = undefined; + outOfTime(); + return; + } } } function startTimer(w, d) { // If something is already running, do nothing - if (activityInterval) { - return; - } + 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 = PLAN[w][d].run * 60; - g.setBgColor("#ff5733"); + activityBgColour = "#ff5733"; // Red background for running } else { currentMode = "walk"; counter = PLAN[w][d].walk * 60; - g.setBgColor("#4da80a"); + activityBgColour = "#4da80a"; // Green background for walking + } + g.setBgColor(activityBgColour); countDown(); if (!activityInterval) { loop--; // Reduce the number of iterations @@ -103,9 +117,7 @@ function populatePlan() { // 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 - } + 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; @@ -129,15 +141,27 @@ function startActivity() { var w = week - 1; var d = day - 1; - if ("walk" in PLAN[w][d]) { - loop = PLAN[w][d].repetition * 2; + loop = ("walk" in PLAN[w][d]) ? PLAN[w][d].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(w, d);}, 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 { - loop = 1; + g.setBgColor(activityBgColour); } - E.showMenu(); // Hide the main menu - buttonWatch = setWatch(showTime, (process.env.HWVERSION == 2) ? BTN1 : BTN2, {repeat: true}); // Show the clock on button press - mainInterval = setInterval(function() {startTimer(w, d);}, 1000); // Check every second if we need to do something } const PLAN = [ diff --git a/apps/c25k/c25k-scrn8.png b/apps/c25k/c25k-scrn8.png new file mode 100644 index 0000000000000000000000000000000000000000..1cd92d876d8583a7d75bb022e71a920ef767e10f GIT binary patch literal 2334 zcmeAS@N?(olHy`uVBq!ia0vp^A3&Ic4M^IBzMKT47>k44ofy`glX=O&z;VOV#WAEJ z?(H4NNw--HeN1E%jnGX#IE$?reE>%r!Iy8i25uldt|?cJKk_m8UYT^F){%lg%yZLI!z zT7KT&YM0#@RPd7Z{?-LQmYk}cw}18e68`wzyYlU)zWdz#S?I@#2_hzq{T+3GikbEw z={?|ngX2%Flji)@^DA;I_c;A`R?vO6&U%;nhl{!wg@5QXy|k-tt;=1Xbb+Og_e-q# zoz?d_Y#QThnD%dTyI-dzYBblsc-e9P=a+3>{<&It>GATu1|0`?3I`>|u{9dN5 zx<{^72AvCk?%6;8-1J!e#(pkOZolXK=l*{^e;KGcb6&~6S2iy{UjDi1wd#jJ#ms{* z|6KgZIY-dz=km{yvyT6-yFEQZ^Q8Fm%T1SmnuJyTDX}{{`CR;5b=x|t__Dq84!E~2 zVO{>&{rPv6a~whzZ_JXj*-VN@b)%Qlt`L?_=^W4UiLn`U&&Oj=9s`#@2C*lv3kD2 z%h`vHmfvaLFSX>3O{2Z}?n~3dUxdqV<+ppz`G)h)8L!xy<_}zdeK_UM3d}fg{>{0b z1247j7>oZubLMEnqwqD`Y|b0hq^s?{SMqOe&iR^euWZES|L;*ZX#6j}KiGEj=lC;A zxM!U^-gt;VX72MxkA;7%c)z8g zr4NC3Vc~^c;FkE0z}WP^3lA-RygdHa-Ko#leNK~_`+fh^*!S8`+#U$rsDI4zuSegTe~DWM4fTPKtn literal 0 HcmV?d00001 diff --git a/apps/c25k/metadata.json b/apps/c25k/metadata.json index da3d061c6..e7c616d94 100644 --- a/apps/c25k/metadata.json +++ b/apps/c25k/metadata.json @@ -2,7 +2,7 @@ "id": "c25k", "name": "C25K", "icon": "app.png", - "version":"0.02", + "version":"0.03", "description": "Unofficial app for the Couch to 5k training plan", "readme": "README.md", "type": "app", @@ -23,6 +23,7 @@ {"url": "c25k-scrn4.png"}, {"url": "c25k-scrn5.png"}, {"url": "c25k-scrn6.png"}, - {"url": "c25k-scrn7.png"} + {"url": "c25k-scrn7.png"}, + {"url": "c25k-scrn8.png"} ] }