incyclist-services 1.7.6 → 1.7.8

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.
@@ -286,7 +286,6 @@ let ActiveRidesService = (() => {
286
286
  const logInfo = all.map(r => `${r?.name}${r?.isUser ? '(*)' : ''}:${r?.avatar?.shirt ?? ''}-${distanceText(r)}-${r?.lap ?? ''}-${r?.power ?? '?'}W`)
287
287
  .join('|');
288
288
  const cnt = (this.others?.length ?? 0) + 1;
289
- console.log('# nearby riders log', logInfo, all);
290
289
  const event = { message: 'NearbyRiders', activityId: this.activity?.id, title: this.activity?.route?.title, cnt, nearbyRiders: logInfo };
291
290
  this.logEvent(event);
292
291
  this.prevLogTS = Date.now();
@@ -477,10 +476,15 @@ let ActiveRidesService = (() => {
477
476
  const format = (v) => {
478
477
  const [C, U] = this.getUnitConversionShortcuts();
479
478
  let value = C(v, 'distance', { digits: 1 });
480
- const unit = U('distance');
479
+ let unit = U('distance');
481
480
  if (value >= 10) {
482
481
  value = Math.round(value);
483
482
  }
483
+ if (value === 0) {
484
+ const units = this.getUnitConverter().getUnits();
485
+ unit = units === 'imperial' ? 'yd' : 'm';
486
+ C(v, 'distance', { digits: 0, to: unit });
487
+ }
484
488
  return { value, unit };
485
489
  };
486
490
  const isLap = this.current?.ride?.isLap;
@@ -802,20 +806,12 @@ let ActiveRidesService = (() => {
802
806
  return;
803
807
  }
804
808
  this.coaches = coaches.map(c => {
805
- const props = c.getDisplayProperties();
806
- const rideEntry = {
807
- id: `coach:${props.name}`,
808
- user: {
809
- name: props.name,
810
- id: `coach:${props.name}`,
811
- },
809
+ const props = c.getRidersListDisplayProperties();
810
+ let routeDistance = props.currentRideDistance;
811
+ const entry = { ...props,
812
812
  ride: this.current?.ride,
813
- tsLastUpdate: Date.now(),
814
- currentRideDistance: c.getProgess(),
815
- currentPosition: c.getPosition(),
816
- isCoach: true
817
813
  };
818
- return rideEntry;
814
+ return entry;
819
815
  });
820
816
  }
821
817
  catch (err) {
@@ -27,7 +27,7 @@ exports.createUIActivitySummary = createUIActivitySummary;
27
27
  const createUIActivityDetails = (details) => {
28
28
  if (!details)
29
29
  return details;
30
- const ui = { ...details };
30
+ const ui = structuredClone(details);
31
31
  const [C, U] = (0, i18n_1.getUnitConversionShortcuts)();
32
32
  ui.distance = { value: C(details.distance, 'distance', { digits: 1 }), unit: U('distance') };
33
33
  if (ui.distance.value > 100)
@@ -4,6 +4,7 @@ exports.Coach = void 0;
4
4
  const gd_eventlog_1 = require("gd-eventlog");
5
5
  const incyclist_devices_1 = require("incyclist-devices");
6
6
  const i18n_1 = require("../i18n");
7
+ const routes_1 = require("../routes");
7
8
  class Coach {
8
9
  _settings;
9
10
  _id;
@@ -12,6 +13,7 @@ class Coach {
12
13
  simulator;
13
14
  logger;
14
15
  position;
16
+ route;
15
17
  constructor(settings) {
16
18
  this._settings = settings;
17
19
  this._id = Date.now().toString();
@@ -29,8 +31,23 @@ class Coach {
29
31
  return 0;
30
32
  return lead;
31
33
  }
34
+ setRoute(route) {
35
+ this.route = route;
36
+ }
32
37
  setProgress(routeDistance) {
33
- this.routeDistance = routeDistance;
38
+ try {
39
+ this.routeDistance = routeDistance;
40
+ if (!this.route?.details?.points)
41
+ return;
42
+ const isLap = this.route?.description?.isLoop;
43
+ const totalDistance = this.route?.description?.distance;
44
+ const lapDistance = isLap ? this.routeDistance % totalDistance : this.routeDistance;
45
+ const position = (0, routes_1.getPointAtDistance)(this.route, lapDistance, true);
46
+ this.setPosition(position);
47
+ }
48
+ catch (err) {
49
+ this.logger.logEvent({ message: 'error', fn: 'setProgress', error: err.message, stack: err.stack });
50
+ }
34
51
  }
35
52
  getProgess() {
36
53
  return this.routeDistance;
@@ -68,6 +85,20 @@ class Coach {
68
85
  };
69
86
  return props;
70
87
  }
88
+ getRidersListDisplayProperties() {
89
+ const { name } = this.settings;
90
+ return {
91
+ id: `coach:${name}`,
92
+ user: {
93
+ name: name,
94
+ id: `coach:${name}`,
95
+ },
96
+ tsLastUpdate: Date.now(),
97
+ currentRideDistance: this.getProgess(),
98
+ currentPosition: this.getPosition(),
99
+ isCoach: true
100
+ };
101
+ }
71
102
  update(settings) {
72
103
  const { name, power, speed: speedEdit, lead: leadEdit } = settings;
73
104
  const getValue = (v, d) => {
@@ -122,6 +153,7 @@ class Coach {
122
153
  return;
123
154
  this.simulator.stop();
124
155
  this.routeDistance = undefined;
156
+ this.route = undefined;
125
157
  }
126
158
  getUnitConversionShortcuts() {
127
159
  return (0, i18n_1.useUnitConverter)().getUnitConversionShortcuts();
@@ -76,6 +76,7 @@ let CoachesService = (() => {
76
76
  coaches = (__runInitializers(this, _instanceExtraInitializers), []);
77
77
  observer;
78
78
  isPaused;
79
+ route;
79
80
  constructor() {
80
81
  super('Coaches');
81
82
  this.isPaused = false;
@@ -114,15 +115,18 @@ let CoachesService = (() => {
114
115
  this.logError(err, 'deleteCoach');
115
116
  }
116
117
  }
117
- async startRide() {
118
+ async startRide(route) {
118
119
  try {
119
120
  if (this.observer) {
120
121
  await this.stopRide();
121
122
  }
122
- if (!this.coaches)
123
+ if (!this.coaches?.length) {
124
+ delete this.observer;
123
125
  return null;
126
+ }
124
127
  this.observer = new observer_1.Observer();
125
128
  this.isPaused = false;
129
+ this.route = route;
126
130
  const onDataUpdate = this.onCoachDataUpdate.bind(this);
127
131
  this.coaches.forEach(c => {
128
132
  const startSettings = this.routesService.getStartSettings();
@@ -131,6 +135,7 @@ let CoachesService = (() => {
131
135
  pos = startSettings.startPos;
132
136
  }
133
137
  const lead = (isNaN(c.settings?.lead) ? 0 : c.settings?.lead) ?? 0;
138
+ c.setRoute(route);
134
139
  c.setProgress(lead + pos);
135
140
  c.setRiderPosition(pos);
136
141
  this.setCoachPosition(c, lead + pos);
@@ -152,7 +157,15 @@ let CoachesService = (() => {
152
157
  }
153
158
  return this.observer;
154
159
  }
160
+ updateRoute(route) {
161
+ this.route = route;
162
+ if (this.observer) {
163
+ this.coaches.forEach(c => { c.setRoute(route); });
164
+ }
165
+ }
155
166
  async stopRide() {
167
+ if (!this.observer)
168
+ return;
156
169
  try {
157
170
  this.coaches.forEach(c => { c.stop(); });
158
171
  this.isPaused = false;
@@ -163,6 +176,8 @@ let CoachesService = (() => {
163
176
  }
164
177
  }
165
178
  pauseRide() {
179
+ if (!this.observer)
180
+ return;
166
181
  try {
167
182
  this.isPaused = true;
168
183
  }
@@ -171,6 +186,8 @@ let CoachesService = (() => {
171
186
  }
172
187
  }
173
188
  resumeRide() {
189
+ if (!this.observer)
190
+ return;
174
191
  try {
175
192
  this.isPaused = false;
176
193
  }
@@ -197,10 +214,10 @@ let CoachesService = (() => {
197
214
  return;
198
215
  const startSettings = this.routesService.getStartSettings();
199
216
  const { distance } = data;
200
- const route = this.getRideDisplay().route;
217
+ const route = this.route;
201
218
  if (!route || !coach || !data)
202
219
  return;
203
- const prevRouteDistance = coach.getProgess();
220
+ const prevRouteDistance = coach.getProgess() ?? 0;
204
221
  const newRouteDistance = prevRouteDistance + data.distance;
205
222
  coach.setProgress(newRouteDistance);
206
223
  if (startSettings.type === 'Free-Ride')
@@ -735,7 +735,7 @@ let DeviceRideService = (() => {
735
735
  const adapters = this.rideAdapters?.filter(ai => ai.adapter.getInterface() === ifName);
736
736
  const stillHealthy = adapters.filter(ai => ai.isHealthy === undefined || ai.isHealthy);
737
737
  this.logEvent({ message: 'reconnect confirmed', device: unhealthy.adapter.getUniqueName(), udid: unhealthy.udid, noDataSince: (Date.now() - unhealthy.tsLastData), tsLastData: unhealthy.tsLastData, stillHealthy: stillHealthy?.length, onSameInterface: adapters.length });
738
- if (!stillHealthy?.length && adapters.length > 1) {
738
+ if (!stillHealthy?.length && adapters.length > 1 && ifName !== 'ble') {
739
739
  await this.reconnectInterface(ifName, adapters);
740
740
  }
741
741
  else {
@@ -51,6 +51,7 @@ const FollowRouteDisplayService_1 = require("../route/FollowRouteDisplayService"
51
51
  const WorkoutDisplayService_1 = require("../workout/WorkoutDisplayService");
52
52
  const api_1 = require("../../api");
53
53
  const RLVDisplayService_1 = require("../route/RLVDisplayService");
54
+ const coaches_1 = require("../../coaches");
54
55
  let RideDisplayService = (() => {
55
56
  let _classDecorators = [types_1.Singleton];
56
57
  let _classDescriptor;
@@ -66,6 +67,7 @@ let RideDisplayService = (() => {
66
67
  let _getUserSettings_decorators;
67
68
  let _getDeviceConfiguration_decorators;
68
69
  let _getUIBinding_decorators;
70
+ let _getCoaches_decorators;
69
71
  var RideDisplayService = class extends _classSuper {
70
72
  static { _classThis = this; }
71
73
  static {
@@ -78,6 +80,7 @@ let RideDisplayService = (() => {
78
80
  _getUserSettings_decorators = [decorators_1.Injectable];
79
81
  _getDeviceConfiguration_decorators = [decorators_1.Injectable];
80
82
  _getUIBinding_decorators = [decorators_1.Injectable];
83
+ _getCoaches_decorators = [decorators_1.Injectable];
81
84
  __esDecorate(this, null, _getActivityRide_decorators, { kind: "method", name: "getActivityRide", static: false, private: false, access: { has: obj => "getActivityRide" in obj, get: obj => obj.getActivityRide }, metadata: _metadata }, null, _instanceExtraInitializers);
82
85
  __esDecorate(this, null, _getWorkoutRide_decorators, { kind: "method", name: "getWorkoutRide", static: false, private: false, access: { has: obj => "getWorkoutRide" in obj, get: obj => obj.getWorkoutRide }, metadata: _metadata }, null, _instanceExtraInitializers);
83
86
  __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);
@@ -86,6 +89,7 @@ let RideDisplayService = (() => {
86
89
  __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);
87
90
  __esDecorate(this, null, _getDeviceConfiguration_decorators, { kind: "method", name: "getDeviceConfiguration", static: false, private: false, access: { has: obj => "getDeviceConfiguration" in obj, get: obj => obj.getDeviceConfiguration }, metadata: _metadata }, null, _instanceExtraInitializers);
88
91
  __esDecorate(this, null, _getUIBinding_decorators, { kind: "method", name: "getUIBinding", static: false, private: false, access: { has: obj => "getUIBinding" in obj, get: obj => obj.getUIBinding }, metadata: _metadata }, null, _instanceExtraInitializers);
92
+ __esDecorate(this, null, _getCoaches_decorators, { kind: "method", name: "getCoaches", static: false, private: false, access: { has: obj => "getCoaches" in obj, get: obj => obj.getCoaches }, metadata: _metadata }, null, _instanceExtraInitializers);
89
93
  __esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
90
94
  RideDisplayService = _classThis = _classDescriptor.value;
91
95
  if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
@@ -140,6 +144,7 @@ let RideDisplayService = (() => {
140
144
  }
141
145
  this.startDevices();
142
146
  this.startRide();
147
+ this.getCoaches().startRide(this.route);
143
148
  this.setState('Starting');
144
149
  this.logEvent({ message: 'overlay shown', overlay: 'start overlay' });
145
150
  }
@@ -191,6 +196,7 @@ let RideDisplayService = (() => {
191
196
  return;
192
197
  this.logEvent({ message: "pause activity request", activity: this.activity?.id, userRequested: requester === 'user' });
193
198
  this.state = 'Paused';
199
+ this.getCoaches().pauseRide();
194
200
  if (requester === 'user') {
195
201
  this.getActivityRide().pause(false);
196
202
  }
@@ -210,6 +216,7 @@ let RideDisplayService = (() => {
210
216
  this.logEvent({ message: "continue activity request", activity: this.activity?.id, userRequested: requester === 'user' });
211
217
  this.isResuming = true;
212
218
  this.state = 'Active';
219
+ this.getCoaches().resumeRide();
213
220
  if (requester === 'user') {
214
221
  this.getActivityRide().resume('user');
215
222
  }
@@ -251,6 +258,7 @@ let RideDisplayService = (() => {
251
258
  }
252
259
  await this.stopRide({ exit, noStateUpdates: true });
253
260
  this.getActivityRide().cleanup();
261
+ this.getCoaches().stopRide();
254
262
  delete this.type;
255
263
  }
256
264
  toggleCyclingMode() {
@@ -533,7 +541,7 @@ let RideDisplayService = (() => {
533
541
  return;
534
542
  this.resume('device');
535
543
  }
536
- onActivityUpdate(data) {
544
+ onActivityUpdate() {
537
545
  if (this.state === 'Active') {
538
546
  const currentValues = this.getActivityRide().getCurrentValues();
539
547
  if (!currentValues)
@@ -543,6 +551,8 @@ let RideDisplayService = (() => {
543
551
  this.isResuming = false;
544
552
  delete this.pauseReason;
545
553
  }
554
+ const { time, speed, routeDistance, distance } = currentValues;
555
+ const data = { time, speed, routeDistance, distance };
546
556
  this.getRideModeService().onActivityUpdate(data, currentValues);
547
557
  this.observer.emit('data-update', data, currentValues);
548
558
  }
@@ -1004,9 +1014,9 @@ let RideDisplayService = (() => {
1004
1014
  getStartOverlayProps = () => {
1005
1015
  const mode = this.getRideType();
1006
1016
  const readyToStart = this.isStartDeviceReadyToStart() && this.getRideModeService().isStartRideCompleted();
1007
- const devices = this.deviceInfo ?? [];
1017
+ const devicesState = this.deviceInfo ?? [];
1008
1018
  const displayOverlayProps = this.getRideModeService().getStartOverlayProps() ?? {};
1009
- return { mode, rideState: this.state, devices, readyToStart, ...displayOverlayProps };
1019
+ return { mode, rideState: this.state, devicesState, readyToStart, ...displayOverlayProps };
1010
1020
  };
1011
1021
  getDeviceStartSettings() {
1012
1022
  let forceErgMode = false;
@@ -1091,6 +1101,9 @@ let RideDisplayService = (() => {
1091
1101
  getUIBinding() {
1092
1102
  return (0, api_1.getBindings)().ui;
1093
1103
  }
1104
+ getCoaches() {
1105
+ return (0, coaches_1.getCoachesService)();
1106
+ }
1094
1107
  };
1095
1108
  return RideDisplayService = _classThis;
1096
1109
  })();
@@ -37,6 +37,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
37
37
  exports.RLVDisplayService = void 0;
38
38
  const decorators_1 = require("../../base/decorators");
39
39
  const types_1 = require("../../base/types");
40
+ const coaches_1 = require("../../coaches");
40
41
  const i18n_1 = require("../../i18n");
41
42
  const utils_1 = require("../../maps/MapArea/utils");
42
43
  const routes_1 = require("../../routes");
@@ -48,13 +49,16 @@ let RLVDisplayService = (() => {
48
49
  let _instanceExtraInitializers = [];
49
50
  let _getRouteList_decorators;
50
51
  let _getLocalization_decorators;
52
+ let _getCoaches_decorators;
51
53
  return class RLVDisplayService extends _classSuper {
52
54
  static {
53
55
  const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
54
56
  _getRouteList_decorators = [decorators_1.Injectable];
55
57
  _getLocalization_decorators = [decorators_1.Injectable];
58
+ _getCoaches_decorators = [decorators_1.Injectable];
56
59
  __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);
57
60
  __esDecorate(this, null, _getLocalization_decorators, { kind: "method", name: "getLocalization", static: false, private: false, access: { has: obj => "getLocalization" in obj, get: obj => obj.getLocalization }, metadata: _metadata }, null, _instanceExtraInitializers);
61
+ __esDecorate(this, null, _getCoaches_decorators, { kind: "method", name: "getCoaches", static: false, private: false, access: { has: obj => "getCoaches" in obj, get: obj => obj.getCoaches }, metadata: _metadata }, null, _instanceExtraInitializers);
58
62
  if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
59
63
  }
60
64
  currentVideo = __runInitializers(this, _instanceExtraInitializers);
@@ -255,6 +259,7 @@ let RLVDisplayService = (() => {
255
259
  (0, utils_1.concatPaths)(currentPoints, nextPoints, 'after');
256
260
  (0, routes_1.validateRoute)(this.getCurrentRoute(), false);
257
261
  this.emit('route-updated', this.getCurrentRoute());
262
+ this.getCoaches().updateRoute(this.getCurrentRoute());
258
263
  this.logEvent({ message: 'switching to next video', route: this.getCurrentRoute().details.title,
259
264
  segment: this.currentVideo.route.description.title, offset: this.offset, segmentDistance: this.currentVideo.route.description.distance,
260
265
  totalDistance: this.getCurrentRoute().details.distance });
@@ -561,6 +566,9 @@ let RLVDisplayService = (() => {
561
566
  getLocalization() {
562
567
  return (0, i18n_1.useLocalization)();
563
568
  }
569
+ getCoaches() {
570
+ return (0, coaches_1.getCoachesService)();
571
+ }
564
572
  };
565
573
  })();
566
574
  exports.RLVDisplayService = RLVDisplayService;
@@ -283,7 +283,6 @@ let ActiveRidesService = (() => {
283
283
  const logInfo = all.map(r => `${r?.name}${r?.isUser ? '(*)' : ''}:${r?.avatar?.shirt ?? ''}-${distanceText(r)}-${r?.lap ?? ''}-${r?.power ?? '?'}W`)
284
284
  .join('|');
285
285
  const cnt = (this.others?.length ?? 0) + 1;
286
- console.log('# nearby riders log', logInfo, all);
287
286
  const event = { message: 'NearbyRiders', activityId: this.activity?.id, title: this.activity?.route?.title, cnt, nearbyRiders: logInfo };
288
287
  this.logEvent(event);
289
288
  this.prevLogTS = Date.now();
@@ -474,10 +473,15 @@ let ActiveRidesService = (() => {
474
473
  const format = (v) => {
475
474
  const [C, U] = this.getUnitConversionShortcuts();
476
475
  let value = C(v, 'distance', { digits: 1 });
477
- const unit = U('distance');
476
+ let unit = U('distance');
478
477
  if (value >= 10) {
479
478
  value = Math.round(value);
480
479
  }
480
+ if (value === 0) {
481
+ const units = this.getUnitConverter().getUnits();
482
+ unit = units === 'imperial' ? 'yd' : 'm';
483
+ C(v, 'distance', { digits: 0, to: unit });
484
+ }
481
485
  return { value, unit };
482
486
  };
483
487
  const isLap = this.current?.ride?.isLap;
@@ -799,20 +803,12 @@ let ActiveRidesService = (() => {
799
803
  return;
800
804
  }
801
805
  this.coaches = coaches.map(c => {
802
- const props = c.getDisplayProperties();
803
- const rideEntry = {
804
- id: `coach:${props.name}`,
805
- user: {
806
- name: props.name,
807
- id: `coach:${props.name}`,
808
- },
806
+ const props = c.getRidersListDisplayProperties();
807
+ let routeDistance = props.currentRideDistance;
808
+ const entry = { ...props,
809
809
  ride: this.current?.ride,
810
- tsLastUpdate: Date.now(),
811
- currentRideDistance: c.getProgess(),
812
- currentPosition: c.getPosition(),
813
- isCoach: true
814
810
  };
815
- return rideEntry;
811
+ return entry;
816
812
  });
817
813
  }
818
814
  catch (err) {
@@ -22,7 +22,7 @@ export const createUIActivitySummary = (summary) => {
22
22
  export const createUIActivityDetails = (details) => {
23
23
  if (!details)
24
24
  return details;
25
- const ui = { ...details };
25
+ const ui = structuredClone(details);
26
26
  const [C, U] = getUnitConversionShortcuts();
27
27
  ui.distance = { value: C(details.distance, 'distance', { digits: 1 }), unit: U('distance') };
28
28
  if (ui.distance.value > 100)
@@ -1,6 +1,7 @@
1
1
  import { EventLogger } from "gd-eventlog";
2
2
  import { AdapterFactory, INTERFACE } from 'incyclist-devices';
3
3
  import { useUnitConverter } from "../i18n";
4
+ import { getPointAtDistance } from "../routes";
4
5
  export class Coach {
5
6
  _settings;
6
7
  _id;
@@ -9,6 +10,7 @@ export class Coach {
9
10
  simulator;
10
11
  logger;
11
12
  position;
13
+ route;
12
14
  constructor(settings) {
13
15
  this._settings = settings;
14
16
  this._id = Date.now().toString();
@@ -26,8 +28,23 @@ export class Coach {
26
28
  return 0;
27
29
  return lead;
28
30
  }
31
+ setRoute(route) {
32
+ this.route = route;
33
+ }
29
34
  setProgress(routeDistance) {
30
- this.routeDistance = routeDistance;
35
+ try {
36
+ this.routeDistance = routeDistance;
37
+ if (!this.route?.details?.points)
38
+ return;
39
+ const isLap = this.route?.description?.isLoop;
40
+ const totalDistance = this.route?.description?.distance;
41
+ const lapDistance = isLap ? this.routeDistance % totalDistance : this.routeDistance;
42
+ const position = getPointAtDistance(this.route, lapDistance, true);
43
+ this.setPosition(position);
44
+ }
45
+ catch (err) {
46
+ this.logger.logEvent({ message: 'error', fn: 'setProgress', error: err.message, stack: err.stack });
47
+ }
31
48
  }
32
49
  getProgess() {
33
50
  return this.routeDistance;
@@ -65,6 +82,20 @@ export class Coach {
65
82
  };
66
83
  return props;
67
84
  }
85
+ getRidersListDisplayProperties() {
86
+ const { name } = this.settings;
87
+ return {
88
+ id: `coach:${name}`,
89
+ user: {
90
+ name: name,
91
+ id: `coach:${name}`,
92
+ },
93
+ tsLastUpdate: Date.now(),
94
+ currentRideDistance: this.getProgess(),
95
+ currentPosition: this.getPosition(),
96
+ isCoach: true
97
+ };
98
+ }
68
99
  update(settings) {
69
100
  const { name, power, speed: speedEdit, lead: leadEdit } = settings;
70
101
  const getValue = (v, d) => {
@@ -119,6 +150,7 @@ export class Coach {
119
150
  return;
120
151
  this.simulator.stop();
121
152
  this.routeDistance = undefined;
153
+ this.route = undefined;
122
154
  }
123
155
  getUnitConversionShortcuts() {
124
156
  return useUnitConverter().getUnitConversionShortcuts();
@@ -73,6 +73,7 @@ let CoachesService = (() => {
73
73
  coaches = (__runInitializers(this, _instanceExtraInitializers), []);
74
74
  observer;
75
75
  isPaused;
76
+ route;
76
77
  constructor() {
77
78
  super('Coaches');
78
79
  this.isPaused = false;
@@ -111,15 +112,18 @@ let CoachesService = (() => {
111
112
  this.logError(err, 'deleteCoach');
112
113
  }
113
114
  }
114
- async startRide() {
115
+ async startRide(route) {
115
116
  try {
116
117
  if (this.observer) {
117
118
  await this.stopRide();
118
119
  }
119
- if (!this.coaches)
120
+ if (!this.coaches?.length) {
121
+ delete this.observer;
120
122
  return null;
123
+ }
121
124
  this.observer = new Observer();
122
125
  this.isPaused = false;
126
+ this.route = route;
123
127
  const onDataUpdate = this.onCoachDataUpdate.bind(this);
124
128
  this.coaches.forEach(c => {
125
129
  const startSettings = this.routesService.getStartSettings();
@@ -128,6 +132,7 @@ let CoachesService = (() => {
128
132
  pos = startSettings.startPos;
129
133
  }
130
134
  const lead = (isNaN(c.settings?.lead) ? 0 : c.settings?.lead) ?? 0;
135
+ c.setRoute(route);
131
136
  c.setProgress(lead + pos);
132
137
  c.setRiderPosition(pos);
133
138
  this.setCoachPosition(c, lead + pos);
@@ -149,7 +154,15 @@ let CoachesService = (() => {
149
154
  }
150
155
  return this.observer;
151
156
  }
157
+ updateRoute(route) {
158
+ this.route = route;
159
+ if (this.observer) {
160
+ this.coaches.forEach(c => { c.setRoute(route); });
161
+ }
162
+ }
152
163
  async stopRide() {
164
+ if (!this.observer)
165
+ return;
153
166
  try {
154
167
  this.coaches.forEach(c => { c.stop(); });
155
168
  this.isPaused = false;
@@ -160,6 +173,8 @@ let CoachesService = (() => {
160
173
  }
161
174
  }
162
175
  pauseRide() {
176
+ if (!this.observer)
177
+ return;
163
178
  try {
164
179
  this.isPaused = true;
165
180
  }
@@ -168,6 +183,8 @@ let CoachesService = (() => {
168
183
  }
169
184
  }
170
185
  resumeRide() {
186
+ if (!this.observer)
187
+ return;
171
188
  try {
172
189
  this.isPaused = false;
173
190
  }
@@ -194,10 +211,10 @@ let CoachesService = (() => {
194
211
  return;
195
212
  const startSettings = this.routesService.getStartSettings();
196
213
  const { distance } = data;
197
- const route = this.getRideDisplay().route;
214
+ const route = this.route;
198
215
  if (!route || !coach || !data)
199
216
  return;
200
- const prevRouteDistance = coach.getProgess();
217
+ const prevRouteDistance = coach.getProgess() ?? 0;
201
218
  const newRouteDistance = prevRouteDistance + data.distance;
202
219
  coach.setProgress(newRouteDistance);
203
220
  if (startSettings.type === 'Free-Ride')
@@ -729,7 +729,7 @@ let DeviceRideService = (() => {
729
729
  const adapters = this.rideAdapters?.filter(ai => ai.adapter.getInterface() === ifName);
730
730
  const stillHealthy = adapters.filter(ai => ai.isHealthy === undefined || ai.isHealthy);
731
731
  this.logEvent({ message: 'reconnect confirmed', device: unhealthy.adapter.getUniqueName(), udid: unhealthy.udid, noDataSince: (Date.now() - unhealthy.tsLastData), tsLastData: unhealthy.tsLastData, stillHealthy: stillHealthy?.length, onSameInterface: adapters.length });
732
- if (!stillHealthy?.length && adapters.length > 1) {
732
+ if (!stillHealthy?.length && adapters.length > 1 && ifName !== 'ble') {
733
733
  await this.reconnectInterface(ifName, adapters);
734
734
  }
735
735
  else {
@@ -48,6 +48,7 @@ import { FollowRouteDisplayService } from "../route/FollowRouteDisplayService";
48
48
  import { WorkoutDisplayService } from "../workout/WorkoutDisplayService";
49
49
  import { getBindings } from "../../api";
50
50
  import { RLVDisplayService } from "../route/RLVDisplayService";
51
+ import { getCoachesService } from "../../coaches";
51
52
  let RideDisplayService = (() => {
52
53
  let _classDecorators = [Singleton];
53
54
  let _classDescriptor;
@@ -63,6 +64,7 @@ let RideDisplayService = (() => {
63
64
  let _getUserSettings_decorators;
64
65
  let _getDeviceConfiguration_decorators;
65
66
  let _getUIBinding_decorators;
67
+ let _getCoaches_decorators;
66
68
  var RideDisplayService = class extends _classSuper {
67
69
  static { _classThis = this; }
68
70
  static {
@@ -75,6 +77,7 @@ let RideDisplayService = (() => {
75
77
  _getUserSettings_decorators = [Injectable];
76
78
  _getDeviceConfiguration_decorators = [Injectable];
77
79
  _getUIBinding_decorators = [Injectable];
80
+ _getCoaches_decorators = [Injectable];
78
81
  __esDecorate(this, null, _getActivityRide_decorators, { kind: "method", name: "getActivityRide", static: false, private: false, access: { has: obj => "getActivityRide" in obj, get: obj => obj.getActivityRide }, metadata: _metadata }, null, _instanceExtraInitializers);
79
82
  __esDecorate(this, null, _getWorkoutRide_decorators, { kind: "method", name: "getWorkoutRide", static: false, private: false, access: { has: obj => "getWorkoutRide" in obj, get: obj => obj.getWorkoutRide }, metadata: _metadata }, null, _instanceExtraInitializers);
80
83
  __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);
@@ -83,6 +86,7 @@ let RideDisplayService = (() => {
83
86
  __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);
84
87
  __esDecorate(this, null, _getDeviceConfiguration_decorators, { kind: "method", name: "getDeviceConfiguration", static: false, private: false, access: { has: obj => "getDeviceConfiguration" in obj, get: obj => obj.getDeviceConfiguration }, metadata: _metadata }, null, _instanceExtraInitializers);
85
88
  __esDecorate(this, null, _getUIBinding_decorators, { kind: "method", name: "getUIBinding", static: false, private: false, access: { has: obj => "getUIBinding" in obj, get: obj => obj.getUIBinding }, metadata: _metadata }, null, _instanceExtraInitializers);
89
+ __esDecorate(this, null, _getCoaches_decorators, { kind: "method", name: "getCoaches", static: false, private: false, access: { has: obj => "getCoaches" in obj, get: obj => obj.getCoaches }, metadata: _metadata }, null, _instanceExtraInitializers);
86
90
  __esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
87
91
  RideDisplayService = _classThis = _classDescriptor.value;
88
92
  if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
@@ -137,6 +141,7 @@ let RideDisplayService = (() => {
137
141
  }
138
142
  this.startDevices();
139
143
  this.startRide();
144
+ this.getCoaches().startRide(this.route);
140
145
  this.setState('Starting');
141
146
  this.logEvent({ message: 'overlay shown', overlay: 'start overlay' });
142
147
  }
@@ -188,6 +193,7 @@ let RideDisplayService = (() => {
188
193
  return;
189
194
  this.logEvent({ message: "pause activity request", activity: this.activity?.id, userRequested: requester === 'user' });
190
195
  this.state = 'Paused';
196
+ this.getCoaches().pauseRide();
191
197
  if (requester === 'user') {
192
198
  this.getActivityRide().pause(false);
193
199
  }
@@ -207,6 +213,7 @@ let RideDisplayService = (() => {
207
213
  this.logEvent({ message: "continue activity request", activity: this.activity?.id, userRequested: requester === 'user' });
208
214
  this.isResuming = true;
209
215
  this.state = 'Active';
216
+ this.getCoaches().resumeRide();
210
217
  if (requester === 'user') {
211
218
  this.getActivityRide().resume('user');
212
219
  }
@@ -248,6 +255,7 @@ let RideDisplayService = (() => {
248
255
  }
249
256
  await this.stopRide({ exit, noStateUpdates: true });
250
257
  this.getActivityRide().cleanup();
258
+ this.getCoaches().stopRide();
251
259
  delete this.type;
252
260
  }
253
261
  toggleCyclingMode() {
@@ -530,7 +538,7 @@ let RideDisplayService = (() => {
530
538
  return;
531
539
  this.resume('device');
532
540
  }
533
- onActivityUpdate(data) {
541
+ onActivityUpdate() {
534
542
  if (this.state === 'Active') {
535
543
  const currentValues = this.getActivityRide().getCurrentValues();
536
544
  if (!currentValues)
@@ -540,6 +548,8 @@ let RideDisplayService = (() => {
540
548
  this.isResuming = false;
541
549
  delete this.pauseReason;
542
550
  }
551
+ const { time, speed, routeDistance, distance } = currentValues;
552
+ const data = { time, speed, routeDistance, distance };
543
553
  this.getRideModeService().onActivityUpdate(data, currentValues);
544
554
  this.observer.emit('data-update', data, currentValues);
545
555
  }
@@ -1001,9 +1011,9 @@ let RideDisplayService = (() => {
1001
1011
  getStartOverlayProps = () => {
1002
1012
  const mode = this.getRideType();
1003
1013
  const readyToStart = this.isStartDeviceReadyToStart() && this.getRideModeService().isStartRideCompleted();
1004
- const devices = this.deviceInfo ?? [];
1014
+ const devicesState = this.deviceInfo ?? [];
1005
1015
  const displayOverlayProps = this.getRideModeService().getStartOverlayProps() ?? {};
1006
- return { mode, rideState: this.state, devices, readyToStart, ...displayOverlayProps };
1016
+ return { mode, rideState: this.state, devicesState, readyToStart, ...displayOverlayProps };
1007
1017
  };
1008
1018
  getDeviceStartSettings() {
1009
1019
  let forceErgMode = false;
@@ -1088,6 +1098,9 @@ let RideDisplayService = (() => {
1088
1098
  getUIBinding() {
1089
1099
  return getBindings().ui;
1090
1100
  }
1101
+ getCoaches() {
1102
+ return getCoachesService();
1103
+ }
1091
1104
  };
1092
1105
  return RideDisplayService = _classThis;
1093
1106
  })();
@@ -34,6 +34,7 @@ var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn,
34
34
  };
35
35
  import { Injectable } from "../../base/decorators";
36
36
  import { Observer } from "../../base/types";
37
+ import { getCoachesService } from "../../coaches";
37
38
  import { useLocalization } from "../../i18n";
38
39
  import { concatPaths } from "../../maps/MapArea/utils";
39
40
  import { correctDistanceValues, getNextVideoId, hasNextVideo, useRouteList, validateRoute } from "../../routes";
@@ -45,13 +46,16 @@ let RLVDisplayService = (() => {
45
46
  let _instanceExtraInitializers = [];
46
47
  let _getRouteList_decorators;
47
48
  let _getLocalization_decorators;
49
+ let _getCoaches_decorators;
48
50
  return class RLVDisplayService extends _classSuper {
49
51
  static {
50
52
  const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
51
53
  _getRouteList_decorators = [Injectable];
52
54
  _getLocalization_decorators = [Injectable];
55
+ _getCoaches_decorators = [Injectable];
53
56
  __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);
54
57
  __esDecorate(this, null, _getLocalization_decorators, { kind: "method", name: "getLocalization", static: false, private: false, access: { has: obj => "getLocalization" in obj, get: obj => obj.getLocalization }, metadata: _metadata }, null, _instanceExtraInitializers);
58
+ __esDecorate(this, null, _getCoaches_decorators, { kind: "method", name: "getCoaches", static: false, private: false, access: { has: obj => "getCoaches" in obj, get: obj => obj.getCoaches }, metadata: _metadata }, null, _instanceExtraInitializers);
55
59
  if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
56
60
  }
57
61
  currentVideo = __runInitializers(this, _instanceExtraInitializers);
@@ -252,6 +256,7 @@ let RLVDisplayService = (() => {
252
256
  concatPaths(currentPoints, nextPoints, 'after');
253
257
  validateRoute(this.getCurrentRoute(), false);
254
258
  this.emit('route-updated', this.getCurrentRoute());
259
+ this.getCoaches().updateRoute(this.getCurrentRoute());
255
260
  this.logEvent({ message: 'switching to next video', route: this.getCurrentRoute().details.title,
256
261
  segment: this.currentVideo.route.description.title, offset: this.offset, segmentDistance: this.currentVideo.route.description.distance,
257
262
  totalDistance: this.getCurrentRoute().details.distance });
@@ -558,6 +563,9 @@ let RLVDisplayService = (() => {
558
563
  getLocalization() {
559
564
  return useLocalization();
560
565
  }
566
+ getCoaches() {
567
+ return getCoachesService();
568
+ }
561
569
  };
562
570
  })();
563
571
  export { RLVDisplayService };
@@ -2,6 +2,8 @@ import { EventLogger } from "gd-eventlog";
2
2
  import { CoachEditProps, CoachSettings } from "./types";
3
3
  import { IncyclistDeviceAdapter } from 'incyclist-devices';
4
4
  import { RoutePoint } from "../routes/base/types";
5
+ import { ActiveRideEntry } from "../activities";
6
+ import { Route } from "../routes/base/model/route";
5
7
  export declare class Coach {
6
8
  protected _settings: CoachSettings;
7
9
  protected _id: string;
@@ -10,10 +12,12 @@ export declare class Coach {
10
12
  protected simulator: IncyclistDeviceAdapter;
11
13
  protected logger: EventLogger;
12
14
  protected position: RoutePoint;
15
+ protected route: Route;
13
16
  constructor(settings: CoachSettings);
14
17
  get id(): string;
15
18
  get settings(): CoachSettings;
16
19
  get lead(): number;
20
+ setRoute(route: Route): void;
17
21
  setProgress(routeDistance: number): void;
18
22
  getProgess(): number;
19
23
  setPosition(point: RoutePoint): void;
@@ -21,6 +25,7 @@ export declare class Coach {
21
25
  setRiderPosition(routeDistance: number): void;
22
26
  sendDeviceUpdate(request: any): void;
23
27
  getDisplayProperties(): CoachEditProps;
28
+ getRidersListDisplayProperties(): Partial<ActiveRideEntry>;
24
29
  update(settings: CoachEditProps): void;
25
30
  initSimulator(user: {
26
31
  weight: number;
@@ -6,16 +6,19 @@ import { UserSettingsService } from "../settings";
6
6
  import { Coach } from "./coach";
7
7
  import { DeviceData } from "incyclist-devices";
8
8
  import { RideDisplayService } from "../ride";
9
+ import { Route } from "../routes/base/model/route";
9
10
  export declare class CoachesService extends IncyclistService {
10
11
  protected coaches: Array<Coach>;
11
12
  protected observer: Observer;
12
13
  protected isPaused: boolean;
14
+ protected route: Route;
13
15
  constructor();
14
16
  getCoaches(): Array<Coach>;
15
17
  openCoachEdit(coach?: Coach): Coach;
16
18
  saveCoach(coach: Coach): void;
17
19
  deleteCoach(coach: Coach): void;
18
- startRide(): Promise<Observer | null>;
20
+ startRide(route: Route): Promise<Observer | null>;
21
+ updateRoute(route: Route): void;
19
22
  stopRide(): Promise<void>;
20
23
  pauseRide(): void;
21
24
  resumeRide(): void;
@@ -70,7 +70,7 @@ export declare class RideDisplayService extends IncyclistService implements ICur
70
70
  protected onActivityWentActive(): void;
71
71
  protected onActivityPaused(autoResume: any): void;
72
72
  protected onActivityResumed(): void;
73
- protected onActivityUpdate(data: any): void;
73
+ protected onActivityUpdate(): void;
74
74
  protected onWorkoutStopped(): void;
75
75
  protected onWorkoutCompleted(): void;
76
76
  protected checkCyclingModeToggle(): void;
@@ -131,5 +131,6 @@ export declare class RideDisplayService extends IncyclistService implements ICur
131
131
  protected getUserSettings(): import("../../settings").UserSettingsService;
132
132
  protected getDeviceConfiguration(): import("../../devices").DeviceConfigurationService;
133
133
  protected getUIBinding(): INativeUI;
134
+ protected getCoaches(): import("../../coaches").CoachesService;
134
135
  }
135
136
  export declare const useRideDisplay: () => RideDisplayService;
@@ -94,5 +94,6 @@ export declare class RLVDisplayService extends RouteDisplayService {
94
94
  protected checkForAdditionalVideos(route?: Route): Promise<boolean>;
95
95
  protected getRouteList(): RouteListService;
96
96
  protected getLocalization(): LocalizationService;
97
+ protected getCoaches(): import("../../coaches").CoachesService;
97
98
  }
98
99
  export {};
package/package.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "incyclist-services",
3
- "version": "1.7.6",
3
+ "version": "1.7.8",
4
4
  "peerDependencies": {
5
5
  "gd-eventlog": "^0.1.27"
6
6
  },
7
7
  "dependencies": {
8
8
  "axios": "^1.13.4",
9
- "incyclist-devices": "^3.0.3",
9
+ "incyclist-devices": "^3.0.6",
10
10
  "promise.any": "^2.0.6",
11
11
  "semver": "^7.7.3",
12
12
  "tcx-builder": "^1.1.1",