incyclist-services 1.7.80 → 1.7.82
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/base/model/Workout.js +12 -2
- package/lib/cjs/workouts/list/service.js +9 -5
- package/lib/cjs/workouts/page/service.js +24 -4
- package/lib/cjs/workouts/ride/page/service.js +4 -13
- package/lib/esm/routes/list/cards/RouteCard.js +25 -1
- package/lib/esm/workouts/base/model/Workout.js +12 -2
- package/lib/esm/workouts/list/service.js +9 -5
- package/lib/esm/workouts/page/service.js +24 -4
- package/lib/esm/workouts/ride/page/service.js +4 -13
- package/lib/types/appstate/types.d.ts +1 -1
- package/lib/types/routes/list/cards/RouteCard.d.ts +1 -0
- package/lib/types/workouts/base/model/Workout.d.ts +2 -0
- package/lib/types/workouts/page/service.d.ts +1 -0
- package/lib/types/workouts/ride/page/service.d.ts +0 -1
- package/package.json +1 -1
|
@@ -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
|
}
|
|
@@ -11,11 +11,12 @@ class Workout extends Segment_1.Segment {
|
|
|
11
11
|
name;
|
|
12
12
|
description;
|
|
13
13
|
category;
|
|
14
|
+
explicitId;
|
|
14
15
|
constructor(opts) {
|
|
15
16
|
super(opts, true);
|
|
16
17
|
this.name = opts.name || '';
|
|
17
18
|
this._hash = opts.hash;
|
|
18
|
-
this.
|
|
19
|
+
this.explicitId = !!(opts.id || opts.hash);
|
|
19
20
|
this.description = opts.description || undefined;
|
|
20
21
|
this.repeat = 1;
|
|
21
22
|
this.type = 'workout';
|
|
@@ -32,6 +33,7 @@ class Workout extends Segment_1.Segment {
|
|
|
32
33
|
catch {
|
|
33
34
|
}
|
|
34
35
|
});
|
|
36
|
+
this.id = opts.id || this.hash;
|
|
35
37
|
}
|
|
36
38
|
get hash() {
|
|
37
39
|
if (this._hash)
|
|
@@ -41,6 +43,12 @@ class Workout extends Segment_1.Segment {
|
|
|
41
43
|
this._hash = crypto.createHash('md5').update(JSON.stringify({ name, description, steps, repeat })).digest('hex');
|
|
42
44
|
return this._hash;
|
|
43
45
|
}
|
|
46
|
+
refreshHash() {
|
|
47
|
+
if (this.explicitId)
|
|
48
|
+
return;
|
|
49
|
+
this._hash = undefined;
|
|
50
|
+
this.id = this.hash;
|
|
51
|
+
}
|
|
44
52
|
getSegment(time) {
|
|
45
53
|
const s = this.steps.find(s => s.getStart() <= time && s.getEnd() > time);
|
|
46
54
|
if (s?.type === 'segment')
|
|
@@ -57,6 +65,7 @@ class Workout extends Segment_1.Segment {
|
|
|
57
65
|
const s = new Step_1.Step(step);
|
|
58
66
|
this.push(s);
|
|
59
67
|
}
|
|
68
|
+
this.refreshHash();
|
|
60
69
|
}
|
|
61
70
|
}
|
|
62
71
|
addSegment(segment) {
|
|
@@ -68,6 +77,7 @@ class Workout extends Segment_1.Segment {
|
|
|
68
77
|
const s = new Segment_1.Segment(segment);
|
|
69
78
|
this.push(s);
|
|
70
79
|
}
|
|
80
|
+
this.refreshHash();
|
|
71
81
|
}
|
|
72
82
|
}
|
|
73
83
|
}
|
|
@@ -84,10 +94,10 @@ class Plan {
|
|
|
84
94
|
this.type = 'plan';
|
|
85
95
|
const { id, name, description, workouts, hash } = plan;
|
|
86
96
|
this._hash = hash;
|
|
87
|
-
this.id = id || this.hash;
|
|
88
97
|
this.name = name;
|
|
89
98
|
this.description = description;
|
|
90
99
|
this.workouts = workouts;
|
|
100
|
+
this.id = id || this.hash;
|
|
91
101
|
}
|
|
92
102
|
get hash() {
|
|
93
103
|
if (this._hash)
|
|
@@ -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;
|
|
@@ -575,7 +579,7 @@ let WorkoutListService = (() => {
|
|
|
575
579
|
return;
|
|
576
580
|
const card = list.getCards().find(c => c.getData()?.id === id);
|
|
577
581
|
if (card)
|
|
578
|
-
res = { card, list
|
|
582
|
+
res = { card, list };
|
|
579
583
|
});
|
|
580
584
|
return res;
|
|
581
585
|
}
|
|
@@ -596,11 +600,11 @@ let WorkoutListService = (() => {
|
|
|
596
600
|
const workout = await this.parse(info);
|
|
597
601
|
const existing = this.findCard(workout);
|
|
598
602
|
if (existing) {
|
|
599
|
-
existing.
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
this.items.push(workout);
|
|
603
|
+
const card = existing.card;
|
|
604
|
+
card.update(workout);
|
|
605
|
+
return card;
|
|
603
606
|
}
|
|
607
|
+
this.items.push(workout);
|
|
604
608
|
const card = new WorkoutCard_1.WorkoutCard(workout, { list: this.myWorkouts });
|
|
605
609
|
card.save();
|
|
606
610
|
card.enableDelete(true);
|
|
@@ -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');
|
|
@@ -314,6 +324,8 @@ let WorkoutListPageService = (() => {
|
|
|
314
324
|
this.getWorkoutList().import(file, { showImportCards: false })
|
|
315
325
|
.then(([card]) => {
|
|
316
326
|
const group = this.getLastUsedImportGroup();
|
|
327
|
+
if (group !== DEFAULT_IMPORT_GROUP)
|
|
328
|
+
card.move(group);
|
|
317
329
|
this.importPhase = 'result';
|
|
318
330
|
this.importResult = { id: card.getId(), workoutName: card.getTitle(), group };
|
|
319
331
|
observer.emit('success');
|
|
@@ -364,7 +376,7 @@ let WorkoutListPageService = (() => {
|
|
|
364
376
|
const todayId = calendar.getScheduledToday()?.id ?? null;
|
|
365
377
|
const selectedWorkout = this.getWorkoutList().getSelected();
|
|
366
378
|
const items = scheduled.map(w => ({
|
|
367
|
-
id: w.id,
|
|
379
|
+
id: w.workout?.id,
|
|
368
380
|
title: w.workout?.name,
|
|
369
381
|
date: w.day,
|
|
370
382
|
duration: this.formatDuration(w.workout?.duration),
|
|
@@ -446,7 +458,15 @@ let WorkoutListPageService = (() => {
|
|
|
446
458
|
this.getPageObserver()?.emit('page-update');
|
|
447
459
|
}
|
|
448
460
|
emitImportUpdate() {
|
|
449
|
-
|
|
461
|
+
try {
|
|
462
|
+
this.getPageObserver()?.emit('import-update');
|
|
463
|
+
}
|
|
464
|
+
catch (err) {
|
|
465
|
+
this.logError(err, 'emitImportUpdate');
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
getDevicePairing() {
|
|
469
|
+
return (0, devices_1.useDevicePairing)();
|
|
450
470
|
}
|
|
451
471
|
getWorkoutList() {
|
|
452
472
|
return (0, service_1.useWorkoutList)();
|
|
@@ -77,7 +77,6 @@ let WorkoutRidePageService = (() => {
|
|
|
77
77
|
backgroundTimer;
|
|
78
78
|
backgroundPausedByService = false;
|
|
79
79
|
menuProps = null;
|
|
80
|
-
isInitialized = false;
|
|
81
80
|
constructor() {
|
|
82
81
|
super('WorkoutRidePage');
|
|
83
82
|
this.rideEventHandler['state-update'] = this.onRideStateUpdate.bind(this);
|
|
@@ -95,10 +94,6 @@ let WorkoutRidePageService = (() => {
|
|
|
95
94
|
super.openPage();
|
|
96
95
|
try {
|
|
97
96
|
const service = this.getRideDisplay();
|
|
98
|
-
if (!this.isInitialized) {
|
|
99
|
-
service.init();
|
|
100
|
-
this.isInitialized = true;
|
|
101
|
-
}
|
|
102
97
|
this.registerRideEventHandlers();
|
|
103
98
|
this.subscribeToWorkoutObserver();
|
|
104
99
|
service.start(simulate);
|
|
@@ -120,7 +115,6 @@ let WorkoutRidePageService = (() => {
|
|
|
120
115
|
this.unregisterRideEventHandlers();
|
|
121
116
|
this.unsubscribeFromWorkoutObserver();
|
|
122
117
|
this.menuProps = null;
|
|
123
|
-
this.isInitialized = false;
|
|
124
118
|
super.closePage();
|
|
125
119
|
}
|
|
126
120
|
catch (err) {
|
|
@@ -314,19 +308,15 @@ let WorkoutRidePageService = (() => {
|
|
|
314
308
|
switch (state) {
|
|
315
309
|
case 'Paused':
|
|
316
310
|
this.menuProps = { showResume: true, ...this.getStepFlags() };
|
|
317
|
-
this.updatePageDisplay();
|
|
318
311
|
break;
|
|
319
312
|
case 'Active':
|
|
320
313
|
this.menuProps = null;
|
|
321
|
-
this.updatePageDisplay();
|
|
322
314
|
break;
|
|
323
315
|
case 'Finished':
|
|
324
316
|
this.emitNavigateBack();
|
|
325
|
-
|
|
326
|
-
case 'Error':
|
|
327
|
-
this.updatePageDisplay();
|
|
328
|
-
break;
|
|
317
|
+
return;
|
|
329
318
|
}
|
|
319
|
+
this.updatePageDisplay();
|
|
330
320
|
}
|
|
331
321
|
onWorkoutUpdate() {
|
|
332
322
|
this.updatePageDisplay();
|
|
@@ -373,7 +363,8 @@ let WorkoutRidePageService = (() => {
|
|
|
373
363
|
}
|
|
374
364
|
const bars = (0, graph_1.getWorkoutGraphSeries)(current, { ftp, absValues: true });
|
|
375
365
|
const lastBarX = bars.length ? bars.at(-1).x : 0;
|
|
376
|
-
const
|
|
366
|
+
const maxXCandidates = [this.getLastLogTime(), lastBarX, current.duration ?? 0].filter(Number.isFinite);
|
|
367
|
+
const maxX = maxXCandidates.length ? Math.max(...maxXCandidates) : 0;
|
|
377
368
|
const maxBarPower = bars.length ? Math.max(...bars.map(b => b.y)) : 0;
|
|
378
369
|
return {
|
|
379
370
|
bars,
|
|
@@ -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
|
}
|
|
@@ -8,11 +8,12 @@ export class Workout extends Segment {
|
|
|
8
8
|
name;
|
|
9
9
|
description;
|
|
10
10
|
category;
|
|
11
|
+
explicitId;
|
|
11
12
|
constructor(opts) {
|
|
12
13
|
super(opts, true);
|
|
13
14
|
this.name = opts.name || '';
|
|
14
15
|
this._hash = opts.hash;
|
|
15
|
-
this.
|
|
16
|
+
this.explicitId = !!(opts.id || opts.hash);
|
|
16
17
|
this.description = opts.description || undefined;
|
|
17
18
|
this.repeat = 1;
|
|
18
19
|
this.type = 'workout';
|
|
@@ -29,6 +30,7 @@ export class Workout extends Segment {
|
|
|
29
30
|
catch {
|
|
30
31
|
}
|
|
31
32
|
});
|
|
33
|
+
this.id = opts.id || this.hash;
|
|
32
34
|
}
|
|
33
35
|
get hash() {
|
|
34
36
|
if (this._hash)
|
|
@@ -38,6 +40,12 @@ export class Workout extends Segment {
|
|
|
38
40
|
this._hash = crypto.createHash('md5').update(JSON.stringify({ name, description, steps, repeat })).digest('hex');
|
|
39
41
|
return this._hash;
|
|
40
42
|
}
|
|
43
|
+
refreshHash() {
|
|
44
|
+
if (this.explicitId)
|
|
45
|
+
return;
|
|
46
|
+
this._hash = undefined;
|
|
47
|
+
this.id = this.hash;
|
|
48
|
+
}
|
|
41
49
|
getSegment(time) {
|
|
42
50
|
const s = this.steps.find(s => s.getStart() <= time && s.getEnd() > time);
|
|
43
51
|
if (s?.type === 'segment')
|
|
@@ -54,6 +62,7 @@ export class Workout extends Segment {
|
|
|
54
62
|
const s = new Step(step);
|
|
55
63
|
this.push(s);
|
|
56
64
|
}
|
|
65
|
+
this.refreshHash();
|
|
57
66
|
}
|
|
58
67
|
}
|
|
59
68
|
addSegment(segment) {
|
|
@@ -65,6 +74,7 @@ export class Workout extends Segment {
|
|
|
65
74
|
const s = new Segment(segment);
|
|
66
75
|
this.push(s);
|
|
67
76
|
}
|
|
77
|
+
this.refreshHash();
|
|
68
78
|
}
|
|
69
79
|
}
|
|
70
80
|
}
|
|
@@ -80,10 +90,10 @@ export class Plan {
|
|
|
80
90
|
this.type = 'plan';
|
|
81
91
|
const { id, name, description, workouts, hash } = plan;
|
|
82
92
|
this._hash = hash;
|
|
83
|
-
this.id = id || this.hash;
|
|
84
93
|
this.name = name;
|
|
85
94
|
this.description = description;
|
|
86
95
|
this.workouts = workouts;
|
|
96
|
+
this.id = id || this.hash;
|
|
87
97
|
}
|
|
88
98
|
get hash() {
|
|
89
99
|
if (this._hash)
|
|
@@ -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;
|
|
@@ -572,7 +576,7 @@ let WorkoutListService = (() => {
|
|
|
572
576
|
return;
|
|
573
577
|
const card = list.getCards().find(c => c.getData()?.id === id);
|
|
574
578
|
if (card)
|
|
575
|
-
res = { card, list
|
|
579
|
+
res = { card, list };
|
|
576
580
|
});
|
|
577
581
|
return res;
|
|
578
582
|
}
|
|
@@ -593,11 +597,11 @@ let WorkoutListService = (() => {
|
|
|
593
597
|
const workout = await this.parse(info);
|
|
594
598
|
const existing = this.findCard(workout);
|
|
595
599
|
if (existing) {
|
|
596
|
-
existing.
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
this.items.push(workout);
|
|
600
|
+
const card = existing.card;
|
|
601
|
+
card.update(workout);
|
|
602
|
+
return card;
|
|
600
603
|
}
|
|
604
|
+
this.items.push(workout);
|
|
601
605
|
const card = new WorkoutCard(workout, { list: this.myWorkouts });
|
|
602
606
|
card.save();
|
|
603
607
|
card.enableDelete(true);
|
|
@@ -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');
|
|
@@ -311,6 +321,8 @@ let WorkoutListPageService = (() => {
|
|
|
311
321
|
this.getWorkoutList().import(file, { showImportCards: false })
|
|
312
322
|
.then(([card]) => {
|
|
313
323
|
const group = this.getLastUsedImportGroup();
|
|
324
|
+
if (group !== DEFAULT_IMPORT_GROUP)
|
|
325
|
+
card.move(group);
|
|
314
326
|
this.importPhase = 'result';
|
|
315
327
|
this.importResult = { id: card.getId(), workoutName: card.getTitle(), group };
|
|
316
328
|
observer.emit('success');
|
|
@@ -361,7 +373,7 @@ let WorkoutListPageService = (() => {
|
|
|
361
373
|
const todayId = calendar.getScheduledToday()?.id ?? null;
|
|
362
374
|
const selectedWorkout = this.getWorkoutList().getSelected();
|
|
363
375
|
const items = scheduled.map(w => ({
|
|
364
|
-
id: w.id,
|
|
376
|
+
id: w.workout?.id,
|
|
365
377
|
title: w.workout?.name,
|
|
366
378
|
date: w.day,
|
|
367
379
|
duration: this.formatDuration(w.workout?.duration),
|
|
@@ -443,7 +455,15 @@ let WorkoutListPageService = (() => {
|
|
|
443
455
|
this.getPageObserver()?.emit('page-update');
|
|
444
456
|
}
|
|
445
457
|
emitImportUpdate() {
|
|
446
|
-
|
|
458
|
+
try {
|
|
459
|
+
this.getPageObserver()?.emit('import-update');
|
|
460
|
+
}
|
|
461
|
+
catch (err) {
|
|
462
|
+
this.logError(err, 'emitImportUpdate');
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
getDevicePairing() {
|
|
466
|
+
return useDevicePairing();
|
|
447
467
|
}
|
|
448
468
|
getWorkoutList() {
|
|
449
469
|
return useWorkoutList();
|
|
@@ -74,7 +74,6 @@ let WorkoutRidePageService = (() => {
|
|
|
74
74
|
backgroundTimer;
|
|
75
75
|
backgroundPausedByService = false;
|
|
76
76
|
menuProps = null;
|
|
77
|
-
isInitialized = false;
|
|
78
77
|
constructor() {
|
|
79
78
|
super('WorkoutRidePage');
|
|
80
79
|
this.rideEventHandler['state-update'] = this.onRideStateUpdate.bind(this);
|
|
@@ -92,10 +91,6 @@ let WorkoutRidePageService = (() => {
|
|
|
92
91
|
super.openPage();
|
|
93
92
|
try {
|
|
94
93
|
const service = this.getRideDisplay();
|
|
95
|
-
if (!this.isInitialized) {
|
|
96
|
-
service.init();
|
|
97
|
-
this.isInitialized = true;
|
|
98
|
-
}
|
|
99
94
|
this.registerRideEventHandlers();
|
|
100
95
|
this.subscribeToWorkoutObserver();
|
|
101
96
|
service.start(simulate);
|
|
@@ -117,7 +112,6 @@ let WorkoutRidePageService = (() => {
|
|
|
117
112
|
this.unregisterRideEventHandlers();
|
|
118
113
|
this.unsubscribeFromWorkoutObserver();
|
|
119
114
|
this.menuProps = null;
|
|
120
|
-
this.isInitialized = false;
|
|
121
115
|
super.closePage();
|
|
122
116
|
}
|
|
123
117
|
catch (err) {
|
|
@@ -311,19 +305,15 @@ let WorkoutRidePageService = (() => {
|
|
|
311
305
|
switch (state) {
|
|
312
306
|
case 'Paused':
|
|
313
307
|
this.menuProps = { showResume: true, ...this.getStepFlags() };
|
|
314
|
-
this.updatePageDisplay();
|
|
315
308
|
break;
|
|
316
309
|
case 'Active':
|
|
317
310
|
this.menuProps = null;
|
|
318
|
-
this.updatePageDisplay();
|
|
319
311
|
break;
|
|
320
312
|
case 'Finished':
|
|
321
313
|
this.emitNavigateBack();
|
|
322
|
-
|
|
323
|
-
case 'Error':
|
|
324
|
-
this.updatePageDisplay();
|
|
325
|
-
break;
|
|
314
|
+
return;
|
|
326
315
|
}
|
|
316
|
+
this.updatePageDisplay();
|
|
327
317
|
}
|
|
328
318
|
onWorkoutUpdate() {
|
|
329
319
|
this.updatePageDisplay();
|
|
@@ -370,7 +360,8 @@ let WorkoutRidePageService = (() => {
|
|
|
370
360
|
}
|
|
371
361
|
const bars = getWorkoutGraphSeries(current, { ftp, absValues: true });
|
|
372
362
|
const lastBarX = bars.length ? bars.at(-1).x : 0;
|
|
373
|
-
const
|
|
363
|
+
const maxXCandidates = [this.getLastLogTime(), lastBarX, current.duration ?? 0].filter(Number.isFinite);
|
|
364
|
+
const maxX = maxXCandidates.length ? Math.max(...maxXCandidates) : 0;
|
|
374
365
|
const maxBarPower = bars.length ? Math.max(...bars.map(b => b.y)) : 0;
|
|
375
366
|
return {
|
|
376
367
|
bars,
|
|
@@ -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;
|
|
@@ -6,8 +6,10 @@ export declare class Workout extends Segment implements WorkoutDefinition {
|
|
|
6
6
|
name: string;
|
|
7
7
|
description: string;
|
|
8
8
|
category?: Category;
|
|
9
|
+
protected explicitId: boolean;
|
|
9
10
|
constructor(opts: WorkoutDefinition);
|
|
10
11
|
get hash(): string;
|
|
12
|
+
protected refreshHash(): void;
|
|
11
13
|
getSegment(time: number): Segment;
|
|
12
14
|
addStep(step: StepDefinition): void;
|
|
13
15
|
addSegment(segment: SegmentDefinition): 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;
|
|
@@ -12,7 +12,6 @@ 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 isInitialized: boolean;
|
|
16
15
|
constructor();
|
|
17
16
|
openPage(simulate?: boolean): IObserver;
|
|
18
17
|
closePage(): void;
|