incyclist-services 1.5.3 → 1.5.5
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.
- package/lib/devices/ride/service.js +5 -3
- package/lib/ride/display/service.js +2 -2
- package/lib/ride/route/GpxDisplayService.js +12 -2
- package/lib/routes/base/parsers/incyclist.js +8 -2
- package/lib/routes/base/utils/points.d.ts +1 -0
- package/lib/routes/base/utils/points.js +227 -148
- package/lib/workouts/list/cards/WorkoutCard.d.ts +1 -0
- package/lib/workouts/list/cards/WorkoutCard.js +248 -191
- package/lib/workouts/list/cards/types.d.ts +1 -0
- package/package.json +1 -1
|
@@ -129,9 +129,11 @@ let DeviceRideService = (() => {
|
|
|
129
129
|
return this.rideAdapters;
|
|
130
130
|
this.rideAdapters = this.adapters = this.getConfiguredAdapters(true);
|
|
131
131
|
const controlDevice = (_b = (_a = this.adapters.find(d => d.capabilities.includes('control'))) !== null && _a !== void 0 ? _a : this.adapters.find(d => d.capabilities.includes('power'))) !== null && _b !== void 0 ? _b : this.adapters.find(d => d.capabilities.includes('speed'));
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
132
|
+
if (controlDevice) {
|
|
133
|
+
this.rideAdapters.forEach(ai => {
|
|
134
|
+
ai.isControl = (ai.udid === controlDevice.udid);
|
|
135
|
+
});
|
|
136
|
+
}
|
|
135
137
|
if (!this.simulatorEnforced)
|
|
136
138
|
return this.adapters;
|
|
137
139
|
const adapter = incyclist_devices_1.AdapterFactory.create({ interface: 'simulator', name: 'Simulator' });
|
|
@@ -130,7 +130,7 @@ let RideDisplayService = (() => {
|
|
|
130
130
|
this.logEvent({ message: 'overlay shown', overlay: 'start overlay' });
|
|
131
131
|
}
|
|
132
132
|
catch (err) {
|
|
133
|
-
this.logError(err, '
|
|
133
|
+
this.logError(err, 'start');
|
|
134
134
|
}
|
|
135
135
|
}
|
|
136
136
|
startWithMissingSensors() {
|
|
@@ -409,7 +409,7 @@ let RideDisplayService = (() => {
|
|
|
409
409
|
this.state = 'Idle';
|
|
410
410
|
}
|
|
411
411
|
catch (err) {
|
|
412
|
-
this.logError(err, '
|
|
412
|
+
this.logError(err, 'stopRide');
|
|
413
413
|
}
|
|
414
414
|
delete this.type;
|
|
415
415
|
delete this.displayService;
|
|
@@ -164,9 +164,8 @@ let GpxDisplayService = (() => {
|
|
|
164
164
|
const rideView = this.getUserSettings().get('preferences.rideView', 'sv');
|
|
165
165
|
if (rideView === 'sv') {
|
|
166
166
|
const updatePending = (Date.now() - ((_b = this.tsPrevSVUpdate) !== null && _b !== void 0 ? _b : 0)) > this.getDefaultUpdateFrequency();
|
|
167
|
-
const stillBusy = (!this.tsPositionUpdateConfirmed && (Date.now() - ((_c = this.tsPrevSVUpdate) !== null && _c !== void 0 ? _c : 0)) < 500) || (Date.now() - this.tsLastSVEvent) < this.getMinimalPause();
|
|
167
|
+
const stillBusy = (!this.tsPositionUpdateConfirmed && (Date.now() - ((_c = this.tsPrevSVUpdate) !== null && _c !== void 0 ? _c : 0)) < 500) || (Date.now() - ((_d = this.tsLastSVEvent) !== null && _d !== void 0 ? _d : 0)) < this.getMinimalPause();
|
|
168
168
|
const updatePossible = this.tsPositionUpdateConfirmed && (Date.now() - this.tsLastSVEvent) > this.getBestCaseUpdateFrequency();
|
|
169
|
-
console.log('# service.onPositionUpdate', rideView, this.tsLastSVEvent - ((_d = this.tsPrevSVUpdate) !== null && _d !== void 0 ? _d : 0), Object.assign({ stillBusy, updatePossible, updatePending }, state));
|
|
170
169
|
if ((!stillBusy || !this.tsPrevSVUpdate) && (updatePending || updatePossible)) {
|
|
171
170
|
if (position) {
|
|
172
171
|
const freq = this.tsPrevSVUpdate ? Date.now() - this.tsPrevSVUpdate : undefined;
|
|
@@ -180,6 +179,17 @@ let GpxDisplayService = (() => {
|
|
|
180
179
|
delete this.tsLastSVEvent;
|
|
181
180
|
}
|
|
182
181
|
}
|
|
182
|
+
else {
|
|
183
|
+
const duration = this.tsPrevSVUpdate ? Date.now() - this.tsPrevSVUpdate : undefined;
|
|
184
|
+
if (stillBusy) {
|
|
185
|
+
this.logEvent({ message: 'street view position update skipped', reason: 'busy', duration });
|
|
186
|
+
if (duration > 10000) {
|
|
187
|
+
delete this.tsPrevSVUpdate;
|
|
188
|
+
delete this.tsPositionUpdateConfirmed;
|
|
189
|
+
delete this.tsLastSVEvent;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
183
193
|
}
|
|
184
194
|
else {
|
|
185
195
|
console.log('# position update', this.position);
|
|
@@ -58,8 +58,14 @@ class IncyclistXMLParser extends xml_1.XMLParser {
|
|
|
58
58
|
try {
|
|
59
59
|
if (context.data['autoCorrect']) {
|
|
60
60
|
const gpx = yield new gpx_1.GPXParser({ addTime: true, keepZero: true }).import(gpxFile);
|
|
61
|
-
|
|
62
|
-
(0, points_1.fixAnomalies)(
|
|
61
|
+
const points = [...gpx.details.points];
|
|
62
|
+
const { fixed, time, error } = (0, points_1.fixAnomalies)(points);
|
|
63
|
+
this.logger.logEvent({ message: 'gpx file autocorrect', cntFixed: fixed, duration: time, error: error === null || error === void 0 ? void 0 : error.message });
|
|
64
|
+
if (error) {
|
|
65
|
+
route.points = gpx.details.points;
|
|
66
|
+
}
|
|
67
|
+
route.points = route.points.filter(p => p.distance !== 0);
|
|
68
|
+
route.points.forEach((p, idx) => { p.cnt = idx; });
|
|
63
69
|
(0, utils_2.validateRoute)(route);
|
|
64
70
|
}
|
|
65
71
|
else {
|
|
@@ -12,6 +12,7 @@ interface Anomaly {
|
|
|
12
12
|
retry?: number;
|
|
13
13
|
}
|
|
14
14
|
export declare const calculateSpeed: (points: RoutePoint[], idx: number) => number;
|
|
15
|
+
export declare const getPointsWithSpeed: (points: RoutePoint[]) => RoutePointEval[];
|
|
15
16
|
export declare const detectAnomalies: (points: RoutePoint[], maxCount?: number) => Anomaly[];
|
|
16
17
|
export declare const fixAnomaly: (anomaly: Anomaly, points: RoutePoint[]) => void;
|
|
17
18
|
export declare const fixAnomalies: (points: RoutePoint[], maxAttempts?: number) => {
|
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.fixAnomalies = exports.fixAnomaly = exports.detectAnomalies = exports.calculateSpeed = void 0;
|
|
4
|
-
const MAX_LOOKUP =
|
|
3
|
+
exports.fixAnomalies = exports.fixAnomaly = exports.detectAnomalies = exports.getPointsWithSpeed = exports.calculateSpeed = void 0;
|
|
4
|
+
const MAX_LOOKUP = 100;
|
|
5
|
+
const isJump = (v1, v2) => {
|
|
6
|
+
if (v2 === v1 || v1 < 0.2 || v2 < 0.2)
|
|
7
|
+
return false;
|
|
8
|
+
return (Math.abs(v2 - v1) > 3) ||
|
|
9
|
+
(v2 > v1 * 1.4 && Math.abs(v2 - v1) > 2);
|
|
10
|
+
};
|
|
5
11
|
const calculateSpeed = (points, idx) => {
|
|
6
12
|
const p = points === null || points === void 0 ? void 0 : points[idx];
|
|
7
13
|
if (!p || idx === 0)
|
|
@@ -11,51 +17,73 @@ const calculateSpeed = (points, idx) => {
|
|
|
11
17
|
return speed;
|
|
12
18
|
};
|
|
13
19
|
exports.calculateSpeed = calculateSpeed;
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
return [];
|
|
17
|
-
const data = points.map((p, idx) => {
|
|
20
|
+
const getPointsWithSpeed = (points) => {
|
|
21
|
+
return points.map((p, idx) => {
|
|
18
22
|
const d = Object.assign({}, p);
|
|
19
23
|
d.speed = (0, exports.calculateSpeed)(points, idx);
|
|
20
24
|
return d;
|
|
21
25
|
});
|
|
26
|
+
};
|
|
27
|
+
exports.getPointsWithSpeed = getPointsWithSpeed;
|
|
28
|
+
const detectAnomalies = (points, maxCount) => {
|
|
29
|
+
if (points[0].time === undefined)
|
|
30
|
+
return [];
|
|
31
|
+
const data = (0, exports.getPointsWithSpeed)(points);
|
|
22
32
|
const anomalies = [];
|
|
23
33
|
let lastValidSpeedIdx = 0;
|
|
24
34
|
let done = false;
|
|
25
35
|
const isSpeedJump = (p1, p2) => {
|
|
26
|
-
return
|
|
27
|
-
p2.speed > p1.speed * 1.5 && p2.speed > 2 ||
|
|
28
|
-
Math.abs(p2.speed - p1.speed) > 3;
|
|
36
|
+
return isJump(p1.speed, p2.speed);
|
|
29
37
|
};
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
38
|
+
const isCloseToNull = (p) => {
|
|
39
|
+
return (p.distance < 0.5 || p.speed < 0.5);
|
|
40
|
+
};
|
|
41
|
+
const onNullValueDetected = (point, idx) => {
|
|
42
|
+
const speedPrev = data[idx - 1].speed;
|
|
43
|
+
if (speedPrev < 2)
|
|
33
44
|
return;
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
45
|
+
const speedNext = data[idx + 1].speed;
|
|
46
|
+
if (speedPrev > speedNext && !isJump(speedPrev / 2, speedNext)) {
|
|
47
|
+
anomalies.push({ idx: idx - 1, type: 'speedJump', point, nextNullIdx: idx });
|
|
48
|
+
}
|
|
49
|
+
let nextJumpIdx;
|
|
50
|
+
const idxPrev = lastValidSpeedIdx === 0 ? idx - 1 : lastValidSpeedIdx;
|
|
51
|
+
for (let j = idx + 1; j < idx + MAX_LOOKUP && nextJumpIdx === undefined; j++) {
|
|
52
|
+
if (isSpeedJump(data[idxPrev], data[j])) {
|
|
53
|
+
nextJumpIdx = j;
|
|
41
54
|
}
|
|
42
|
-
anomalies.push({ idx, type: 'noDistance', point, nextJumpIdx });
|
|
43
55
|
}
|
|
56
|
+
anomalies.push({ idx, type: 'noDistance', point, nextJumpIdx });
|
|
57
|
+
};
|
|
58
|
+
const onSpeedJumpDetected = (point, idx) => {
|
|
44
59
|
const prevPoint = data[lastValidSpeedIdx];
|
|
45
|
-
|
|
46
|
-
if (
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
60
|
+
let nextJumpIdx, nextNullIdx;
|
|
61
|
+
if (prevPoint.speed === 0) {
|
|
62
|
+
anomalies.push({ idx: lastValidSpeedIdx, type: 'noDistance', point });
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
let nextJumpFound = false;
|
|
66
|
+
for (let j = idx + 1; j < idx + MAX_LOOKUP && !nextJumpFound && nextNullIdx === undefined; j++) {
|
|
67
|
+
if (isCloseToNull(data[j])) {
|
|
68
|
+
nextNullIdx = j;
|
|
69
|
+
}
|
|
70
|
+
else if (j > idx + 1 && isSpeedJump(data[j], data[j - 1])) {
|
|
71
|
+
nextJumpFound = true;
|
|
72
|
+
continue;
|
|
56
73
|
}
|
|
57
|
-
anomalies.push({ idx, type: 'speedJump', point, nextNullIdx });
|
|
58
74
|
}
|
|
75
|
+
anomalies.push({ idx, type: 'speedJump', point, nextNullIdx, nextJumpIdx });
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
data.forEach((point, idx) => {
|
|
79
|
+
var _a;
|
|
80
|
+
if (idx === 0 || done)
|
|
81
|
+
return;
|
|
82
|
+
if (point.speed === 0 || point.distance === 0) {
|
|
83
|
+
onNullValueDetected(point, idx);
|
|
84
|
+
}
|
|
85
|
+
else if (isSpeedJump(data[lastValidSpeedIdx], point)) {
|
|
86
|
+
onSpeedJumpDetected(point, idx);
|
|
59
87
|
}
|
|
60
88
|
if (!!maxCount && anomalies.length > maxCount - 1) {
|
|
61
89
|
done = true;
|
|
@@ -70,119 +98,10 @@ const detectAnomalies = (points, maxCount) => {
|
|
|
70
98
|
exports.detectAnomalies = detectAnomalies;
|
|
71
99
|
const fixAnomaly = (anomaly, points) => {
|
|
72
100
|
if (anomaly.type === 'speedJump') {
|
|
73
|
-
|
|
74
|
-
const idx = anomaly.idx;
|
|
75
|
-
const idxNull = anomaly.nextNullIdx;
|
|
76
|
-
let offset;
|
|
77
|
-
if (idxNull === idx + 1) {
|
|
78
|
-
offset = ((0, exports.calculateSpeed)(points, idx) - (0, exports.calculateSpeed)(points, idxNull)) / 2;
|
|
79
|
-
const t = points[idx].time - points[idx - 1].time;
|
|
80
|
-
const vPrev = (0, exports.calculateSpeed)(points, idx);
|
|
81
|
-
const v = vPrev - offset;
|
|
82
|
-
const d = v * t;
|
|
83
|
-
const dOffset = points[idx].distance - d;
|
|
84
|
-
points[idx].distance = d;
|
|
85
|
-
points[idx].routeDistance -= dOffset;
|
|
86
|
-
const t0 = points[idxNull].time - points[idxNull - 1].time;
|
|
87
|
-
const v0 = offset;
|
|
88
|
-
points[idxNull].distance += v0 * t0;
|
|
89
|
-
}
|
|
90
|
-
else {
|
|
91
|
-
const offsetEnd = (0, exports.calculateSpeed)(points, idxNull - 1) - (0, exports.calculateSpeed)(points, idx - 1);
|
|
92
|
-
const offsetStart = (0, exports.calculateSpeed)(points, idx) - (0, exports.calculateSpeed)(points, idx - 1);
|
|
93
|
-
const offsetAverage = (offsetStart + offsetEnd) / 2;
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
if (anomaly.nextNullIdx !== undefined) {
|
|
97
|
-
const idx = anomaly.idx;
|
|
98
|
-
const idxNull = anomaly.nextNullIdx;
|
|
99
|
-
const offsetNext = idxNull === idx + 1 ? (0, exports.calculateSpeed)(points, idx) / 2 : (0, exports.calculateSpeed)(points, idxNull - 1);
|
|
100
|
-
const offsetPrev = idxNull === idx + 1 ? offsetNext : (0, exports.calculateSpeed)(points, idx) - (0, exports.calculateSpeed)(points, idx - 1);
|
|
101
|
-
const offset = (offsetNext + offsetPrev) / 2;
|
|
102
|
-
const t = points[idx].time - points[idx - 1].time;
|
|
103
|
-
const vPrev = (0, exports.calculateSpeed)(points, idx);
|
|
104
|
-
const v = vPrev - offset;
|
|
105
|
-
const d = v * t;
|
|
106
|
-
const dOffset = points[idx].distance - d;
|
|
107
|
-
points[idx].distance = d;
|
|
108
|
-
points[idx].routeDistance -= dOffset;
|
|
109
|
-
for (let j = idx + 1; j < idxNull; j++) {
|
|
110
|
-
points[j].routeDistance -= dOffset;
|
|
111
|
-
}
|
|
112
|
-
const t0 = points[idxNull].time - points[idxNull - 1].time;
|
|
113
|
-
const v0 = offset;
|
|
114
|
-
points[idxNull].distance = v0 * t0;
|
|
115
|
-
}
|
|
116
|
-
else {
|
|
117
|
-
const idx = anomaly.idx;
|
|
118
|
-
const next = points === null || points === void 0 ? void 0 : points[idx + 1];
|
|
119
|
-
const prev = points === null || points === void 0 ? void 0 : points[idx - 1];
|
|
120
|
-
if (next && prev) {
|
|
121
|
-
next.distance = next.routeDistance - prev.routeDistance;
|
|
122
|
-
}
|
|
123
|
-
points.splice(idx, 1);
|
|
124
|
-
}
|
|
101
|
+
fixSpeedJump(anomaly, points);
|
|
125
102
|
}
|
|
126
103
|
else if (anomaly.type === 'noDistance') {
|
|
127
|
-
|
|
128
|
-
const next = points === null || points === void 0 ? void 0 : points[idx + 1];
|
|
129
|
-
const prev = points === null || points === void 0 ? void 0 : points[idx - 1];
|
|
130
|
-
if (anomaly.nextJumpIdx !== undefined) {
|
|
131
|
-
const endIdx = anomaly.nextJumpIdx;
|
|
132
|
-
const vEnd = (0, exports.calculateSpeed)(points, endIdx);
|
|
133
|
-
const vStart = (0, exports.calculateSpeed)(points, endIdx - 1);
|
|
134
|
-
if (endIdx === idx + 1) {
|
|
135
|
-
const offset = vEnd / 2;
|
|
136
|
-
const t0 = points[idx].time - points[idx - 1].time;
|
|
137
|
-
const v0 = offset;
|
|
138
|
-
const d0 = v0 * t0;
|
|
139
|
-
points[idx].distance = d0;
|
|
140
|
-
points[idx].routeDistance += d0;
|
|
141
|
-
const t = points[endIdx].time - points[endIdx - 1].time;
|
|
142
|
-
const vPrev = (0, exports.calculateSpeed)(points, endIdx);
|
|
143
|
-
const v = vPrev - offset;
|
|
144
|
-
const d = v * t;
|
|
145
|
-
points[endIdx].distance = d;
|
|
146
|
-
}
|
|
147
|
-
else {
|
|
148
|
-
const offset = vEnd - vStart;
|
|
149
|
-
for (let j = anomaly.idx; j < endIdx; j++) {
|
|
150
|
-
const t = points[j].time - points[j - 1].time;
|
|
151
|
-
const vPrev = (0, exports.calculateSpeed)(points, j);
|
|
152
|
-
const v = vPrev + offset;
|
|
153
|
-
const d = v * t;
|
|
154
|
-
const dOffset = points[j].distance - d;
|
|
155
|
-
points[j].distance = d;
|
|
156
|
-
points[j].routeDistance += dOffset;
|
|
157
|
-
}
|
|
158
|
-
const t = points[endIdx].time - points[endIdx - 1].time;
|
|
159
|
-
const vPrev = (0, exports.calculateSpeed)(points, endIdx);
|
|
160
|
-
const v = vPrev - offset;
|
|
161
|
-
const d = v * t;
|
|
162
|
-
points[endIdx].distance = d;
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
else {
|
|
166
|
-
if (idx > 2 && idx < points.length - 2) {
|
|
167
|
-
const s = points[idx + 2].routeDistance - points[idx - 2].routeDistance;
|
|
168
|
-
const t = points[idx + 2].time - points[idx - 2].time;
|
|
169
|
-
const avgSpeed = s / t;
|
|
170
|
-
const nextSpeed = (0, exports.calculateSpeed)(points, idx + 1);
|
|
171
|
-
const prevSpeed = (0, exports.calculateSpeed)(points, idx - 1);
|
|
172
|
-
if ((Math.abs(prevSpeed - avgSpeed) - Math.abs(nextSpeed - avgSpeed)) > 0.5) {
|
|
173
|
-
points[idx].distance = points[idx].routeDistance - points[idx - 2].routeDistance;
|
|
174
|
-
points.splice(idx - 1, 1);
|
|
175
|
-
}
|
|
176
|
-
else {
|
|
177
|
-
next.distance = next.routeDistance - prev.routeDistance;
|
|
178
|
-
points.splice(idx, 1);
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
else {
|
|
182
|
-
next.distance = next.routeDistance - prev.routeDistance;
|
|
183
|
-
points.splice(idx, 1);
|
|
184
|
-
}
|
|
185
|
-
}
|
|
104
|
+
fixNoDistance(anomaly, points);
|
|
186
105
|
}
|
|
187
106
|
};
|
|
188
107
|
exports.fixAnomaly = fixAnomaly;
|
|
@@ -194,19 +113,23 @@ const fixAnomalies = (points, maxAttempts = 1000) => {
|
|
|
194
113
|
let prev;
|
|
195
114
|
let stuck = false;
|
|
196
115
|
let error;
|
|
116
|
+
let retry = 0;
|
|
197
117
|
const fixedRecords = [];
|
|
198
118
|
try {
|
|
199
119
|
do {
|
|
200
120
|
anomalies = (0, exports.detectAnomalies)(points, 1);
|
|
201
121
|
if (anomalies.length > 0) {
|
|
202
122
|
const current = anomalies[0];
|
|
203
|
-
if ((prev === null || prev === void 0 ? void 0 : prev.idx) === current.idx) {
|
|
123
|
+
if ((prev === null || prev === void 0 ? void 0 : prev.idx) === current.idx && ++retry > 5) {
|
|
204
124
|
stuck = true;
|
|
205
125
|
continue;
|
|
206
126
|
}
|
|
207
|
-
else
|
|
208
|
-
|
|
209
|
-
current.
|
|
127
|
+
else {
|
|
128
|
+
retry = 0;
|
|
129
|
+
if ((prev === null || prev === void 0 ? void 0 : prev.type) === current.type && (prev === null || prev === void 0 ? void 0 : prev.type) === 'speedJump' && current.idx > (prev === null || prev === void 0 ? void 0 : prev.idx) && current.idx < (prev === null || prev === void 0 ? void 0 : prev.nextNullIdx)) {
|
|
130
|
+
current.nextNullIdx = prev.nextNullIdx;
|
|
131
|
+
current.retry = ((_a = prev.retry) !== null && _a !== void 0 ? _a : 0) + 1;
|
|
132
|
+
}
|
|
210
133
|
}
|
|
211
134
|
(0, exports.fixAnomaly)(anomalies[0], points);
|
|
212
135
|
fixedRecords.push(anomalies[0]);
|
|
@@ -223,5 +146,161 @@ const fixAnomalies = (points, maxAttempts = 1000) => {
|
|
|
223
146
|
return { fixed, time: tsStop - tsStart, fixedRecords, error };
|
|
224
147
|
};
|
|
225
148
|
exports.fixAnomalies = fixAnomalies;
|
|
226
|
-
const
|
|
149
|
+
const fixNoDistance = (anomaly, points) => {
|
|
150
|
+
const idx = anomaly.idx;
|
|
151
|
+
const next = points === null || points === void 0 ? void 0 : points[idx + 1];
|
|
152
|
+
const prev = points === null || points === void 0 ? void 0 : points[idx - 1];
|
|
153
|
+
const fixNullWithoutJump = () => {
|
|
154
|
+
if (idx > 2 && idx < points.length - 2) {
|
|
155
|
+
const s = points[idx + 2].routeDistance - points[idx - 2].routeDistance;
|
|
156
|
+
const t = points[idx + 2].time - points[idx - 2].time;
|
|
157
|
+
const avgSpeed = s / t;
|
|
158
|
+
const nextSpeed = (0, exports.calculateSpeed)(points, idx + 1);
|
|
159
|
+
const prevSpeed = (0, exports.calculateSpeed)(points, idx - 1);
|
|
160
|
+
if ((Math.abs(prevSpeed - avgSpeed) - Math.abs(nextSpeed - avgSpeed)) > 0.5) {
|
|
161
|
+
points[idx].distance = points[idx].routeDistance - points[idx - 2].routeDistance;
|
|
162
|
+
points.splice(idx - 1, 1);
|
|
163
|
+
}
|
|
164
|
+
else {
|
|
165
|
+
next.distance = next.routeDistance - prev.routeDistance;
|
|
166
|
+
points.splice(idx, 1);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
else {
|
|
170
|
+
next.distance = next.routeDistance - prev.routeDistance;
|
|
171
|
+
points.splice(idx, 1);
|
|
172
|
+
}
|
|
173
|
+
};
|
|
174
|
+
const fixNullFollowedByJump = () => {
|
|
175
|
+
const endIdx = anomaly.nextJumpIdx;
|
|
176
|
+
const vEnd = (0, exports.calculateSpeed)(points, endIdx);
|
|
177
|
+
const vStart = (0, exports.calculateSpeed)(points, endIdx - 1);
|
|
178
|
+
if (endIdx === idx + 1) {
|
|
179
|
+
const offset = vEnd / 2;
|
|
180
|
+
const t0 = points[idx].time - points[idx - 1].time;
|
|
181
|
+
const v0 = offset;
|
|
182
|
+
const d0 = v0 * t0;
|
|
183
|
+
points[idx].distance = d0;
|
|
184
|
+
points[idx].routeDistance += d0;
|
|
185
|
+
const t = points[endIdx].time - points[endIdx - 1].time;
|
|
186
|
+
const vPrev = (0, exports.calculateSpeed)(points, endIdx);
|
|
187
|
+
const v = vPrev - offset;
|
|
188
|
+
const d = v * t;
|
|
189
|
+
points[endIdx].distance = d;
|
|
190
|
+
}
|
|
191
|
+
else {
|
|
192
|
+
const offset = vEnd - vStart;
|
|
193
|
+
for (let j = anomaly.idx; j < endIdx; j++) {
|
|
194
|
+
const t = points[j].time - points[j - 1].time;
|
|
195
|
+
const vPrev = (0, exports.calculateSpeed)(points, j);
|
|
196
|
+
const v = vPrev + offset;
|
|
197
|
+
const d = v * t;
|
|
198
|
+
const dOffset = points[j].distance - d;
|
|
199
|
+
points[j].distance = d;
|
|
200
|
+
points[j].routeDistance += dOffset;
|
|
201
|
+
}
|
|
202
|
+
const t = points[endIdx].time - points[endIdx - 1].time;
|
|
203
|
+
const vPrev = (0, exports.calculateSpeed)(points, endIdx);
|
|
204
|
+
const v = vPrev - offset;
|
|
205
|
+
const d = v * t;
|
|
206
|
+
points[endIdx].distance = d;
|
|
207
|
+
}
|
|
208
|
+
};
|
|
209
|
+
if (anomaly.nextJumpIdx !== undefined) {
|
|
210
|
+
fixNullFollowedByJump();
|
|
211
|
+
}
|
|
212
|
+
else {
|
|
213
|
+
fixNullWithoutJump();
|
|
214
|
+
}
|
|
215
|
+
};
|
|
216
|
+
const fixSpeedJump = (anomaly, points) => {
|
|
217
|
+
const fixJumpFollowedByNull = () => {
|
|
218
|
+
const idx = anomaly.idx;
|
|
219
|
+
const idxNull = anomaly.nextNullIdx;
|
|
220
|
+
const vIssue = (0, exports.calculateSpeed)(points, idx);
|
|
221
|
+
let offset;
|
|
222
|
+
if (idx + 1 === idxNull) {
|
|
223
|
+
offset = vIssue / 2;
|
|
224
|
+
}
|
|
225
|
+
else {
|
|
226
|
+
const vEnd = (0, exports.calculateSpeed)(points, idxNull - 1);
|
|
227
|
+
const vStart = (0, exports.calculateSpeed)(points, idx - 1);
|
|
228
|
+
let vTarget;
|
|
229
|
+
const v1 = vIssue - vStart;
|
|
230
|
+
const v2 = vIssue - v1;
|
|
231
|
+
if (vStart > vEnd) {
|
|
232
|
+
vTarget = Math.max(v1, v2);
|
|
233
|
+
}
|
|
234
|
+
else {
|
|
235
|
+
vTarget = isJump(v1, v2) ? (v1 + v2) / 2 : Math.min(v1, v2);
|
|
236
|
+
}
|
|
237
|
+
offset = vIssue - vTarget;
|
|
238
|
+
}
|
|
239
|
+
let t = points[idx].time - points[idx - 1].time;
|
|
240
|
+
let v = vIssue - offset;
|
|
241
|
+
let s = v * t;
|
|
242
|
+
let dOffset = points[idx].distance - s;
|
|
243
|
+
points[idx].distance = s;
|
|
244
|
+
points[idx].routeDistance -= dOffset;
|
|
245
|
+
v = offset;
|
|
246
|
+
for (let j = idx + 1; j < idxNull; j++) {
|
|
247
|
+
t = points[j].time - points[j - 1].time;
|
|
248
|
+
s = v * t;
|
|
249
|
+
v = offset = (0, exports.calculateSpeed)(points, j);
|
|
250
|
+
dOffset = points[j].distance - s;
|
|
251
|
+
points[j].distance = s;
|
|
252
|
+
points[j].routeDistance -= dOffset;
|
|
253
|
+
}
|
|
254
|
+
t = points[idxNull].time - points[idxNull - 1].time;
|
|
255
|
+
v = offset;
|
|
256
|
+
points[idxNull].distance = v * t;
|
|
257
|
+
};
|
|
258
|
+
const fixJumpFollowedByNullRetry = () => {
|
|
259
|
+
const idx = anomaly.idx;
|
|
260
|
+
const idxNull = anomaly.nextNullIdx;
|
|
261
|
+
let offset;
|
|
262
|
+
if (idxNull === idx + 1) {
|
|
263
|
+
offset = ((0, exports.calculateSpeed)(points, idx) - (0, exports.calculateSpeed)(points, idxNull)) / 2;
|
|
264
|
+
const t = points[idx].time - points[idx - 1].time;
|
|
265
|
+
const vPrev = (0, exports.calculateSpeed)(points, idx);
|
|
266
|
+
const v = vPrev - offset;
|
|
267
|
+
const d = v * t;
|
|
268
|
+
const dOffset = points[idx].distance - d;
|
|
269
|
+
points[idx].distance = d;
|
|
270
|
+
points[idx].routeDistance -= dOffset;
|
|
271
|
+
const t0 = points[idxNull].time - points[idxNull - 1].time;
|
|
272
|
+
const v0 = offset;
|
|
273
|
+
points[idxNull].distance += v0 * t0;
|
|
274
|
+
}
|
|
275
|
+
};
|
|
276
|
+
const fixJumpFollowedByJump = () => {
|
|
277
|
+
const idx = anomaly.idx;
|
|
278
|
+
const current = points === null || points === void 0 ? void 0 : points[idx];
|
|
279
|
+
const next = points === null || points === void 0 ? void 0 : points[idx + 1];
|
|
280
|
+
const v = ((0, exports.calculateSpeed)(points, idx) + (0, exports.calculateSpeed)(points, idx + 1)) / 2;
|
|
281
|
+
const t = points[idx].time - points[idx - 1].time;
|
|
282
|
+
const d = v * t;
|
|
283
|
+
const offset = current.distance - d;
|
|
284
|
+
current.distance = d;
|
|
285
|
+
current.routeDistance -= offset;
|
|
286
|
+
next.distance += offset;
|
|
287
|
+
};
|
|
288
|
+
if (anomaly.nextNullIdx !== undefined && anomaly.retry > 0) {
|
|
289
|
+
fixJumpFollowedByNullRetry();
|
|
290
|
+
}
|
|
291
|
+
else if (anomaly.nextNullIdx !== undefined) {
|
|
292
|
+
fixJumpFollowedByNull();
|
|
293
|
+
}
|
|
294
|
+
else if (anomaly.nextJumpIdx !== undefined) {
|
|
295
|
+
fixJumpFollowedByJump();
|
|
296
|
+
}
|
|
297
|
+
else {
|
|
298
|
+
const idx = anomaly.idx;
|
|
299
|
+
const next = points === null || points === void 0 ? void 0 : points[idx + 1];
|
|
300
|
+
const prev = points === null || points === void 0 ? void 0 : points[idx - 1];
|
|
301
|
+
if (next && prev) {
|
|
302
|
+
next.distance = next.routeDistance - prev.routeDistance;
|
|
303
|
+
}
|
|
304
|
+
points.splice(idx, 1);
|
|
305
|
+
}
|
|
227
306
|
};
|
|
@@ -1,4 +1,38 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
|
|
3
|
+
var useValue = arguments.length > 2;
|
|
4
|
+
for (var i = 0; i < initializers.length; i++) {
|
|
5
|
+
value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
|
|
6
|
+
}
|
|
7
|
+
return useValue ? value : void 0;
|
|
8
|
+
};
|
|
9
|
+
var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
|
|
10
|
+
function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
|
|
11
|
+
var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
|
|
12
|
+
var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
|
|
13
|
+
var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
|
|
14
|
+
var _, done = false;
|
|
15
|
+
for (var i = decorators.length - 1; i >= 0; i--) {
|
|
16
|
+
var context = {};
|
|
17
|
+
for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
|
|
18
|
+
for (var p in contextIn.access) context.access[p] = contextIn.access[p];
|
|
19
|
+
context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
|
|
20
|
+
var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
|
|
21
|
+
if (kind === "accessor") {
|
|
22
|
+
if (result === void 0) continue;
|
|
23
|
+
if (result === null || typeof result !== "object") throw new TypeError("Object expected");
|
|
24
|
+
if (_ = accept(result.get)) descriptor.get = _;
|
|
25
|
+
if (_ = accept(result.set)) descriptor.set = _;
|
|
26
|
+
if (_ = accept(result.init)) initializers.unshift(_);
|
|
27
|
+
}
|
|
28
|
+
else if (_ = accept(result)) {
|
|
29
|
+
if (kind === "field") initializers.unshift(_);
|
|
30
|
+
else descriptor[key] = _;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
if (target) Object.defineProperty(target, contextIn.name, descriptor);
|
|
34
|
+
done = true;
|
|
35
|
+
};
|
|
2
36
|
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
37
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
38
|
return new (P || (P = Promise))(function (resolve, reject) {
|
|
@@ -18,200 +52,223 @@ const settings_1 = require("../../../settings");
|
|
|
18
52
|
const service_1 = require("../service");
|
|
19
53
|
const utils_1 = require("../../../utils");
|
|
20
54
|
const valid_1 = require("../../../utils/valid");
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
duration = this.calculateDuration();
|
|
40
|
-
ftpRequired = (0, valid_1.valid)(this.workout.steps.find(s => {
|
|
41
|
-
var _a;
|
|
42
|
-
return (s.type == 'step' && ((_a = s.power) === null || _a === void 0 ? void 0 : _a.type) === 'pct of FTP') ||
|
|
43
|
-
(s.type == 'segment' && (s === null || s === void 0 ? void 0 : s.steps.find(s => { var _a; return (s.type == 'step' && ((_a = s.power) === null || _a === void 0 ? void 0 : _a.type) === 'pct of FTP'); })));
|
|
44
|
-
}));
|
|
45
|
-
settings = (_a = service.getStartSettings()) !== null && _a !== void 0 ? _a : {};
|
|
46
|
-
categories = ((_b = service.getLists()) !== null && _b !== void 0 ? _b : []).map(l => l.getTitle());
|
|
47
|
-
category = this.list.getTitle();
|
|
48
|
-
}
|
|
49
|
-
catch (err) {
|
|
50
|
-
this.logError(err, 'openSettings');
|
|
51
|
-
}
|
|
52
|
-
return { settings, ftpRequired, canStart, canStartWorkoutOnly, duration, categories, category };
|
|
53
|
-
}
|
|
54
|
-
select(settings) {
|
|
55
|
-
const service = (0, service_1.getWorkoutList)();
|
|
56
|
-
service.selectCard(this);
|
|
57
|
-
if (settings)
|
|
58
|
-
service.setStartSettings(settings);
|
|
59
|
-
this.emitUpdate();
|
|
60
|
-
}
|
|
61
|
-
unselect() {
|
|
62
|
-
const service = (0, service_1.getWorkoutList)();
|
|
63
|
-
service.unselect();
|
|
64
|
-
this.emitUpdate();
|
|
65
|
-
}
|
|
66
|
-
move(targetListName) {
|
|
67
|
-
if (!(targetListName === null || targetListName === void 0 ? void 0 : targetListName.length))
|
|
68
|
-
return;
|
|
69
|
-
const service = (0, service_1.getWorkoutList)();
|
|
70
|
-
const newList = service.moveCard(this, this.list, targetListName);
|
|
71
|
-
if (newList) {
|
|
72
|
-
this.list = newList;
|
|
73
|
-
}
|
|
74
|
-
this.workout.category = { name: targetListName, index: newList === null || newList === void 0 ? void 0 : newList.length };
|
|
75
|
-
this.save(true);
|
|
76
|
-
}
|
|
77
|
-
save() {
|
|
78
|
-
return __awaiter(this, arguments, void 0, function* (enforce = false) {
|
|
79
|
-
try {
|
|
80
|
-
return yield this.getRepo().save(this.workout, enforce);
|
|
55
|
+
const routes_1 = require("../../../routes");
|
|
56
|
+
const decorators_1 = require("../../../base/decorators");
|
|
57
|
+
let WorkoutCard = (() => {
|
|
58
|
+
var _a;
|
|
59
|
+
let _classSuper = base_1.BaseCard;
|
|
60
|
+
let _instanceExtraInitializers = [];
|
|
61
|
+
let _getRouteList_decorators;
|
|
62
|
+
return _a = class WorkoutCard extends _classSuper {
|
|
63
|
+
constructor(workout, props) {
|
|
64
|
+
super();
|
|
65
|
+
this.workout = __runInitializers(this, _instanceExtraInitializers);
|
|
66
|
+
this.cardObserver = new observer_1.Observer();
|
|
67
|
+
const { list } = props || {};
|
|
68
|
+
this.workout = workout;
|
|
69
|
+
this.list = list;
|
|
70
|
+
this.deleteable = true;
|
|
71
|
+
this.initialized = false;
|
|
72
|
+
this.logger = new gd_eventlog_1.EventLogger('WorkoutCard');
|
|
81
73
|
}
|
|
82
|
-
|
|
83
|
-
|
|
74
|
+
openSettings() {
|
|
75
|
+
var _b, _c;
|
|
76
|
+
let settings, canStart, duration, ftpRequired, categories = [], category, canStartWorkoutOnly;
|
|
77
|
+
try {
|
|
78
|
+
const service = (0, service_1.useWorkoutList)();
|
|
79
|
+
canStart = service.canDisplayStart();
|
|
80
|
+
canStartWorkoutOnly = !canStart;
|
|
81
|
+
duration = this.calculateDuration();
|
|
82
|
+
ftpRequired = (0, valid_1.valid)(this.workout.steps.find(s => {
|
|
83
|
+
var _b;
|
|
84
|
+
return (s.type == 'step' && ((_b = s.power) === null || _b === void 0 ? void 0 : _b.type) === 'pct of FTP') ||
|
|
85
|
+
(s.type == 'segment' && (s === null || s === void 0 ? void 0 : s.steps.find(s => { var _b; return (s.type == 'step' && ((_b = s.power) === null || _b === void 0 ? void 0 : _b.type) === 'pct of FTP'); })));
|
|
86
|
+
}));
|
|
87
|
+
settings = (_b = service.getStartSettings()) !== null && _b !== void 0 ? _b : {};
|
|
88
|
+
categories = ((_c = service.getLists()) !== null && _c !== void 0 ? _c : []).map(l => l.getTitle());
|
|
89
|
+
category = this.list.getTitle();
|
|
90
|
+
}
|
|
91
|
+
catch (err) {
|
|
92
|
+
this.logError(err, 'openSettings');
|
|
93
|
+
}
|
|
94
|
+
return { settings, ftpRequired, canStart, canStartWorkoutOnly, duration, categories, category };
|
|
84
95
|
}
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
this.deleteObserver = new observer_1.PromiseObserver(this._delete());
|
|
94
|
-
return this.deleteObserver;
|
|
95
|
-
}
|
|
96
|
-
catch (err) {
|
|
97
|
-
this.logError(err, 'delete');
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
getId() {
|
|
101
|
-
return this.workout.id;
|
|
102
|
-
}
|
|
103
|
-
getTitle() {
|
|
104
|
-
return this.workout.name;
|
|
105
|
-
}
|
|
106
|
-
update(workout) {
|
|
107
|
-
if (!(0, valid_1.valid)(workout))
|
|
108
|
-
return;
|
|
109
|
-
try {
|
|
110
|
-
this.workout = workout;
|
|
111
|
-
this.save();
|
|
112
|
-
this.emitUpdate();
|
|
113
|
-
}
|
|
114
|
-
catch (err) {
|
|
115
|
-
this.logError(err, 'update');
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
getData() {
|
|
119
|
-
return this.workout;
|
|
120
|
-
}
|
|
121
|
-
getCardType() {
|
|
122
|
-
return "Workout";
|
|
123
|
-
}
|
|
124
|
-
getDisplayProperties() {
|
|
125
|
-
const userSettings = (0, settings_1.useUserSettings)();
|
|
126
|
-
let user;
|
|
127
|
-
try {
|
|
128
|
-
user = userSettings.get('user', {});
|
|
129
|
-
}
|
|
130
|
-
catch (_a) {
|
|
131
|
-
user = {};
|
|
132
|
-
}
|
|
133
|
-
const duration = this.calculateDuration();
|
|
134
|
-
return { title: this.workout.name, workout: this.workout, ftp: user === null || user === void 0 ? void 0 : user.ftp, duration,
|
|
135
|
-
canDelete: this.deleteable, visible: this.visible, selected: this.isSelected(),
|
|
136
|
-
observer: this.cardObserver };
|
|
137
|
-
}
|
|
138
|
-
enableDelete(enabled = true) {
|
|
139
|
-
this.deleteable = enabled;
|
|
140
|
-
}
|
|
141
|
-
canDelete() {
|
|
142
|
-
return this.deleteable;
|
|
143
|
-
}
|
|
144
|
-
setVisible(visible) {
|
|
145
|
-
try {
|
|
146
|
-
const prev = this.visible;
|
|
147
|
-
this.visible = visible;
|
|
148
|
-
if (visible !== prev)
|
|
96
|
+
select(settings) {
|
|
97
|
+
const service = (0, service_1.getWorkoutList)();
|
|
98
|
+
service.selectCard(this);
|
|
99
|
+
if (settings)
|
|
100
|
+
service.setStartSettings(settings);
|
|
101
|
+
if (settings.noRoute) {
|
|
102
|
+
this.getRouteList().unselect();
|
|
103
|
+
}
|
|
149
104
|
this.emitUpdate();
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
this.
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
105
|
+
}
|
|
106
|
+
unselect() {
|
|
107
|
+
const service = (0, service_1.getWorkoutList)();
|
|
108
|
+
service.unselect();
|
|
109
|
+
this.emitUpdate();
|
|
110
|
+
}
|
|
111
|
+
move(targetListName) {
|
|
112
|
+
if (!(targetListName === null || targetListName === void 0 ? void 0 : targetListName.length))
|
|
113
|
+
return;
|
|
114
|
+
const service = (0, service_1.getWorkoutList)();
|
|
115
|
+
const newList = service.moveCard(this, this.list, targetListName);
|
|
116
|
+
if (newList) {
|
|
117
|
+
this.list = newList;
|
|
118
|
+
}
|
|
119
|
+
this.workout.category = { name: targetListName, index: newList === null || newList === void 0 ? void 0 : newList.length };
|
|
120
|
+
this.save(true);
|
|
121
|
+
}
|
|
122
|
+
save() {
|
|
123
|
+
return __awaiter(this, arguments, void 0, function* (enforce = false) {
|
|
124
|
+
try {
|
|
125
|
+
return yield this.getRepo().save(this.workout, enforce);
|
|
126
|
+
}
|
|
127
|
+
catch (err) {
|
|
128
|
+
this.logError(err, 'save');
|
|
129
|
+
}
|
|
173
130
|
});
|
|
174
131
|
}
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
}
|
|
132
|
+
delete() {
|
|
133
|
+
try {
|
|
134
|
+
const service = (0, service_1.getWorkoutList)();
|
|
135
|
+
service.unselectCard(this);
|
|
136
|
+
if (this.deleteObserver)
|
|
137
|
+
return this.deleteObserver;
|
|
138
|
+
this.deleteObserver = new observer_1.PromiseObserver(this._delete());
|
|
139
|
+
return this.deleteObserver;
|
|
140
|
+
}
|
|
141
|
+
catch (err) {
|
|
142
|
+
this.logError(err, 'delete');
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
getId() {
|
|
146
|
+
return this.workout.id;
|
|
147
|
+
}
|
|
148
|
+
getTitle() {
|
|
149
|
+
return this.workout.name;
|
|
150
|
+
}
|
|
151
|
+
update(workout) {
|
|
152
|
+
if (!(0, valid_1.valid)(workout))
|
|
153
|
+
return;
|
|
154
|
+
try {
|
|
155
|
+
this.workout = workout;
|
|
156
|
+
this.save();
|
|
157
|
+
this.emitUpdate();
|
|
158
|
+
}
|
|
159
|
+
catch (err) {
|
|
160
|
+
this.logError(err, 'update');
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
getData() {
|
|
164
|
+
return this.workout;
|
|
165
|
+
}
|
|
166
|
+
getCardType() {
|
|
167
|
+
return "Workout";
|
|
168
|
+
}
|
|
169
|
+
getDisplayProperties() {
|
|
170
|
+
const userSettings = (0, settings_1.useUserSettings)();
|
|
171
|
+
let user;
|
|
172
|
+
try {
|
|
173
|
+
user = userSettings.get('user', {});
|
|
174
|
+
}
|
|
175
|
+
catch (_b) {
|
|
176
|
+
user = {};
|
|
177
|
+
}
|
|
178
|
+
const duration = this.calculateDuration();
|
|
179
|
+
return { title: this.workout.name, workout: this.workout, ftp: user === null || user === void 0 ? void 0 : user.ftp, duration,
|
|
180
|
+
canDelete: this.deleteable, visible: this.visible, selected: this.isSelected(),
|
|
181
|
+
observer: this.cardObserver };
|
|
182
|
+
}
|
|
183
|
+
enableDelete(enabled = true) {
|
|
184
|
+
this.deleteable = enabled;
|
|
185
|
+
}
|
|
186
|
+
canDelete() {
|
|
187
|
+
return this.deleteable;
|
|
188
|
+
}
|
|
189
|
+
setVisible(visible) {
|
|
190
|
+
try {
|
|
191
|
+
const prev = this.visible;
|
|
192
|
+
this.visible = visible;
|
|
193
|
+
if (visible !== prev)
|
|
194
|
+
this.emitUpdate();
|
|
195
|
+
}
|
|
196
|
+
catch (err) {
|
|
197
|
+
this.logError(err, 'setVisible');
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
_delete() {
|
|
201
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
202
|
+
yield (0, utils_1.waitNextTick)();
|
|
203
|
+
let deleted = false;
|
|
204
|
+
try {
|
|
205
|
+
this.deleteObserver.emit('started');
|
|
206
|
+
yield this.getRepo().delete(this.workout);
|
|
207
|
+
this.deleteFromUIList();
|
|
208
|
+
(0, service_1.getWorkoutList)().emitLists('updated');
|
|
209
|
+
deleted = true;
|
|
210
|
+
}
|
|
211
|
+
catch (_b) {
|
|
212
|
+
deleted = false;
|
|
213
|
+
}
|
|
214
|
+
finally {
|
|
215
|
+
this.deleteObserver.emit('done', deleted);
|
|
216
|
+
(0, utils_1.waitNextTick)().then(() => {
|
|
217
|
+
delete this.deleteObserver;
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
return deleted;
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
calculateDuration() {
|
|
224
|
+
const { duration } = this.workout;
|
|
225
|
+
if (duration < 120)
|
|
226
|
+
return `${duration.toFixed(0)}s`;
|
|
227
|
+
if (duration % 60 === 0)
|
|
228
|
+
return `${duration / 60}min`;
|
|
229
|
+
const secVal = duration % 60;
|
|
230
|
+
const minVal = (duration - secVal) / 60 % 60;
|
|
231
|
+
const h = Math.floor((duration - secVal - minVal * 60) / 3600);
|
|
232
|
+
const sec = secVal < 10 ? `0${secVal}` : secVal;
|
|
233
|
+
const min = minVal < 10 ? `0${minVal}` : minVal;
|
|
234
|
+
if (h > 0)
|
|
235
|
+
return `${h}:${min}:${sec}`;
|
|
236
|
+
else
|
|
237
|
+
return `${min}:${sec}`;
|
|
238
|
+
}
|
|
239
|
+
deleteFromUIList() {
|
|
240
|
+
if (this.list) {
|
|
241
|
+
this.list.remove(this);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
logError(err, fn) {
|
|
245
|
+
this.logger.logEvent({ message: 'error', error: err.message, fn, stack: err.stack });
|
|
246
|
+
}
|
|
247
|
+
getRepo() {
|
|
248
|
+
return new db_1.WorkoutsDbLoader();
|
|
249
|
+
}
|
|
250
|
+
emitUpdate() {
|
|
251
|
+
if (this.cardObserver)
|
|
252
|
+
this.cardObserver.emit('update', this.getDisplayProperties());
|
|
253
|
+
}
|
|
254
|
+
isSelected() {
|
|
255
|
+
const service = (0, service_1.getWorkoutList)();
|
|
256
|
+
const selectedWorkout = service.getSelected();
|
|
257
|
+
if ((selectedWorkout === null || selectedWorkout === void 0 ? void 0 : selectedWorkout.id) === this.workout.id)
|
|
258
|
+
return true;
|
|
259
|
+
return false;
|
|
260
|
+
}
|
|
261
|
+
getRouteList() {
|
|
262
|
+
return (0, routes_1.useRouteList)();
|
|
263
|
+
}
|
|
264
|
+
},
|
|
265
|
+
(() => {
|
|
266
|
+
var _b;
|
|
267
|
+
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create((_b = _classSuper[Symbol.metadata]) !== null && _b !== void 0 ? _b : null) : void 0;
|
|
268
|
+
_getRouteList_decorators = [decorators_1.Injectable];
|
|
269
|
+
__esDecorate(_a, 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);
|
|
270
|
+
if (_metadata) Object.defineProperty(_a, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
|
|
271
|
+
})(),
|
|
272
|
+
_a;
|
|
273
|
+
})();
|
|
217
274
|
exports.WorkoutCard = WorkoutCard;
|