incyclist-services 1.7.81 → 1.7.83
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/cjs/routes/list/cards/RouteCard.js +24 -0
- package/lib/cjs/workouts/list/service.js +4 -0
- package/lib/cjs/workouts/page/service.js +15 -2
- package/lib/cjs/workouts/ride/page/service.js +42 -15
- package/lib/esm/routes/list/cards/RouteCard.js +25 -1
- package/lib/esm/workouts/list/service.js +4 -0
- package/lib/esm/workouts/page/service.js +15 -2
- package/lib/esm/workouts/ride/page/service.js +42 -15
- package/lib/types/appstate/types.d.ts +1 -1
- package/lib/types/routes/list/cards/RouteCard.d.ts +1 -0
- package/lib/types/workouts/page/service.d.ts +1 -0
- package/lib/types/workouts/ride/page/service.d.ts +8 -2
- package/lib/types/workouts/ride/page/types.d.ts +7 -0
- package/package.json +2 -2
|
@@ -389,6 +389,13 @@ let RouteCard = (() => {
|
|
|
389
389
|
showNextOverwrite = false;
|
|
390
390
|
}
|
|
391
391
|
}
|
|
392
|
+
if (showNextOverwrite) {
|
|
393
|
+
const nextVideoEnabled = this.isMobile() ? this.getAppState().hasFeature('MOBILE_NEXT_VIDEO') : true;
|
|
394
|
+
if (!nextVideoEnabled) {
|
|
395
|
+
showNextOverwrite = false;
|
|
396
|
+
uiSettings.nextOverwrite = true;
|
|
397
|
+
}
|
|
398
|
+
}
|
|
392
399
|
}
|
|
393
400
|
catch (err) {
|
|
394
401
|
this.logError(err, 'openSettings');
|
|
@@ -540,6 +547,7 @@ let RouteCard = (() => {
|
|
|
540
547
|
start() {
|
|
541
548
|
try {
|
|
542
549
|
const service = (0, service_1.getRouteList)();
|
|
550
|
+
this.enforceNextVideoOverrideOnMobile();
|
|
543
551
|
service.select(this.route);
|
|
544
552
|
service.setStartSettings({ type: this.getCardType(), ...this.startSettings });
|
|
545
553
|
this.route.description.tsLastStart = Date.now();
|
|
@@ -556,6 +564,7 @@ let RouteCard = (() => {
|
|
|
556
564
|
addWorkout() {
|
|
557
565
|
try {
|
|
558
566
|
const service = (0, service_1.getRouteList)();
|
|
567
|
+
this.enforceNextVideoOverrideOnMobile();
|
|
559
568
|
service.select(this.route);
|
|
560
569
|
service.setStartSettings({ type: this.getCardType(), ...this.startSettings });
|
|
561
570
|
this.route.description.tsLastStart = Date.now();
|
|
@@ -565,6 +574,21 @@ let RouteCard = (() => {
|
|
|
565
574
|
this.logError(err, 'addWorkout');
|
|
566
575
|
}
|
|
567
576
|
}
|
|
577
|
+
enforceNextVideoOverrideOnMobile() {
|
|
578
|
+
try {
|
|
579
|
+
if (!this.isMobile())
|
|
580
|
+
return;
|
|
581
|
+
if (!this.startSettings || !(0, route_1.hasNextVideo)(this.route))
|
|
582
|
+
return;
|
|
583
|
+
const nextVideoEnabled = this.getAppState().hasFeature('MOBILE_NEXT_VIDEO');
|
|
584
|
+
if (!nextVideoEnabled) {
|
|
585
|
+
this.startSettings.nextOverwrite = true;
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
catch (err) {
|
|
589
|
+
this.logError(err, 'enforceNextVideoOverrideOnMobile');
|
|
590
|
+
}
|
|
591
|
+
}
|
|
568
592
|
getCurrentDownload() {
|
|
569
593
|
return this.downloadObserver;
|
|
570
594
|
}
|
|
@@ -145,6 +145,10 @@ let WorkoutListService = (() => {
|
|
|
145
145
|
}
|
|
146
146
|
close() {
|
|
147
147
|
this.getWorkoutCalendar().setActive(false);
|
|
148
|
+
this.logEvent({ message: 'close workout list' });
|
|
149
|
+
this.emit('closed', this.observer);
|
|
150
|
+
this.observer?.emit('stopped');
|
|
151
|
+
this.observer?.reset();
|
|
148
152
|
}
|
|
149
153
|
openSettings() {
|
|
150
154
|
let workouts;
|
|
@@ -43,6 +43,7 @@ const observer_1 = require("../../base/types/observer");
|
|
|
43
43
|
const settings_1 = require("../../settings");
|
|
44
44
|
const calendar_1 = require("../calendar");
|
|
45
45
|
const service_1 = require("../list/service");
|
|
46
|
+
const devices_1 = require("../../devices");
|
|
46
47
|
const DEFAULT_IMPORT_GROUP = 'My Workouts';
|
|
47
48
|
const UPCOMING_COLLAPSED_COUNT = 3;
|
|
48
49
|
let WorkoutListPageService = (() => {
|
|
@@ -52,6 +53,7 @@ let WorkoutListPageService = (() => {
|
|
|
52
53
|
let _classThis;
|
|
53
54
|
let _classSuper = pages_1.IncyclistPageService;
|
|
54
55
|
let _instanceExtraInitializers = [];
|
|
56
|
+
let _getDevicePairing_decorators;
|
|
55
57
|
let _getWorkoutList_decorators;
|
|
56
58
|
let _getWorkoutCalendar_decorators;
|
|
57
59
|
let _getUserSettings_decorators;
|
|
@@ -60,10 +62,12 @@ let WorkoutListPageService = (() => {
|
|
|
60
62
|
static { _classThis = this; }
|
|
61
63
|
static {
|
|
62
64
|
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
|
|
65
|
+
_getDevicePairing_decorators = [decorators_1.Injectable];
|
|
63
66
|
_getWorkoutList_decorators = [decorators_1.Injectable];
|
|
64
67
|
_getWorkoutCalendar_decorators = [decorators_1.Injectable];
|
|
65
68
|
_getUserSettings_decorators = [decorators_1.Injectable];
|
|
66
69
|
_getAppState_decorators = [decorators_1.Injectable];
|
|
70
|
+
__esDecorate(this, null, _getDevicePairing_decorators, { kind: "method", name: "getDevicePairing", static: false, private: false, access: { has: obj => "getDevicePairing" in obj, get: obj => obj.getDevicePairing }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
67
71
|
__esDecorate(this, null, _getWorkoutList_decorators, { kind: "method", name: "getWorkoutList", static: false, private: false, access: { has: obj => "getWorkoutList" in obj, get: obj => obj.getWorkoutList }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
68
72
|
__esDecorate(this, null, _getWorkoutCalendar_decorators, { kind: "method", name: "getWorkoutCalendar", static: false, private: false, access: { has: obj => "getWorkoutCalendar" in obj, get: obj => obj.getWorkoutCalendar }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
69
73
|
__esDecorate(this, null, _getUserSettings_decorators, { kind: "method", name: "getUserSettings", static: false, private: false, access: { has: obj => "getUserSettings" in obj, get: obj => obj.getUserSettings }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
@@ -264,9 +268,15 @@ let WorkoutListPageService = (() => {
|
|
|
264
268
|
const card = this.findWorkoutCard(id);
|
|
265
269
|
if (!card)
|
|
266
270
|
return;
|
|
267
|
-
const
|
|
271
|
+
const service = this.getWorkoutList();
|
|
272
|
+
const pairing = this.getDevicePairing();
|
|
273
|
+
const settings = service.getStartSettings() ?? {};
|
|
268
274
|
card.select({ ...settings, noRoute: opts?.noRoute });
|
|
269
|
-
this.
|
|
275
|
+
this.logEvent({ message: 'Attempting to start a ride', id, ...settings, noRoute: opts?.noRoute, readyToStart: pairing.isReadyToStart(), });
|
|
276
|
+
this.detailWorkoutId = null;
|
|
277
|
+
service.close();
|
|
278
|
+
const next = pairing.isReadyToStart() ? '/rideDeviceOK' : '/pairingStart';
|
|
279
|
+
this.moveTo(next);
|
|
270
280
|
}
|
|
271
281
|
catch (err) {
|
|
272
282
|
this.logError(err, 'onStart');
|
|
@@ -455,6 +465,9 @@ let WorkoutListPageService = (() => {
|
|
|
455
465
|
this.logError(err, 'emitImportUpdate');
|
|
456
466
|
}
|
|
457
467
|
}
|
|
468
|
+
getDevicePairing() {
|
|
469
|
+
return (0, devices_1.useDevicePairing)();
|
|
470
|
+
}
|
|
458
471
|
getWorkoutList() {
|
|
459
472
|
return (0, service_1.useWorkoutList)();
|
|
460
473
|
}
|
|
@@ -41,11 +41,13 @@ const types_1 = require("../../../base/types");
|
|
|
41
41
|
const pages_1 = require("../../../base/pages");
|
|
42
42
|
const display_1 = require("../../../ride/display");
|
|
43
43
|
const activities_1 = require("../../../activities");
|
|
44
|
+
const settings_1 = require("../../../settings");
|
|
44
45
|
const service_1 = require("../service");
|
|
45
46
|
const graph_1 = require("../../base/graph");
|
|
46
47
|
const BACKGROUND_PAUSE_TIMEOUT_MS = 300000;
|
|
47
48
|
const UPCOMING_STEPS_COUNT = 3;
|
|
48
49
|
const DEFAULT_LOAD_INCREMENT = 1;
|
|
50
|
+
const HINTS_WORKOUT_GESTURES_KEY = 'hints.workoutRideGestures';
|
|
49
51
|
let WorkoutRidePageService = (() => {
|
|
50
52
|
let _classDecorators = [types_1.Singleton];
|
|
51
53
|
let _classDescriptor;
|
|
@@ -56,6 +58,7 @@ let WorkoutRidePageService = (() => {
|
|
|
56
58
|
let _getRideDisplay_decorators;
|
|
57
59
|
let _getWorkoutRide_decorators;
|
|
58
60
|
let _getActivityRide_decorators;
|
|
61
|
+
let _getUserSettings_decorators;
|
|
59
62
|
var WorkoutRidePageService = class extends _classSuper {
|
|
60
63
|
static { _classThis = this; }
|
|
61
64
|
static {
|
|
@@ -63,9 +66,11 @@ let WorkoutRidePageService = (() => {
|
|
|
63
66
|
_getRideDisplay_decorators = [decorators_1.Injectable];
|
|
64
67
|
_getWorkoutRide_decorators = [decorators_1.Injectable];
|
|
65
68
|
_getActivityRide_decorators = [decorators_1.Injectable];
|
|
69
|
+
_getUserSettings_decorators = [decorators_1.Injectable];
|
|
66
70
|
__esDecorate(this, null, _getRideDisplay_decorators, { kind: "method", name: "getRideDisplay", static: false, private: false, access: { has: obj => "getRideDisplay" in obj, get: obj => obj.getRideDisplay }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
67
71
|
__esDecorate(this, null, _getWorkoutRide_decorators, { kind: "method", name: "getWorkoutRide", static: false, private: false, access: { has: obj => "getWorkoutRide" in obj, get: obj => obj.getWorkoutRide }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
68
72
|
__esDecorate(this, null, _getActivityRide_decorators, { kind: "method", name: "getActivityRide", static: false, private: false, access: { has: obj => "getActivityRide" in obj, get: obj => obj.getActivityRide }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
73
|
+
__esDecorate(this, null, _getUserSettings_decorators, { kind: "method", name: "getUserSettings", static: false, private: false, access: { has: obj => "getUserSettings" in obj, get: obj => obj.getUserSettings }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
69
74
|
__esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
|
|
70
75
|
WorkoutRidePageService = _classThis = _classDescriptor.value;
|
|
71
76
|
if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
|
|
@@ -77,7 +82,7 @@ let WorkoutRidePageService = (() => {
|
|
|
77
82
|
backgroundTimer;
|
|
78
83
|
backgroundPausedByService = false;
|
|
79
84
|
menuProps = null;
|
|
80
|
-
|
|
85
|
+
gestureHintDismissed = false;
|
|
81
86
|
constructor() {
|
|
82
87
|
super('WorkoutRidePage');
|
|
83
88
|
this.rideEventHandler['state-update'] = this.onRideStateUpdate.bind(this);
|
|
@@ -92,13 +97,10 @@ let WorkoutRidePageService = (() => {
|
|
|
92
97
|
try {
|
|
93
98
|
this.logEvent({ message: 'page shown', page: 'WorkoutRide' });
|
|
94
99
|
gd_eventlog_1.EventLogger.setGlobalConfig('page', 'WorkoutRide');
|
|
100
|
+
this.gestureHintDismissed = false;
|
|
95
101
|
super.openPage();
|
|
96
102
|
try {
|
|
97
103
|
const service = this.getRideDisplay();
|
|
98
|
-
if (!this.isInitialized) {
|
|
99
|
-
service.init();
|
|
100
|
-
this.isInitialized = true;
|
|
101
|
-
}
|
|
102
104
|
this.registerRideEventHandlers();
|
|
103
105
|
this.subscribeToWorkoutObserver();
|
|
104
106
|
service.start(simulate);
|
|
@@ -120,7 +122,6 @@ let WorkoutRidePageService = (() => {
|
|
|
120
122
|
this.unregisterRideEventHandlers();
|
|
121
123
|
this.unsubscribeFromWorkoutObserver();
|
|
122
124
|
this.menuProps = null;
|
|
123
|
-
this.isInitialized = false;
|
|
124
125
|
super.closePage();
|
|
125
126
|
}
|
|
126
127
|
catch (err) {
|
|
@@ -168,7 +169,8 @@ let WorkoutRidePageService = (() => {
|
|
|
168
169
|
title: wo.title ?? '',
|
|
169
170
|
graph: this.buildGraphPlan(current, wo.ftp),
|
|
170
171
|
steps: this.buildUpcomingSteps(current, wo.ftp),
|
|
171
|
-
dashboard: this.buildDashboardLine(wo)
|
|
172
|
+
dashboard: this.buildDashboardLine(wo),
|
|
173
|
+
gestureHint: this.buildGestureHint(base.startOverlayProps === null)
|
|
172
174
|
};
|
|
173
175
|
}
|
|
174
176
|
catch (err) {
|
|
@@ -284,6 +286,18 @@ let WorkoutRidePageService = (() => {
|
|
|
284
286
|
this.logError(err, 'onIgnoreStart');
|
|
285
287
|
}
|
|
286
288
|
}
|
|
289
|
+
onGestureHintDismissed({ dontShowAgain }) {
|
|
290
|
+
try {
|
|
291
|
+
this.gestureHintDismissed = true;
|
|
292
|
+
if (dontShowAgain) {
|
|
293
|
+
this.getUserSettings().set(HINTS_WORKOUT_GESTURES_KEY, true);
|
|
294
|
+
}
|
|
295
|
+
this.updatePageDisplay();
|
|
296
|
+
}
|
|
297
|
+
catch (err) {
|
|
298
|
+
this.logError(err, 'onGestureHintDismissed');
|
|
299
|
+
}
|
|
300
|
+
}
|
|
287
301
|
onCancelStart() {
|
|
288
302
|
try {
|
|
289
303
|
this.rideObserver?.stop();
|
|
@@ -314,19 +328,15 @@ let WorkoutRidePageService = (() => {
|
|
|
314
328
|
switch (state) {
|
|
315
329
|
case 'Paused':
|
|
316
330
|
this.menuProps = { showResume: true, ...this.getStepFlags() };
|
|
317
|
-
this.updatePageDisplay();
|
|
318
331
|
break;
|
|
319
332
|
case 'Active':
|
|
320
333
|
this.menuProps = null;
|
|
321
|
-
this.updatePageDisplay();
|
|
322
334
|
break;
|
|
323
335
|
case 'Finished':
|
|
324
336
|
this.emitNavigateBack();
|
|
325
|
-
|
|
326
|
-
case 'Error':
|
|
327
|
-
this.updatePageDisplay();
|
|
328
|
-
break;
|
|
337
|
+
return;
|
|
329
338
|
}
|
|
339
|
+
this.updatePageDisplay();
|
|
330
340
|
}
|
|
331
341
|
onWorkoutUpdate() {
|
|
332
342
|
this.updatePageDisplay();
|
|
@@ -367,13 +377,26 @@ let WorkoutRidePageService = (() => {
|
|
|
367
377
|
startGateProps: null
|
|
368
378
|
};
|
|
369
379
|
}
|
|
380
|
+
buildGestureHint(startOverlayCleared) {
|
|
381
|
+
if (this.gestureHintDismissed || !startOverlayCleared)
|
|
382
|
+
return null;
|
|
383
|
+
if (this.getElapsedActivityTime() !== 0 || this.getCurrentCadence() !== 0)
|
|
384
|
+
return null;
|
|
385
|
+
if (this.getUserSettings().get(HINTS_WORKOUT_GESTURES_KEY, false))
|
|
386
|
+
return null;
|
|
387
|
+
return { visible: true };
|
|
388
|
+
}
|
|
389
|
+
getCurrentCadence() {
|
|
390
|
+
return this.getActivityRide().getCurrentValues?.()?.cadence ?? 0;
|
|
391
|
+
}
|
|
370
392
|
buildGraphPlan(current, ftp) {
|
|
371
393
|
if (!current) {
|
|
372
394
|
return { bars: [], ftp: ftp ?? 0, ftpLine: ftp ?? 0, domain: { x: [0, 0], y: [0, 0] } };
|
|
373
395
|
}
|
|
374
396
|
const bars = (0, graph_1.getWorkoutGraphSeries)(current, { ftp, absValues: true });
|
|
375
397
|
const lastBarX = bars.length ? bars.at(-1).x : 0;
|
|
376
|
-
const
|
|
398
|
+
const maxXCandidates = [this.getLastLogTime(), lastBarX, current.duration ?? 0].filter(Number.isFinite);
|
|
399
|
+
const maxX = maxXCandidates.length ? Math.max(...maxXCandidates) : 0;
|
|
377
400
|
const maxBarPower = bars.length ? Math.max(...bars.map(b => b.y)) : 0;
|
|
378
401
|
return {
|
|
379
402
|
bars,
|
|
@@ -460,7 +483,8 @@ let WorkoutRidePageService = (() => {
|
|
|
460
483
|
title: '',
|
|
461
484
|
graph: { bars: [], ftp: 0, ftpLine: 0, domain: { x: [0, 0], y: [0, 0] } },
|
|
462
485
|
steps: { previous: null, current: null, upcoming: [], hasMore: false },
|
|
463
|
-
dashboard: { text: '', mode: null }
|
|
486
|
+
dashboard: { text: '', mode: null },
|
|
487
|
+
gestureHint: null
|
|
464
488
|
};
|
|
465
489
|
}
|
|
466
490
|
updatePageDisplay() {
|
|
@@ -490,6 +514,9 @@ let WorkoutRidePageService = (() => {
|
|
|
490
514
|
getActivityRide() {
|
|
491
515
|
return (0, activities_1.useActivityRide)();
|
|
492
516
|
}
|
|
517
|
+
getUserSettings() {
|
|
518
|
+
return (0, settings_1.useUserSettings)();
|
|
519
|
+
}
|
|
493
520
|
};
|
|
494
521
|
return WorkoutRidePageService = _classThis;
|
|
495
522
|
})();
|
|
@@ -43,7 +43,7 @@ import { valid } from "../../../utils/valid";
|
|
|
43
43
|
import { waitNextTick } from "../../../utils";
|
|
44
44
|
import { useRouteDownload } from "../../download/service";
|
|
45
45
|
import { EventLogger } from "gd-eventlog";
|
|
46
|
-
import { checkIsLoop, getNextVideoId, getPosition, updateSlopes } from "../../base/utils/route";
|
|
46
|
+
import { checkIsLoop, getNextVideoId, hasNextVideo, getPosition, updateSlopes } from "../../base/utils/route";
|
|
47
47
|
import { getWorkoutList } from "../../../workouts";
|
|
48
48
|
import { checkIsNew } from "../utils";
|
|
49
49
|
import { useOnlineStatusMonitoring } from "../../../monitoring";
|
|
@@ -386,6 +386,13 @@ let RouteCard = (() => {
|
|
|
386
386
|
showNextOverwrite = false;
|
|
387
387
|
}
|
|
388
388
|
}
|
|
389
|
+
if (showNextOverwrite) {
|
|
390
|
+
const nextVideoEnabled = this.isMobile() ? this.getAppState().hasFeature('MOBILE_NEXT_VIDEO') : true;
|
|
391
|
+
if (!nextVideoEnabled) {
|
|
392
|
+
showNextOverwrite = false;
|
|
393
|
+
uiSettings.nextOverwrite = true;
|
|
394
|
+
}
|
|
395
|
+
}
|
|
389
396
|
}
|
|
390
397
|
catch (err) {
|
|
391
398
|
this.logError(err, 'openSettings');
|
|
@@ -537,6 +544,7 @@ let RouteCard = (() => {
|
|
|
537
544
|
start() {
|
|
538
545
|
try {
|
|
539
546
|
const service = getRouteList();
|
|
547
|
+
this.enforceNextVideoOverrideOnMobile();
|
|
540
548
|
service.select(this.route);
|
|
541
549
|
service.setStartSettings({ type: this.getCardType(), ...this.startSettings });
|
|
542
550
|
this.route.description.tsLastStart = Date.now();
|
|
@@ -553,6 +561,7 @@ let RouteCard = (() => {
|
|
|
553
561
|
addWorkout() {
|
|
554
562
|
try {
|
|
555
563
|
const service = getRouteList();
|
|
564
|
+
this.enforceNextVideoOverrideOnMobile();
|
|
556
565
|
service.select(this.route);
|
|
557
566
|
service.setStartSettings({ type: this.getCardType(), ...this.startSettings });
|
|
558
567
|
this.route.description.tsLastStart = Date.now();
|
|
@@ -562,6 +571,21 @@ let RouteCard = (() => {
|
|
|
562
571
|
this.logError(err, 'addWorkout');
|
|
563
572
|
}
|
|
564
573
|
}
|
|
574
|
+
enforceNextVideoOverrideOnMobile() {
|
|
575
|
+
try {
|
|
576
|
+
if (!this.isMobile())
|
|
577
|
+
return;
|
|
578
|
+
if (!this.startSettings || !hasNextVideo(this.route))
|
|
579
|
+
return;
|
|
580
|
+
const nextVideoEnabled = this.getAppState().hasFeature('MOBILE_NEXT_VIDEO');
|
|
581
|
+
if (!nextVideoEnabled) {
|
|
582
|
+
this.startSettings.nextOverwrite = true;
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
catch (err) {
|
|
586
|
+
this.logError(err, 'enforceNextVideoOverrideOnMobile');
|
|
587
|
+
}
|
|
588
|
+
}
|
|
565
589
|
getCurrentDownload() {
|
|
566
590
|
return this.downloadObserver;
|
|
567
591
|
}
|
|
@@ -142,6 +142,10 @@ let WorkoutListService = (() => {
|
|
|
142
142
|
}
|
|
143
143
|
close() {
|
|
144
144
|
this.getWorkoutCalendar().setActive(false);
|
|
145
|
+
this.logEvent({ message: 'close workout list' });
|
|
146
|
+
this.emit('closed', this.observer);
|
|
147
|
+
this.observer?.emit('stopped');
|
|
148
|
+
this.observer?.reset();
|
|
145
149
|
}
|
|
146
150
|
openSettings() {
|
|
147
151
|
let workouts;
|
|
@@ -40,6 +40,7 @@ import { Observer } from "../../base/types/observer";
|
|
|
40
40
|
import { useUserSettings } from "../../settings";
|
|
41
41
|
import { useWorkoutCalendar } from "../calendar";
|
|
42
42
|
import { useWorkoutList } from "../list/service";
|
|
43
|
+
import { useDevicePairing } from "../../devices";
|
|
43
44
|
const DEFAULT_IMPORT_GROUP = 'My Workouts';
|
|
44
45
|
const UPCOMING_COLLAPSED_COUNT = 3;
|
|
45
46
|
let WorkoutListPageService = (() => {
|
|
@@ -49,6 +50,7 @@ let WorkoutListPageService = (() => {
|
|
|
49
50
|
let _classThis;
|
|
50
51
|
let _classSuper = IncyclistPageService;
|
|
51
52
|
let _instanceExtraInitializers = [];
|
|
53
|
+
let _getDevicePairing_decorators;
|
|
52
54
|
let _getWorkoutList_decorators;
|
|
53
55
|
let _getWorkoutCalendar_decorators;
|
|
54
56
|
let _getUserSettings_decorators;
|
|
@@ -57,10 +59,12 @@ let WorkoutListPageService = (() => {
|
|
|
57
59
|
static { _classThis = this; }
|
|
58
60
|
static {
|
|
59
61
|
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
|
|
62
|
+
_getDevicePairing_decorators = [Injectable];
|
|
60
63
|
_getWorkoutList_decorators = [Injectable];
|
|
61
64
|
_getWorkoutCalendar_decorators = [Injectable];
|
|
62
65
|
_getUserSettings_decorators = [Injectable];
|
|
63
66
|
_getAppState_decorators = [Injectable];
|
|
67
|
+
__esDecorate(this, null, _getDevicePairing_decorators, { kind: "method", name: "getDevicePairing", static: false, private: false, access: { has: obj => "getDevicePairing" in obj, get: obj => obj.getDevicePairing }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
64
68
|
__esDecorate(this, null, _getWorkoutList_decorators, { kind: "method", name: "getWorkoutList", static: false, private: false, access: { has: obj => "getWorkoutList" in obj, get: obj => obj.getWorkoutList }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
65
69
|
__esDecorate(this, null, _getWorkoutCalendar_decorators, { kind: "method", name: "getWorkoutCalendar", static: false, private: false, access: { has: obj => "getWorkoutCalendar" in obj, get: obj => obj.getWorkoutCalendar }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
66
70
|
__esDecorate(this, null, _getUserSettings_decorators, { kind: "method", name: "getUserSettings", static: false, private: false, access: { has: obj => "getUserSettings" in obj, get: obj => obj.getUserSettings }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
@@ -261,9 +265,15 @@ let WorkoutListPageService = (() => {
|
|
|
261
265
|
const card = this.findWorkoutCard(id);
|
|
262
266
|
if (!card)
|
|
263
267
|
return;
|
|
264
|
-
const
|
|
268
|
+
const service = this.getWorkoutList();
|
|
269
|
+
const pairing = this.getDevicePairing();
|
|
270
|
+
const settings = service.getStartSettings() ?? {};
|
|
265
271
|
card.select({ ...settings, noRoute: opts?.noRoute });
|
|
266
|
-
this.
|
|
272
|
+
this.logEvent({ message: 'Attempting to start a ride', id, ...settings, noRoute: opts?.noRoute, readyToStart: pairing.isReadyToStart(), });
|
|
273
|
+
this.detailWorkoutId = null;
|
|
274
|
+
service.close();
|
|
275
|
+
const next = pairing.isReadyToStart() ? '/rideDeviceOK' : '/pairingStart';
|
|
276
|
+
this.moveTo(next);
|
|
267
277
|
}
|
|
268
278
|
catch (err) {
|
|
269
279
|
this.logError(err, 'onStart');
|
|
@@ -452,6 +462,9 @@ let WorkoutListPageService = (() => {
|
|
|
452
462
|
this.logError(err, 'emitImportUpdate');
|
|
453
463
|
}
|
|
454
464
|
}
|
|
465
|
+
getDevicePairing() {
|
|
466
|
+
return useDevicePairing();
|
|
467
|
+
}
|
|
455
468
|
getWorkoutList() {
|
|
456
469
|
return useWorkoutList();
|
|
457
470
|
}
|
|
@@ -38,11 +38,13 @@ import { Singleton } from "../../../base/types";
|
|
|
38
38
|
import { IncyclistPageService } from "../../../base/pages";
|
|
39
39
|
import { useRideDisplay } from "../../../ride/display";
|
|
40
40
|
import { useActivityRide } from "../../../activities";
|
|
41
|
+
import { useUserSettings } from "../../../settings";
|
|
41
42
|
import { useWorkoutRide } from "../service";
|
|
42
43
|
import { getFlattenedSteps, getStepDuration, getStepTargetText, getWorkoutGraphSeries } from "../../base/graph";
|
|
43
44
|
const BACKGROUND_PAUSE_TIMEOUT_MS = 300000;
|
|
44
45
|
const UPCOMING_STEPS_COUNT = 3;
|
|
45
46
|
const DEFAULT_LOAD_INCREMENT = 1;
|
|
47
|
+
const HINTS_WORKOUT_GESTURES_KEY = 'hints.workoutRideGestures';
|
|
46
48
|
let WorkoutRidePageService = (() => {
|
|
47
49
|
let _classDecorators = [Singleton];
|
|
48
50
|
let _classDescriptor;
|
|
@@ -53,6 +55,7 @@ let WorkoutRidePageService = (() => {
|
|
|
53
55
|
let _getRideDisplay_decorators;
|
|
54
56
|
let _getWorkoutRide_decorators;
|
|
55
57
|
let _getActivityRide_decorators;
|
|
58
|
+
let _getUserSettings_decorators;
|
|
56
59
|
var WorkoutRidePageService = class extends _classSuper {
|
|
57
60
|
static { _classThis = this; }
|
|
58
61
|
static {
|
|
@@ -60,9 +63,11 @@ let WorkoutRidePageService = (() => {
|
|
|
60
63
|
_getRideDisplay_decorators = [Injectable];
|
|
61
64
|
_getWorkoutRide_decorators = [Injectable];
|
|
62
65
|
_getActivityRide_decorators = [Injectable];
|
|
66
|
+
_getUserSettings_decorators = [Injectable];
|
|
63
67
|
__esDecorate(this, null, _getRideDisplay_decorators, { kind: "method", name: "getRideDisplay", static: false, private: false, access: { has: obj => "getRideDisplay" in obj, get: obj => obj.getRideDisplay }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
64
68
|
__esDecorate(this, null, _getWorkoutRide_decorators, { kind: "method", name: "getWorkoutRide", static: false, private: false, access: { has: obj => "getWorkoutRide" in obj, get: obj => obj.getWorkoutRide }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
65
69
|
__esDecorate(this, null, _getActivityRide_decorators, { kind: "method", name: "getActivityRide", static: false, private: false, access: { has: obj => "getActivityRide" in obj, get: obj => obj.getActivityRide }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
70
|
+
__esDecorate(this, null, _getUserSettings_decorators, { kind: "method", name: "getUserSettings", static: false, private: false, access: { has: obj => "getUserSettings" in obj, get: obj => obj.getUserSettings }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
66
71
|
__esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
|
|
67
72
|
WorkoutRidePageService = _classThis = _classDescriptor.value;
|
|
68
73
|
if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
|
|
@@ -74,7 +79,7 @@ let WorkoutRidePageService = (() => {
|
|
|
74
79
|
backgroundTimer;
|
|
75
80
|
backgroundPausedByService = false;
|
|
76
81
|
menuProps = null;
|
|
77
|
-
|
|
82
|
+
gestureHintDismissed = false;
|
|
78
83
|
constructor() {
|
|
79
84
|
super('WorkoutRidePage');
|
|
80
85
|
this.rideEventHandler['state-update'] = this.onRideStateUpdate.bind(this);
|
|
@@ -89,13 +94,10 @@ let WorkoutRidePageService = (() => {
|
|
|
89
94
|
try {
|
|
90
95
|
this.logEvent({ message: 'page shown', page: 'WorkoutRide' });
|
|
91
96
|
EventLogger.setGlobalConfig('page', 'WorkoutRide');
|
|
97
|
+
this.gestureHintDismissed = false;
|
|
92
98
|
super.openPage();
|
|
93
99
|
try {
|
|
94
100
|
const service = this.getRideDisplay();
|
|
95
|
-
if (!this.isInitialized) {
|
|
96
|
-
service.init();
|
|
97
|
-
this.isInitialized = true;
|
|
98
|
-
}
|
|
99
101
|
this.registerRideEventHandlers();
|
|
100
102
|
this.subscribeToWorkoutObserver();
|
|
101
103
|
service.start(simulate);
|
|
@@ -117,7 +119,6 @@ let WorkoutRidePageService = (() => {
|
|
|
117
119
|
this.unregisterRideEventHandlers();
|
|
118
120
|
this.unsubscribeFromWorkoutObserver();
|
|
119
121
|
this.menuProps = null;
|
|
120
|
-
this.isInitialized = false;
|
|
121
122
|
super.closePage();
|
|
122
123
|
}
|
|
123
124
|
catch (err) {
|
|
@@ -165,7 +166,8 @@ let WorkoutRidePageService = (() => {
|
|
|
165
166
|
title: wo.title ?? '',
|
|
166
167
|
graph: this.buildGraphPlan(current, wo.ftp),
|
|
167
168
|
steps: this.buildUpcomingSteps(current, wo.ftp),
|
|
168
|
-
dashboard: this.buildDashboardLine(wo)
|
|
169
|
+
dashboard: this.buildDashboardLine(wo),
|
|
170
|
+
gestureHint: this.buildGestureHint(base.startOverlayProps === null)
|
|
169
171
|
};
|
|
170
172
|
}
|
|
171
173
|
catch (err) {
|
|
@@ -281,6 +283,18 @@ let WorkoutRidePageService = (() => {
|
|
|
281
283
|
this.logError(err, 'onIgnoreStart');
|
|
282
284
|
}
|
|
283
285
|
}
|
|
286
|
+
onGestureHintDismissed({ dontShowAgain }) {
|
|
287
|
+
try {
|
|
288
|
+
this.gestureHintDismissed = true;
|
|
289
|
+
if (dontShowAgain) {
|
|
290
|
+
this.getUserSettings().set(HINTS_WORKOUT_GESTURES_KEY, true);
|
|
291
|
+
}
|
|
292
|
+
this.updatePageDisplay();
|
|
293
|
+
}
|
|
294
|
+
catch (err) {
|
|
295
|
+
this.logError(err, 'onGestureHintDismissed');
|
|
296
|
+
}
|
|
297
|
+
}
|
|
284
298
|
onCancelStart() {
|
|
285
299
|
try {
|
|
286
300
|
this.rideObserver?.stop();
|
|
@@ -311,19 +325,15 @@ let WorkoutRidePageService = (() => {
|
|
|
311
325
|
switch (state) {
|
|
312
326
|
case 'Paused':
|
|
313
327
|
this.menuProps = { showResume: true, ...this.getStepFlags() };
|
|
314
|
-
this.updatePageDisplay();
|
|
315
328
|
break;
|
|
316
329
|
case 'Active':
|
|
317
330
|
this.menuProps = null;
|
|
318
|
-
this.updatePageDisplay();
|
|
319
331
|
break;
|
|
320
332
|
case 'Finished':
|
|
321
333
|
this.emitNavigateBack();
|
|
322
|
-
|
|
323
|
-
case 'Error':
|
|
324
|
-
this.updatePageDisplay();
|
|
325
|
-
break;
|
|
334
|
+
return;
|
|
326
335
|
}
|
|
336
|
+
this.updatePageDisplay();
|
|
327
337
|
}
|
|
328
338
|
onWorkoutUpdate() {
|
|
329
339
|
this.updatePageDisplay();
|
|
@@ -364,13 +374,26 @@ let WorkoutRidePageService = (() => {
|
|
|
364
374
|
startGateProps: null
|
|
365
375
|
};
|
|
366
376
|
}
|
|
377
|
+
buildGestureHint(startOverlayCleared) {
|
|
378
|
+
if (this.gestureHintDismissed || !startOverlayCleared)
|
|
379
|
+
return null;
|
|
380
|
+
if (this.getElapsedActivityTime() !== 0 || this.getCurrentCadence() !== 0)
|
|
381
|
+
return null;
|
|
382
|
+
if (this.getUserSettings().get(HINTS_WORKOUT_GESTURES_KEY, false))
|
|
383
|
+
return null;
|
|
384
|
+
return { visible: true };
|
|
385
|
+
}
|
|
386
|
+
getCurrentCadence() {
|
|
387
|
+
return this.getActivityRide().getCurrentValues?.()?.cadence ?? 0;
|
|
388
|
+
}
|
|
367
389
|
buildGraphPlan(current, ftp) {
|
|
368
390
|
if (!current) {
|
|
369
391
|
return { bars: [], ftp: ftp ?? 0, ftpLine: ftp ?? 0, domain: { x: [0, 0], y: [0, 0] } };
|
|
370
392
|
}
|
|
371
393
|
const bars = getWorkoutGraphSeries(current, { ftp, absValues: true });
|
|
372
394
|
const lastBarX = bars.length ? bars.at(-1).x : 0;
|
|
373
|
-
const
|
|
395
|
+
const maxXCandidates = [this.getLastLogTime(), lastBarX, current.duration ?? 0].filter(Number.isFinite);
|
|
396
|
+
const maxX = maxXCandidates.length ? Math.max(...maxXCandidates) : 0;
|
|
374
397
|
const maxBarPower = bars.length ? Math.max(...bars.map(b => b.y)) : 0;
|
|
375
398
|
return {
|
|
376
399
|
bars,
|
|
@@ -457,7 +480,8 @@ let WorkoutRidePageService = (() => {
|
|
|
457
480
|
title: '',
|
|
458
481
|
graph: { bars: [], ftp: 0, ftpLine: 0, domain: { x: [0, 0], y: [0, 0] } },
|
|
459
482
|
steps: { previous: null, current: null, upcoming: [], hasMore: false },
|
|
460
|
-
dashboard: { text: '', mode: null }
|
|
483
|
+
dashboard: { text: '', mode: null },
|
|
484
|
+
gestureHint: null
|
|
461
485
|
};
|
|
462
486
|
}
|
|
463
487
|
updatePageDisplay() {
|
|
@@ -487,6 +511,9 @@ let WorkoutRidePageService = (() => {
|
|
|
487
511
|
getActivityRide() {
|
|
488
512
|
return useActivityRide();
|
|
489
513
|
}
|
|
514
|
+
getUserSettings() {
|
|
515
|
+
return useUserSettings();
|
|
516
|
+
}
|
|
490
517
|
};
|
|
491
518
|
return WorkoutRidePageService = _classThis;
|
|
492
519
|
})();
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type FeatureToggle = 'NEW_SEARCH_UI' | 'CONTROLLERS' | 'MOBILE_WORKOUTS' | 'WEBBLE_WINDOWS';
|
|
1
|
+
export type FeatureToggle = 'NEW_SEARCH_UI' | 'CONTROLLERS' | 'MOBILE_WORKOUTS' | 'WEBBLE_WINDOWS' | 'MOBILE_NEXT_VIDEO';
|
|
2
2
|
export type Interfaces = 'ant' | 'ble' | 'serial' | 'wifi' | 'tcpip';
|
|
3
3
|
export type BLEFeatures = {
|
|
4
4
|
services: Array<string>;
|
|
@@ -78,6 +78,7 @@ export declare class RouteCard extends BaseCard implements Card<Route> {
|
|
|
78
78
|
start(): void;
|
|
79
79
|
cancel(): void;
|
|
80
80
|
addWorkout(): void;
|
|
81
|
+
protected enforceNextVideoOverrideOnMobile(): void;
|
|
81
82
|
getCurrentDownload(): Observer;
|
|
82
83
|
getVideoDir(): string;
|
|
83
84
|
setVideoDir(dir: string): void;
|
|
@@ -50,6 +50,7 @@ export declare class WorkoutListPageService extends IncyclistPageService impleme
|
|
|
50
50
|
protected formatDuration(duration: number): string;
|
|
51
51
|
protected emitPageUpdate(): void;
|
|
52
52
|
protected emitImportUpdate(): void;
|
|
53
|
+
protected getDevicePairing(): import("../../devices").DevicePairingService;
|
|
53
54
|
protected getWorkoutList(): WorkoutListService;
|
|
54
55
|
protected getWorkoutCalendar(): import("../calendar").WorkoutCalendarService;
|
|
55
56
|
protected getUserSettings(): import("../../settings").UserSettingsService;
|
|
@@ -4,7 +4,7 @@ import type { CurrentRideState, RideType } from "../../../types";
|
|
|
4
4
|
import type { WorkoutDisplayProperties } from "../types";
|
|
5
5
|
import type { Workout } from "../../base/model";
|
|
6
6
|
import type { StepDefinition } from "../../base/model/types";
|
|
7
|
-
import type { IWorkoutRidePageService, WorkoutDashboardLine, WorkoutGraphActuals, WorkoutGraphPlan, WorkoutRideMenuProps, WorkoutRidePageDisplayProps, WorkoutUpcomingSteps } from "./types";
|
|
7
|
+
import type { IWorkoutRidePageService, WorkoutDashboardLine, WorkoutGestureHint, WorkoutGraphActuals, WorkoutGraphPlan, WorkoutRideMenuProps, WorkoutRidePageDisplayProps, WorkoutUpcomingSteps } from "./types";
|
|
8
8
|
export declare class WorkoutRidePageService extends IncyclistPageService implements IWorkoutRidePageService {
|
|
9
9
|
protected rideEventHandler: Record<string, any>;
|
|
10
10
|
protected workoutEventHandler: Record<string, any>;
|
|
@@ -12,7 +12,7 @@ export declare class WorkoutRidePageService extends IncyclistPageService impleme
|
|
|
12
12
|
protected backgroundTimer: NodeJS.Timeout | undefined;
|
|
13
13
|
protected backgroundPausedByService: boolean;
|
|
14
14
|
protected menuProps: WorkoutRideMenuProps | null;
|
|
15
|
-
protected
|
|
15
|
+
protected gestureHintDismissed: boolean;
|
|
16
16
|
constructor();
|
|
17
17
|
openPage(simulate?: boolean): IObserver;
|
|
18
18
|
closePage(): void;
|
|
@@ -32,6 +32,9 @@ export declare class WorkoutRidePageService extends IncyclistPageService impleme
|
|
|
32
32
|
onDecreaseLoad(): void;
|
|
33
33
|
onRetryStart(): void;
|
|
34
34
|
onIgnoreStart(): void;
|
|
35
|
+
onGestureHintDismissed({ dontShowAgain }: {
|
|
36
|
+
dontShowAgain: boolean;
|
|
37
|
+
}): void;
|
|
35
38
|
onCancelStart(): void;
|
|
36
39
|
adjustLoad(deltaPct: number): void;
|
|
37
40
|
protected onRideStateUpdate(state: CurrentRideState): void;
|
|
@@ -48,6 +51,8 @@ export declare class WorkoutRidePageService extends IncyclistPageService impleme
|
|
|
48
51
|
menuProps: WorkoutRideMenuProps;
|
|
49
52
|
startGateProps: any;
|
|
50
53
|
};
|
|
54
|
+
protected buildGestureHint(startOverlayCleared: boolean): WorkoutGestureHint | null;
|
|
55
|
+
protected getCurrentCadence(): number;
|
|
51
56
|
protected buildGraphPlan(current: Workout | undefined, ftp: number): WorkoutGraphPlan;
|
|
52
57
|
protected buildUpcomingSteps(current: Workout | undefined, ftp: number): WorkoutUpcomingSteps;
|
|
53
58
|
protected buildDashboardLine(wo: WorkoutDisplayProperties): WorkoutDashboardLine;
|
|
@@ -66,5 +71,6 @@ export declare class WorkoutRidePageService extends IncyclistPageService impleme
|
|
|
66
71
|
protected getRideDisplay(): import("../../../ride/display").RideDisplayService;
|
|
67
72
|
protected getWorkoutRide(): import("../service").WorkoutRide;
|
|
68
73
|
protected getActivityRide(): import("../../../activities").ActivityRideService;
|
|
74
|
+
protected getUserSettings(): import("../../../settings").UserSettingsService;
|
|
69
75
|
}
|
|
70
76
|
export declare const getWorkoutRidePageService: () => WorkoutRidePageService;
|
|
@@ -42,12 +42,16 @@ export interface WorkoutRideMenuProps {
|
|
|
42
42
|
canStepBack: boolean;
|
|
43
43
|
canStepForward: boolean;
|
|
44
44
|
}
|
|
45
|
+
export interface WorkoutGestureHint {
|
|
46
|
+
visible: boolean;
|
|
47
|
+
}
|
|
45
48
|
export interface WorkoutRidePageDisplayProps extends RidePageDisplayProps {
|
|
46
49
|
menuProps: WorkoutRideMenuProps | null;
|
|
47
50
|
graph: WorkoutGraphPlan;
|
|
48
51
|
steps: WorkoutUpcomingSteps;
|
|
49
52
|
dashboard: WorkoutDashboardLine;
|
|
50
53
|
title: string;
|
|
54
|
+
gestureHint: WorkoutGestureHint | null;
|
|
51
55
|
}
|
|
52
56
|
export interface WorkoutRidePageCallbacks {
|
|
53
57
|
onMenuOpen(): void;
|
|
@@ -62,6 +66,9 @@ export interface WorkoutRidePageCallbacks {
|
|
|
62
66
|
onRetryStart(): void;
|
|
63
67
|
onIgnoreStart(): void;
|
|
64
68
|
onCancelStart(): void;
|
|
69
|
+
onGestureHintDismissed(props: {
|
|
70
|
+
dontShowAgain: boolean;
|
|
71
|
+
}): void;
|
|
65
72
|
}
|
|
66
73
|
export interface IWorkoutRidePageService extends WorkoutRidePageCallbacks, IPageService {
|
|
67
74
|
getRideObserver(): IObserver | null;
|
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "incyclist-services",
|
|
3
|
-
"version": "1.7.
|
|
3
|
+
"version": "1.7.83",
|
|
4
4
|
"peerDependencies": {
|
|
5
5
|
"gd-eventlog": "^0.1.27"
|
|
6
6
|
},
|
|
7
7
|
"dependencies": {
|
|
8
8
|
"@garmin/fitsdk": "^21.200.0",
|
|
9
9
|
"axios": "^1.15.2",
|
|
10
|
-
"incyclist-devices": "^3.0.
|
|
10
|
+
"incyclist-devices": "^3.0.24",
|
|
11
11
|
"promise.any": "^2.0.6",
|
|
12
12
|
"semver": "^7.7.4",
|
|
13
13
|
"tcx-builder": "^1.1.1",
|