diff --git a/apps/run/ChangeLog b/apps/run/ChangeLog index 3638407ef..e79696c78 100644 --- a/apps/run/ChangeLog +++ b/apps/run/ChangeLog @@ -14,3 +14,4 @@ 0.13: Revert #1578 (stop duplicate entries) as with 2v12 menus it causes other boxes to be wiped (fix #1643) 0.14: Fix Bangle.js 1 issue where after the 'overwrite track' menu, the start/stop button stopped working 0.15: Keep run state between runs (allowing you to exit and restart the app) +0.16: Added ability to resume a run that was stopped previously (fix #1907) \ No newline at end of file diff --git a/apps/run/app.js b/apps/run/app.js index a56fce31c..73278566f 100644 --- a/apps/run/app.js +++ b/apps/run/app.js @@ -51,7 +51,18 @@ function setStatus(running) { // Called to start/stop running function onStartStop() { var running = !exs.state.active; - var prepPromises = []; + var shouldResume = false; + var promise = Promise.resolve(); + + if (running && exs.state.duration > 10000) { // if more than 10 seconds of duration, ask if we should resume? + promise = promise. + then(() => { + isMenuDisplayed = true; + return E.showPrompt("Resume run?",{title:"Run"}); + }).then(r => { + isMenuDisplayed=false;shouldResume=r; + }); + } // start/stop recording // Do this first in case recorder needs to prompt for @@ -59,35 +70,34 @@ function onStartStop() { if (settings.record && WIDGETS["recorder"]) { if (running) { isMenuDisplayed = true; - prepPromises.push( - WIDGETS["recorder"].setRecording(true).then(() => { + promise = promise. + then(() => WIDGETS["recorder"].setRecording(true)). + then(() => { isMenuDisplayed = false; layout.setUI(); // grab our input handling again layout.forgetLazyState(); layout.render(); - }) - ); + }); } else { - prepPromises.push( - WIDGETS["recorder"].setRecording(false) + promise = promise.then( + () => WIDGETS["recorder"].setRecording(false) ); } } - if (!prepPromises.length) // fix for Promise.all bug in 2v12 - prepPromises.push(Promise.resolve()); - - Promise.all(prepPromises) - .then(() => { - if (running) { + promise = promise.then(() => { + if (running) { + if (shouldResume) + exs.resume() + else exs.start(); - } else { - exs.stop(); - } - // if stopping running, don't clear state - // so we can at least refer to what we've done - setStatus(running); - }); + } else { + exs.stop(); + } + // if stopping running, don't clear state + // so we can at least refer to what we've done + setStatus(running); + }); } var lc = []; diff --git a/apps/run/metadata.json b/apps/run/metadata.json index 2d38f0249..ed253a319 100644 --- a/apps/run/metadata.json +++ b/apps/run/metadata.json @@ -1,6 +1,6 @@ { "id": "run", "name": "Run", - "version":"0.15", + "version":"0.16", "description": "Displays distance, time, steps, cadence, pace and more for runners.", "icon": "app.png", "tags": "run,running,fitness,outdoors,gps", diff --git a/modules/exstats.js b/modules/exstats.js index 1d3e27d0a..403314ddf 100644 --- a/modules/exstats.js +++ b/modules/exstats.js @@ -61,7 +61,9 @@ E.showMenu(menu); */ var state = { active : false, // are we working or not? - // startTime, // time exercise started + // startTime, // time exercise started (in ms from 1970) + // lastTime, // time we had our last reading (in ms from 1970) + duration : 0, // the length of this exercise (in ms) lastGPS:{}, thisGPS:{}, // This & previous GPS readings // distance : 0, ///< distance in meters // avrSpeed : 0, ///< speed over whole run in m/sec @@ -146,8 +148,7 @@ Bangle.on("GPS", function(fix) { if (state.lastGPS.fix) state.distance += calcDistance(state.lastGPS, fix); if (stats["dist"]) stats["dist"].emit("changed",stats["dist"]); - var duration = Date.now() - state.startTime; // in ms - state.avrSpeed = state.distance * 1000 / duration; // meters/sec + state.avrSpeed = state.distance * 1000 / state.duration; // meters/sec if (!isNaN(fix.speed)) state.curSpeed = state.curSpeed*0.8 + fix.speed*0.2/3.6; // meters/sec if (stats["pacea"]) stats["pacea"].emit("changed",stats["pacea"]); if (stats["pacec"]) stats["pacec"].emit("changed",stats["pacec"]); @@ -160,8 +161,8 @@ Bangle.on("GPS", function(fix) { Bangle.on("step", function(steps) { if (!state.active) return; if (stats["step"]) stats["step"].emit("changed",stats["step"]); - state.stepHistory[0] += steps-state.lastStepCount; - state.lastStepCount = steps; + state.stepHistory[0] += steps-state.lastSteps; + state.lastSteps = steps; if (state.notify.step.increment > 0 && state.notify.step.next <= steps) { stats["step"].emit("notify",stats["step"]); state.notify.step.next = state.notify.step.next + state.notify.step.increment; @@ -325,9 +326,10 @@ exports.getStats = function(statIDs, options) { if (!state.active) return; // called once a second var now = Date.now(); - var duration = now - state.startTime; // in ms + state.duration += now - state.lastTime; // in ms + state.lastTime = now; // set cadence -> steps over last minute - state.stepsPerMin = Math.round(60000 * E.sum(state.stepHistory) / Math.min(duration,60000)); + state.stepsPerMin = Math.round(60000 * E.sum(state.stepHistory) / Math.min(state.duration,60000)); if (stats["caden"]) stats["caden"].emit("changed",stats["caden"]); // move step history onwards state.stepHistory.set(state.stepHistory,1); @@ -345,9 +347,9 @@ exports.getStats = function(statIDs, options) { } }, 1000); function reset() { - state.startTime = Date.now(); + state.startTime = state.lastTime = Date.now(); + state.duration = 0; state.startSteps = state.lastSteps = Bangle.getStepCount(); - state.lastSteps = 0; state.stepHistory.fill(0); state.stepsPerMin = 0; state.distance = 0; @@ -374,12 +376,17 @@ exports.getStats = function(statIDs, options) { stats : stats, state : state, start : function() { - state.active = true; reset(); + state.active = true; }, stop : function() { state.active = false; - } + }, + resume : function() { + state.lastTime = Date.now(); + state.lastSteps = Bangle.getStepCount() + state.active = true; + }, }; };