From 551a5db61158a3f6bdec51b54f663ca27c702538 Mon Sep 17 00:00:00 2001 From: Erovia Date: Fri, 23 Feb 2024 17:06:16 +0000 Subject: [PATCH] Add possibility of creating a custom exercise --- apps/c25k/ChangeLog | 1 + apps/c25k/README.md | 15 +++++ apps/c25k/app.js | 123 +++++++++++++++++++++++++++------------ apps/c25k/c25k-scrn9.png | Bin 0 -> 3472 bytes apps/c25k/metadata.json | 5 +- 5 files changed, 105 insertions(+), 39 deletions(-) create mode 100644 apps/c25k/c25k-scrn9.png diff --git a/apps/c25k/ChangeLog b/apps/c25k/ChangeLog index 3fa68b916..0e7594334 100644 --- a/apps/c25k/ChangeLog +++ b/apps/c25k/ChangeLog @@ -1,3 +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 index 5d56fe17c..8237199d5 100644 --- a/apps/c25k/README.md +++ b/apps/c25k/README.md @@ -50,6 +50,21 @@ For example `w6d1(r:6|w:3|x2)` means: --- +### Create a custom excercise + +Under the `Custom run` menu, it's possible to create a custom excercise. +![](c25k-scrn9.png) + +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: diff --git a/apps/c25k/app.js b/apps/c25k/app.js index e7cd2276f..eed918e46 100644 --- a/apps/c25k/app.js +++ b/apps/c25k/app.js @@ -1,6 +1,10 @@ -var week = 1; -var day = 1; -var time; +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 @@ -11,8 +15,9 @@ 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 : 8; // Default font size, Banglejs 2 has smaller +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(); @@ -27,6 +32,7 @@ function outOfTime() { 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; } } @@ -51,11 +57,9 @@ function countDown() { 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; + var total = ("walk" in currentActivity) ? currentActivity.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 + 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; @@ -74,7 +78,7 @@ function countDown() { } } -function startTimer(w, d) { +function startTimer() { // If something is already running, do nothing if (activityInterval) return; @@ -82,12 +86,12 @@ function startTimer(w, d) { if (!currentMode || currentMode === "walk") { currentMode = "run"; rep++; // Increase the rep counter every time a "run" activity starts - counter = PLAN[w][d].run * 60; + counter = currentActivity.run * 60; activityBgColour = "#ff5733"; // Red background for running } else { currentMode = "walk"; - counter = PLAN[w][d].walk * 60; + counter = currentActivity.walk * 60; activityBgColour = "#4da80a"; // Green background for walking } @@ -128,27 +132,23 @@ function populatePlan() { } } -// Helper function to generate functions for the PLAN menu +// Helper function to generate functions for the activePlan menu function getFunc(i, j) { return function() { - week = i + 1; - day = j + 1; + currentActivity = PLAN[i][j]; startActivity(); }; } function startActivity() { - var w = week - 1; - var d = day - 1; - - loop = ("walk" in PLAN[w][d]) ? PLAN[w][d].repetition * 2 : 1; + 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(w, d);}, 1000); // Check every second if we need to do something + mainInterval = setInterval(function() {startTimer();}, 1000); // Check every second if we need to do something } // Pause or resume current activity @@ -207,35 +207,84 @@ const PLAN = [ ], ]; +var customRun = {"run": 1}; + // Main menu var mainmenu = { - "" : { - "title" : "-- C25K --" - }, - "Week" : { - value : week, - min:1,max:PLAN.length,step:1, + "": { "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; } + "Day": { + value: day, + min: 1, max: 3, step: 1, + onchange: v => { day = v; } }, - "View plan" : function() { E.showMenu(planmenu); }, - "Start" : function() { startActivity(); }, - "Exit" : function() { load(); }, + "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);}, - } + "": { title: "-- Plan --" }, + "< Back": function() { E.showMenu(mainmenu);}, }; -// Populate the PLAN menu view +// 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/c25k-scrn9.png b/apps/c25k/c25k-scrn9.png new file mode 100644 index 0000000000000000000000000000000000000000..53dbaad1f49b5cc49adb5a3fbc1838d86666cb6a GIT binary patch literal 3472 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 BJLUiY literal 0 HcmV?d00001 diff --git a/apps/c25k/metadata.json b/apps/c25k/metadata.json index e7c616d94..876926a0c 100644 --- a/apps/c25k/metadata.json +++ b/apps/c25k/metadata.json @@ -2,7 +2,7 @@ "id": "c25k", "name": "C25K", "icon": "app.png", - "version":"0.03", + "version":"0.04", "description": "Unofficial app for the Couch to 5k training plan", "readme": "README.md", "type": "app", @@ -24,6 +24,7 @@ {"url": "c25k-scrn5.png"}, {"url": "c25k-scrn6.png"}, {"url": "c25k-scrn7.png"}, - {"url": "c25k-scrn8.png"} + {"url": "c25k-scrn8.png"}, + {"url": "c25k-scrn9.png"} ] }