incyclist-services 1.7.49 → 1.7.50

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.
@@ -65,7 +65,7 @@ let LocalFitConverter = (() => {
65
65
  }
66
66
  }
67
67
  getFitActivity(activity) {
68
- const { id, title, time, timeTotal, timePause, distance } = activity;
68
+ const { id, title, time, timeTotal, timePause, distance, sport = 'cycling' } = activity;
69
69
  const status = 'created';
70
70
  const startTime = new Date(activity.startTime).toISOString();
71
71
  const logs = activity.logs.map(this.mapLogToFit.bind(this));
@@ -75,7 +75,7 @@ let LocalFitConverter = (() => {
75
75
  id: this.getUserSettings().get('uuid', undefined),
76
76
  weight: activity.user.weight
77
77
  };
78
- return { id, title, status, logs, laps, startTime, time, timeTotal, timePause, distance, user, screenshots };
78
+ return { id, title, status, logs, laps, startTime, time, timeTotal, timePause, distance, user, screenshots, sport };
79
79
  }
80
80
  mapLapsToFit(laps, activityStartTime) {
81
81
  const activityStartMs = new Date(activityStartTime).getTime();
@@ -181,7 +181,7 @@ let LocalFitConverter = (() => {
181
181
  totalElapsedTime: activity.timeTotal,
182
182
  totalTimerTime: activity.time,
183
183
  totalDistance: activity.distance,
184
- sport: 'cycling',
184
+ sport: this.mapSport(activity.sport),
185
185
  subSport: 'virtualActivity',
186
186
  event: 'session',
187
187
  eventType: 'stopDisableAll',
@@ -197,6 +197,14 @@ let LocalFitConverter = (() => {
197
197
  const uint8Array = encoder.close();
198
198
  return uint8Array.buffer;
199
199
  }
200
+ mapSport(incyclistSport) {
201
+ if (!incyclistSport || incyclistSport === 'cycling')
202
+ return 'cycling';
203
+ if (incyclistSport === 'running')
204
+ return 'running';
205
+ if (incyclistSport === 'rowing')
206
+ return 'rowing';
207
+ }
200
208
  getUserSettings() {
201
209
  return useUserSettings();
202
210
  }
@@ -26,7 +26,7 @@ export class RemoteFitConverter {
26
26
  return this.api;
27
27
  }
28
28
  getFitActivity(activity) {
29
- const { id, title, time, timeTotal, timePause, distance } = activity;
29
+ const { id, title, time, timeTotal, timePause, distance, sport = 'cycling' } = activity;
30
30
  const status = 'created';
31
31
  const startTime = new Date(activity.startTime).toISOString();
32
32
  const logs = activity.logs.map(this.mapLogToFit.bind(this));
@@ -36,7 +36,7 @@ export class RemoteFitConverter {
36
36
  id: this.getUserSettings().get('uuid', undefined),
37
37
  weight: activity.user.weight
38
38
  };
39
- return { id, title, status, logs, laps, startTime, time, timeTotal, timePause, distance, user, screenshots };
39
+ return { id, title, status, logs, laps, startTime, time, timeTotal, timePause, distance, user, screenshots, sport };
40
40
  }
41
41
  mapLogToFit(log) {
42
42
  const { time, speed, slope, cadence: cadenceOrg, heartrate: heartrateOrg, distance, power: powerOrg, lat, lng, elevation } = log;
@@ -85,7 +85,8 @@ export class TcxConverter {
85
85
  const trackPoints = this.creatTrackPoints(activity, startTime);
86
86
  const laps = this.createLaps(startTime, activity, trackPoints);
87
87
  const creator = new IncyclistAttribution();
88
- const tcxActivity = new Activity('Biking', { Id: startTime, Notes: 'Incyclist Ride', Laps: laps, Creator: creator });
88
+ const sport = this.mapSport(activity.sport);
89
+ const tcxActivity = new Activity(sport, { Id: startTime, Notes: 'Incyclist Ride', Laps: laps, Creator: creator });
89
90
  const activityList = new ActivityList({ activity: [tcxActivity] });
90
91
  const tcxObj = new TrainingCenterDatabase({ activities: activityList });
91
92
  const xml = tcxObj.toXml();
@@ -97,6 +98,14 @@ export class TcxConverter {
97
98
  throw err;
98
99
  }
99
100
  }
101
+ mapSport(incyclistSport) {
102
+ if (!incyclistSport || incyclistSport === 'cycling')
103
+ return 'Biking';
104
+ if (incyclistSport === 'running')
105
+ return 'Running';
106
+ if (incyclistSport === 'rowing')
107
+ return 'Other';
108
+ }
100
109
  createLaps(startTime, activity, trackPoints) {
101
110
  if (!activity.workout && !activity.laps)
102
111
  return this.createActivityLap(startTime, activity, trackPoints);
@@ -1 +1,6 @@
1
1
  export const DEFAULT_ACTIVITY_TITLE = 'Incyclist Ride';
2
+ export const DEFAULT_SPORT_ACTIVITY_TITLE = {
3
+ cycling: 'Incyclist Ride',
4
+ rowing: 'Incyclist Rowing',
5
+ running: 'Incyclist Run'
6
+ };
@@ -42,7 +42,7 @@ import { useRouteList } from "../../../routes";
42
42
  import { ActivitiesDBMigratorFactory } from "./migration/factory";
43
43
  import { Injectable } from "../../../base/decorators/Injection";
44
44
  import { useUnitConverter } from "../../../i18n";
45
- export const DB_VERSION = '4';
45
+ export const DB_VERSION = '5';
46
46
  export const DB_NAME = 'db';
47
47
  let ActivitiesRepository = (() => {
48
48
  let _classDecorators = [Singleton];
@@ -33,7 +33,7 @@ var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn,
33
33
  done = true;
34
34
  };
35
35
  import { useRouteList } from "../../../routes";
36
- import { DEFAULT_ACTIVITY_TITLE } from "../model";
36
+ import { DEFAULT_ACTIVITY_TITLE, DEFAULT_SPORT_ACTIVITY_TITLE } from "../model";
37
37
  import { ActivitiesRepository, DB_VERSION } from "../repo";
38
38
  import { getBindings } from "../../../api";
39
39
  import { useOnlineStatusMonitoring } from "../../../monitoring";
@@ -115,7 +115,8 @@ let Activity = (() => {
115
115
  }
116
116
  getTitle() {
117
117
  let title = this.info.summary.title;
118
- if (title === DEFAULT_ACTIVITY_TITLE) {
118
+ const sport = this.details?.sport ?? 'cycling';
119
+ if (title === DEFAULT_ACTIVITY_TITLE || title === DEFAULT_SPORT_ACTIVITY_TITLE[sport]) {
119
120
  if (this.details?.route?.title) {
120
121
  title = this.details?.route.title;
121
122
  }
@@ -1,5 +1,5 @@
1
1
  export * from './activity';
2
- import { DEFAULT_ACTIVITY_TITLE } from "../model";
2
+ import { DEFAULT_ACTIVITY_TITLE, DEFAULT_SPORT_ACTIVITY_TITLE } from "../model";
3
3
  export const buildSummary = (activity, proposedName) => {
4
4
  const { id, route, screenshots, startTime: startTimeUTC, time: rideTime, distance, startPos, endPos, realityFactor = 100, links, laps, fileName } = activity;
5
5
  let name = proposedName ?? activity.name;
@@ -10,7 +10,8 @@ export const buildSummary = (activity, proposedName) => {
10
10
  const previewImage = preview?.fileName;
11
11
  const totalElevation = activity.totalElevation;
12
12
  let title = activity.title;
13
- if (title === DEFAULT_ACTIVITY_TITLE) {
13
+ const sport = activity.sport ?? 'cycling';
14
+ if (title === DEFAULT_ACTIVITY_TITLE || title === DEFAULT_SPORT_ACTIVITY_TITLE[sport]) {
14
15
  if (activity.routeType === 'Video' && activity.route)
15
16
  title = activity.route.title ?? activity.route.name;
16
17
  else if (activity.route)
@@ -2,7 +2,7 @@ import { getUnitConversionShortcuts } from "../../i18n";
2
2
  export const createUIActivityInfo = (a) => {
3
3
  if (!a)
4
4
  return a;
5
- const { summary, details } = a;
5
+ const { summary } = a;
6
6
  return {
7
7
  summary: createUIActivitySummary(summary),
8
8
  details: undefined
@@ -40,7 +40,7 @@ import { useUserSettings } from "../../settings";
40
40
  import { formatDateTime, formatNumber, formatTime, getLegacyInterface, waitNextTick } from "../../utils";
41
41
  import { IncyclistCapability } from "incyclist-devices";
42
42
  import { useDeviceConfiguration, useDeviceRide } from "../../devices";
43
- import { ActivitiesRepository, ActivityConverter, ActivityConverterFactory, DB_VERSION, DEFAULT_ACTIVITY_TITLE } from "../base";
43
+ import { ActivitiesRepository, ActivityConverter, ActivityConverterFactory, DB_VERSION, DEFAULT_SPORT_ACTIVITY_TITLE } from "../base";
44
44
  import { v4 as generateUUID } from 'uuid';
45
45
  import { addDetails, checkIsLoop, getElevationGainAt, getNextPosition, getPosition, getRouteHash, validateRoute } from "../../routes/base/utils/route";
46
46
  import { Route } from "../../routes/base/model/route";
@@ -56,7 +56,6 @@ import { Injectable } from "../../base/decorators";
56
56
  import { useUnitConverter } from "../../i18n";
57
57
  import { createUIActivityDetails } from "../list/utils";
58
58
  import { sleep } from "../../utils/sleep";
59
- import { EventEmitter } from "node:events";
60
59
  const SAVE_INTERVAL = 5000;
61
60
  let ActivityRideService = (() => {
62
61
  let _classDecorators = [Singleton];
@@ -100,6 +99,11 @@ let ActivityRideService = (() => {
100
99
  deviceDataHandler = this.onDeviceData.bind(this);
101
100
  gearChangeHandler = this.onGearChange.bind(this);
102
101
  dataHealthHandler = this.onDeviceHealthUpdate.bind(this);
102
+ speedHandler = {
103
+ 'cycling': this.getCyclingSpeed.bind(this),
104
+ 'rowing': this.getRowingPace.bind(this),
105
+ 'running': this.getRunningPace.bind(this)
106
+ };
103
107
  current;
104
108
  constructor() {
105
109
  super('ActivityRide');
@@ -162,7 +166,7 @@ let ActivityRideService = (() => {
162
166
  this.isSaveDone = false;
163
167
  this.isDonateShown = false;
164
168
  this.isSummaryShown = false;
165
- this.logEvent({ message: 'activity started' });
169
+ this.logEvent({ message: 'activity started', sport: this.activity.sport ?? 'cycling' });
166
170
  this.startWorker();
167
171
  this.enableDeviceHealthCheck();
168
172
  this.emit('started');
@@ -260,6 +264,34 @@ let ActivityRideService = (() => {
260
264
  return [];
261
265
  }
262
266
  }
267
+ getRowingPace(speed) {
268
+ if (speed > 0) {
269
+ const value = 30 / speed;
270
+ const min = Math.floor(value);
271
+ const sec = Math.floor((value - min) * 60);
272
+ const p = sec < 10 ? '0' : '';
273
+ return { value: `${min}:${p}${sec}`, unit: '' };
274
+ }
275
+ else {
276
+ return { value: '', unit: '' };
277
+ }
278
+ }
279
+ getRunningPace(speed) {
280
+ if (speed > 0) {
281
+ const value = 60 / speed;
282
+ const min = Math.floor(value);
283
+ const sec = Math.floor((value - min) * 60);
284
+ const p = sec < 10 ? '0' : '';
285
+ return { value: `${min}:${p}${sec}`, unit: '' };
286
+ }
287
+ else {
288
+ return { value: '', unit: '' };
289
+ }
290
+ }
291
+ getCyclingSpeed(speed) {
292
+ const [C, U] = this.getUnitConversionShortcuts();
293
+ return { value: C(speed, 'speed')?.toFixed(1) ?? '', unit: U('speed') };
294
+ }
263
295
  buildDashboardInfo(currentValues, avgMaxStats, display) {
264
296
  const { distance, time, speed, power, slope, heartrate, cadence, distanceRemaining, timeRemaining, gear } = currentValues;
265
297
  const { speedDetails, powerDetails, elevationGain, heartrateDetails, cadenceDetails } = avgMaxStats;
@@ -277,9 +309,10 @@ let ActivityRideService = (() => {
277
309
  { value: distanceRemaining === undefined ? undefined : `-${C(distanceRemaining, 'distance', { from: 'km' }).toFixed(2)}` }
278
310
  ]
279
311
  });
312
+ const sport = this.activity.sport ?? 'cycling';
280
313
  info.push({ title: 'Speed',
281
314
  data: [
282
- { value: C(speed, 'speed')?.toFixed(1) ?? '', unit: U('speed') },
315
+ this.speedHandler[sport](speed),
283
316
  speedDetails
284
317
  ],
285
318
  dataState: this.current.dataState?.speed
@@ -291,7 +324,9 @@ let ActivityRideService = (() => {
291
324
  info.push({ title: 'Slope', data: [{ value: formatNumber(slope, 1), unit: '%', info: slopeInfo }, elevationGain] });
292
325
  }
293
326
  info.push({ title: 'Heartrate', data: [{ value: formatNumber(heartrate, 0), unit: 'bpm' }, heartrateDetails], dataState: this.current.dataState?.heartrate });
294
- info.push({ title: 'Cadence', data: [{ value: formatNumber(cadence, 0), unit: 'rpm' }, cadenceDetails], dataState: this.current.dataState?.cadence });
327
+ const cadenceUnit = this.activity.sport === 'rowing' ? 'spm' : 'rpm';
328
+ const cadenceInfo = { title: 'Cadence', data: [{ value: formatNumber(cadence, 0), unit: cadenceUnit }, cadenceDetails], dataState: this.current.dataState?.cadence };
329
+ info.push(cadenceInfo);
295
330
  if (gear) {
296
331
  info.push({ title: 'Gear', data: [{ value: gear }] });
297
332
  }
@@ -328,7 +363,11 @@ let ActivityRideService = (() => {
328
363
  const [C, U] = this.getUnitConversionShortcuts();
329
364
  const stats = this.activity?.stats;
330
365
  const maxSpeed = stats?.speed?.max;
331
- const speedDetails = { value: formatNumber(C(maxSpeed, 'speed'), 1), label: 'max' };
366
+ const sport = this.activity.sport ?? 'cycling';
367
+ const data = this.speedHandler[sport](maxSpeed);
368
+ const speedDetails = this.activity.sport === 'cycling' ?
369
+ { value: formatNumber(C(maxSpeed, 'speed'), 1), label: 'max' } :
370
+ { value: data.value, label: 'max' };
332
371
  const powerDetails = { value: formatNumber(stats?.power?.max, 0), label: 'max' };
333
372
  const heartrateDetails = { value: formatNumber(stats?.hrm?.max, 0), label: 'max' };
334
373
  const cadenceDetails = { value: formatNumber(stats?.cadence?.max, 0), label: 'max' };
@@ -345,7 +384,11 @@ let ActivityRideService = (() => {
345
384
  const [C, U] = this.getUnitConversionShortcuts();
346
385
  const stats = this.activity?.stats;
347
386
  const avgSpeed = stats?.speed?.avg;
348
- const speedDetails = { value: formatNumber(C(avgSpeed, 'speed'), 1), label: 'avg' };
387
+ const sport = this.activity.sport ?? 'cycling';
388
+ const data = this.speedHandler[sport](avgSpeed);
389
+ const speedDetails = this.activity.sport === 'cycling' ?
390
+ { value: formatNumber(C(avgSpeed, 'speed'), 1), label: 'avg' } :
391
+ { value: data.value, label: 'max' };
349
392
  const powerDetails = { value: formatNumber(stats?.power?.avg, 0), label: 'avg' };
350
393
  const heartrateDetails = { value: formatNumber(stats?.hrm?.avg, 0), label: 'avg' };
351
394
  const cadenceDetails = { value: formatNumber(stats?.cadence?.avg, 0), label: 'avg' };
@@ -460,47 +503,17 @@ let ActivityRideService = (() => {
460
503
  };
461
504
  const run = async () => {
462
505
  await sleep(5);
463
- let cntCompleted = 0;
464
506
  let success = false;
465
- const localEmitter = new EventEmitter();
466
- const incCompleted = () => {
467
- cntCompleted++;
468
- if (cntCompleted >= 2) {
469
- localEmitter.emit('completed');
470
- }
471
- };
472
- localEmitter.once('completed', () => {
473
- sleep(0).then(() => {
474
- delete this.saveObserver;
475
- });
476
- });
477
507
  try {
478
508
  emit('start', success);
479
509
  await this._save();
480
- let format = undefined;
481
- let uploadSuccess = false;
482
- let convertSuccess = await this.convert('TCX');
483
- incCompleted();
484
- if (convertSuccess) {
485
- format = 'TCX';
486
- this.convert('FIT')
487
- .then(incCompleted)
488
- .catch(incCompleted);
489
- }
490
- else {
491
- convertSuccess = await this.convert('FIT');
492
- cntCompleted++;
493
- if (convertSuccess)
494
- format = 'FIT';
495
- }
496
- if (convertSuccess) {
497
- uploadSuccess = await this.upload(format);
498
- }
499
- success = convertSuccess && uploadSuccess;
510
+ success = await this._convertAndUpload();
511
+ sleep(0).then(() => {
512
+ delete this.saveObserver;
513
+ });
500
514
  this.isSaveDone = true;
501
515
  }
502
516
  catch {
503
- cntCompleted++;
504
517
  success = false;
505
518
  }
506
519
  emit('done', success);
@@ -830,6 +843,29 @@ let ActivityRideService = (() => {
830
843
  this.logError(err, '_save');
831
844
  }
832
845
  }
846
+ async _convertAndUpload() {
847
+ const successes = [];
848
+ const promises = [
849
+ this.convert('TCX').then(() => successes.push('tcx')),
850
+ this.convert('FIT').then(() => successes.push('fit')),
851
+ ];
852
+ await Promise.allSettled(promises);
853
+ this.logEvent({ message: 'conversion finished, ' });
854
+ const convertSuccess = successes.length > 0;
855
+ let uploadSuccess;
856
+ let format = 'tcx';
857
+ if (this.activity.sport === 'rowing') {
858
+ if (successes.some(e => e === 'fit'))
859
+ format = 'fit';
860
+ }
861
+ else if (!successes.some(e => e === 'tcx')) {
862
+ format = 'fit';
863
+ }
864
+ if (convertSuccess) {
865
+ uploadSuccess = await this.upload(format);
866
+ }
867
+ return convertSuccess && uploadSuccess;
868
+ }
833
869
  getSaveInterval() {
834
870
  return SAVE_INTERVAL;
835
871
  }
@@ -997,7 +1033,8 @@ let ActivityRideService = (() => {
997
1033
  this.current.position = undefined;
998
1034
  }
999
1035
  }
1000
- const title = DEFAULT_ACTIVITY_TITLE;
1036
+ const sport = this.getDeviceRide().getSport() ?? 'cycling';
1037
+ const title = DEFAULT_SPORT_ACTIVITY_TITLE[sport];
1001
1038
  const id = requestedId ?? generateUUID();
1002
1039
  const date = formatDateTime(new Date(), "%Y%m%d%H%M%S", false);
1003
1040
  const name = `${title}-${date}`;
@@ -1024,7 +1061,8 @@ let ActivityRideService = (() => {
1024
1061
  totalElevation: 0,
1025
1062
  logs: [],
1026
1063
  startPos, endPos, segment, realityFactor,
1027
- fileName
1064
+ fileName,
1065
+ sport
1028
1066
  };
1029
1067
  return activity;
1030
1068
  }
@@ -129,7 +129,6 @@ let DeviceRideService = (() => {
129
129
  return this.data;
130
130
  }
131
131
  pauseLogging() {
132
- console.log('# PAUSE LOGGING');
133
132
  this.logPaused = true;
134
133
  const interfaces = this.getEnabledInterfaces();
135
134
  interfaces.forEach(i => i.pauseLogging());
@@ -139,7 +138,6 @@ let DeviceRideService = (() => {
139
138
  .forEach(a => a.pauseLogging());
140
139
  }
141
140
  resumeLogging() {
142
- console.log('# RESUME LOGGING');
143
141
  this.logPaused = false;
144
142
  const interfaces = this.getEnabledInterfaces();
145
143
  interfaces.forEach(i => i.resumeLogging());
@@ -921,6 +919,19 @@ let DeviceRideService = (() => {
921
919
  this.storeOriginalCyclingMode();
922
920
  return this.startAdapters(adapters, 'start', props);
923
921
  }
922
+ getSport() {
923
+ try {
924
+ const info = this.getControlAdapter();
925
+ const adapter = info?.adapter;
926
+ const sports = adapter?.getSupportedSports?.() ?? ['cycling'];
927
+ this.logEvent({ message: '[DeviceRide] getSports', adapter: info.adapter.getName(), sports: sports.join(',') });
928
+ return sports[0];
929
+ }
930
+ catch (err) {
931
+ this.logError(err, 'getSports');
932
+ return 'cycling';
933
+ }
934
+ }
924
935
  async startRetry(props) {
925
936
  await this.lazyInit();
926
937
  const selected = this.getRideAdapters();
@@ -200,8 +200,8 @@ let RouteDisplayService = (() => {
200
200
  const nearbyRides = this.getNearbyRidesProps(props);
201
201
  const [C, U] = this.getUnitConversionShortcuts();
202
202
  const isLoop = this.currentRoute?.description?.isLoop;
203
- const xScale = { value: C(1, 'distance', { from: U('distance') }), unit: U('distance') };
204
- const yScale = { value: C(1, 'elevation', { from: U('elevation') }), unit: U('elevation') };
203
+ const xScale = { value: C(1, 'distance', { from: 'm' }), unit: U('distance') };
204
+ const yScale = { value: C(1, 'elevation', { from: 'm' }), unit: U('elevation') };
205
205
  const mapStartPos = (isLoop && !loopOverwrite) ? undefined : startPos;
206
206
  return {
207
207
  ...parent,
@@ -1,5 +1,6 @@
1
1
  import { EventLogger } from 'gd-eventlog';
2
2
  import { ActivityDetails, ActivityLogRecord, FitExportActivity, FitLapEntry, FitLogEntry, LapSummary } from '../../model';
3
+ import { Sport } from 'incyclist-devices';
3
4
  export declare class LocalFitConverter {
4
5
  protected logger: EventLogger;
5
6
  constructor();
@@ -8,5 +9,6 @@ export declare class LocalFitConverter {
8
9
  protected mapLapsToFit(laps: LapSummary[], activityStartTime: string): FitLapEntry[];
9
10
  protected mapLogToFit(log: ActivityLogRecord): FitLogEntry;
10
11
  protected encode(activity: FitExportActivity): ArrayBuffer;
12
+ protected mapSport(incyclistSport?: Sport): string;
11
13
  protected getUserSettings(): import("../../../../settings").UserSettingsService;
12
14
  }
@@ -4,6 +4,7 @@ import { IActivityConverter } from '../types';
4
4
  import { ActivityDetails } from '../../model';
5
5
  import { TcxLapMarker } from './types';
6
6
  import { Step } from '../../../../workouts';
7
+ import { Sport } from 'incyclist-devices';
7
8
  export declare class IncyclistAttribution extends AbstractSource {
8
9
  toXml(): string;
9
10
  constructor();
@@ -14,6 +15,7 @@ export declare class TcxConverter implements IActivityConverter {
14
15
  protected logger: EventLogger;
15
16
  constructor();
16
17
  convert(activity: ActivityDetails): Promise<string>;
18
+ protected mapSport(incyclistSport: Sport): 'Running' | 'Biking' | 'Other';
17
19
  protected createLaps(startTime: Date, activity: ActivityDetails, trackPoints: TrackPoint[]): ActivityLap[];
18
20
  protected createActivityLap(startTime: Date, activity: ActivityDetails, trackPoints: TrackPoint[]): ActivityLap[];
19
21
  protected getWorkoutLapMarkers(activity: ActivityDetails): Array<TcxLapMarker>;
@@ -1,7 +1,9 @@
1
+ import { Sport } from "incyclist-devices";
1
2
  import { FormattedNumber } from "../../../i18n";
2
3
  import { RoutePoint } from "../../../routes/base/types";
3
4
  import { Workout } from "../../../workouts";
4
5
  export declare const DEFAULT_ACTIVITY_TITLE = "Incyclist Ride";
6
+ export declare const DEFAULT_SPORT_ACTIVITY_TITLE: Record<Sport, string>;
5
7
  export type ActivityUser = {
6
8
  uuid?: string;
7
9
  weight: number;
@@ -141,6 +143,7 @@ export type FitExportActivity = {
141
143
  href?: string;
142
144
  user: FitUser;
143
145
  screenshots: Array<FitScreenshots>;
146
+ sport?: Sport;
144
147
  };
145
148
  interface ActivityDetailsBase {
146
149
  type?: ActivityType;
@@ -170,6 +173,7 @@ interface ActivityDetailsBase {
170
173
  fitFileName?: string;
171
174
  links?: ActivityAppLinks;
172
175
  workout?: Workout;
176
+ sport?: Sport;
173
177
  }
174
178
  export interface ActivityDetails extends ActivityDetailsBase {
175
179
  distance: number;
@@ -3,7 +3,7 @@ import { JsonRepository } from "../../../api";
3
3
  import { Observer, PromiseObserver } from "../../../base/types/observer";
4
4
  import { ActivityDetails, ActivityInfo } from "../model";
5
5
  import { ActivitySearchCriteria } from "./types";
6
- export declare const DB_VERSION = "4";
6
+ export declare const DB_VERSION = "5";
7
7
  export declare const DB_NAME = "db";
8
8
  export declare class ActivitiesRepository {
9
9
  protected repo: JsonRepository;
@@ -1,12 +1,12 @@
1
1
  import { IncyclistService } from "../../base/service";
2
2
  import { Observer, PromiseObserver } from "../../base/types/observer";
3
- import { DeviceData } from "incyclist-devices";
3
+ import { DeviceData, Sport } from "incyclist-devices";
4
4
  import { ExtendedIncyclistCapability, HealthStatus } from "../../devices";
5
5
  import { ActivitiesRepository, ActivityConverterFactory, ActivityDetails, ActivityInfo, ActivityLogRecord, ActivityRouteType, ScreenShotInfo } from "../base";
6
6
  import { FreeRideStartSettings } from "../../routes/list/types";
7
7
  import { RouteSettings } from "../../routes/list/cards/types";
8
8
  import { RoutePoint } from "../../routes/base/types";
9
- import { ActivityState, ActivitySummaryDisplayProperties } from "./types";
9
+ import { ActivityDashboardDataItem, ActivityState, ActivitySummaryDisplayProperties } from "./types";
10
10
  import { Route } from "../../routes/base/model/route";
11
11
  import { ActivityStatsCalculator } from "./stats";
12
12
  import { ActivityDuration } from "./duration";
@@ -37,6 +37,7 @@ export declare class ActivityRideService extends IncyclistService {
37
37
  protected deviceDataHandler: any;
38
38
  protected gearChangeHandler: any;
39
39
  protected dataHealthHandler: any;
40
+ protected speedHandler: Record<Sport, (speed: number) => ActivityDashboardDataItem>;
40
41
  protected current: {
41
42
  route?: Route;
42
43
  position?: RoutePoint;
@@ -67,6 +68,9 @@ export declare class ActivityRideService extends IncyclistService {
67
68
  resume(requester?: 'user' | 'system'): void;
68
69
  ignoreEndPos(): void;
69
70
  getDashboardDisplayProperties(): any[];
71
+ protected getRowingPace(speed: number): ActivityDashboardDataItem;
72
+ protected getRunningPace(speed: number): ActivityDashboardDataItem;
73
+ protected getCyclingSpeed(speed: number): ActivityDashboardDataItem;
70
74
  protected buildDashboardInfo(currentValues: any, avgMaxStats: any, display: any): any[];
71
75
  getCurrentValues(): {
72
76
  position: {};
@@ -85,7 +89,7 @@ export declare class ActivityRideService extends IncyclistService {
85
89
  };
86
90
  protected getAverageValues(): {
87
91
  speedDetails: {
88
- value: string;
92
+ value: string | number;
89
93
  label: string;
90
94
  };
91
95
  powerDetails: {
@@ -114,7 +118,7 @@ export declare class ActivityRideService extends IncyclistService {
114
118
  };
115
119
  protected getMaximumValues(): {
116
120
  speedDetails: {
117
- value: string;
121
+ value: string | number;
118
122
  label: string;
119
123
  };
120
124
  powerDetails: {
@@ -173,6 +177,7 @@ export declare class ActivityRideService extends IncyclistService {
173
177
  protected onDeviceHealthUpdate(udid: string, status: HealthStatus, capabilities: Array<ExtendedIncyclistCapability>): void;
174
178
  emit(eventName: string | symbol, ...args: any[]): boolean;
175
179
  protected _save(): Promise<void>;
180
+ protected _convertAndUpload(): Promise<boolean>;
176
181
  protected getSaveInterval(): number;
177
182
  protected updateRepo(): Promise<void>;
178
183
  protected getTargetFileName(format: string): Promise<string>;
@@ -188,7 +193,7 @@ export declare class ActivityRideService extends IncyclistService {
188
193
  protected update(): void;
189
194
  protected isLoop(): boolean;
190
195
  protected createFreeRide(settings: FreeRideStartSettings): Route;
191
- protected getMode(routeType: ActivityRouteType): "video" | "workout" | "follow route" | "free ride";
196
+ protected getMode(routeType: ActivityRouteType): "workout" | "video" | "follow route" | "free ride";
192
197
  protected updateActivityTime(): void;
193
198
  getRideProps(): any;
194
199
  protected logActivityUpdateMessage(): void;
@@ -1,6 +1,6 @@
1
1
  import { AdapterInfo, IncyclistDeviceSettings } from "../configuration";
2
2
  import { AdapterRideInfo, AdapterStateInfo, LegacyRoute, PreparedRoute, RideServiceCheckFilter, RideServiceDeviceProperties } from "./types";
3
- import { CyclingMode, DeviceData, DeviceSettings, ICyclingMode, IncyclistCapability, IncyclistDeviceAdapter, IncyclistInterface, UpdateRequest } from "incyclist-devices";
3
+ import { CyclingMode, DeviceData, DeviceSettings, ICyclingMode, IncyclistCapability, IncyclistDeviceAdapter, IncyclistInterface, Sport, UpdateRequest } from "incyclist-devices";
4
4
  import { IncyclistService } from "../../base/service";
5
5
  import { Route } from "../../routes/base/model/route";
6
6
  import { RouteApiDetail } from "../../routes/base/api/types";
@@ -92,6 +92,7 @@ export declare class DeviceRideService extends IncyclistService {
92
92
  protected stopDuringInterfaceRestart(unhealthy: AdapterRideInfo): Promise<void>;
93
93
  private reconnectSingle;
94
94
  start(props: RideServiceDeviceProperties): Promise<boolean>;
95
+ getSport(): Sport;
95
96
  startRetry(props: RideServiceDeviceProperties): Promise<boolean>;
96
97
  cancelStart(): Promise<boolean>;
97
98
  registerOnDataHandler(adapters: AdapterRideInfo[]): void;
@@ -1,3 +1,5 @@
1
+ import type { Sport } from 'incyclist-devices';
1
2
  export type * from './page/types';
2
3
  export type * from './ride/types';
3
4
  export type * from './configuration/types';
5
+ export type { Sport };
@@ -20,4 +20,4 @@ export * from './utils';
20
20
  export * from './video';
21
21
  export * from './workouts';
22
22
  export type * from './types';
23
- export { CyclingModeProperyType } from 'incyclist-devices';
23
+ export { CyclingModeProperyType, Sport } from 'incyclist-devices';
@@ -120,7 +120,7 @@ export declare class RideDisplayService extends IncyclistService implements ICur
120
120
  protected isSimulator(): boolean;
121
121
  protected getBike(): string;
122
122
  protected getBikeInterface(): string;
123
- protected getLogRideMode(): "video" | "workout" | "free-ride" | "follow-route";
123
+ protected getLogRideMode(): "workout" | "video" | "free-ride" | "follow-route";
124
124
  protected isDebug(): boolean;
125
125
  protected isVirtualShiftingEnabled(): boolean;
126
126
  protected getActivityRide(): import("../../activities").ActivityRideService;
@@ -81,7 +81,7 @@ export declare class RouteCard extends BaseCard implements Card<Route> {
81
81
  getCurrentDownload(): Observer;
82
82
  getVideoDir(): string;
83
83
  setVideoDir(dir: string): void;
84
- onVideoSelected(info: FileInfo): Promise<"Could not open file" | "Unsupported video format - Please select MP4 or AVI">;
84
+ onVideoSelected(info: FileInfo): Promise<"Unsupported video format - Please select MP4 or AVI" | "Could not open file">;
85
85
  download(): Observer;
86
86
  stopDownload(immediate?: boolean): void;
87
87
  deleteDownload(): Promise<void>;
package/package.json CHANGED
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "name": "incyclist-services",
3
- "version": "1.7.49",
3
+ "version": "1.7.50",
4
4
  "peerDependencies": {
5
5
  "gd-eventlog": "^0.1.27"
6
6
  },
7
7
  "dependencies": {
8
8
  "@garmin/fitsdk": "^21.200.0",
9
9
  "axios": "^1.15.0",
10
- "incyclist-devices": "^3.0.12",
10
+ "incyclist-devices": "^3.0.13",
11
11
  "promise.any": "^2.0.6",
12
12
  "semver": "^7.7.4",
13
13
  "tcx-builder": "^1.1.1",