incyclist-services 1.7.99 → 1.7.100

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.
@@ -40,6 +40,7 @@ const decorators_1 = require("../../base/decorators");
40
40
  const pages_1 = require("../../base/pages");
41
41
  const list_1 = require("../list");
42
42
  const sleep_1 = require("../../utils/sleep");
43
+ const workouts_1 = require("../../workouts");
43
44
  let ActivitiesPageService = (() => {
44
45
  let _classDecorators = [decorators_1.Singleton];
45
46
  let _classDescriptor;
@@ -48,12 +49,15 @@ let ActivitiesPageService = (() => {
48
49
  let _classSuper = pages_1.IncyclistPageService;
49
50
  let _instanceExtraInitializers = [];
50
51
  let _getActivityList_decorators;
52
+ let _getWorkoutList_decorators;
51
53
  var ActivitiesPageService = class extends _classSuper {
52
54
  static { _classThis = this; }
53
55
  static {
54
56
  const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
55
57
  _getActivityList_decorators = [decorators_1.Injectable];
58
+ _getWorkoutList_decorators = [decorators_1.Injectable];
56
59
  __esDecorate(this, null, _getActivityList_decorators, { kind: "method", name: "getActivityList", static: false, private: false, access: { has: obj => "getActivityList" in obj, get: obj => obj.getActivityList }, metadata: _metadata }, null, _instanceExtraInitializers);
60
+ __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);
57
61
  __esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
58
62
  ActivitiesPageService = _classThis = _classDescriptor.value;
59
63
  if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
@@ -146,6 +150,27 @@ let ActivitiesPageService = (() => {
146
150
  this.logError(err, 'onCloseActivity');
147
151
  }
148
152
  }
153
+ getActivityDetailsProps(activityId) {
154
+ const comboEnabled = this.isWorkoutComboEnabled();
155
+ try {
156
+ const workout = this.getWorkoutList().getSelected();
157
+ const attachedWorkout = workout ? { id: workout.id, title: workout.name } : null;
158
+ return { activityId, attachedWorkout, comboEnabled };
159
+ }
160
+ catch (err) {
161
+ this.logError(err, 'getActivityDetailsProps');
162
+ return { activityId, attachedWorkout: null, comboEnabled };
163
+ }
164
+ }
165
+ onClearWorkoutSelection() {
166
+ try {
167
+ this.getWorkoutList().unselect();
168
+ this.updatePageDisplay();
169
+ }
170
+ catch (err) {
171
+ this.logError(err, 'onClearWorkoutSelection');
172
+ }
173
+ }
149
174
  updatePageDisplay() {
150
175
  this.getPageObserver()?.emit('page-update');
151
176
  }
@@ -169,6 +194,9 @@ let ActivitiesPageService = (() => {
169
194
  getActivityList() {
170
195
  return (0, list_1.useActivityList)();
171
196
  }
197
+ getWorkoutList() {
198
+ return (0, workouts_1.useWorkoutList)();
199
+ }
172
200
  };
173
201
  return ActivitiesPageService = _classThis;
174
202
  })();
@@ -122,6 +122,17 @@ let IncyclistPageService = (() => {
122
122
  getAppState() {
123
123
  return (0, appstate_1.useAppState)();
124
124
  }
125
+ isWorkoutComboEnabled() {
126
+ try {
127
+ const appState = this.getAppState();
128
+ return appState.hasFeature('MOBILE_WORKOUTS')
129
+ && appState.hasFeature('MOBILE_WORKOUT_ROUTE_COMBO');
130
+ }
131
+ catch (err) {
132
+ this.logError(err, 'isWorkoutComboEnabled');
133
+ return false;
134
+ }
135
+ }
125
136
  };
126
137
  })();
127
138
  exports.IncyclistPageService = IncyclistPageService;
@@ -50,6 +50,7 @@ const UPCOMING_STEPS_COUNT = 3;
50
50
  const DEFAULT_LOAD_INCREMENT = 1;
51
51
  const HINTS_WORKOUT_GESTURES_KEY = 'hints.workoutRideGestures';
52
52
  const LOAD_INCREMENT_SETTING_KEY = 'preferences.workouts.loadIncrement';
53
+ const CORNER_WIDGET_SETTING_KEY = 'preferences.workouts.rideCornerWidget';
53
54
  let RidePageService = (() => {
54
55
  let _classDecorators = [decorators_1.Singleton];
55
56
  let _classDescriptor;
@@ -84,6 +85,7 @@ let RidePageService = (() => {
84
85
  eventHandler = (__runInitializers(this, _instanceExtraInitializers), {});
85
86
  workoutEventHandler = {};
86
87
  workoutObserverSubscribed = false;
88
+ workoutObserver;
87
89
  backgroundTimer;
88
90
  backgroundPausedByService = false;
89
91
  menuProps = null;
@@ -251,7 +253,7 @@ let RidePageService = (() => {
251
253
  onMenuOpen() {
252
254
  try {
253
255
  const state = this.getRideDisplay().getState();
254
- this.menuProps = this.isRideType('Workout')
256
+ this.menuProps = this.isWorkoutAttached()
255
257
  ? { showResume: state === 'Paused', ...this.getStepFlags() }
256
258
  : { showResume: state === 'Paused' };
257
259
  this.updatePageDisplay();
@@ -321,8 +323,10 @@ let RidePageService = (() => {
321
323
  }
322
324
  getVideoRideDisplayProps() {
323
325
  const props = this.rideDisplayProps;
326
+ const base = this.buildBaseDisplayProps();
324
327
  const displayProps = {
325
- ...this.buildBaseDisplayProps(),
328
+ ...base,
329
+ ...this.buildWorkoutOverlayProps(props, base.startOverlayProps === null),
326
330
  video: props.video,
327
331
  videos: props.videos,
328
332
  route: props.route
@@ -331,14 +335,61 @@ let RidePageService = (() => {
331
335
  }
332
336
  getGPXRideDisplayProps() {
333
337
  const props = this.rideDisplayProps;
338
+ const base = this.buildBaseDisplayProps();
334
339
  const displayProps = {
335
- ...this.buildBaseDisplayProps(),
340
+ ...base,
341
+ ...this.buildWorkoutOverlayProps(props, base.startOverlayProps === null),
336
342
  rideView: props.rideView,
337
343
  route: props.route,
338
344
  displayObserver: props.displayObserver
339
345
  };
340
346
  return displayProps;
341
347
  }
348
+ buildWorkoutOverlayProps(props, startOverlayCleared) {
349
+ const cornerWidget = this.getCornerWidget();
350
+ if (!this.isWorkoutAttached() || !props?.showWorkout)
351
+ return { workoutAttached: false, cornerWidget };
352
+ try {
353
+ const wo = this.getWorkoutRide().getDashboardDisplayProperties();
354
+ return {
355
+ workoutAttached: true,
356
+ cornerWidget,
357
+ title: wo.title ?? '',
358
+ graph: this.buildGraphPlan(props.workout, wo.ftp),
359
+ steps: this.buildUpcomingSteps(props.workout, wo.ftp),
360
+ dashboard: this.buildDashboardLine(wo),
361
+ gestureHint: this.buildGestureHint(startOverlayCleared),
362
+ loadIncrement: this.getLoadIncrement(),
363
+ loadButtonMode: wo.loadButtonMode ?? 'power'
364
+ };
365
+ }
366
+ catch (err) {
367
+ this.logError(err, 'buildWorkoutOverlayProps');
368
+ return { workoutAttached: false, cornerWidget };
369
+ }
370
+ }
371
+ getCornerWidget() {
372
+ try {
373
+ if (!this.isWorkoutAttached() || !this.isWorkoutComboEnabled())
374
+ return undefined;
375
+ return this.getUserSettings().get(CORNER_WIDGET_SETTING_KEY, 'elevation');
376
+ }
377
+ catch (err) {
378
+ this.logError(err, 'getCornerWidget');
379
+ return undefined;
380
+ }
381
+ }
382
+ onToggleCornerWidget() {
383
+ try {
384
+ const current = this.getUserSettings().get(CORNER_WIDGET_SETTING_KEY, 'elevation');
385
+ const next = current === 'elevation' ? 'workout' : 'elevation';
386
+ this.getUserSettings().set(CORNER_WIDGET_SETTING_KEY, next);
387
+ this.updatePageDisplay();
388
+ }
389
+ catch (err) {
390
+ this.logError(err, 'onToggleCornerWidget');
391
+ }
392
+ }
342
393
  async checkSecretValidity() {
343
394
  if (this.getBindings().appInfo?.getChannel() === 'mobile') {
344
395
  const secretsStatus = this.getSecretBinding()?.getSecretsStatus?.();
@@ -370,6 +421,8 @@ let RidePageService = (() => {
370
421
  }
371
422
  getGraphActuals() {
372
423
  try {
424
+ if (!this.isWorkoutAttached())
425
+ return { power: [], heartrate: [], position: 0 };
373
426
  const state = this.getRideDisplay().getState();
374
427
  if (state === 'Idle' || state === 'Starting' || state === 'Started') {
375
428
  return { power: [], heartrate: [], position: 0 };
@@ -400,6 +453,8 @@ let RidePageService = (() => {
400
453
  }
401
454
  onStepBack() {
402
455
  try {
456
+ if (!this.isWorkoutAttached())
457
+ return;
403
458
  this.getRideDisplay().backward();
404
459
  }
405
460
  catch (err) {
@@ -408,6 +463,8 @@ let RidePageService = (() => {
408
463
  }
409
464
  onStepForward() {
410
465
  try {
466
+ if (!this.isWorkoutAttached())
467
+ return;
411
468
  this.getRideDisplay().forward();
412
469
  }
413
470
  catch (err) {
@@ -494,7 +551,8 @@ let RidePageService = (() => {
494
551
  }
495
552
  onWorkoutFinished() {
496
553
  try {
497
- this.menuProps = this.buildFinishedMenuProps();
554
+ if (this.isRideType('Workout'))
555
+ this.menuProps = this.buildFinishedMenuProps();
498
556
  this.updatePageDisplay();
499
557
  }
500
558
  catch (err) {
@@ -503,21 +561,24 @@ let RidePageService = (() => {
503
561
  }
504
562
  finishRide() {
505
563
  this.getRideDisplay().stop(true);
506
- this.onWorkoutFinished();
564
+ this.menuProps = this.buildFinishedMenuProps();
565
+ this.updatePageDisplay();
507
566
  }
508
567
  subscribeToWorkoutObserver() {
509
- if (!this.isRideType('Workout') || this.workoutObserverSubscribed)
568
+ if (this.workoutObserverSubscribed || !this.isWorkoutAttached())
510
569
  return;
511
570
  const observer = this.getWorkoutRide().getObserver();
512
571
  if (!observer)
513
572
  return;
514
573
  this.registerHandlers(observer, this.workoutEventHandler);
574
+ this.workoutObserver = observer;
515
575
  this.workoutObserverSubscribed = true;
516
576
  }
517
577
  unsubscribeFromWorkoutObserver() {
518
578
  if (!this.workoutObserverSubscribed)
519
579
  return;
520
- this.unregisterHandlers(this.getWorkoutRide().getObserver(), this.workoutEventHandler);
580
+ this.unregisterHandlers(this.workoutObserver, this.workoutEventHandler);
581
+ this.workoutObserver = undefined;
521
582
  this.workoutObserverSubscribed = false;
522
583
  }
523
584
  buildGestureHint(startOverlayCleared) {
@@ -655,13 +716,28 @@ let RidePageService = (() => {
655
716
  return false;
656
717
  }
657
718
  }
719
+ isWorkoutAttached() {
720
+ try {
721
+ if (this.isRideType('Workout'))
722
+ return true;
723
+ if (!this.isRideType('Video', 'GPX'))
724
+ return false;
725
+ if (!this.isWorkoutComboEnabled())
726
+ return false;
727
+ return this.getWorkoutRide().inUse();
728
+ }
729
+ catch (err) {
730
+ this.logError(err, 'isWorkoutAttached');
731
+ return false;
732
+ }
733
+ }
658
734
  buildPausedMenuProps() {
659
- return this.isRideType('Workout')
735
+ return this.isWorkoutAttached()
660
736
  ? { showResume: true, ...this.getStepFlags() }
661
737
  : { showResume: true };
662
738
  }
663
739
  buildFinishedMenuProps() {
664
- return this.isRideType('Workout')
740
+ return this.isWorkoutAttached()
665
741
  ? { showResume: false, finished: true, canStepBack: false, canStepForward: false }
666
742
  : { showResume: false, finished: true };
667
743
  }
@@ -45,6 +45,7 @@ const sleep_1 = require("../../utils/sleep");
45
45
  const devices_1 = require("../../devices");
46
46
  const service_1 = require("../download/service");
47
47
  const service_2 = require("../library/service");
48
+ const workouts_1 = require("../../workouts");
48
49
  let RoutesPageService = (() => {
49
50
  let _classDecorators = [decorators_1.Singleton];
50
51
  let _classDescriptor;
@@ -57,6 +58,7 @@ let RoutesPageService = (() => {
57
58
  let _getUserSettings_decorators;
58
59
  let _getRouteDownload_decorators;
59
60
  let _getRouteLibraryScanner_decorators;
61
+ let _getWorkoutList_decorators;
60
62
  var RoutesPageService = class extends _classSuper {
61
63
  static { _classThis = this; }
62
64
  static {
@@ -66,11 +68,13 @@ let RoutesPageService = (() => {
66
68
  _getUserSettings_decorators = [decorators_1.Injectable];
67
69
  _getRouteDownload_decorators = [decorators_1.Injectable];
68
70
  _getRouteLibraryScanner_decorators = [decorators_1.Injectable];
71
+ _getWorkoutList_decorators = [decorators_1.Injectable];
69
72
  __esDecorate(this, null, _getRouteList_decorators, { kind: "method", name: "getRouteList", static: false, private: false, access: { has: obj => "getRouteList" in obj, get: obj => obj.getRouteList }, metadata: _metadata }, null, _instanceExtraInitializers);
70
73
  __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);
71
74
  __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);
72
75
  __esDecorate(this, null, _getRouteDownload_decorators, { kind: "method", name: "getRouteDownload", static: false, private: false, access: { has: obj => "getRouteDownload" in obj, get: obj => obj.getRouteDownload }, metadata: _metadata }, null, _instanceExtraInitializers);
73
76
  __esDecorate(this, null, _getRouteLibraryScanner_decorators, { kind: "method", name: "getRouteLibraryScanner", static: false, private: false, access: { has: obj => "getRouteLibraryScanner" in obj, get: obj => obj.getRouteLibraryScanner }, metadata: _metadata }, null, _instanceExtraInitializers);
77
+ __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);
74
78
  __esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
75
79
  RoutesPageService = _classThis = _classDescriptor.value;
76
80
  if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
@@ -316,6 +320,31 @@ let RoutesPageService = (() => {
316
320
  this.logError(err, 'start');
317
321
  }
318
322
  }
323
+ getRouteDetailsProps(routeId) {
324
+ const comboEnabled = this.isWorkoutComboEnabled();
325
+ try {
326
+ return { routeId, attachedWorkout: this.getAttachedWorkoutProps(), comboEnabled };
327
+ }
328
+ catch (err) {
329
+ this.logError(err, 'getRouteDetailsProps');
330
+ return { routeId, attachedWorkout: null, comboEnabled };
331
+ }
332
+ }
333
+ getAttachedWorkoutProps() {
334
+ const workout = this.getWorkoutList().getSelected();
335
+ if (!workout)
336
+ return null;
337
+ return { id: workout.id, title: workout.name };
338
+ }
339
+ onClearWorkoutSelection() {
340
+ try {
341
+ this.getWorkoutList().unselect();
342
+ this.updatePageDisplay();
343
+ }
344
+ catch (err) {
345
+ this.logError(err, 'onClearWorkoutSelection');
346
+ }
347
+ }
319
348
  getDownloadDisplayProps() {
320
349
  return Array.from(this.downloadCache.values());
321
350
  }
@@ -453,6 +482,9 @@ let RoutesPageService = (() => {
453
482
  getRouteLibraryScanner() {
454
483
  return (0, service_2.useRouteLibraryScanner)();
455
484
  }
485
+ getWorkoutList() {
486
+ return (0, workouts_1.useWorkoutList)();
487
+ }
456
488
  };
457
489
  return RoutesPageService = _classThis;
458
490
  })();
@@ -44,6 +44,7 @@ const settings_1 = require("../../settings");
44
44
  const calendar_1 = require("../calendar");
45
45
  const service_1 = require("../list/service");
46
46
  const devices_1 = require("../../devices");
47
+ const routes_1 = require("../../routes");
47
48
  const DEFAULT_IMPORT_GROUP = 'My Workouts';
48
49
  const UPCOMING_COLLAPSED_COUNT = 3;
49
50
  let WorkoutListPageService = (() => {
@@ -55,6 +56,7 @@ let WorkoutListPageService = (() => {
55
56
  let _instanceExtraInitializers = [];
56
57
  let _getDevicePairing_decorators;
57
58
  let _getWorkoutList_decorators;
59
+ let _getRouteList_decorators;
58
60
  let _getWorkoutCalendar_decorators;
59
61
  let _getUserSettings_decorators;
60
62
  let _getAppState_decorators;
@@ -64,11 +66,13 @@ let WorkoutListPageService = (() => {
64
66
  const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
65
67
  _getDevicePairing_decorators = [decorators_1.Injectable];
66
68
  _getWorkoutList_decorators = [decorators_1.Injectable];
69
+ _getRouteList_decorators = [decorators_1.Injectable];
67
70
  _getWorkoutCalendar_decorators = [decorators_1.Injectable];
68
71
  _getUserSettings_decorators = [decorators_1.Injectable];
69
72
  _getAppState_decorators = [decorators_1.Injectable];
70
73
  __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);
71
74
  __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);
75
+ __esDecorate(this, null, _getRouteList_decorators, { kind: "method", name: "getRouteList", static: false, private: false, access: { has: obj => "getRouteList" in obj, get: obj => obj.getRouteList }, metadata: _metadata }, null, _instanceExtraInitializers);
72
76
  __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);
73
77
  __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);
74
78
  __esDecorate(this, null, _getAppState_decorators, { kind: "method", name: "getAppState", static: false, private: false, access: { has: obj => "getAppState" in obj, get: obj => obj.getAppState }, metadata: _metadata }, null, _instanceExtraInitializers);
@@ -171,7 +175,9 @@ let WorkoutListPageService = (() => {
171
175
  group: settingsProps.category,
172
176
  canDelete: card.canDelete(),
173
177
  isScheduled,
174
- date: isScheduled ? settingsProps.date : undefined
178
+ date: isScheduled ? settingsProps.date : undefined,
179
+ attachedRoute: this.getAttachedRouteProps(),
180
+ comboEnabled: this.isWorkoutComboEnabled()
175
181
  };
176
182
  }
177
183
  catch (err) {
@@ -179,6 +185,18 @@ let WorkoutListPageService = (() => {
179
185
  return null;
180
186
  }
181
187
  }
188
+ getAttachedRouteProps() {
189
+ try {
190
+ const route = this.getRouteList().getSelected();
191
+ if (!route)
192
+ return null;
193
+ return { id: route.description?.id, title: route.title };
194
+ }
195
+ catch (err) {
196
+ this.logError(err, 'getAttachedRouteProps');
197
+ return null;
198
+ }
199
+ }
182
200
  getImportDisplayProps() {
183
201
  try {
184
202
  const phase = this.importPhase ?? 'landing';
@@ -309,6 +327,15 @@ let WorkoutListPageService = (() => {
309
327
  this.logError(err, 'onClearSelection');
310
328
  }
311
329
  }
330
+ onClearRouteSelection() {
331
+ try {
332
+ this.getRouteList().unselect();
333
+ this.emitPageUpdate();
334
+ }
335
+ catch (err) {
336
+ this.logError(err, 'onClearRouteSelection');
337
+ }
338
+ }
312
339
  onImportOpen() {
313
340
  try {
314
341
  this.importPhase = 'landing';
@@ -489,6 +516,9 @@ let WorkoutListPageService = (() => {
489
516
  getWorkoutList() {
490
517
  return (0, service_1.useWorkoutList)();
491
518
  }
519
+ getRouteList() {
520
+ return (0, routes_1.useRouteList)();
521
+ }
492
522
  getWorkoutCalendar() {
493
523
  return (0, calendar_1.useWorkoutCalendar)();
494
524
  }
@@ -37,6 +37,7 @@ import { Injectable, Singleton } from "../../base/decorators";
37
37
  import { IncyclistPageService } from "../../base/pages";
38
38
  import { useActivityList } from "../list";
39
39
  import { sleep } from "../../utils/sleep";
40
+ import { useWorkoutList } from "../../workouts";
40
41
  let ActivitiesPageService = (() => {
41
42
  let _classDecorators = [Singleton];
42
43
  let _classDescriptor;
@@ -45,12 +46,15 @@ let ActivitiesPageService = (() => {
45
46
  let _classSuper = IncyclistPageService;
46
47
  let _instanceExtraInitializers = [];
47
48
  let _getActivityList_decorators;
49
+ let _getWorkoutList_decorators;
48
50
  var ActivitiesPageService = class extends _classSuper {
49
51
  static { _classThis = this; }
50
52
  static {
51
53
  const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
52
54
  _getActivityList_decorators = [Injectable];
55
+ _getWorkoutList_decorators = [Injectable];
53
56
  __esDecorate(this, null, _getActivityList_decorators, { kind: "method", name: "getActivityList", static: false, private: false, access: { has: obj => "getActivityList" in obj, get: obj => obj.getActivityList }, metadata: _metadata }, null, _instanceExtraInitializers);
57
+ __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);
54
58
  __esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
55
59
  ActivitiesPageService = _classThis = _classDescriptor.value;
56
60
  if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
@@ -143,6 +147,27 @@ let ActivitiesPageService = (() => {
143
147
  this.logError(err, 'onCloseActivity');
144
148
  }
145
149
  }
150
+ getActivityDetailsProps(activityId) {
151
+ const comboEnabled = this.isWorkoutComboEnabled();
152
+ try {
153
+ const workout = this.getWorkoutList().getSelected();
154
+ const attachedWorkout = workout ? { id: workout.id, title: workout.name } : null;
155
+ return { activityId, attachedWorkout, comboEnabled };
156
+ }
157
+ catch (err) {
158
+ this.logError(err, 'getActivityDetailsProps');
159
+ return { activityId, attachedWorkout: null, comboEnabled };
160
+ }
161
+ }
162
+ onClearWorkoutSelection() {
163
+ try {
164
+ this.getWorkoutList().unselect();
165
+ this.updatePageDisplay();
166
+ }
167
+ catch (err) {
168
+ this.logError(err, 'onClearWorkoutSelection');
169
+ }
170
+ }
146
171
  updatePageDisplay() {
147
172
  this.getPageObserver()?.emit('page-update');
148
173
  }
@@ -166,6 +191,9 @@ let ActivitiesPageService = (() => {
166
191
  getActivityList() {
167
192
  return useActivityList();
168
193
  }
194
+ getWorkoutList() {
195
+ return useWorkoutList();
196
+ }
169
197
  };
170
198
  return ActivitiesPageService = _classThis;
171
199
  })();
@@ -119,6 +119,17 @@ let IncyclistPageService = (() => {
119
119
  getAppState() {
120
120
  return useAppState();
121
121
  }
122
+ isWorkoutComboEnabled() {
123
+ try {
124
+ const appState = this.getAppState();
125
+ return appState.hasFeature('MOBILE_WORKOUTS')
126
+ && appState.hasFeature('MOBILE_WORKOUT_ROUTE_COMBO');
127
+ }
128
+ catch (err) {
129
+ this.logError(err, 'isWorkoutComboEnabled');
130
+ return false;
131
+ }
132
+ }
122
133
  };
123
134
  })();
124
135
  export { IncyclistPageService };
@@ -47,6 +47,7 @@ const UPCOMING_STEPS_COUNT = 3;
47
47
  const DEFAULT_LOAD_INCREMENT = 1;
48
48
  const HINTS_WORKOUT_GESTURES_KEY = 'hints.workoutRideGestures';
49
49
  const LOAD_INCREMENT_SETTING_KEY = 'preferences.workouts.loadIncrement';
50
+ const CORNER_WIDGET_SETTING_KEY = 'preferences.workouts.rideCornerWidget';
50
51
  let RidePageService = (() => {
51
52
  let _classDecorators = [Singleton];
52
53
  let _classDescriptor;
@@ -81,6 +82,7 @@ let RidePageService = (() => {
81
82
  eventHandler = (__runInitializers(this, _instanceExtraInitializers), {});
82
83
  workoutEventHandler = {};
83
84
  workoutObserverSubscribed = false;
85
+ workoutObserver;
84
86
  backgroundTimer;
85
87
  backgroundPausedByService = false;
86
88
  menuProps = null;
@@ -248,7 +250,7 @@ let RidePageService = (() => {
248
250
  onMenuOpen() {
249
251
  try {
250
252
  const state = this.getRideDisplay().getState();
251
- this.menuProps = this.isRideType('Workout')
253
+ this.menuProps = this.isWorkoutAttached()
252
254
  ? { showResume: state === 'Paused', ...this.getStepFlags() }
253
255
  : { showResume: state === 'Paused' };
254
256
  this.updatePageDisplay();
@@ -318,8 +320,10 @@ let RidePageService = (() => {
318
320
  }
319
321
  getVideoRideDisplayProps() {
320
322
  const props = this.rideDisplayProps;
323
+ const base = this.buildBaseDisplayProps();
321
324
  const displayProps = {
322
- ...this.buildBaseDisplayProps(),
325
+ ...base,
326
+ ...this.buildWorkoutOverlayProps(props, base.startOverlayProps === null),
323
327
  video: props.video,
324
328
  videos: props.videos,
325
329
  route: props.route
@@ -328,14 +332,61 @@ let RidePageService = (() => {
328
332
  }
329
333
  getGPXRideDisplayProps() {
330
334
  const props = this.rideDisplayProps;
335
+ const base = this.buildBaseDisplayProps();
331
336
  const displayProps = {
332
- ...this.buildBaseDisplayProps(),
337
+ ...base,
338
+ ...this.buildWorkoutOverlayProps(props, base.startOverlayProps === null),
333
339
  rideView: props.rideView,
334
340
  route: props.route,
335
341
  displayObserver: props.displayObserver
336
342
  };
337
343
  return displayProps;
338
344
  }
345
+ buildWorkoutOverlayProps(props, startOverlayCleared) {
346
+ const cornerWidget = this.getCornerWidget();
347
+ if (!this.isWorkoutAttached() || !props?.showWorkout)
348
+ return { workoutAttached: false, cornerWidget };
349
+ try {
350
+ const wo = this.getWorkoutRide().getDashboardDisplayProperties();
351
+ return {
352
+ workoutAttached: true,
353
+ cornerWidget,
354
+ title: wo.title ?? '',
355
+ graph: this.buildGraphPlan(props.workout, wo.ftp),
356
+ steps: this.buildUpcomingSteps(props.workout, wo.ftp),
357
+ dashboard: this.buildDashboardLine(wo),
358
+ gestureHint: this.buildGestureHint(startOverlayCleared),
359
+ loadIncrement: this.getLoadIncrement(),
360
+ loadButtonMode: wo.loadButtonMode ?? 'power'
361
+ };
362
+ }
363
+ catch (err) {
364
+ this.logError(err, 'buildWorkoutOverlayProps');
365
+ return { workoutAttached: false, cornerWidget };
366
+ }
367
+ }
368
+ getCornerWidget() {
369
+ try {
370
+ if (!this.isWorkoutAttached() || !this.isWorkoutComboEnabled())
371
+ return undefined;
372
+ return this.getUserSettings().get(CORNER_WIDGET_SETTING_KEY, 'elevation');
373
+ }
374
+ catch (err) {
375
+ this.logError(err, 'getCornerWidget');
376
+ return undefined;
377
+ }
378
+ }
379
+ onToggleCornerWidget() {
380
+ try {
381
+ const current = this.getUserSettings().get(CORNER_WIDGET_SETTING_KEY, 'elevation');
382
+ const next = current === 'elevation' ? 'workout' : 'elevation';
383
+ this.getUserSettings().set(CORNER_WIDGET_SETTING_KEY, next);
384
+ this.updatePageDisplay();
385
+ }
386
+ catch (err) {
387
+ this.logError(err, 'onToggleCornerWidget');
388
+ }
389
+ }
339
390
  async checkSecretValidity() {
340
391
  if (this.getBindings().appInfo?.getChannel() === 'mobile') {
341
392
  const secretsStatus = this.getSecretBinding()?.getSecretsStatus?.();
@@ -367,6 +418,8 @@ let RidePageService = (() => {
367
418
  }
368
419
  getGraphActuals() {
369
420
  try {
421
+ if (!this.isWorkoutAttached())
422
+ return { power: [], heartrate: [], position: 0 };
370
423
  const state = this.getRideDisplay().getState();
371
424
  if (state === 'Idle' || state === 'Starting' || state === 'Started') {
372
425
  return { power: [], heartrate: [], position: 0 };
@@ -397,6 +450,8 @@ let RidePageService = (() => {
397
450
  }
398
451
  onStepBack() {
399
452
  try {
453
+ if (!this.isWorkoutAttached())
454
+ return;
400
455
  this.getRideDisplay().backward();
401
456
  }
402
457
  catch (err) {
@@ -405,6 +460,8 @@ let RidePageService = (() => {
405
460
  }
406
461
  onStepForward() {
407
462
  try {
463
+ if (!this.isWorkoutAttached())
464
+ return;
408
465
  this.getRideDisplay().forward();
409
466
  }
410
467
  catch (err) {
@@ -491,7 +548,8 @@ let RidePageService = (() => {
491
548
  }
492
549
  onWorkoutFinished() {
493
550
  try {
494
- this.menuProps = this.buildFinishedMenuProps();
551
+ if (this.isRideType('Workout'))
552
+ this.menuProps = this.buildFinishedMenuProps();
495
553
  this.updatePageDisplay();
496
554
  }
497
555
  catch (err) {
@@ -500,21 +558,24 @@ let RidePageService = (() => {
500
558
  }
501
559
  finishRide() {
502
560
  this.getRideDisplay().stop(true);
503
- this.onWorkoutFinished();
561
+ this.menuProps = this.buildFinishedMenuProps();
562
+ this.updatePageDisplay();
504
563
  }
505
564
  subscribeToWorkoutObserver() {
506
- if (!this.isRideType('Workout') || this.workoutObserverSubscribed)
565
+ if (this.workoutObserverSubscribed || !this.isWorkoutAttached())
507
566
  return;
508
567
  const observer = this.getWorkoutRide().getObserver();
509
568
  if (!observer)
510
569
  return;
511
570
  this.registerHandlers(observer, this.workoutEventHandler);
571
+ this.workoutObserver = observer;
512
572
  this.workoutObserverSubscribed = true;
513
573
  }
514
574
  unsubscribeFromWorkoutObserver() {
515
575
  if (!this.workoutObserverSubscribed)
516
576
  return;
517
- this.unregisterHandlers(this.getWorkoutRide().getObserver(), this.workoutEventHandler);
577
+ this.unregisterHandlers(this.workoutObserver, this.workoutEventHandler);
578
+ this.workoutObserver = undefined;
518
579
  this.workoutObserverSubscribed = false;
519
580
  }
520
581
  buildGestureHint(startOverlayCleared) {
@@ -652,13 +713,28 @@ let RidePageService = (() => {
652
713
  return false;
653
714
  }
654
715
  }
716
+ isWorkoutAttached() {
717
+ try {
718
+ if (this.isRideType('Workout'))
719
+ return true;
720
+ if (!this.isRideType('Video', 'GPX'))
721
+ return false;
722
+ if (!this.isWorkoutComboEnabled())
723
+ return false;
724
+ return this.getWorkoutRide().inUse();
725
+ }
726
+ catch (err) {
727
+ this.logError(err, 'isWorkoutAttached');
728
+ return false;
729
+ }
730
+ }
655
731
  buildPausedMenuProps() {
656
- return this.isRideType('Workout')
732
+ return this.isWorkoutAttached()
657
733
  ? { showResume: true, ...this.getStepFlags() }
658
734
  : { showResume: true };
659
735
  }
660
736
  buildFinishedMenuProps() {
661
- return this.isRideType('Workout')
737
+ return this.isWorkoutAttached()
662
738
  ? { showResume: false, finished: true, canStepBack: false, canStepForward: false }
663
739
  : { showResume: false, finished: true };
664
740
  }
@@ -42,6 +42,7 @@ import { sleep } from "../../utils/sleep";
42
42
  import { useDevicePairing } from "../../devices";
43
43
  import { useRouteDownload } from "../download/service";
44
44
  import { useRouteLibraryScanner } from "../library/service";
45
+ import { useWorkoutList } from "../../workouts";
45
46
  let RoutesPageService = (() => {
46
47
  let _classDecorators = [Singleton];
47
48
  let _classDescriptor;
@@ -54,6 +55,7 @@ let RoutesPageService = (() => {
54
55
  let _getUserSettings_decorators;
55
56
  let _getRouteDownload_decorators;
56
57
  let _getRouteLibraryScanner_decorators;
58
+ let _getWorkoutList_decorators;
57
59
  var RoutesPageService = class extends _classSuper {
58
60
  static { _classThis = this; }
59
61
  static {
@@ -63,11 +65,13 @@ let RoutesPageService = (() => {
63
65
  _getUserSettings_decorators = [Injectable];
64
66
  _getRouteDownload_decorators = [Injectable];
65
67
  _getRouteLibraryScanner_decorators = [Injectable];
68
+ _getWorkoutList_decorators = [Injectable];
66
69
  __esDecorate(this, null, _getRouteList_decorators, { kind: "method", name: "getRouteList", static: false, private: false, access: { has: obj => "getRouteList" in obj, get: obj => obj.getRouteList }, metadata: _metadata }, null, _instanceExtraInitializers);
67
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);
68
71
  __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
72
  __esDecorate(this, null, _getRouteDownload_decorators, { kind: "method", name: "getRouteDownload", static: false, private: false, access: { has: obj => "getRouteDownload" in obj, get: obj => obj.getRouteDownload }, metadata: _metadata }, null, _instanceExtraInitializers);
70
73
  __esDecorate(this, null, _getRouteLibraryScanner_decorators, { kind: "method", name: "getRouteLibraryScanner", static: false, private: false, access: { has: obj => "getRouteLibraryScanner" in obj, get: obj => obj.getRouteLibraryScanner }, metadata: _metadata }, null, _instanceExtraInitializers);
74
+ __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);
71
75
  __esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
72
76
  RoutesPageService = _classThis = _classDescriptor.value;
73
77
  if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
@@ -313,6 +317,31 @@ let RoutesPageService = (() => {
313
317
  this.logError(err, 'start');
314
318
  }
315
319
  }
320
+ getRouteDetailsProps(routeId) {
321
+ const comboEnabled = this.isWorkoutComboEnabled();
322
+ try {
323
+ return { routeId, attachedWorkout: this.getAttachedWorkoutProps(), comboEnabled };
324
+ }
325
+ catch (err) {
326
+ this.logError(err, 'getRouteDetailsProps');
327
+ return { routeId, attachedWorkout: null, comboEnabled };
328
+ }
329
+ }
330
+ getAttachedWorkoutProps() {
331
+ const workout = this.getWorkoutList().getSelected();
332
+ if (!workout)
333
+ return null;
334
+ return { id: workout.id, title: workout.name };
335
+ }
336
+ onClearWorkoutSelection() {
337
+ try {
338
+ this.getWorkoutList().unselect();
339
+ this.updatePageDisplay();
340
+ }
341
+ catch (err) {
342
+ this.logError(err, 'onClearWorkoutSelection');
343
+ }
344
+ }
316
345
  getDownloadDisplayProps() {
317
346
  return Array.from(this.downloadCache.values());
318
347
  }
@@ -450,6 +479,9 @@ let RoutesPageService = (() => {
450
479
  getRouteLibraryScanner() {
451
480
  return useRouteLibraryScanner();
452
481
  }
482
+ getWorkoutList() {
483
+ return useWorkoutList();
484
+ }
453
485
  };
454
486
  return RoutesPageService = _classThis;
455
487
  })();
@@ -41,6 +41,7 @@ import { useUserSettings } from "../../settings";
41
41
  import { useWorkoutCalendar } from "../calendar";
42
42
  import { useWorkoutList } from "../list/service";
43
43
  import { useDevicePairing } from "../../devices";
44
+ import { useRouteList } from "../../routes";
44
45
  const DEFAULT_IMPORT_GROUP = 'My Workouts';
45
46
  const UPCOMING_COLLAPSED_COUNT = 3;
46
47
  let WorkoutListPageService = (() => {
@@ -52,6 +53,7 @@ let WorkoutListPageService = (() => {
52
53
  let _instanceExtraInitializers = [];
53
54
  let _getDevicePairing_decorators;
54
55
  let _getWorkoutList_decorators;
56
+ let _getRouteList_decorators;
55
57
  let _getWorkoutCalendar_decorators;
56
58
  let _getUserSettings_decorators;
57
59
  let _getAppState_decorators;
@@ -61,11 +63,13 @@ let WorkoutListPageService = (() => {
61
63
  const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
62
64
  _getDevicePairing_decorators = [Injectable];
63
65
  _getWorkoutList_decorators = [Injectable];
66
+ _getRouteList_decorators = [Injectable];
64
67
  _getWorkoutCalendar_decorators = [Injectable];
65
68
  _getUserSettings_decorators = [Injectable];
66
69
  _getAppState_decorators = [Injectable];
67
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);
68
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);
72
+ __esDecorate(this, null, _getRouteList_decorators, { kind: "method", name: "getRouteList", static: false, private: false, access: { has: obj => "getRouteList" in obj, get: obj => obj.getRouteList }, metadata: _metadata }, null, _instanceExtraInitializers);
69
73
  __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);
70
74
  __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);
71
75
  __esDecorate(this, null, _getAppState_decorators, { kind: "method", name: "getAppState", static: false, private: false, access: { has: obj => "getAppState" in obj, get: obj => obj.getAppState }, metadata: _metadata }, null, _instanceExtraInitializers);
@@ -168,7 +172,9 @@ let WorkoutListPageService = (() => {
168
172
  group: settingsProps.category,
169
173
  canDelete: card.canDelete(),
170
174
  isScheduled,
171
- date: isScheduled ? settingsProps.date : undefined
175
+ date: isScheduled ? settingsProps.date : undefined,
176
+ attachedRoute: this.getAttachedRouteProps(),
177
+ comboEnabled: this.isWorkoutComboEnabled()
172
178
  };
173
179
  }
174
180
  catch (err) {
@@ -176,6 +182,18 @@ let WorkoutListPageService = (() => {
176
182
  return null;
177
183
  }
178
184
  }
185
+ getAttachedRouteProps() {
186
+ try {
187
+ const route = this.getRouteList().getSelected();
188
+ if (!route)
189
+ return null;
190
+ return { id: route.description?.id, title: route.title };
191
+ }
192
+ catch (err) {
193
+ this.logError(err, 'getAttachedRouteProps');
194
+ return null;
195
+ }
196
+ }
179
197
  getImportDisplayProps() {
180
198
  try {
181
199
  const phase = this.importPhase ?? 'landing';
@@ -306,6 +324,15 @@ let WorkoutListPageService = (() => {
306
324
  this.logError(err, 'onClearSelection');
307
325
  }
308
326
  }
327
+ onClearRouteSelection() {
328
+ try {
329
+ this.getRouteList().unselect();
330
+ this.emitPageUpdate();
331
+ }
332
+ catch (err) {
333
+ this.logError(err, 'onClearRouteSelection');
334
+ }
335
+ }
309
336
  onImportOpen() {
310
337
  try {
311
338
  this.importPhase = 'landing';
@@ -486,6 +513,9 @@ let WorkoutListPageService = (() => {
486
513
  getWorkoutList() {
487
514
  return useWorkoutList();
488
515
  }
516
+ getRouteList() {
517
+ return useRouteList();
518
+ }
489
519
  getWorkoutCalendar() {
490
520
  return useWorkoutCalendar();
491
521
  }
@@ -1,5 +1,5 @@
1
1
  import { IncyclistPageService } from "../../base/pages";
2
- import { ActivitiesPageDisplayProps, IActivitiesPageService } from "./types";
2
+ import { ActivitiesPageDisplayProps, ActivityDetailsProps, IActivitiesPageService } from "./types";
3
3
  import { IObserver } from "../../types";
4
4
  import { ActivityListDisplayProperties } from "../list";
5
5
  export declare class ActivitiesPageService extends IncyclistPageService implements IActivitiesPageService {
@@ -15,10 +15,13 @@ export declare class ActivitiesPageService extends IncyclistPageService implemen
15
15
  getPageDisplayProps(): ActivitiesPageDisplayProps;
16
16
  onOpenActivity(id: string | null): void;
17
17
  onCloseActivity(): void;
18
+ getActivityDetailsProps(activityId: string): ActivityDetailsProps;
19
+ onClearWorkoutSelection(): void;
18
20
  protected updatePageDisplay(): void;
19
21
  protected onStateUpdate(): void;
20
22
  protected startEventListener(): void;
21
23
  protected stopEventListener(final?: boolean): void;
22
24
  getActivityList(): import("../list").ActivityListService;
25
+ protected getWorkoutList(): import("../../workouts").WorkoutListService;
23
26
  }
24
27
  export declare const getActivitiesPageService: () => ActivitiesPageService;
@@ -1,10 +1,19 @@
1
1
  import { IPageService } from "../../base/pages";
2
2
  import { ActivityInfoUI } from "../base";
3
+ import { AttachedWorkoutProps } from "../../routes/page/types";
3
4
  export interface ActivitiesPageDisplayProps {
4
5
  loading: boolean;
5
6
  activities?: Array<ActivityInfoUI>;
6
7
  detailActivityId?: string;
7
8
  }
9
+ export type { AttachedWorkoutProps };
10
+ export interface ActivityDetailsProps {
11
+ activityId: string;
12
+ attachedWorkout: AttachedWorkoutProps | null;
13
+ comboEnabled: boolean;
14
+ }
8
15
  export interface IActivitiesPageService extends IPageService {
9
16
  getPageDisplayProps(): ActivitiesPageDisplayProps;
17
+ getActivityDetailsProps(activityId: string): ActivityDetailsProps;
18
+ onClearWorkoutSelection(): void;
10
19
  }
@@ -20,4 +20,5 @@ export declare class IncyclistPageService extends IncyclistService implements IP
20
20
  protected getUIBinding(): import("../../api").INativeUI;
21
21
  protected getBindings(): import("../../api").IncyclistBindings;
22
22
  protected getAppState(): import("../../appstate").AppStateService;
23
+ protected isWorkoutComboEnabled(): boolean;
23
24
  }
@@ -1,6 +1,6 @@
1
1
  import { IncyclistPageService } from "../../base/pages";
2
2
  import { CurrentRideDisplayProps, CurrentRideState, IObserver, RideType } from "../../types";
3
- import { AnyRidePageDisplayProps, GPXRidePageDisplayProps, IRidePageService, RideMenuProps, StartGateProps, VideoRidePageDisplayProps, WorkoutDashboardLine, WorkoutGestureHint, WorkoutGraphActuals, WorkoutGraphPlan, WorkoutRideMenuProps, WorkoutRidePageDisplayProps, WorkoutUpcomingSteps } from "./types";
3
+ import { AnyRidePageDisplayProps, GPXRidePageDisplayProps, IRidePageService, RideMenuProps, RidePageDisplayProps, StartGateProps, VideoRidePageDisplayProps, WorkoutDashboardLine, WorkoutGestureHint, WorkoutGraphActuals, WorkoutGraphPlan, WorkoutRideMenuProps, WorkoutRidePageDisplayProps, WorkoutUpcomingSteps } from "./types";
4
4
  import { ISecretBinding } from "../../api/secret";
5
5
  import type { LoadButtonMode, PowerAdjustmentResult, WorkoutDisplayProperties } from "../../workouts/ride/types";
6
6
  import type { Workout } from "../../workouts/base/model";
@@ -9,6 +9,7 @@ export declare class RidePageService extends IncyclistPageService implements IRi
9
9
  protected eventHandler: Record<string, any>;
10
10
  protected workoutEventHandler: Record<string, any>;
11
11
  protected workoutObserverSubscribed: boolean;
12
+ protected workoutObserver: IObserver | undefined;
12
13
  protected backgroundTimer: NodeJS.Timeout | undefined;
13
14
  protected backgroundPausedByService: boolean;
14
15
  protected menuProps: RideMenuProps | null;
@@ -36,6 +37,11 @@ export declare class RidePageService extends IncyclistPageService implements IRi
36
37
  onEndRide(): void;
37
38
  protected getVideoRideDisplayProps(): VideoRidePageDisplayProps;
38
39
  protected getGPXRideDisplayProps(): GPXRidePageDisplayProps;
40
+ protected buildWorkoutOverlayProps(props: CurrentRideDisplayProps & {
41
+ showWorkout?: boolean;
42
+ }, startOverlayCleared: boolean): Partial<RidePageDisplayProps>;
43
+ protected getCornerWidget(): 'elevation' | 'workout' | undefined;
44
+ onToggleCornerWidget(): void;
39
45
  protected checkSecretValidity(): Promise<void>;
40
46
  protected showStartGate(): void;
41
47
  protected hideStartgate(): void;
@@ -78,6 +84,7 @@ export declare class RidePageService extends IncyclistPageService implements IRi
78
84
  protected requiresOwnInit(): boolean;
79
85
  protected getBackgroundPauseRequester(): 'user' | 'device';
80
86
  protected isRideType(...types: RideType[]): boolean;
87
+ protected isWorkoutAttached(): boolean;
81
88
  protected buildPausedMenuProps(): RideMenuProps | WorkoutRideMenuProps;
82
89
  protected buildFinishedMenuProps(): RideMenuProps | WorkoutRideMenuProps;
83
90
  protected buildBaseDisplayProps(): {
@@ -27,6 +27,9 @@ export interface RidePageDisplayProps {
27
27
  title?: string;
28
28
  gestureHint?: WorkoutGestureHint | null;
29
29
  loadIncrement?: number;
30
+ workoutAttached?: boolean;
31
+ loadButtonMode?: LoadButtonMode;
32
+ cornerWidget?: 'elevation' | 'workout';
30
33
  }
31
34
  export interface VideoRidePageDisplayProps extends RidePageDisplayProps {
32
35
  video?: VideoDisplayProps;
@@ -57,6 +60,7 @@ interface RidePageCallbacks {
57
60
  onGestureHintDismissed(props: {
58
61
  dontShowAgain: boolean;
59
62
  }): void;
63
+ onToggleCornerWidget(): void;
60
64
  }
61
65
  export interface IRidePageService extends RidePageCallbacks, IPageService {
62
66
  initPage(): Promise<RideType | undefined>;
@@ -1,7 +1,7 @@
1
1
  import { IncyclistPageService } from "../../base/pages";
2
2
  import { FileInfo, FolderInfo, ImportDisplayProps, IObserver, ParsedRoute, ScannedRoute } from "../../types";
3
3
  import { SearchFilter, SearchState } from "../list/types";
4
- import { DownloadRowDisplayProps, IRoutePageService, RouteItemProps, RoutePageDisplayProps } from "./types";
4
+ import { AttachedWorkoutProps, DownloadRowDisplayProps, IRoutePageService, RouteDetailsProps, RouteItemProps, RoutePageDisplayProps } from "./types";
5
5
  import { Observer } from "../../base/types";
6
6
  import { Route } from "../base/model/route";
7
7
  import { DownloadObserver } from "../download/types";
@@ -42,6 +42,9 @@ export declare class RoutesPageService extends IncyclistPageService implements I
42
42
  onSelect(id: string): void;
43
43
  onDelete(id: string): void;
44
44
  start(): void;
45
+ getRouteDetailsProps(routeId: string): RouteDetailsProps;
46
+ protected getAttachedWorkoutProps(): AttachedWorkoutProps | null;
47
+ onClearWorkoutSelection(): void;
45
48
  protected getDownloadDisplayProps(): DownloadRowDisplayProps[];
46
49
  protected updatePageDisplay(): void;
47
50
  protected getRoutesDisplayProps(): Array<RouteItemProps>;
@@ -62,5 +65,6 @@ export declare class RoutesPageService extends IncyclistPageService implements I
62
65
  protected getUserSettings(): import("../../settings").UserSettingsService;
63
66
  protected getRouteDownload(): import("../download/service").RouteDownloadService;
64
67
  protected getRouteLibraryScanner(): import("../library/service").RouteLibraryScannerService;
68
+ protected getWorkoutList(): import("../../workouts").WorkoutListService;
65
69
  }
66
70
  export declare const getRoutesPageService: () => RoutesPageService;
@@ -31,6 +31,17 @@ export interface IRoutePageService extends IPageService, IPageCallBacks {
31
31
  getPageDisplayProps(): RoutePageDisplayProps;
32
32
  onImportClosed(): void;
33
33
  getImportDisplayProps(): ImportDisplayProps;
34
+ getRouteDetailsProps(routeId: string): RouteDetailsProps;
35
+ onClearWorkoutSelection(): void;
36
+ }
37
+ export interface AttachedWorkoutProps {
38
+ id: string;
39
+ title: string;
40
+ }
41
+ export interface RouteDetailsProps {
42
+ routeId: string;
43
+ attachedWorkout: AttachedWorkoutProps | null;
44
+ comboEnabled: boolean;
34
45
  }
35
46
  export type DownloadStatus = 'downloading' | 'done' | 'failed' | 'required';
36
47
  export interface DownloadRowDisplayProps {
@@ -3,7 +3,7 @@ import { IObserver } from "../../types";
3
3
  import { FileInfo } from "../../api";
4
4
  import { WorkoutCard } from "../list/cards/WorkoutCard";
5
5
  import { WorkoutListService } from "../list/service";
6
- import { GroupFilterProps, IWorkoutListPageService, UpcomingTrainingProps, WorkoutDetailsProps, WorkoutImportDisplayProps, WorkoutListItemProps, WorkoutListPageDisplayProps } from "./types";
6
+ import { AttachedRouteProps, GroupFilterProps, IWorkoutListPageService, UpcomingTrainingProps, WorkoutDetailsProps, WorkoutImportDisplayProps, WorkoutListItemProps, WorkoutListPageDisplayProps } from "./types";
7
7
  export declare class WorkoutListPageService extends IncyclistPageService implements IWorkoutListPageService {
8
8
  protected groupFilter: string | null;
9
9
  protected detailWorkoutId: string | null;
@@ -24,6 +24,7 @@ export declare class WorkoutListPageService extends IncyclistPageService impleme
24
24
  closePage(): void;
25
25
  getPageDisplayProps(): WorkoutListPageDisplayProps;
26
26
  getWorkoutDetailsProps(id: string): WorkoutDetailsProps | null;
27
+ protected getAttachedRouteProps(): AttachedRouteProps | null;
27
28
  getImportDisplayProps(): WorkoutImportDisplayProps;
28
29
  onSelectGroup(group: string | null): void;
29
30
  onOpenDetails(id: string): void;
@@ -37,6 +38,7 @@ export declare class WorkoutListPageService extends IncyclistPageService impleme
37
38
  }): void;
38
39
  onMarkForRoute(id: string): void;
39
40
  onClearSelection(): void;
41
+ onClearRouteSelection(): void;
40
42
  onImportOpen(): void;
41
43
  onImportFile(file: FileInfo): IObserver;
42
44
  onImportSetGroup(id: string, group: string): void;
@@ -55,6 +57,7 @@ export declare class WorkoutListPageService extends IncyclistPageService impleme
55
57
  protected emitImportUpdate(): void;
56
58
  protected getDevicePairing(): import("../../devices").DevicePairingService;
57
59
  protected getWorkoutList(): WorkoutListService;
60
+ protected getRouteList(): import("../../routes").RouteListService;
58
61
  protected getWorkoutCalendar(): import("../calendar").WorkoutCalendarService;
59
62
  protected getUserSettings(): import("../../settings").UserSettingsService;
60
63
  protected getAppState(): import("../../appstate").AppStateService;
@@ -41,6 +41,10 @@ export interface WorkoutListItemProps {
41
41
  canDelete: boolean;
42
42
  workout: Workout;
43
43
  }
44
+ export interface AttachedRouteProps {
45
+ id: string;
46
+ title: string;
47
+ }
44
48
  export interface WorkoutDetailsProps {
45
49
  id: string;
46
50
  title: string;
@@ -57,6 +61,8 @@ export interface WorkoutDetailsProps {
57
61
  canDelete: boolean;
58
62
  isScheduled: boolean;
59
63
  date?: Date;
64
+ attachedRoute: AttachedRouteProps | null;
65
+ comboEnabled: boolean;
60
66
  }
61
67
  export interface WorkoutImportDisplayProps {
62
68
  phase: 'landing' | 'importing' | 'result' | 'error';
@@ -84,6 +90,7 @@ export interface WorkoutListPageCallbacks {
84
90
  }) => void;
85
91
  onMarkForRoute?: (id: string) => void;
86
92
  onClearSelection: () => void;
93
+ onClearRouteSelection: () => void;
87
94
  onImportOpen: () => void;
88
95
  onImportFile: (file: FileInfo) => IObserver;
89
96
  onImportSetGroup: (id: string, group: string) => void;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "incyclist-services",
3
- "version": "1.7.99",
3
+ "version": "1.7.100",
4
4
  "peerDependencies": {
5
5
  "gd-eventlog": "^0.1.27"
6
6
  },