incyclist-services 1.7.71 → 1.7.73

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 (36) hide show
  1. package/lib/cjs/devices/ride/service.js +7 -0
  2. package/lib/cjs/ride/display/service.js +4 -4
  3. package/lib/cjs/ride/page/service.js +18 -0
  4. package/lib/cjs/ride/route/RouteDisplayService.js +1 -1
  5. package/lib/cjs/routes/list/cards/RouteCard.js +11 -1
  6. package/lib/cjs/workouts/list/index.js +1 -0
  7. package/lib/cjs/workouts/list/pageService.js +98 -0
  8. package/lib/esm/activities/upload/trainingpeaks.js +123 -0
  9. package/lib/esm/apps/base/api/trainingpeaks/api.js +143 -0
  10. package/lib/esm/apps/base/api/trainingpeaks/index.js +1 -0
  11. package/lib/esm/apps/base/api/trainingpeaks/types.js +1 -0
  12. package/lib/esm/apps/trainingpeaks/TrainingPeaksAppConnection.js +189 -0
  13. package/lib/esm/apps/trainingpeaks/types.js +1 -0
  14. package/lib/esm/devices/ride/service.js +7 -0
  15. package/lib/esm/ride/display/service.js +4 -4
  16. package/lib/esm/ride/page/service.js +18 -0
  17. package/lib/esm/ride/route/RouteDisplayService.js +1 -1
  18. package/lib/esm/routes/list/cards/RouteCard.js +11 -1
  19. package/lib/esm/workouts/calendar/sync/trainingpeaks/provider.js +201 -0
  20. package/lib/esm/workouts/list/index.js +1 -0
  21. package/lib/esm/workouts/list/pageService.js +94 -0
  22. package/lib/types/activities/upload/trainingpeaks.d.ts +16 -0
  23. package/lib/types/apps/base/api/trainingpeaks/api.d.ts +30 -0
  24. package/lib/types/apps/base/api/trainingpeaks/index.d.ts +2 -0
  25. package/lib/types/apps/base/api/trainingpeaks/types.d.ts +55 -0
  26. package/lib/types/apps/trainingpeaks/TrainingPeaksAppConnection.d.ts +22 -0
  27. package/lib/types/apps/trainingpeaks/types.d.ts +6 -0
  28. package/lib/types/appstate/types.d.ts +1 -1
  29. package/lib/types/ride/page/service.d.ts +1 -0
  30. package/lib/types/ride/page/types.d.ts +2 -1
  31. package/lib/types/routes/list/cards/RouteCard.d.ts +1 -0
  32. package/lib/types/routes/list/cards/types.d.ts +1 -0
  33. package/lib/types/workouts/calendar/sync/trainingpeaks/provider.d.ts +22 -0
  34. package/lib/types/workouts/list/index.d.ts +1 -0
  35. package/lib/types/workouts/list/pageService.d.ts +18 -0
  36. package/package.json +2 -2
@@ -0,0 +1,189 @@
1
+ var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
2
+ var useValue = arguments.length > 2;
3
+ for (var i = 0; i < initializers.length; i++) {
4
+ value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
5
+ }
6
+ return useValue ? value : void 0;
7
+ };
8
+ var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
9
+ function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
10
+ var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
11
+ var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
12
+ var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
13
+ var _, done = false;
14
+ for (var i = decorators.length - 1; i >= 0; i--) {
15
+ var context = {};
16
+ for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
17
+ for (var p in contextIn.access) context.access[p] = contextIn.access[p];
18
+ context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
19
+ var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
20
+ if (kind === "accessor") {
21
+ if (result === void 0) continue;
22
+ if (result === null || typeof result !== "object") throw new TypeError("Object expected");
23
+ if (_ = accept(result.get)) descriptor.get = _;
24
+ if (_ = accept(result.set)) descriptor.set = _;
25
+ if (_ = accept(result.init)) initializers.unshift(_);
26
+ }
27
+ else if (_ = accept(result)) {
28
+ if (kind === "field") initializers.unshift(_);
29
+ else descriptor[key] = _;
30
+ }
31
+ }
32
+ if (target) Object.defineProperty(target, contextIn.name, descriptor);
33
+ done = true;
34
+ };
35
+ import { getBindings } from '../../api';
36
+ import { Injectable, Singleton } from '../../base/decorators';
37
+ import { valid } from '../../utils/valid';
38
+ import { TrainingPeaksApi } from '../base/api/trainingpeaks';
39
+ import { ConnectedAppService } from '../base/app';
40
+ let TrainingPeaksAppConnection = (() => {
41
+ let _classDecorators = [Singleton];
42
+ let _classDescriptor;
43
+ let _classExtraInitializers = [];
44
+ let _classThis;
45
+ let _classSuper = ConnectedAppService;
46
+ let _instanceExtraInitializers = [];
47
+ let _getSecretBindings_decorators;
48
+ var TrainingPeaksAppConnection = class extends _classSuper {
49
+ static { _classThis = this; }
50
+ static {
51
+ const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
52
+ _getSecretBindings_decorators = [Injectable];
53
+ __esDecorate(this, null, _getSecretBindings_decorators, { kind: "method", name: "getSecretBindings", static: false, private: false, access: { has: obj => "getSecretBindings" in obj, get: obj => obj.getSecretBindings }, metadata: _metadata }, null, _instanceExtraInitializers);
54
+ __esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
55
+ TrainingPeaksAppConnection = _classThis = _classDescriptor.value;
56
+ if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
57
+ __runInitializers(_classThis, _classExtraInitializers);
58
+ }
59
+ config = __runInitializers(this, _instanceExtraInitializers);
60
+ api;
61
+ tokenUpdateHandler = this.updateConfig.bind(this);
62
+ constructor() {
63
+ super('TrainingPeaksAppConnection', 'trainingpeaks');
64
+ }
65
+ async connect(credentials) {
66
+ this.ensureInitialized();
67
+ this.logEvent({ message: 'Connect with TrainingPeaks' });
68
+ try {
69
+ const isConnected = this.isConnected();
70
+ const config = this.buildConfigFromCredentials(credentials);
71
+ if (isConnected) {
72
+ this.getApi().update(config);
73
+ }
74
+ else {
75
+ this.initApi(config);
76
+ this.saveCredentials(config);
77
+ }
78
+ this.logEvent({ message: 'Connect with TrainingPeaks success' });
79
+ return true;
80
+ }
81
+ catch (err) {
82
+ this.logError(err, 'connect');
83
+ throw err;
84
+ }
85
+ }
86
+ isConnecting() {
87
+ return false;
88
+ }
89
+ disconnect() {
90
+ try {
91
+ this.config = undefined;
92
+ this.getApi().init(undefined);
93
+ this.saveCredentials();
94
+ }
95
+ catch (err) {
96
+ this.logError(err, 'disconnect');
97
+ }
98
+ }
99
+ isConnected() {
100
+ if (!this.isInitialized) {
101
+ this.init();
102
+ }
103
+ return valid(this.config);
104
+ }
105
+ getCredentials() {
106
+ try {
107
+ return this.getUserSettings().get('user.auth.trainingpeaks', null);
108
+ }
109
+ catch {
110
+ return null;
111
+ }
112
+ }
113
+ getApi() {
114
+ if (!this.api)
115
+ this.api = new TrainingPeaksApi();
116
+ return this.api;
117
+ }
118
+ initAuth() {
119
+ let isInitialized = false;
120
+ try {
121
+ const auth = this.getCredentials();
122
+ const clientId = this.getSecret('TRAININGPEAKS_CLIENT_ID');
123
+ const clientSecret = this.getSecret('TRAININGPEAKS_CLIENT_SECRET');
124
+ if (clientId && clientSecret && auth) {
125
+ this.logEvent({ message: 'TrainingPeaks init done', hasCredentials: true });
126
+ this.config = this.buildConfigFromCredentials(auth);
127
+ this.initApi(this.config);
128
+ }
129
+ else {
130
+ this.logEvent({ message: 'TrainingPeaks init done', hasCredentials: false });
131
+ }
132
+ isInitialized = true;
133
+ }
134
+ catch (err) {
135
+ this.logEvent({ message: 'error', error: err.message, fn: 'init', stack: err.stack });
136
+ isInitialized = false;
137
+ delete this.config;
138
+ }
139
+ return isInitialized;
140
+ }
141
+ updateConfig(config) {
142
+ const { accessToken, refreshToken, expiration } = config;
143
+ this.config = { ...this.config, accessToken, refreshToken, expiration };
144
+ this.saveCredentials();
145
+ }
146
+ saveCredentials(config) {
147
+ if (config)
148
+ this.config = config;
149
+ try {
150
+ if (!this.isConnected()) {
151
+ this.logEvent({ message: 'TrainingPeaks delete credentials' });
152
+ this.getUserSettings().set('user.auth.trainingpeaks', null);
153
+ return;
154
+ }
155
+ this.logEvent({ message: 'TrainingPeaks save credentials' });
156
+ this.getUserSettings().set('user.auth.trainingpeaks', {
157
+ accesstoken: this.config.accessToken,
158
+ refreshtoken: this.config.refreshToken,
159
+ expiration: this.config.expiration?.valueOf().toString()
160
+ });
161
+ }
162
+ catch (err) {
163
+ this.logEvent({ message: 'error', fn: 'saveCredentials', error: err.message, stack: err.stack });
164
+ }
165
+ this.logEvent({ message: 'TrainingPeaks save credentials done' });
166
+ }
167
+ buildConfigFromCredentials(credentials) {
168
+ return {
169
+ clientId: this.getSecret('TRAININGPEAKS_CLIENT_ID'),
170
+ clientSecret: this.getSecret('TRAININGPEAKS_CLIENT_SECRET'),
171
+ accessToken: credentials?.accesstoken,
172
+ refreshToken: credentials?.refreshtoken,
173
+ expiration: credentials?.expiration ? new Date(Number(credentials.expiration)) : undefined
174
+ };
175
+ }
176
+ initApi(config) {
177
+ const observer = this.getApi().init(config);
178
+ observer.on('token.updated', this.tokenUpdateHandler);
179
+ }
180
+ getSecret(key) {
181
+ return this.getSecretBindings()?.getSecret(key);
182
+ }
183
+ getSecretBindings() {
184
+ return getBindings()?.secret;
185
+ }
186
+ };
187
+ return TrainingPeaksAppConnection = _classThis;
188
+ })();
189
+ export { TrainingPeaksAppConnection };
@@ -0,0 +1 @@
1
+ export {};
@@ -1356,8 +1356,15 @@ let DeviceRideService = (() => {
1356
1356
  canEnforceSimulator() {
1357
1357
  const selected = getRouteList().getSelected();
1358
1358
  const personalApiKey = this.getGoogleMaps().hasPersonalApiKey();
1359
+ if (!selected?.description)
1360
+ return false;
1359
1361
  if (selected?.description?.hasVideo || personalApiKey)
1360
1362
  return true;
1363
+ if (!selected.description.hasVideo) {
1364
+ const rideView = useUserSettings().getValue('preferences.rideView', null);
1365
+ if (rideView === 'map')
1366
+ return true;
1367
+ }
1361
1368
  return useUserSettings().isNewUser();
1362
1369
  }
1363
1370
  logEvent(event) {
@@ -374,7 +374,7 @@ let RideDisplayService = (() => {
374
374
  return { ...props, ...childProps };
375
375
  }
376
376
  catch (err) {
377
- this.logError(err, 'getDisplayProperties');
377
+ this.logError(err, 'getDisplayProperties', { state: this.state });
378
378
  return { state: this.state };
379
379
  }
380
380
  }
@@ -422,7 +422,7 @@ let RideDisplayService = (() => {
422
422
  async stopRide(props = {}) {
423
423
  try {
424
424
  if (this.state !== 'Starting' && this.state !== 'Idle') {
425
- this.logEvent({ message: "activity stopped", activity: this.activity?.id });
425
+ this.logEvent({ message: "activity stopped", activity: this.activity?.id, lastState: this.state });
426
426
  }
427
427
  const prevState = this.state;
428
428
  this.state = prevState === 'Starting' ? 'Closing' : 'Finished';
@@ -446,7 +446,6 @@ let RideDisplayService = (() => {
446
446
  }
447
447
  if (prevState !== 'Starting')
448
448
  this.enableScreensaver();
449
- this.state = 'Idle';
450
449
  }
451
450
  catch (err) {
452
451
  this.logError(err, 'stopRide');
@@ -455,9 +454,10 @@ let RideDisplayService = (() => {
455
454
  }
456
455
  async closePrevRide() {
457
456
  try {
458
- if (this.observer || (this.state !== 'Idle')) {
457
+ if (this.observer || (this.state !== 'Idle' && this.state !== 'Finished')) {
459
458
  await this.stopRide({ noStateUpdates: true });
460
459
  }
460
+ this.state = 'Idle';
461
461
  }
462
462
  catch (err) {
463
463
  this.logError(err, 'init');
@@ -193,6 +193,12 @@ let RidePageService = (() => {
193
193
  }
194
194
  onMenuClose() {
195
195
  try {
196
+ const state = this.getRideDisplay().getState();
197
+ if (state === 'Finished' || this.menuProps.finished) {
198
+ this.moveToPreviousPage();
199
+ this.closePage();
200
+ return;
201
+ }
196
202
  this.menuProps = null;
197
203
  this.updatePageDisplay();
198
204
  }
@@ -220,6 +226,15 @@ let RidePageService = (() => {
220
226
  this.logError(err, 'onResume');
221
227
  }
222
228
  }
229
+ onFinished() {
230
+ try {
231
+ this.menuProps = { showResume: false, finished: true };
232
+ this.updatePageDisplay();
233
+ }
234
+ catch (err) {
235
+ this.logError(err, 'onResume');
236
+ }
237
+ }
223
238
  onEndRide() {
224
239
  try {
225
240
  this.getRideDisplay().stop();
@@ -333,6 +348,9 @@ let RidePageService = (() => {
333
348
  case 'Paused':
334
349
  this.menuProps = { showResume: true };
335
350
  break;
351
+ case 'Finished':
352
+ this.menuProps = { showResume: false, finished: true };
353
+ break;
336
354
  case 'Active':
337
355
  this.menuProps = null;
338
356
  break;
@@ -270,7 +270,7 @@ let RouteDisplayService = (() => {
270
270
  const mode = this.getDeviceRide().getCyclingMode();
271
271
  const isSIM = mode?.isSIM();
272
272
  const realityFactor = this.startSettings?.realityFactor ?? 100;
273
- const targetSlope = (this.position.slope ?? 0) * realityFactor / 100;
273
+ const targetSlope = (this.position?.slope ?? 0) * realityFactor / 100;
274
274
  if (props?.limits && !isSIM) {
275
275
  delete this.prevRequestSlope;
276
276
  return { ...props?.limits, slope: targetSlope };
@@ -50,6 +50,7 @@ import { useOnlineStatusMonitoring } from "../../../monitoring";
50
50
  import { distanceBetween } from "../../../utils/geo";
51
51
  import { getUnitConversionShortcuts } from "../../../i18n";
52
52
  import { Injectable } from "../../../base/decorators";
53
+ import { useAppState } from "../../../appstate";
53
54
  export const DEFAULT_TITLE = 'Import Route';
54
55
  export const DEFAULT_FILTERS = [
55
56
  { name: 'Routes', extensions: ['gpx', 'epm', 'xml', 'rlv', 'pgmf'] },
@@ -76,13 +77,16 @@ let RouteCard = (() => {
76
77
  let _instanceExtraInitializers = [];
77
78
  let _getBindings_decorators;
78
79
  let _getOnlineStatusMonitoring_decorators;
80
+ let _getAppState_decorators;
79
81
  return class RouteCard extends _classSuper {
80
82
  static {
81
83
  const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
82
84
  _getBindings_decorators = [Injectable];
83
85
  _getOnlineStatusMonitoring_decorators = [Injectable];
86
+ _getAppState_decorators = [Injectable];
84
87
  __esDecorate(this, null, _getBindings_decorators, { kind: "method", name: "getBindings", static: false, private: false, access: { has: obj => "getBindings" in obj, get: obj => obj.getBindings }, metadata: _metadata }, null, _instanceExtraInitializers);
85
88
  __esDecorate(this, null, _getOnlineStatusMonitoring_decorators, { kind: "method", name: "getOnlineStatusMonitoring", static: false, private: false, access: { has: obj => "getOnlineStatusMonitoring" in obj, get: obj => obj.getOnlineStatusMonitoring }, metadata: _metadata }, null, _instanceExtraInitializers);
89
+ __esDecorate(this, null, _getAppState_decorators, { kind: "method", name: "getAppState", static: false, private: false, access: { has: obj => "getAppState" in obj, get: obj => obj.getAppState }, metadata: _metadata }, null, _instanceExtraInitializers);
86
90
  if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
87
91
  }
88
92
  downloadObserver = __runInitializers(this, _instanceExtraInitializers);
@@ -367,11 +371,14 @@ let RouteCard = (() => {
367
371
  }
368
372
  let showLoopOverwrite, showNextOverwrite;
369
373
  let hasWorkout = true;
374
+ let showWorkoutOption = false;
370
375
  try {
371
376
  showLoopOverwrite = this.route?.description?.isLoop;
372
377
  const next = getNextVideoId(this.route);
373
378
  showNextOverwrite = !!next;
374
379
  hasWorkout = valid(workouts.getSelected());
380
+ const workoutsEnabled = this.isMobile() ? this.getAppState().hasFeature('MOBILE_WORKOUTS') : true;
381
+ showWorkoutOption = workoutsEnabled && !hasWorkout;
375
382
  if (showNextOverwrite) {
376
383
  const card = getRouteList().getCard(next);
377
384
  const route = card?.getData();
@@ -389,7 +396,7 @@ let RouteCard = (() => {
389
396
  const totalElevation = { value: C(this.route.description.elevation, 'elevation', { digits: 0 }), unit: uEl };
390
397
  const xScale = { value: C(1, 'distance'), unit: uDist };
391
398
  const yScale = { value: C(1, 'elevation'), unit: uEl };
392
- return { settings: uiSettings, totalDistance, totalElevation, showLoopOverwrite, showNextOverwrite, hasWorkout, canStart, videoChecking, videoMissing,
399
+ return { settings: uiSettings, totalDistance, totalElevation, showLoopOverwrite, showNextOverwrite, hasWorkout, showWorkoutOption, canStart, videoChecking, videoMissing,
393
400
  xScale, yScale,
394
401
  updateStartPos: this.updateStartPos.bind(this),
395
402
  updateMarkers: this.updateMarkers.bind(this)
@@ -906,6 +913,9 @@ let RouteCard = (() => {
906
913
  getOnlineStatusMonitoring() {
907
914
  return useOnlineStatusMonitoring();
908
915
  }
916
+ getAppState() {
917
+ return useAppState();
918
+ }
909
919
  getRouteDownload() {
910
920
  return useRouteDownload();
911
921
  }
@@ -0,0 +1,201 @@
1
+ var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
2
+ var useValue = arguments.length > 2;
3
+ for (var i = 0; i < initializers.length; i++) {
4
+ value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
5
+ }
6
+ return useValue ? value : void 0;
7
+ };
8
+ var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
9
+ function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
10
+ var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
11
+ var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
12
+ var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
13
+ var _, done = false;
14
+ for (var i = decorators.length - 1; i >= 0; i--) {
15
+ var context = {};
16
+ for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
17
+ for (var p in contextIn.access) context.access[p] = contextIn.access[p];
18
+ context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
19
+ var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
20
+ if (kind === "accessor") {
21
+ if (result === void 0) continue;
22
+ if (result === null || typeof result !== "object") throw new TypeError("Object expected");
23
+ if (_ = accept(result.get)) descriptor.get = _;
24
+ if (_ = accept(result.set)) descriptor.set = _;
25
+ if (_ = accept(result.init)) initializers.unshift(_);
26
+ }
27
+ else if (_ = accept(result)) {
28
+ if (kind === "field") initializers.unshift(_);
29
+ else descriptor[key] = _;
30
+ }
31
+ }
32
+ if (target) Object.defineProperty(target, contextIn.name, descriptor);
33
+ done = true;
34
+ };
35
+ import { useAppsService } from '../../../../apps';
36
+ import { TrainingPeaksAppConnection } from '../../../../apps/trainingpeaks/TrainingPeaksAppConnection';
37
+ import { Injectable } from '../../../../base/decorators';
38
+ import { IncyclistService } from '../../../../base/service';
39
+ import { Observer } from '../../../../base/types';
40
+ import { getFirstDayOfCurrentWeek, waitNextTick } from '../../../../utils';
41
+ import { ZwoParser } from '../../../base/parsers/zwo/zwo';
42
+ import { WorkoutSyncFactory } from '../factory';
43
+ const SYNC_DAYS = 30;
44
+ let TrainingPeaksCalendarSyncProvider = (() => {
45
+ let _classSuper = IncyclistService;
46
+ let _instanceExtraInitializers = [];
47
+ let _getApi_decorators;
48
+ let _getConnection_decorators;
49
+ let _getAppsService_decorators;
50
+ return class TrainingPeaksCalendarSyncProvider extends _classSuper {
51
+ static {
52
+ const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
53
+ _getApi_decorators = [Injectable];
54
+ _getConnection_decorators = [Injectable];
55
+ _getAppsService_decorators = [Injectable];
56
+ __esDecorate(this, null, _getApi_decorators, { kind: "method", name: "getApi", static: false, private: false, access: { has: obj => "getApi" in obj, get: obj => obj.getApi }, metadata: _metadata }, null, _instanceExtraInitializers);
57
+ __esDecorate(this, null, _getConnection_decorators, { kind: "method", name: "getConnection", static: false, private: false, access: { has: obj => "getConnection" in obj, get: obj => obj.getConnection }, metadata: _metadata }, null, _instanceExtraInitializers);
58
+ __esDecorate(this, null, _getAppsService_decorators, { kind: "method", name: "getAppsService", static: false, private: false, access: { has: obj => "getAppsService" in obj, get: obj => obj.getAppsService }, metadata: _metadata }, null, _instanceExtraInitializers);
59
+ if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
60
+ }
61
+ lastSyncTS = __runInitializers(this, _instanceExtraInitializers);
62
+ observer;
63
+ stopRequested;
64
+ workouts;
65
+ constructor() {
66
+ super('TrainingPeaksCalendarSync');
67
+ this.lastSyncTS = 0;
68
+ this.workouts = [];
69
+ }
70
+ sync() {
71
+ if (this.observer)
72
+ return this.observer;
73
+ this.observer = new Observer();
74
+ const onDone = () => {
75
+ waitNextTick().then(() => {
76
+ this.stopRequested = false;
77
+ delete this.observer;
78
+ });
79
+ };
80
+ this.observer.once('done', onDone);
81
+ this.observer.once('loaded', onDone);
82
+ this.observer.once('stop', () => { this.stopSync(); });
83
+ this.loadWorkouts();
84
+ return this.observer;
85
+ }
86
+ isConnected() {
87
+ try {
88
+ if (this.getApi().isAuthenticated())
89
+ return true;
90
+ return this.getConnection().isConnected();
91
+ }
92
+ catch {
93
+ return false;
94
+ }
95
+ }
96
+ reset() {
97
+ this.lastSyncTS = 0;
98
+ this.workouts = [];
99
+ }
100
+ stopSync() {
101
+ this.stopRequested = true;
102
+ }
103
+ async loadWorkouts() {
104
+ const isFirst = this.lastSyncTS === 0;
105
+ const event = isFirst ? 'loaded' : 'done';
106
+ try {
107
+ if (!this.isConnected()) {
108
+ this.observer.emit(event, [], 'trainingpeaks');
109
+ return [];
110
+ }
111
+ if (!this.getAppsService().isEnabled('trainingpeaks', 'WorkoutDownload')) {
112
+ await waitNextTick();
113
+ this.observer.emit(event, [], 'trainingpeaks');
114
+ return [];
115
+ }
116
+ const oldest = getFirstDayOfCurrentWeek();
117
+ const newest = new Date(oldest.valueOf() + SYNC_DAYS * 24 * 60 * 60 * 1000);
118
+ const all = await this.getApi().getCalendarWorkouts({ oldest, newest }) ?? [];
119
+ const bike = all.filter(w => w.WorkoutType === 'Bike');
120
+ await this.parseWorkouts(bike);
121
+ this.observer.emit(event, this.workouts, 'trainingpeaks');
122
+ this.lastSyncTS = Date.now();
123
+ return this.workouts;
124
+ }
125
+ catch {
126
+ this.observer.emit(event, [], 'trainingpeaks');
127
+ return [];
128
+ }
129
+ }
130
+ async parseWorkouts(workouts) {
131
+ const zwoParser = new ZwoParser();
132
+ const promises = [];
133
+ const transform = async (w) => {
134
+ try {
135
+ const day = new Date(w.WorkoutDay);
136
+ const updated = w.LastModifiedDate ? new Date(w.LastModifiedDate) : undefined;
137
+ if (!w.WorkoutFileFormats?.includes('zwo')) {
138
+ this.logEvent({
139
+ message: 'workout skipped - no ZWO format available',
140
+ workoutId: w.Id,
141
+ title: w.Title,
142
+ availableFormats: w.WorkoutFileFormats ?? []
143
+ });
144
+ return;
145
+ }
146
+ const fileContent = await this.getApi().getWorkoutFile(w.Id, 'zwo');
147
+ const workout = await zwoParser.fromStr(fileContent, w.Title);
148
+ const entry = {
149
+ day,
150
+ updated,
151
+ workoutId: String(w.Id),
152
+ workout
153
+ };
154
+ const existingIdx = this.workouts.findIndex(e => e.workoutId === String(w.Id));
155
+ const isExisting = existingIdx !== -1;
156
+ if (this.lastSyncTS > 0) {
157
+ if (!isExisting) {
158
+ this.observer.emit('added', entry, 'trainingpeaks');
159
+ }
160
+ else if (updated && updated.valueOf() > this.lastSyncTS) {
161
+ this.observer.emit('updated', entry, 'trainingpeaks');
162
+ }
163
+ }
164
+ if (isExisting) {
165
+ this.workouts[existingIdx] = entry;
166
+ }
167
+ else {
168
+ this.workouts.push(entry);
169
+ }
170
+ }
171
+ catch (err) {
172
+ this.logEvent({ message: 'error parsing workout', error: err.message, workoutId: w.Id, title: w.Title });
173
+ }
174
+ };
175
+ if (this.lastSyncTS > 0) {
176
+ const deleted = this.workouts.filter(e => !workouts.some(w => String(w.Id) === e.workoutId));
177
+ for (const e of deleted) {
178
+ this.observer.emit('deleted', e, 'trainingpeaks');
179
+ }
180
+ this.workouts = this.workouts.filter(e => workouts.some(w => String(w.Id) === e.workoutId));
181
+ }
182
+ for (const w of workouts) {
183
+ promises.push(transform(w));
184
+ }
185
+ await Promise.all(promises);
186
+ return this.workouts;
187
+ }
188
+ getApi() {
189
+ return this.getConnection().getApi();
190
+ }
191
+ getConnection() {
192
+ return new TrainingPeaksAppConnection();
193
+ }
194
+ getAppsService() {
195
+ return useAppsService();
196
+ }
197
+ };
198
+ })();
199
+ export { TrainingPeaksCalendarSyncProvider };
200
+ const factory = new WorkoutSyncFactory();
201
+ factory.add('trainingpeaks', new TrainingPeaksCalendarSyncProvider());
@@ -1,2 +1,3 @@
1
1
  export * from './service';
2
2
  export * from './cards';
3
+ export * from './pageService';
@@ -0,0 +1,94 @@
1
+ var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
2
+ var useValue = arguments.length > 2;
3
+ for (var i = 0; i < initializers.length; i++) {
4
+ value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
5
+ }
6
+ return useValue ? value : void 0;
7
+ };
8
+ var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
9
+ function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
10
+ var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
11
+ var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
12
+ var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
13
+ var _, done = false;
14
+ for (var i = decorators.length - 1; i >= 0; i--) {
15
+ var context = {};
16
+ for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
17
+ for (var p in contextIn.access) context.access[p] = contextIn.access[p];
18
+ context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
19
+ var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
20
+ if (kind === "accessor") {
21
+ if (result === void 0) continue;
22
+ if (result === null || typeof result !== "object") throw new TypeError("Object expected");
23
+ if (_ = accept(result.get)) descriptor.get = _;
24
+ if (_ = accept(result.set)) descriptor.set = _;
25
+ if (_ = accept(result.init)) initializers.unshift(_);
26
+ }
27
+ else if (_ = accept(result)) {
28
+ if (kind === "field") initializers.unshift(_);
29
+ else descriptor[key] = _;
30
+ }
31
+ }
32
+ if (target) Object.defineProperty(target, contextIn.name, descriptor);
33
+ done = true;
34
+ };
35
+ import { Singleton } from "../../base/types";
36
+ import { IncyclistPageService } from "../../base/pages";
37
+ import { Injectable } from "../../base/decorators";
38
+ import { useAppState } from "../../appstate";
39
+ let WorkoutListPageService = (() => {
40
+ let _classDecorators = [Singleton];
41
+ let _classDescriptor;
42
+ let _classExtraInitializers = [];
43
+ let _classThis;
44
+ let _classSuper = IncyclistPageService;
45
+ let _instanceExtraInitializers = [];
46
+ let _getAppState_decorators;
47
+ var WorkoutListPageService = class extends _classSuper {
48
+ static { _classThis = this; }
49
+ static {
50
+ const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
51
+ _getAppState_decorators = [Injectable];
52
+ __esDecorate(this, null, _getAppState_decorators, { kind: "method", name: "getAppState", static: false, private: false, access: { has: obj => "getAppState" in obj, get: obj => obj.getAppState }, metadata: _metadata }, null, _instanceExtraInitializers);
53
+ __esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
54
+ WorkoutListPageService = _classThis = _classDescriptor.value;
55
+ if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
56
+ __runInitializers(_classThis, _classExtraInitializers);
57
+ }
58
+ constructor() {
59
+ super('WorkoutListPage');
60
+ __runInitializers(this, _instanceExtraInitializers);
61
+ }
62
+ openPage() {
63
+ try {
64
+ super.openPage();
65
+ this.logEvent({ message: 'page shown', page: 'Workouts' });
66
+ return this.getPageObserver();
67
+ }
68
+ catch (err) {
69
+ this.logError(err, 'openPage');
70
+ }
71
+ }
72
+ closePage() {
73
+ try {
74
+ this.logEvent({ message: 'page closed', page: 'Workouts' });
75
+ super.closePage();
76
+ }
77
+ catch (err) {
78
+ this.logError(err, 'closePage');
79
+ }
80
+ }
81
+ getPageDisplayProps() {
82
+ if (!this.getAppState().hasFeature('MOBILE_WORKOUTS')) {
83
+ return { pageType: 'placeholder' };
84
+ }
85
+ return { pageType: 'list' };
86
+ }
87
+ getAppState() {
88
+ return useAppState();
89
+ }
90
+ };
91
+ return WorkoutListPageService = _classThis;
92
+ })();
93
+ export { WorkoutListPageService };
94
+ export const getWorkoutListPageService = () => new WorkoutListPageService();