incyclist-services 1.7.94 → 1.7.95

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.
Files changed (32) hide show
  1. package/lib/cjs/activities/upload/index.js +0 -1
  2. package/lib/cjs/apps/index.js +0 -1
  3. package/lib/cjs/apps/service.js +1 -3
  4. package/lib/cjs/devices/page/service.js +9 -3
  5. package/lib/cjs/devices/page/statemachine.js +14 -4
  6. package/lib/cjs/devices/ride/cyclingMode.js +29 -0
  7. package/lib/cjs/devices/ride/index.js +1 -0
  8. package/lib/cjs/ride/display/service.js +7 -13
  9. package/lib/cjs/ride/workout/WorkoutDisplayService.js +6 -2
  10. package/lib/cjs/workouts/ride/page/service.js +13 -2
  11. package/lib/cjs/workouts/ride/service.js +80 -11
  12. package/lib/esm/activities/upload/index.js +0 -1
  13. package/lib/esm/apps/index.js +0 -1
  14. package/lib/esm/apps/service.js +1 -3
  15. package/lib/esm/devices/page/service.js +9 -3
  16. package/lib/esm/devices/page/statemachine.js +14 -4
  17. package/lib/esm/devices/ride/cyclingMode.js +25 -0
  18. package/lib/esm/devices/ride/index.js +1 -0
  19. package/lib/esm/ride/display/service.js +8 -14
  20. package/lib/esm/ride/workout/WorkoutDisplayService.js +6 -2
  21. package/lib/esm/workouts/ride/page/service.js +13 -2
  22. package/lib/esm/workouts/ride/service.js +81 -12
  23. package/lib/types/activities/upload/index.d.ts +0 -1
  24. package/lib/types/apps/index.d.ts +0 -1
  25. package/lib/types/devices/page/statemachine.d.ts +2 -0
  26. package/lib/types/devices/ride/cyclingMode.d.ts +4 -0
  27. package/lib/types/devices/ride/index.d.ts +1 -0
  28. package/lib/types/workouts/ride/page/service.d.ts +2 -1
  29. package/lib/types/workouts/ride/page/types.d.ts +3 -0
  30. package/lib/types/workouts/ride/service.d.ts +10 -1
  31. package/lib/types/workouts/ride/types.d.ts +10 -1
  32. package/package.json +1 -1
@@ -14,7 +14,6 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
- __exportStar(require("./velohero"), exports);
18
17
  __exportStar(require("./strava"), exports);
19
18
  __exportStar(require("./intervals"), exports);
20
19
  __exportStar(require("./types"), exports);
@@ -18,4 +18,3 @@ __exportStar(require("./base"), exports);
18
18
  __exportStar(require("./googleMaps"), exports);
19
19
  __exportStar(require("./service"), exports);
20
20
  __exportStar(require("./strava"), exports);
21
- __exportStar(require("./velohero"), exports);
@@ -43,7 +43,6 @@ const settings_1 = require("../settings");
43
43
  const base_1 = require("./base");
44
44
  const IntervalsAppConnection_1 = require("./intervals/IntervalsAppConnection");
45
45
  const komoot_1 = require("./komoot");
46
- const VeloHeroAppConnection_1 = require("./velohero/VeloHeroAppConnection");
47
46
  let AppsService = (() => {
48
47
  let _classDecorators = [types_1.Singleton];
49
48
  let _classDescriptor;
@@ -67,7 +66,7 @@ let AppsService = (() => {
67
66
  __runInitializers(_classThis, _classExtraInitializers);
68
67
  }
69
68
  services = (__runInitializers(this, _instanceExtraInitializers), {
70
- ActivityUpload: ['strava', 'velohero', 'intervals'],
69
+ ActivityUpload: ['strava', 'intervals'],
71
70
  WorkoutUpload: [],
72
71
  WorkoutDownload: ['intervals'],
73
72
  ActivityDownload: [],
@@ -75,7 +74,6 @@ let AppsService = (() => {
75
74
  });
76
75
  serviceMap = [
77
76
  { name: 'Strava', key: 'strava', iconUrl: 'https://static.cdnlogo.com/logos/s/42/strava-wordmark.svg', connection: new base_1.StravaAppConnection() },
78
- { name: 'VeloHero', key: 'velohero', iconUrl: 'images/velo-white.png', connection: new VeloHeroAppConnection_1.VeloHeroAppConnection() },
79
77
  { name: 'Komoot', key: 'komoot', iconUrl: 'https://www.komoot.com/assets/4d8ae313eec53e6e.svg', connection: new komoot_1.KomootAppConnection() },
80
78
  { name: 'Intervals.icu', key: 'intervals', iconUrl: 'images/intervals.png', connection: new IntervalsAppConnection_1.IntervalsAppConnection() },
81
79
  ];
@@ -95,9 +95,15 @@ let DevicesPageService = (() => {
95
95
  if (this.promiseOpen !== undefined) {
96
96
  return this.getPageObserver();
97
97
  }
98
- this.stateMachine.start(() => {
98
+ const onStateMachineUpdate = () => {
99
99
  this.getPageObserver().emit('page-update');
100
- });
100
+ };
101
+ this.stateMachine.start(onStateMachineUpdate);
102
+ if (this.stateMachine.state !== 'Idle') {
103
+ this.logEvent({ message: 'state machine was not in expected state on open, resetting', page: 'Pairing', state: this.stateMachine.state });
104
+ this.stateMachine.stop();
105
+ this.stateMachine.start(onStateMachineUpdate);
106
+ }
101
107
  this.promiseOpen = new Promise((done) => {
102
108
  this.start()
103
109
  .catch((err) => { this.logError(err, 'openPage'); })
@@ -321,7 +327,7 @@ let DevicesPageService = (() => {
321
327
  this.updatePage();
322
328
  }
323
329
  async closeDeviceSelection(enabled) {
324
- this.logEvent({ message: 'capability closed', capability: this.openedCapability });
330
+ this.logEvent({ message: 'capability closed', capability: this.openedCapability, enabled, caller: new Error().stack });
325
331
  if (!enabled) {
326
332
  const all = this.state.capabilities ?? [];
327
333
  const requested = all.find(c => c.capability === this.openedCapability);
@@ -68,6 +68,8 @@ let PairingPageStateMachine = (() => {
68
68
  selectStateChangeCallback;
69
69
  retryTimeout;
70
70
  selectionTimeout;
71
+ pairingPromise;
72
+ scanningPromise;
71
73
  constructor() {
72
74
  this.logger = new gd_eventlog_1.EventLogger('PairingPageState');
73
75
  }
@@ -99,6 +101,8 @@ let PairingPageStateMachine = (() => {
99
101
  this.unregisterServiceEventHandlers();
100
102
  delete this.stateChangeCallback;
101
103
  this.resetTimeouts();
104
+ delete this.pairingPromise;
105
+ delete this.scanningPromise;
102
106
  this.setState('Closed');
103
107
  this.logIncomingEvent('stop', prev, 'Closed');
104
108
  }
@@ -199,14 +203,20 @@ let PairingPageStateMachine = (() => {
199
203
  this.resetTimeouts();
200
204
  this.setState('Done');
201
205
  }
202
- else {
206
+ else if (!this.pairingPromise) {
203
207
  this.setState('Pairing');
204
- service.startPairing(adapters, {});
208
+ this.pairingPromise = Promise.resolve(service.startPairing(adapters, {}))
209
+ .catch(err => { this.logError(err, 'startPairing'); })
210
+ .finally(() => { delete this.pairingPromise; });
205
211
  }
206
212
  }
207
213
  else if (this.selectState === 'Closed' || this.selectState === 'Active') {
208
- this.setState('Scanning');
209
- service.startScanning(adapters, {});
214
+ if (!this.scanningPromise) {
215
+ this.setState('Scanning');
216
+ this.scanningPromise = Promise.resolve(service.startScanning(adapters, {}))
217
+ .catch(err => { this.logError(err, 'startScanning'); })
218
+ .finally(() => { delete this.scanningPromise; });
219
+ }
210
220
  }
211
221
  if (this.state !== oldState)
212
222
  this.logger.logEvent({ message: 'state changed', stateTransition: { from: oldState, to: this.state } });
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.isVirtualShiftingEnabled = isVirtualShiftingEnabled;
4
+ exports.getLoadButtonMode = getLoadButtonMode;
5
+ function isVirtualShiftingEnabled(mode) {
6
+ try {
7
+ if (!mode)
8
+ return false;
9
+ if (mode.isSIM()) {
10
+ const virtshiftMode = mode.getSetting('virtshift');
11
+ return (virtshiftMode === 'Mixed' || virtshiftMode === 'Incyclist' || virtshiftMode === 'SmartTrainer' || virtshiftMode === 'Enabled');
12
+ }
13
+ if (mode.isResistance()) {
14
+ return true;
15
+ }
16
+ return false;
17
+ }
18
+ catch {
19
+ return false;
20
+ }
21
+ }
22
+ function getLoadButtonMode(mode) {
23
+ if (!mode)
24
+ return 'power';
25
+ if (mode.isSIM() || mode.isResistance()) {
26
+ return isVirtualShiftingEnabled(mode) ? 'gear' : 'hidden';
27
+ }
28
+ return 'power';
29
+ }
@@ -15,3 +15,4 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
17
  __exportStar(require("./service"), exports);
18
+ __exportStar(require("./cyclingMode"), exports);
@@ -432,8 +432,11 @@ let RideDisplayService = (() => {
432
432
  this.observer?.stop({ immediately: props.noStateUpdates });
433
433
  if (props.noStateUpdates)
434
434
  delete this.observer;
435
- else
436
- (0, utils_1.waitNextTick)().then(() => delete this.observer);
435
+ else {
436
+ const observerToClear = this.observer;
437
+ (0, utils_1.waitNextTick)().then(() => { if (this.observer === observerToClear)
438
+ delete this.observer; });
439
+ }
437
440
  if (prevState === 'Finished' || prevState === 'Idle' || prevState === 'Closing') {
438
441
  this.state = 'Idle';
439
442
  return;
@@ -553,7 +556,7 @@ let RideDisplayService = (() => {
553
556
  const { time, speed, routeDistance, distance } = currentValues;
554
557
  const data = { time, speed, routeDistance, distance };
555
558
  this.getRideModeService().onActivityUpdate(data, currentValues);
556
- this.observer.emit('data-update', data, currentValues);
559
+ this.observer?.emit('data-update', data, currentValues);
557
560
  }
558
561
  }
559
562
  onWorkoutStopped() {
@@ -1085,16 +1088,7 @@ let RideDisplayService = (() => {
1085
1088
  isVirtualShiftingEnabled() {
1086
1089
  try {
1087
1090
  const mode = this.getDeviceRide().getCyclingMode();
1088
- if (!mode)
1089
- return false;
1090
- if (mode.isSIM()) {
1091
- const virtshiftMode = mode.getSetting('virtshift');
1092
- return (virtshiftMode === 'Mixed' || virtshiftMode === 'Incyclist' || virtshiftMode === 'SmartTrainer' || virtshiftMode === 'Enabled');
1093
- }
1094
- if (mode.isResistance()) {
1095
- return true;
1096
- }
1097
- return false;
1091
+ return (0, devices_1.isVirtualShiftingEnabled)(mode);
1098
1092
  }
1099
1093
  catch (err) {
1100
1094
  this.logError(err, 'isVirtualShiftingEnabled');
@@ -35,6 +35,7 @@ var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn,
35
35
  };
36
36
  Object.defineProperty(exports, "__esModule", { value: true });
37
37
  exports.WorkoutDisplayService = void 0;
38
+ const devices_1 = require("../../devices");
38
39
  const workouts_1 = require("../../workouts");
39
40
  const base_1 = require("../base/base");
40
41
  const decorators_1 = require("../../base/decorators");
@@ -56,6 +57,9 @@ let WorkoutDisplayService = (() => {
56
57
  prevPowerTs = __runInitializers(this, _instanceExtraInitializers);
57
58
  buildRequest(props = {}) {
58
59
  if (props?.limits) {
60
+ const mode = this.getDeviceRide().getCyclingMode();
61
+ if ((0, devices_1.getLoadButtonMode)(mode) !== 'power')
62
+ return {};
59
63
  return props.limits;
60
64
  }
61
65
  else
@@ -76,12 +80,12 @@ let WorkoutDisplayService = (() => {
76
80
  }
77
81
  }
78
82
  getLogProps() {
79
- const workout = this.getWorkoutList().getSelected();
83
+ const workout = this.getWorkoutList().getSelected() ?? this.getWorkoutRide().getWorkout();
80
84
  const settings = this.getWorkoutList().getStartSettings() ?? {};
81
85
  const bikeProps = this.getBikeLogProps();
82
86
  return {
83
87
  mode: 'workout',
84
- workout: workout.name,
88
+ workout: workout?.name,
85
89
  ...settings,
86
90
  ...bikeProps
87
91
  };
@@ -172,7 +172,8 @@ let WorkoutRidePageService = (() => {
172
172
  steps: this.buildUpcomingSteps(current, wo.ftp),
173
173
  dashboard: this.buildDashboardLine(wo),
174
174
  gestureHint: this.buildGestureHint(base.startOverlayProps === null),
175
- loadIncrement: this.getLoadIncrement()
175
+ loadIncrement: this.getLoadIncrement(),
176
+ loadButtonMode: wo.loadButtonMode ?? 'power'
176
177
  };
177
178
  }
178
179
  catch (err) {
@@ -334,6 +335,15 @@ let WorkoutRidePageService = (() => {
334
335
  return undefined;
335
336
  }
336
337
  }
338
+ getLoadButtonMode() {
339
+ try {
340
+ return this.getWorkoutRide().getLoadButtonMode();
341
+ }
342
+ catch (err) {
343
+ this.logError(err, 'getLoadButtonMode');
344
+ return 'power';
345
+ }
346
+ }
337
347
  onRideStateUpdate(state) {
338
348
  this.subscribeToWorkoutObserver();
339
349
  switch (state) {
@@ -512,7 +522,8 @@ let WorkoutRidePageService = (() => {
512
522
  steps: { previous: null, current: null, upcoming: [], hasMore: false },
513
523
  dashboard: { text: '', mode: null },
514
524
  gestureHint: null,
515
- loadIncrement: DEFAULT_LOAD_INCREMENT
525
+ loadIncrement: DEFAULT_LOAD_INCREMENT,
526
+ loadButtonMode: 'power'
516
527
  };
517
528
  }
518
529
  updatePageDisplay() {
@@ -57,14 +57,17 @@ let WorkoutRide = (() => {
57
57
  let _instanceExtraInitializers = [];
58
58
  let _getUserSettings_decorators;
59
59
  let _getWorkoutList_decorators;
60
+ let _getDeviceRide_decorators;
60
61
  var WorkoutRide = class extends _classSuper {
61
62
  static { _classThis = this; }
62
63
  static {
63
64
  const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
64
65
  _getUserSettings_decorators = [decorators_1.Injectable];
65
66
  _getWorkoutList_decorators = [decorators_1.Injectable];
67
+ _getDeviceRide_decorators = [decorators_1.Injectable];
66
68
  __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);
67
69
  __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);
70
+ __esDecorate(this, null, _getDeviceRide_decorators, { kind: "method", name: "getDeviceRide", static: false, private: false, access: { has: obj => "getDeviceRide" in obj, get: obj => obj.getDeviceRide }, metadata: _metadata }, null, _instanceExtraInitializers);
68
71
  __esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
69
72
  WorkoutRide = _classThis = _classDescriptor.value;
70
73
  if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
@@ -269,16 +272,68 @@ let WorkoutRide = (() => {
269
272
  this.logError(err, 'backward', { ts, limits });
270
273
  }
271
274
  }
275
+ isPowerRangeAdjustable(delta) {
276
+ if (this.currentLimits?.minPower === this.currentLimits?.maxPower)
277
+ return false;
278
+ return delta >= 0
279
+ ? this.currentLimits?.targetPower < this.currentLimits?.maxPower
280
+ : this.currentLimits?.targetPower > this.currentLimits?.minPower;
281
+ }
282
+ getPowerRangeDeltaVal(magnitude) {
283
+ if (!this.settings?.ftp)
284
+ return magnitude;
285
+ return magnitude === 1 ? 5 : 50;
286
+ }
287
+ getPowerRangeAdjustmentWatts(magnitude, increase) {
288
+ const nominal = this.getPowerRangeDeltaVal(magnitude);
289
+ const headroom = increase
290
+ ? this.currentLimits.maxPower - this.currentLimits.targetPower
291
+ : this.currentLimits.targetPower - this.currentLimits.minPower;
292
+ return Math.min(nominal, headroom);
293
+ }
294
+ getLoadButtonMode() {
295
+ try {
296
+ const mode = this.getDeviceRide().getCyclingMode();
297
+ return (0, devices_1.getLoadButtonMode)(mode);
298
+ }
299
+ catch (err) {
300
+ this.logError(err, 'getLoadButtonMode');
301
+ return 'power';
302
+ }
303
+ }
304
+ getGearButtonLabels() {
305
+ return { inc5: '+5', inc1: '+1', dec1: '-1', dec5: '-5' };
306
+ }
307
+ getLoadButtonLabels() {
308
+ const label = (magnitude, increase) => {
309
+ const sign = increase ? '+' : '-';
310
+ const delta = increase ? magnitude : -magnitude;
311
+ return this.isPowerRangeAdjustable(delta)
312
+ ? `${sign}${this.getPowerRangeAdjustmentWatts(magnitude, increase)}W`
313
+ : `${sign}${magnitude}%`;
314
+ };
315
+ return {
316
+ inc5: label(5, true),
317
+ inc1: label(1, true),
318
+ dec1: label(1, false),
319
+ dec5: label(5, false),
320
+ };
321
+ }
272
322
  powerUp(delta) {
273
323
  if (delta < 0)
274
324
  return this.powerDown(-delta);
275
325
  this.logEvent({ message: 'workout power up', delta });
276
326
  try {
277
- if (this.currentLimits?.minPower !== this.currentLimits?.maxPower && this.currentLimits?.targetPower < this.currentLimits?.maxPower) {
278
- let deltaVal = delta;
279
- if (this.settings?.ftp) {
280
- deltaVal = delta === 1 ? 5 : 50;
281
- }
327
+ const loadButtonMode = this.getLoadButtonMode();
328
+ if (loadButtonMode === 'hidden')
329
+ return undefined;
330
+ if (loadButtonMode === 'gear') {
331
+ this.gearChange(delta);
332
+ this.logEvent({ message: 'workout gear shift', gearDelta: delta });
333
+ return { type: 'gear', value: delta };
334
+ }
335
+ if (this.isPowerRangeAdjustable(delta)) {
336
+ const deltaVal = this.getPowerRangeDeltaVal(delta);
282
337
  this.currentLimits.targetPower = Math.min(this.currentLimits.targetPower + deltaVal, this.currentLimits.maxPower);
283
338
  this.logEvent({ message: 'workout target power adjusted', targetPower: this.currentLimits.targetPower });
284
339
  this.emit('update', this.getDashboardDisplayProperties());
@@ -304,11 +359,16 @@ let WorkoutRide = (() => {
304
359
  powerDown(delta) {
305
360
  this.logEvent({ message: 'workout power down', delta });
306
361
  try {
307
- if (this.currentLimits?.minPower !== this.currentLimits?.maxPower && this.currentLimits?.targetPower > this.currentLimits?.minPower) {
308
- let deltaVal = delta;
309
- if (this.settings?.ftp) {
310
- deltaVal = delta === 1 ? 5 : 50;
311
- }
362
+ const loadButtonMode = this.getLoadButtonMode();
363
+ if (loadButtonMode === 'hidden')
364
+ return undefined;
365
+ if (loadButtonMode === 'gear') {
366
+ this.gearChange(-delta);
367
+ this.logEvent({ message: 'workout gear shift', gearDelta: -delta });
368
+ return { type: 'gear', value: -delta };
369
+ }
370
+ if (this.isPowerRangeAdjustable(-delta)) {
371
+ const deltaVal = this.getPowerRangeDeltaVal(delta);
312
372
  this.currentLimits.targetPower = Math.max(this.currentLimits.targetPower - deltaVal, this.currentLimits.minPower);
313
373
  this.logEvent({ message: 'workout target power adjusted', targetPower: this.currentLimits.targetPower });
314
374
  this.emit('update', this.getDashboardDisplayProperties());
@@ -331,6 +391,9 @@ let WorkoutRide = (() => {
331
391
  return undefined;
332
392
  }
333
393
  }
394
+ gearChange(gearDelta) {
395
+ this.getDeviceRide().sendUpdate({ gearDelta });
396
+ }
334
397
  toggleCyclingMode() {
335
398
  const deviceRide = (0, devices_1.useDeviceRide)();
336
399
  deviceRide.toggleCyclingMode();
@@ -344,6 +407,7 @@ let WorkoutRide = (() => {
344
407
  const { start, stop } = this.getZoomParameters(this.trainingTime);
345
408
  const title = this.getStepTitle(this.trainingTime);
346
409
  const canShowBackward = Math.round((this.trainingTime ?? 0)) > 0;
410
+ const loadButtonMode = this.getLoadButtonMode();
347
411
  const props = {
348
412
  workout: this.workout, title,
349
413
  ftp: this.settings.ftp,
@@ -351,7 +415,9 @@ let WorkoutRide = (() => {
351
415
  start, stop,
352
416
  mode: this.getCyclingModeText(),
353
417
  canShowBackward,
354
- canShowForward: true
418
+ canShowForward: true,
419
+ loadButtonMode,
420
+ loadButtons: loadButtonMode === 'power' ? this.getLoadButtonLabels() : this.getGearButtonLabels()
355
421
  };
356
422
  return props;
357
423
  }
@@ -618,6 +684,9 @@ let WorkoutRide = (() => {
618
684
  getWorkoutList() {
619
685
  return (0, list_1.useWorkoutList)();
620
686
  }
687
+ getDeviceRide() {
688
+ return (0, devices_1.useDeviceRide)();
689
+ }
621
690
  };
622
691
  return WorkoutRide = _classThis;
623
692
  })();
@@ -1,4 +1,3 @@
1
- export * from './velohero';
2
1
  export * from './strava';
3
2
  export * from './intervals';
4
3
  export * from './types';
@@ -2,4 +2,3 @@ export * from './base';
2
2
  export * from './googleMaps';
3
3
  export * from './service';
4
4
  export * from './strava';
5
- export * from './velohero';
@@ -40,7 +40,6 @@ import { useUserSettings } from "../settings";
40
40
  import { StravaAppConnection } from "./base";
41
41
  import { IntervalsAppConnection } from "./intervals/IntervalsAppConnection";
42
42
  import { KomootAppConnection } from "./komoot";
43
- import { VeloHeroAppConnection } from "./velohero/VeloHeroAppConnection";
44
43
  let AppsService = (() => {
45
44
  let _classDecorators = [Singleton];
46
45
  let _classDescriptor;
@@ -64,7 +63,7 @@ let AppsService = (() => {
64
63
  __runInitializers(_classThis, _classExtraInitializers);
65
64
  }
66
65
  services = (__runInitializers(this, _instanceExtraInitializers), {
67
- ActivityUpload: ['strava', 'velohero', 'intervals'],
66
+ ActivityUpload: ['strava', 'intervals'],
68
67
  WorkoutUpload: [],
69
68
  WorkoutDownload: ['intervals'],
70
69
  ActivityDownload: [],
@@ -72,7 +71,6 @@ let AppsService = (() => {
72
71
  });
73
72
  serviceMap = [
74
73
  { name: 'Strava', key: 'strava', iconUrl: 'https://static.cdnlogo.com/logos/s/42/strava-wordmark.svg', connection: new StravaAppConnection() },
75
- { name: 'VeloHero', key: 'velohero', iconUrl: 'images/velo-white.png', connection: new VeloHeroAppConnection() },
76
74
  { name: 'Komoot', key: 'komoot', iconUrl: 'https://www.komoot.com/assets/4d8ae313eec53e6e.svg', connection: new KomootAppConnection() },
77
75
  { name: 'Intervals.icu', key: 'intervals', iconUrl: 'images/intervals.png', connection: new IntervalsAppConnection() },
78
76
  ];
@@ -92,9 +92,15 @@ let DevicesPageService = (() => {
92
92
  if (this.promiseOpen !== undefined) {
93
93
  return this.getPageObserver();
94
94
  }
95
- this.stateMachine.start(() => {
95
+ const onStateMachineUpdate = () => {
96
96
  this.getPageObserver().emit('page-update');
97
- });
97
+ };
98
+ this.stateMachine.start(onStateMachineUpdate);
99
+ if (this.stateMachine.state !== 'Idle') {
100
+ this.logEvent({ message: 'state machine was not in expected state on open, resetting', page: 'Pairing', state: this.stateMachine.state });
101
+ this.stateMachine.stop();
102
+ this.stateMachine.start(onStateMachineUpdate);
103
+ }
98
104
  this.promiseOpen = new Promise((done) => {
99
105
  this.start()
100
106
  .catch((err) => { this.logError(err, 'openPage'); })
@@ -318,7 +324,7 @@ let DevicesPageService = (() => {
318
324
  this.updatePage();
319
325
  }
320
326
  async closeDeviceSelection(enabled) {
321
- this.logEvent({ message: 'capability closed', capability: this.openedCapability });
327
+ this.logEvent({ message: 'capability closed', capability: this.openedCapability, enabled, caller: new Error().stack });
322
328
  if (!enabled) {
323
329
  const all = this.state.capabilities ?? [];
324
330
  const requested = all.find(c => c.capability === this.openedCapability);
@@ -65,6 +65,8 @@ let PairingPageStateMachine = (() => {
65
65
  selectStateChangeCallback;
66
66
  retryTimeout;
67
67
  selectionTimeout;
68
+ pairingPromise;
69
+ scanningPromise;
68
70
  constructor() {
69
71
  this.logger = new EventLogger('PairingPageState');
70
72
  }
@@ -96,6 +98,8 @@ let PairingPageStateMachine = (() => {
96
98
  this.unregisterServiceEventHandlers();
97
99
  delete this.stateChangeCallback;
98
100
  this.resetTimeouts();
101
+ delete this.pairingPromise;
102
+ delete this.scanningPromise;
99
103
  this.setState('Closed');
100
104
  this.logIncomingEvent('stop', prev, 'Closed');
101
105
  }
@@ -196,14 +200,20 @@ let PairingPageStateMachine = (() => {
196
200
  this.resetTimeouts();
197
201
  this.setState('Done');
198
202
  }
199
- else {
203
+ else if (!this.pairingPromise) {
200
204
  this.setState('Pairing');
201
- service.startPairing(adapters, {});
205
+ this.pairingPromise = Promise.resolve(service.startPairing(adapters, {}))
206
+ .catch(err => { this.logError(err, 'startPairing'); })
207
+ .finally(() => { delete this.pairingPromise; });
202
208
  }
203
209
  }
204
210
  else if (this.selectState === 'Closed' || this.selectState === 'Active') {
205
- this.setState('Scanning');
206
- service.startScanning(adapters, {});
211
+ if (!this.scanningPromise) {
212
+ this.setState('Scanning');
213
+ this.scanningPromise = Promise.resolve(service.startScanning(adapters, {}))
214
+ .catch(err => { this.logError(err, 'startScanning'); })
215
+ .finally(() => { delete this.scanningPromise; });
216
+ }
207
217
  }
208
218
  if (this.state !== oldState)
209
219
  this.logger.logEvent({ message: 'state changed', stateTransition: { from: oldState, to: this.state } });
@@ -0,0 +1,25 @@
1
+ export function isVirtualShiftingEnabled(mode) {
2
+ try {
3
+ if (!mode)
4
+ return false;
5
+ if (mode.isSIM()) {
6
+ const virtshiftMode = mode.getSetting('virtshift');
7
+ return (virtshiftMode === 'Mixed' || virtshiftMode === 'Incyclist' || virtshiftMode === 'SmartTrainer' || virtshiftMode === 'Enabled');
8
+ }
9
+ if (mode.isResistance()) {
10
+ return true;
11
+ }
12
+ return false;
13
+ }
14
+ catch {
15
+ return false;
16
+ }
17
+ }
18
+ export function getLoadButtonMode(mode) {
19
+ if (!mode)
20
+ return 'power';
21
+ if (mode.isSIM() || mode.isResistance()) {
22
+ return isVirtualShiftingEnabled(mode) ? 'gear' : 'hidden';
23
+ }
24
+ return 'power';
25
+ }
@@ -1 +1,2 @@
1
1
  export * from './service';
2
+ export * from './cyclingMode';
@@ -38,7 +38,7 @@ import { Observer, Singleton } from "../../base/types";
38
38
  import { Injectable } from "../../base/decorators";
39
39
  import { Step, useWorkoutList, useWorkoutRide, Workout } from "../../workouts";
40
40
  import { useRouteList } from "../../routes";
41
- import { useDeviceConfiguration, useDeviceRide } from "../../devices";
41
+ import { isVirtualShiftingEnabled as checkVirtualShiftingEnabled, useDeviceConfiguration, useDeviceRide } from "../../devices";
42
42
  import { useUserSettings } from "../../settings";
43
43
  import { IncyclistCapability } from "incyclist-devices";
44
44
  import { formatDateTime, getLegacyInterface, waitNextTick } from "../../utils";
@@ -429,8 +429,11 @@ let RideDisplayService = (() => {
429
429
  this.observer?.stop({ immediately: props.noStateUpdates });
430
430
  if (props.noStateUpdates)
431
431
  delete this.observer;
432
- else
433
- waitNextTick().then(() => delete this.observer);
432
+ else {
433
+ const observerToClear = this.observer;
434
+ waitNextTick().then(() => { if (this.observer === observerToClear)
435
+ delete this.observer; });
436
+ }
434
437
  if (prevState === 'Finished' || prevState === 'Idle' || prevState === 'Closing') {
435
438
  this.state = 'Idle';
436
439
  return;
@@ -550,7 +553,7 @@ let RideDisplayService = (() => {
550
553
  const { time, speed, routeDistance, distance } = currentValues;
551
554
  const data = { time, speed, routeDistance, distance };
552
555
  this.getRideModeService().onActivityUpdate(data, currentValues);
553
- this.observer.emit('data-update', data, currentValues);
556
+ this.observer?.emit('data-update', data, currentValues);
554
557
  }
555
558
  }
556
559
  onWorkoutStopped() {
@@ -1082,16 +1085,7 @@ let RideDisplayService = (() => {
1082
1085
  isVirtualShiftingEnabled() {
1083
1086
  try {
1084
1087
  const mode = this.getDeviceRide().getCyclingMode();
1085
- if (!mode)
1086
- return false;
1087
- if (mode.isSIM()) {
1088
- const virtshiftMode = mode.getSetting('virtshift');
1089
- return (virtshiftMode === 'Mixed' || virtshiftMode === 'Incyclist' || virtshiftMode === 'SmartTrainer' || virtshiftMode === 'Enabled');
1090
- }
1091
- if (mode.isResistance()) {
1092
- return true;
1093
- }
1094
- return false;
1088
+ return checkVirtualShiftingEnabled(mode);
1095
1089
  }
1096
1090
  catch (err) {
1097
1091
  this.logError(err, 'isVirtualShiftingEnabled');
@@ -32,6 +32,7 @@ var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn,
32
32
  if (target) Object.defineProperty(target, contextIn.name, descriptor);
33
33
  done = true;
34
34
  };
35
+ import { getLoadButtonMode } from "../../devices";
35
36
  import { useWorkoutList, useWorkoutRide } from "../../workouts";
36
37
  import { RideModeService } from "../base/base";
37
38
  import { Injectable } from "../../base/decorators";
@@ -53,6 +54,9 @@ let WorkoutDisplayService = (() => {
53
54
  prevPowerTs = __runInitializers(this, _instanceExtraInitializers);
54
55
  buildRequest(props = {}) {
55
56
  if (props?.limits) {
57
+ const mode = this.getDeviceRide().getCyclingMode();
58
+ if (getLoadButtonMode(mode) !== 'power')
59
+ return {};
56
60
  return props.limits;
57
61
  }
58
62
  else
@@ -73,12 +77,12 @@ let WorkoutDisplayService = (() => {
73
77
  }
74
78
  }
75
79
  getLogProps() {
76
- const workout = this.getWorkoutList().getSelected();
80
+ const workout = this.getWorkoutList().getSelected() ?? this.getWorkoutRide().getWorkout();
77
81
  const settings = this.getWorkoutList().getStartSettings() ?? {};
78
82
  const bikeProps = this.getBikeLogProps();
79
83
  return {
80
84
  mode: 'workout',
81
- workout: workout.name,
85
+ workout: workout?.name,
82
86
  ...settings,
83
87
  ...bikeProps
84
88
  };
@@ -169,7 +169,8 @@ let WorkoutRidePageService = (() => {
169
169
  steps: this.buildUpcomingSteps(current, wo.ftp),
170
170
  dashboard: this.buildDashboardLine(wo),
171
171
  gestureHint: this.buildGestureHint(base.startOverlayProps === null),
172
- loadIncrement: this.getLoadIncrement()
172
+ loadIncrement: this.getLoadIncrement(),
173
+ loadButtonMode: wo.loadButtonMode ?? 'power'
173
174
  };
174
175
  }
175
176
  catch (err) {
@@ -331,6 +332,15 @@ let WorkoutRidePageService = (() => {
331
332
  return undefined;
332
333
  }
333
334
  }
335
+ getLoadButtonMode() {
336
+ try {
337
+ return this.getWorkoutRide().getLoadButtonMode();
338
+ }
339
+ catch (err) {
340
+ this.logError(err, 'getLoadButtonMode');
341
+ return 'power';
342
+ }
343
+ }
334
344
  onRideStateUpdate(state) {
335
345
  this.subscribeToWorkoutObserver();
336
346
  switch (state) {
@@ -509,7 +519,8 @@ let WorkoutRidePageService = (() => {
509
519
  steps: { previous: null, current: null, upcoming: [], hasMore: false },
510
520
  dashboard: { text: '', mode: null },
511
521
  gestureHint: null,
512
- loadIncrement: DEFAULT_LOAD_INCREMENT
522
+ loadIncrement: DEFAULT_LOAD_INCREMENT,
523
+ loadButtonMode: 'power'
513
524
  };
514
525
  }
515
526
  updatePageDisplay() {
@@ -36,7 +36,7 @@ import { getBindings } from "../../api";
36
36
  import { IncyclistService } from "../../base/service";
37
37
  import { Singleton } from "../../base/types";
38
38
  import { Observer } from "../../base/types/observer";
39
- import { useDeviceRide } from "../../devices";
39
+ import { getLoadButtonMode, useDeviceRide } from "../../devices";
40
40
  import { useUserSettings } from "../../settings";
41
41
  import { waitNextTick } from "../../utils";
42
42
  import { valid } from "../../utils/valid";
@@ -54,14 +54,17 @@ let WorkoutRide = (() => {
54
54
  let _instanceExtraInitializers = [];
55
55
  let _getUserSettings_decorators;
56
56
  let _getWorkoutList_decorators;
57
+ let _getDeviceRide_decorators;
57
58
  var WorkoutRide = class extends _classSuper {
58
59
  static { _classThis = this; }
59
60
  static {
60
61
  const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
61
62
  _getUserSettings_decorators = [Injectable];
62
63
  _getWorkoutList_decorators = [Injectable];
64
+ _getDeviceRide_decorators = [Injectable];
63
65
  __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);
64
66
  __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);
67
+ __esDecorate(this, null, _getDeviceRide_decorators, { kind: "method", name: "getDeviceRide", static: false, private: false, access: { has: obj => "getDeviceRide" in obj, get: obj => obj.getDeviceRide }, metadata: _metadata }, null, _instanceExtraInitializers);
65
68
  __esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
66
69
  WorkoutRide = _classThis = _classDescriptor.value;
67
70
  if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
@@ -266,16 +269,68 @@ let WorkoutRide = (() => {
266
269
  this.logError(err, 'backward', { ts, limits });
267
270
  }
268
271
  }
272
+ isPowerRangeAdjustable(delta) {
273
+ if (this.currentLimits?.minPower === this.currentLimits?.maxPower)
274
+ return false;
275
+ return delta >= 0
276
+ ? this.currentLimits?.targetPower < this.currentLimits?.maxPower
277
+ : this.currentLimits?.targetPower > this.currentLimits?.minPower;
278
+ }
279
+ getPowerRangeDeltaVal(magnitude) {
280
+ if (!this.settings?.ftp)
281
+ return magnitude;
282
+ return magnitude === 1 ? 5 : 50;
283
+ }
284
+ getPowerRangeAdjustmentWatts(magnitude, increase) {
285
+ const nominal = this.getPowerRangeDeltaVal(magnitude);
286
+ const headroom = increase
287
+ ? this.currentLimits.maxPower - this.currentLimits.targetPower
288
+ : this.currentLimits.targetPower - this.currentLimits.minPower;
289
+ return Math.min(nominal, headroom);
290
+ }
291
+ getLoadButtonMode() {
292
+ try {
293
+ const mode = this.getDeviceRide().getCyclingMode();
294
+ return getLoadButtonMode(mode);
295
+ }
296
+ catch (err) {
297
+ this.logError(err, 'getLoadButtonMode');
298
+ return 'power';
299
+ }
300
+ }
301
+ getGearButtonLabels() {
302
+ return { inc5: '+5', inc1: '+1', dec1: '-1', dec5: '-5' };
303
+ }
304
+ getLoadButtonLabels() {
305
+ const label = (magnitude, increase) => {
306
+ const sign = increase ? '+' : '-';
307
+ const delta = increase ? magnitude : -magnitude;
308
+ return this.isPowerRangeAdjustable(delta)
309
+ ? `${sign}${this.getPowerRangeAdjustmentWatts(magnitude, increase)}W`
310
+ : `${sign}${magnitude}%`;
311
+ };
312
+ return {
313
+ inc5: label(5, true),
314
+ inc1: label(1, true),
315
+ dec1: label(1, false),
316
+ dec5: label(5, false),
317
+ };
318
+ }
269
319
  powerUp(delta) {
270
320
  if (delta < 0)
271
321
  return this.powerDown(-delta);
272
322
  this.logEvent({ message: 'workout power up', delta });
273
323
  try {
274
- if (this.currentLimits?.minPower !== this.currentLimits?.maxPower && this.currentLimits?.targetPower < this.currentLimits?.maxPower) {
275
- let deltaVal = delta;
276
- if (this.settings?.ftp) {
277
- deltaVal = delta === 1 ? 5 : 50;
278
- }
324
+ const loadButtonMode = this.getLoadButtonMode();
325
+ if (loadButtonMode === 'hidden')
326
+ return undefined;
327
+ if (loadButtonMode === 'gear') {
328
+ this.gearChange(delta);
329
+ this.logEvent({ message: 'workout gear shift', gearDelta: delta });
330
+ return { type: 'gear', value: delta };
331
+ }
332
+ if (this.isPowerRangeAdjustable(delta)) {
333
+ const deltaVal = this.getPowerRangeDeltaVal(delta);
279
334
  this.currentLimits.targetPower = Math.min(this.currentLimits.targetPower + deltaVal, this.currentLimits.maxPower);
280
335
  this.logEvent({ message: 'workout target power adjusted', targetPower: this.currentLimits.targetPower });
281
336
  this.emit('update', this.getDashboardDisplayProperties());
@@ -301,11 +356,16 @@ let WorkoutRide = (() => {
301
356
  powerDown(delta) {
302
357
  this.logEvent({ message: 'workout power down', delta });
303
358
  try {
304
- if (this.currentLimits?.minPower !== this.currentLimits?.maxPower && this.currentLimits?.targetPower > this.currentLimits?.minPower) {
305
- let deltaVal = delta;
306
- if (this.settings?.ftp) {
307
- deltaVal = delta === 1 ? 5 : 50;
308
- }
359
+ const loadButtonMode = this.getLoadButtonMode();
360
+ if (loadButtonMode === 'hidden')
361
+ return undefined;
362
+ if (loadButtonMode === 'gear') {
363
+ this.gearChange(-delta);
364
+ this.logEvent({ message: 'workout gear shift', gearDelta: -delta });
365
+ return { type: 'gear', value: -delta };
366
+ }
367
+ if (this.isPowerRangeAdjustable(-delta)) {
368
+ const deltaVal = this.getPowerRangeDeltaVal(delta);
309
369
  this.currentLimits.targetPower = Math.max(this.currentLimits.targetPower - deltaVal, this.currentLimits.minPower);
310
370
  this.logEvent({ message: 'workout target power adjusted', targetPower: this.currentLimits.targetPower });
311
371
  this.emit('update', this.getDashboardDisplayProperties());
@@ -328,6 +388,9 @@ let WorkoutRide = (() => {
328
388
  return undefined;
329
389
  }
330
390
  }
391
+ gearChange(gearDelta) {
392
+ this.getDeviceRide().sendUpdate({ gearDelta });
393
+ }
331
394
  toggleCyclingMode() {
332
395
  const deviceRide = useDeviceRide();
333
396
  deviceRide.toggleCyclingMode();
@@ -341,6 +404,7 @@ let WorkoutRide = (() => {
341
404
  const { start, stop } = this.getZoomParameters(this.trainingTime);
342
405
  const title = this.getStepTitle(this.trainingTime);
343
406
  const canShowBackward = Math.round((this.trainingTime ?? 0)) > 0;
407
+ const loadButtonMode = this.getLoadButtonMode();
344
408
  const props = {
345
409
  workout: this.workout, title,
346
410
  ftp: this.settings.ftp,
@@ -348,7 +412,9 @@ let WorkoutRide = (() => {
348
412
  start, stop,
349
413
  mode: this.getCyclingModeText(),
350
414
  canShowBackward,
351
- canShowForward: true
415
+ canShowForward: true,
416
+ loadButtonMode,
417
+ loadButtons: loadButtonMode === 'power' ? this.getLoadButtonLabels() : this.getGearButtonLabels()
352
418
  };
353
419
  return props;
354
420
  }
@@ -615,6 +681,9 @@ let WorkoutRide = (() => {
615
681
  getWorkoutList() {
616
682
  return useWorkoutList();
617
683
  }
684
+ getDeviceRide() {
685
+ return useDeviceRide();
686
+ }
618
687
  };
619
688
  return WorkoutRide = _classThis;
620
689
  })();
@@ -1,4 +1,3 @@
1
- export * from './velohero';
2
1
  export * from './strava';
3
2
  export * from './intervals';
4
3
  export * from './types';
@@ -2,4 +2,3 @@ export * from './base';
2
2
  export * from './googleMaps';
3
3
  export * from './service';
4
4
  export * from './strava';
5
- export * from './velohero';
@@ -11,6 +11,8 @@ export declare class PairingPageStateMachine {
11
11
  protected selectStateChangeCallback: () => void;
12
12
  protected retryTimeout: NodeJS.Timeout | undefined;
13
13
  protected selectionTimeout: NodeJS.Timeout | undefined;
14
+ protected pairingPromise: Promise<void> | undefined;
15
+ protected scanningPromise: Promise<void> | undefined;
14
16
  constructor();
15
17
  get state(): PageState;
16
18
  get selectState(): SelectState;
@@ -0,0 +1,4 @@
1
+ import { CyclingMode } from "incyclist-devices";
2
+ export declare function isVirtualShiftingEnabled(mode: CyclingMode): boolean;
3
+ export type LoadButtonMode = 'power' | 'gear' | 'hidden';
4
+ export declare function getLoadButtonMode(mode: CyclingMode): LoadButtonMode;
@@ -1,2 +1,3 @@
1
1
  export * from './service';
2
2
  export type * from './types';
3
+ export * from './cyclingMode';
@@ -1,7 +1,7 @@
1
1
  import { IncyclistPageService } from "../../../base/pages";
2
2
  import type { IObserver } from "../../../base/typedefs";
3
3
  import type { CurrentRideState, RideType } from "../../../types";
4
- import type { PowerAdjustmentResult, WorkoutDisplayProperties } from "../types";
4
+ import type { LoadButtonMode, PowerAdjustmentResult, WorkoutDisplayProperties } from "../types";
5
5
  import type { Workout } from "../../base/model";
6
6
  import type { StepDefinition } from "../../base/model/types";
7
7
  import type { IWorkoutRidePageService, WorkoutDashboardLine, WorkoutGestureHint, WorkoutGraphActuals, WorkoutGraphPlan, WorkoutRideMenuProps, WorkoutRidePageDisplayProps, WorkoutUpcomingSteps } from "./types";
@@ -38,6 +38,7 @@ export declare class WorkoutRidePageService extends IncyclistPageService impleme
38
38
  }): void;
39
39
  onCancelStart(): void;
40
40
  adjustLoad(deltaPct: number): PowerAdjustmentResult | undefined;
41
+ getLoadButtonMode(): LoadButtonMode;
41
42
  protected onRideStateUpdate(state: CurrentRideState): void;
42
43
  protected onWorkoutUpdate(): void;
43
44
  protected onFinished(): void;
@@ -2,6 +2,7 @@ import type { IObserver } from "../../../base/typedefs";
2
2
  import type { IPageService } from "../../../base/pages";
3
3
  import type { RideMenuProps, RidePageDisplayProps } from "../../../ride/page/types";
4
4
  import type { WorkoutGraphPlanBar } from "../../base/graph/types";
5
+ import type { LoadButtonMode } from "../types";
5
6
  export interface WorkoutGraphPoint {
6
7
  x: number;
7
8
  y: number;
@@ -52,6 +53,7 @@ export interface WorkoutRidePageDisplayProps extends RidePageDisplayProps {
52
53
  title: string;
53
54
  gestureHint: WorkoutGestureHint | null;
54
55
  loadIncrement: number;
56
+ loadButtonMode: LoadButtonMode;
55
57
  }
56
58
  export interface WorkoutRidePageCallbacks {
57
59
  onMenuOpen(): void;
@@ -76,4 +78,5 @@ export interface IWorkoutRidePageService extends WorkoutRidePageCallbacks, IPage
76
78
  getPageDisplayProps(): WorkoutRidePageDisplayProps;
77
79
  getGraphActuals(): WorkoutGraphActuals;
78
80
  adjustLoad(deltaPct: number): void;
81
+ getLoadButtonMode(): LoadButtonMode;
79
82
  }
@@ -1,10 +1,11 @@
1
1
  import { IncyclistService } from "../../base/service";
2
2
  import { Observer } from "../../base/types/observer";
3
+ import { DeviceRideService } from "../../devices";
3
4
  import { Workout } from "../base/model";
4
5
  import { CurrentStep, PowerLimit, StepDefinition } from "../base/model/types";
5
6
  import { WorkoutListService } from "../list";
6
7
  import { WorkoutSettings } from "../list/cards/types";
7
- import { ActiveWorkoutLimit, PowerAdjustmentResult, WorkoutDisplayProperties } from "./types";
8
+ import { ActiveWorkoutLimit, LoadButtonMode, PowerAdjustmentResult, WorkoutDisplayProperties } from "./types";
8
9
  export declare class WorkoutRide extends IncyclistService {
9
10
  protected manualTimeOffset: number;
10
11
  protected manualPowerOffset: number;
@@ -33,8 +34,15 @@ export declare class WorkoutRide extends IncyclistService {
33
34
  }): void;
34
35
  forward(): void;
35
36
  backward(): void;
37
+ private isPowerRangeAdjustable;
38
+ private getPowerRangeDeltaVal;
39
+ private getPowerRangeAdjustmentWatts;
40
+ getLoadButtonMode(): LoadButtonMode;
41
+ private getGearButtonLabels;
42
+ private getLoadButtonLabels;
36
43
  powerUp(delta: number): PowerAdjustmentResult | undefined;
37
44
  powerDown(delta: number): PowerAdjustmentResult | undefined;
45
+ private gearChange;
38
46
  toggleCyclingMode(): void;
39
47
  getDashboardDisplayProperties(): WorkoutDisplayProperties;
40
48
  getCurrentLimits(): ActiveWorkoutLimit;
@@ -66,6 +74,7 @@ export declare class WorkoutRide extends IncyclistService {
66
74
  protected getCyclingModeText(): string;
67
75
  protected getUserSettings(): import("../../settings").UserSettingsService;
68
76
  protected getWorkoutList(): WorkoutListService;
77
+ protected getDeviceRide(): DeviceRideService;
69
78
  }
70
79
  export declare const useWorkoutRide: () => WorkoutRide;
71
80
  export declare const getWorkoutRide: () => WorkoutRide;
@@ -1,5 +1,7 @@
1
1
  import { Workout } from "../base/model";
2
2
  import { StepDefinition } from "../base/model/types";
3
+ import { LoadButtonMode } from "../../devices";
4
+ export type { LoadButtonMode };
3
5
  export interface WorkoutRequest {
4
6
  time: number;
5
7
  minPower?: number;
@@ -16,7 +18,7 @@ export interface ActiveWorkoutLimit extends WorkoutRequest {
16
18
  step?: StepDefinition;
17
19
  }
18
20
  export interface PowerAdjustmentResult {
19
- type: 'ftp' | 'targetPower';
21
+ type: 'ftp' | 'targetPower' | 'gear';
20
22
  value: number;
21
23
  }
22
24
  export interface WorkoutDisplayProperties {
@@ -29,4 +31,11 @@ export interface WorkoutDisplayProperties {
29
31
  mode?: string;
30
32
  canShowBackward?: boolean;
31
33
  canShowForward?: boolean;
34
+ loadButtonMode?: LoadButtonMode;
35
+ loadButtons?: {
36
+ inc5: string;
37
+ inc1: string;
38
+ dec1: string;
39
+ dec5: string;
40
+ };
32
41
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "incyclist-services",
3
- "version": "1.7.94",
3
+ "version": "1.7.95",
4
4
  "peerDependencies": {
5
5
  "gd-eventlog": "^0.1.27"
6
6
  },