feat(statistiques): implémentation backend statistiques de progression (ticket #82)
Lots B1+B2+B3 : schéma/domaine, requêtes d'agrégation et ports/use cases pour les statistiques de progression, avec tests associés. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@ -2255,6 +2255,168 @@ void main() {
|
||||
throwsA(isA<DomainException>()),
|
||||
);
|
||||
});
|
||||
|
||||
test('Progression stats use case resolves four week overview', () async {
|
||||
final repository = _FakeProgressionStatsRepository();
|
||||
final now = DateTime.utc(2026, 7, 22, 12);
|
||||
repository.globalStats = ProgressionGlobalStatsData(
|
||||
completedSessionCount: 2,
|
||||
totalActiveMs: 180000,
|
||||
activeWeekStarts: [DateTime(2026, 7, 13), DateTime(2026, 7, 20)],
|
||||
hasAnyCompletedHistory: true,
|
||||
);
|
||||
repository.exerciseOptions = [
|
||||
ProgressionExerciseOptionData(
|
||||
exerciseKey: 'exercise-1',
|
||||
nameSnapshot: 'Shoot',
|
||||
isArchived: false,
|
||||
lastPerformedAt: now,
|
||||
),
|
||||
];
|
||||
repository.measureOptions['exercise-1'] = const [
|
||||
ProgressionMeasureOptionData(
|
||||
measure: ProgressionMeasure.manualScore,
|
||||
label: 'Score',
|
||||
scoreLabel: 'Réussites',
|
||||
scoreUnit: 'paniers',
|
||||
lowerIsBetter: false,
|
||||
),
|
||||
];
|
||||
|
||||
final overview = await ProgressionStatsUseCase(
|
||||
repository: repository,
|
||||
clock: _FakeClock(now),
|
||||
).getOverview(ProgressionPeriod.fourWeeks);
|
||||
|
||||
expect(repository.lastGlobalRange!.startedAt, DateTime(2026, 6, 29));
|
||||
expect(repository.lastGlobalRange!.endedAt, now);
|
||||
expect(overview.totalWeekCount, 4);
|
||||
expect(overview.activeWeekCount, 2);
|
||||
expect(overview.rangeLabelKind, ProgressionRangeLabelKind.sinceDate);
|
||||
expect(
|
||||
overview.exerciseOptions.single.measures.single.scoreUnit,
|
||||
'paniers',
|
||||
);
|
||||
});
|
||||
|
||||
test('Progression stats use case resolves all-time empty overview', () async {
|
||||
final repository = _FakeProgressionStatsRepository();
|
||||
repository.globalStats = const ProgressionGlobalStatsData(
|
||||
completedSessionCount: 0,
|
||||
totalActiveMs: 0,
|
||||
activeWeekStarts: [],
|
||||
hasAnyCompletedHistory: false,
|
||||
);
|
||||
|
||||
final overview = await ProgressionStatsUseCase(
|
||||
repository: repository,
|
||||
clock: _FakeClock(DateTime.utc(2026, 7, 22, 12)),
|
||||
).getOverview(ProgressionPeriod.all);
|
||||
|
||||
expect(repository.lastGlobalRange!.startedAt, isNull);
|
||||
expect(overview.totalWeekCount, isNull);
|
||||
expect(overview.rangeLabelKind, ProgressionRangeLabelKind.none);
|
||||
expect(overview.hasAnyCompletedHistory, isFalse);
|
||||
});
|
||||
|
||||
test(
|
||||
'Progression stats use case maps series summaries and empty period',
|
||||
() async {
|
||||
final repository = _FakeProgressionStatsRepository();
|
||||
final now = DateTime.utc(2026, 7, 22, 12);
|
||||
repository.series = ProgressionExerciseSeriesData(
|
||||
exerciseKey: 'exercise-1',
|
||||
exerciseNameSnapshot: 'Shoot',
|
||||
measure: const ProgressionMeasureOptionData(
|
||||
measure: ProgressionMeasure.reps,
|
||||
label: 'Répétitions',
|
||||
lowerIsBetter: false,
|
||||
),
|
||||
points: [
|
||||
ProgressionPointData(
|
||||
workoutHistoryId: 'history-1',
|
||||
workoutNameSnapshot: 'Séance 1',
|
||||
startedAt: now.subtract(const Duration(days: 1)),
|
||||
value: 12,
|
||||
rawValue: 12,
|
||||
),
|
||||
ProgressionPointData(
|
||||
workoutHistoryId: 'history-2',
|
||||
workoutNameSnapshot: 'Séance 2',
|
||||
startedAt: now,
|
||||
value: 15,
|
||||
rawValue: 15,
|
||||
),
|
||||
],
|
||||
hasAnyAllTimeData: true,
|
||||
hasAnyCompletedExerciseResult: true,
|
||||
);
|
||||
|
||||
final series =
|
||||
await ProgressionStatsUseCase(
|
||||
repository: repository,
|
||||
clock: _FakeClock(now),
|
||||
).getExerciseSeries(
|
||||
period: ProgressionPeriod.fourWeeks,
|
||||
exerciseKey: 'exercise-1',
|
||||
measure: ProgressionMeasure.reps,
|
||||
);
|
||||
|
||||
expect(series.state, ProgressionSeriesState.ready);
|
||||
expect(series.summary.kind, ProgressionSeriesSummaryKind.totals);
|
||||
expect(series.summary.recentTotal, 27);
|
||||
expect(series.summary.lastSessionTotal, 15);
|
||||
|
||||
repository.series = const ProgressionExerciseSeriesData(
|
||||
exerciseKey: 'exercise-1',
|
||||
exerciseNameSnapshot: 'Shoot',
|
||||
measure: ProgressionMeasureOptionData(
|
||||
measure: ProgressionMeasure.manualScore,
|
||||
label: 'Score',
|
||||
lowerIsBetter: false,
|
||||
),
|
||||
points: [],
|
||||
hasAnyAllTimeData: true,
|
||||
hasAnyCompletedExerciseResult: true,
|
||||
);
|
||||
final empty =
|
||||
await ProgressionStatsUseCase(
|
||||
repository: repository,
|
||||
clock: _FakeClock(now),
|
||||
).getExerciseSeries(
|
||||
period: ProgressionPeriod.fourWeeks,
|
||||
exerciseKey: 'exercise-1',
|
||||
measure: ProgressionMeasure.manualScore,
|
||||
);
|
||||
|
||||
expect(empty.state, ProgressionSeriesState.emptyButHasAllTimeData);
|
||||
expect(empty.summary.kind, ProgressionSeriesSummaryKind.none);
|
||||
|
||||
repository.series = const ProgressionExerciseSeriesData(
|
||||
exerciseKey: 'exercise-1',
|
||||
exerciseNameSnapshot: 'Shoot',
|
||||
measure: ProgressionMeasureOptionData(
|
||||
measure: ProgressionMeasure.manualScore,
|
||||
label: 'Score',
|
||||
lowerIsBetter: false,
|
||||
),
|
||||
points: [],
|
||||
hasAnyAllTimeData: false,
|
||||
hasAnyCompletedExerciseResult: true,
|
||||
);
|
||||
final noGraphable =
|
||||
await ProgressionStatsUseCase(
|
||||
repository: repository,
|
||||
clock: _FakeClock(now),
|
||||
).getExerciseSeries(
|
||||
period: ProgressionPeriod.all,
|
||||
exerciseKey: 'exercise-1',
|
||||
measure: ProgressionMeasure.manualScore,
|
||||
);
|
||||
|
||||
expect(noGraphable.state, ProgressionSeriesState.noGraphableMeasure);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
ExerciseStep _step({
|
||||
@ -2313,6 +2475,65 @@ final class _FakeIds implements IdGenerator {
|
||||
}
|
||||
}
|
||||
|
||||
final class _FakeProgressionStatsRepository
|
||||
implements ProgressionStatsRepository {
|
||||
ProgressionDateRange? lastGlobalRange;
|
||||
ProgressionDateRange? lastSeriesRange;
|
||||
ProgressionGlobalStatsData globalStats = const ProgressionGlobalStatsData(
|
||||
completedSessionCount: 0,
|
||||
totalActiveMs: 0,
|
||||
activeWeekStarts: [],
|
||||
hasAnyCompletedHistory: false,
|
||||
);
|
||||
List<ProgressionExerciseOptionData> exerciseOptions = const [];
|
||||
final measureOptions = <String, List<ProgressionMeasureOptionData>>{};
|
||||
ProgressionExerciseSeriesData series = const ProgressionExerciseSeriesData(
|
||||
exerciseKey: 'exercise-1',
|
||||
exerciseNameSnapshot: 'Exercise',
|
||||
measure: ProgressionMeasureOptionData(
|
||||
measure: ProgressionMeasure.manualScore,
|
||||
label: 'Score',
|
||||
lowerIsBetter: false,
|
||||
),
|
||||
points: [],
|
||||
hasAnyAllTimeData: false,
|
||||
hasAnyCompletedExerciseResult: false,
|
||||
);
|
||||
|
||||
@override
|
||||
Future<ProgressionGlobalStatsData> readGlobalStats(
|
||||
ProgressionDateRange range,
|
||||
) async {
|
||||
lastGlobalRange = range;
|
||||
return globalStats;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<ProgressionExerciseOptionData>> listExerciseOptions(
|
||||
ProgressionDateRange range,
|
||||
) async {
|
||||
return exerciseOptions;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<ProgressionMeasureOptionData>> listMeasureOptions({
|
||||
required ProgressionDateRange range,
|
||||
required String exerciseKey,
|
||||
}) async {
|
||||
return measureOptions[exerciseKey] ?? const [];
|
||||
}
|
||||
|
||||
@override
|
||||
Future<ProgressionExerciseSeriesData> readExerciseSeries({
|
||||
required ProgressionDateRange range,
|
||||
required String exerciseKey,
|
||||
required ProgressionMeasure measure,
|
||||
}) async {
|
||||
lastSeriesRange = range;
|
||||
return series;
|
||||
}
|
||||
}
|
||||
|
||||
AuthUseCases _authUseCase({
|
||||
_FakeAuthTokenStore? tokenStore,
|
||||
_FakeOnlineAccountRepository? accountRepository,
|
||||
@ -3253,10 +3474,8 @@ ActiveWorkoutSession _sessionWithSnapshot({
|
||||
'exerciseStepsSnapshot': exerciseSteps
|
||||
.map((step) => step.toSnapshotJson())
|
||||
.toList(),
|
||||
if (autoStartNextTimedStepSnapshot != null)
|
||||
'autoStartNextTimedStepSnapshot': autoStartNextTimedStepSnapshot,
|
||||
if (autoStartNextTimedStepOverride != null)
|
||||
'autoStartNextTimedStepOverride': autoStartNextTimedStepOverride,
|
||||
'autoStartNextTimedStepSnapshot': ?autoStartNextTimedStepSnapshot,
|
||||
'autoStartNextTimedStepOverride': ?autoStartNextTimedStepOverride,
|
||||
};
|
||||
return ActiveWorkoutSession(
|
||||
metadata: _metadata('session-1'),
|
||||
|
||||
@ -14,6 +14,7 @@ void main() {
|
||||
late local.DriftActiveSessionRepository activeRepository;
|
||||
late local.DriftWorkoutTemplateRepository templateRepository;
|
||||
late local.DriftWorkoutHistoryRepository historyRepository;
|
||||
late local.DriftProgressionStatsRepository progressionStatsRepository;
|
||||
late local.DriftExercisePerformanceReferenceRepository
|
||||
performanceReferenceRepository;
|
||||
|
||||
@ -24,6 +25,9 @@ void main() {
|
||||
activeRepository = local.DriftActiveSessionRepository(database);
|
||||
templateRepository = local.DriftWorkoutTemplateRepository(database);
|
||||
historyRepository = local.DriftWorkoutHistoryRepository(database);
|
||||
progressionStatsRepository = local.DriftProgressionStatsRepository(
|
||||
database,
|
||||
);
|
||||
performanceReferenceRepository =
|
||||
local.DriftExercisePerformanceReferenceRepository(database);
|
||||
});
|
||||
@ -1086,6 +1090,283 @@ void main() {
|
||||
expect(latest!.actualReps, 13);
|
||||
});
|
||||
|
||||
test(
|
||||
'progression global stats count active weeks and ignore inactive rows',
|
||||
() async {
|
||||
final now = DateTime.utc(2026, 7, 22, 13);
|
||||
await historyRepository.save(
|
||||
_history(
|
||||
id: 'progression-week-1',
|
||||
startedAt: now.subtract(const Duration(days: 1)),
|
||||
totalActiveMs: 120000,
|
||||
result: _historySetResult(
|
||||
id: 'progression-result-1',
|
||||
historyId: 'progression-week-1',
|
||||
sourceExerciseId: 'exercise-1',
|
||||
setIndex: 0,
|
||||
startedAt: now.subtract(const Duration(days: 1)),
|
||||
actualReps: 10,
|
||||
),
|
||||
),
|
||||
);
|
||||
await historyRepository.save(
|
||||
_history(
|
||||
id: 'progression-week-2',
|
||||
startedAt: now.subtract(const Duration(days: 8)),
|
||||
totalActiveMs: 180000,
|
||||
result: _historySetResult(
|
||||
id: 'progression-result-2',
|
||||
historyId: 'progression-week-2',
|
||||
sourceExerciseId: 'exercise-1',
|
||||
setIndex: 0,
|
||||
startedAt: now.subtract(const Duration(days: 8)),
|
||||
actualReps: 8,
|
||||
),
|
||||
),
|
||||
);
|
||||
await historyRepository.save(
|
||||
_history(
|
||||
id: 'progression-incomplete',
|
||||
startedAt: now,
|
||||
completed: false,
|
||||
result: _historySetResult(
|
||||
id: 'progression-result-incomplete',
|
||||
historyId: 'progression-incomplete',
|
||||
sourceExerciseId: 'exercise-1',
|
||||
setIndex: 0,
|
||||
startedAt: now,
|
||||
actualReps: 99,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
final stats = await progressionStatsRepository.readGlobalStats(
|
||||
ProgressionDateRange(
|
||||
startedAt: now.subtract(const Duration(days: 28)),
|
||||
endedAt: now,
|
||||
),
|
||||
);
|
||||
|
||||
expect(stats.completedSessionCount, 2);
|
||||
expect(stats.totalActiveMs, 300000);
|
||||
expect(stats.activeWeekStarts, hasLength(2));
|
||||
expect(stats.hasAnyCompletedHistory, isTrue);
|
||||
},
|
||||
);
|
||||
|
||||
test(
|
||||
'progression lists exercises, archive state and measure options',
|
||||
() async {
|
||||
final now = DateTime.utc(2026, 7, 22, 14);
|
||||
await exerciseRepository.save(
|
||||
Exercise(
|
||||
metadata: _metadata('exercise-active', now),
|
||||
name: 'Active drill',
|
||||
hasTimeMeasure: false,
|
||||
hasRepsMeasure: true,
|
||||
hasScoreMeasure: false,
|
||||
),
|
||||
);
|
||||
await exerciseRepository.save(
|
||||
Exercise(
|
||||
metadata: _metadata('exercise-archived', now),
|
||||
name: 'Archived drill',
|
||||
hasTimeMeasure: false,
|
||||
hasRepsMeasure: true,
|
||||
hasScoreMeasure: false,
|
||||
archivedAt: now,
|
||||
),
|
||||
);
|
||||
await historyRepository.save(
|
||||
_history(
|
||||
id: 'progression-options',
|
||||
startedAt: now,
|
||||
results: [
|
||||
_historySetResult(
|
||||
id: 'progression-active-score',
|
||||
historyId: 'progression-options',
|
||||
sourceExerciseId: 'exercise-active',
|
||||
setIndex: 0,
|
||||
startedAt: now,
|
||||
actualScore: 12,
|
||||
),
|
||||
_historySetResult(
|
||||
id: 'progression-active-chrono',
|
||||
historyId: 'progression-options',
|
||||
sourceExerciseId: 'exercise-active',
|
||||
setIndex: 1,
|
||||
startedAt: now,
|
||||
scoreInputMode: ScoreInputMode.stopwatch,
|
||||
actualScoreTimeMs: 42000,
|
||||
),
|
||||
_historySetResult(
|
||||
id: 'progression-archived-reps',
|
||||
historyId: 'progression-options',
|
||||
sourceExerciseId: 'exercise-archived',
|
||||
setIndex: 2,
|
||||
startedAt: now,
|
||||
actualReps: 15,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
final range = ProgressionDateRange(
|
||||
startedAt: now.subtract(const Duration(days: 1)),
|
||||
endedAt: now,
|
||||
);
|
||||
final options = await progressionStatsRepository.listExerciseOptions(
|
||||
range,
|
||||
);
|
||||
final activeMeasures = await progressionStatsRepository
|
||||
.listMeasureOptions(range: range, exerciseKey: 'exercise-active');
|
||||
|
||||
expect(options.map((option) => option.exerciseKey), [
|
||||
'exercise-active',
|
||||
'exercise-archived',
|
||||
]);
|
||||
expect(options.first.isArchived, isFalse);
|
||||
expect(options.last.isArchived, isTrue);
|
||||
expect(activeMeasures.map((option) => option.measure), [
|
||||
ProgressionMeasure.manualScore,
|
||||
ProgressionMeasure.stopwatchScore,
|
||||
]);
|
||||
expect(activeMeasures.first.scoreLabel, 'Score');
|
||||
expect(activeMeasures.first.scoreUnit, 'pts');
|
||||
expect(activeMeasures.last.lowerIsBetter, isTrue);
|
||||
},
|
||||
);
|
||||
|
||||
test(
|
||||
'progression exercise series aggregate each measure by session',
|
||||
() async {
|
||||
final now = DateTime.utc(2026, 7, 22, 15);
|
||||
await historyRepository.save(
|
||||
_history(
|
||||
id: 'progression-series-old',
|
||||
startedAt: now.subtract(const Duration(days: 2)),
|
||||
results: [
|
||||
_historySetResult(
|
||||
id: 'progression-old-score-low',
|
||||
historyId: 'progression-series-old',
|
||||
sourceExerciseId: 'exercise-1',
|
||||
setIndex: 0,
|
||||
startedAt: now.subtract(const Duration(days: 2)),
|
||||
actualScore: 7,
|
||||
),
|
||||
_historySetResult(
|
||||
id: 'progression-old-score-high',
|
||||
historyId: 'progression-series-old',
|
||||
sourceExerciseId: 'exercise-1',
|
||||
setIndex: 1,
|
||||
startedAt: now.subtract(const Duration(days: 2)),
|
||||
actualScore: 9,
|
||||
actualReps: 4,
|
||||
actualTimeMs: 10000,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
await historyRepository.save(
|
||||
_history(
|
||||
id: 'progression-series-new',
|
||||
startedAt: now,
|
||||
results: [
|
||||
_historySetResult(
|
||||
id: 'progression-new-score',
|
||||
historyId: 'progression-series-new',
|
||||
sourceExerciseId: 'exercise-1',
|
||||
setIndex: 0,
|
||||
startedAt: now,
|
||||
actualScore: 11,
|
||||
actualReps: 6,
|
||||
actualTimeMs: 12000,
|
||||
),
|
||||
_historySetResult(
|
||||
id: 'progression-new-chrono-slow',
|
||||
historyId: 'progression-series-new',
|
||||
sourceExerciseId: 'exercise-1',
|
||||
setIndex: 1,
|
||||
startedAt: now,
|
||||
scoreInputMode: ScoreInputMode.stopwatch,
|
||||
actualScoreTimeMs: 45000,
|
||||
),
|
||||
_historySetResult(
|
||||
id: 'progression-new-chrono-fast',
|
||||
historyId: 'progression-series-new',
|
||||
sourceExerciseId: 'exercise-1',
|
||||
setIndex: 2,
|
||||
startedAt: now,
|
||||
scoreInputMode: ScoreInputMode.stopwatch,
|
||||
actualScoreTimeMs: 42000,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
final range = ProgressionDateRange(
|
||||
startedAt: now.subtract(const Duration(days: 7)),
|
||||
endedAt: now,
|
||||
);
|
||||
|
||||
final score = await progressionStatsRepository.readExerciseSeries(
|
||||
range: range,
|
||||
exerciseKey: 'exercise-1',
|
||||
measure: ProgressionMeasure.manualScore,
|
||||
);
|
||||
final chrono = await progressionStatsRepository.readExerciseSeries(
|
||||
range: range,
|
||||
exerciseKey: 'exercise-1',
|
||||
measure: ProgressionMeasure.stopwatchScore,
|
||||
);
|
||||
final reps = await progressionStatsRepository.readExerciseSeries(
|
||||
range: range,
|
||||
exerciseKey: 'exercise-1',
|
||||
measure: ProgressionMeasure.reps,
|
||||
);
|
||||
final time = await progressionStatsRepository.readExerciseSeries(
|
||||
range: range,
|
||||
exerciseKey: 'exercise-1',
|
||||
measure: ProgressionMeasure.time,
|
||||
);
|
||||
|
||||
expect(score.points.map((point) => point.rawValue), [9.0, 11.0]);
|
||||
expect(chrono.points.single.rawValue, 42000);
|
||||
expect(reps.points.map((point) => point.rawValue), [4, 6]);
|
||||
expect(time.points.map((point) => point.rawValue), [10000, 12000]);
|
||||
expect(score.points.first.workoutHistoryId, 'progression-series-old');
|
||||
},
|
||||
);
|
||||
|
||||
test('progression reports all-time data outside selected period', () async {
|
||||
final now = DateTime.utc(2026, 7, 22, 16);
|
||||
await historyRepository.save(
|
||||
_history(
|
||||
id: 'progression-all-time',
|
||||
startedAt: now.subtract(const Duration(days: 60)),
|
||||
result: _historySetResult(
|
||||
id: 'progression-all-time-score',
|
||||
historyId: 'progression-all-time',
|
||||
sourceExerciseId: 'exercise-1',
|
||||
setIndex: 0,
|
||||
startedAt: now.subtract(const Duration(days: 60)),
|
||||
actualScore: 10,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
final series = await progressionStatsRepository.readExerciseSeries(
|
||||
range: ProgressionDateRange(
|
||||
startedAt: now.subtract(const Duration(days: 7)),
|
||||
endedAt: now,
|
||||
),
|
||||
exerciseKey: 'exercise-1',
|
||||
measure: ProgressionMeasure.manualScore,
|
||||
);
|
||||
|
||||
expect(series.points, isEmpty);
|
||||
expect(series.hasAnyAllTimeData, isTrue);
|
||||
});
|
||||
|
||||
test(
|
||||
'performance reference use case prioritizes record score metric',
|
||||
() async {
|
||||
@ -1157,14 +1438,16 @@ WorkoutHistory _history({
|
||||
required DateTime startedAt,
|
||||
WorkoutHistorySetResult? result,
|
||||
List<WorkoutHistorySetResult>? results,
|
||||
bool completed = true,
|
||||
int totalActiveMs = 300000,
|
||||
}) {
|
||||
return WorkoutHistory(
|
||||
metadata: _metadata(id, startedAt),
|
||||
nameSnapshot: id,
|
||||
startedAt: startedAt,
|
||||
endedAt: startedAt.add(const Duration(minutes: 5)),
|
||||
totalActiveMs: 300000,
|
||||
completed: true,
|
||||
totalActiveMs: totalActiveMs,
|
||||
completed: completed,
|
||||
historySnapshotJson: '{"name":"$id"}',
|
||||
results: results ?? [result!],
|
||||
);
|
||||
|
||||
@ -212,6 +212,10 @@ final class _FakeBootstrap implements AppDependencies {
|
||||
repository: _FakeWorkoutHistoryRepository(),
|
||||
clock: _FakeClock(DateTime.utc(2026, 7, 17, 12)),
|
||||
),
|
||||
progressionStatsUseCase = ProgressionStatsUseCase(
|
||||
repository: _FakeProgressionStatsRepository(),
|
||||
clock: _FakeClock(DateTime.utc(2026, 7, 17, 12)),
|
||||
),
|
||||
exercisePerformanceReferenceUseCase = ExercisePerformanceReferenceUseCase(
|
||||
repository: _FakeExercisePerformanceReferenceRepository(),
|
||||
);
|
||||
@ -249,6 +253,9 @@ final class _FakeBootstrap implements AppDependencies {
|
||||
@override
|
||||
final WorkoutHistoryUseCases workoutHistoryUseCases;
|
||||
|
||||
@override
|
||||
final ProgressionStatsUseCase progressionStatsUseCase;
|
||||
|
||||
@override
|
||||
final ExercisePerformanceReferenceUseCase exercisePerformanceReferenceUseCase;
|
||||
}
|
||||
@ -711,6 +718,56 @@ final class _FakeWorkoutHistoryRepository implements WorkoutHistoryRepository {
|
||||
Future<void> saveStepResult(WorkoutHistoryStepResult result) async {}
|
||||
}
|
||||
|
||||
final class _FakeProgressionStatsRepository
|
||||
implements ProgressionStatsRepository {
|
||||
@override
|
||||
Future<ProgressionGlobalStatsData> readGlobalStats(
|
||||
ProgressionDateRange range,
|
||||
) async {
|
||||
return const ProgressionGlobalStatsData(
|
||||
completedSessionCount: 0,
|
||||
totalActiveMs: 0,
|
||||
activeWeekStarts: [],
|
||||
hasAnyCompletedHistory: false,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<ProgressionExerciseOptionData>> listExerciseOptions(
|
||||
ProgressionDateRange range,
|
||||
) async {
|
||||
return const [];
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<ProgressionMeasureOptionData>> listMeasureOptions({
|
||||
required ProgressionDateRange range,
|
||||
required String exerciseKey,
|
||||
}) async {
|
||||
return const [];
|
||||
}
|
||||
|
||||
@override
|
||||
Future<ProgressionExerciseSeriesData> readExerciseSeries({
|
||||
required ProgressionDateRange range,
|
||||
required String exerciseKey,
|
||||
required ProgressionMeasure measure,
|
||||
}) async {
|
||||
return ProgressionExerciseSeriesData(
|
||||
exerciseKey: exerciseKey,
|
||||
exerciseNameSnapshot: exerciseKey,
|
||||
measure: ProgressionMeasureOptionData(
|
||||
measure: measure,
|
||||
label: 'Score',
|
||||
lowerIsBetter: false,
|
||||
),
|
||||
points: const [],
|
||||
hasAnyAllTimeData: false,
|
||||
hasAnyCompletedExerciseResult: false,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
final class _FakeExercisePerformanceReferenceRepository
|
||||
implements ExercisePerformanceReferenceRepository {
|
||||
@override
|
||||
|
||||
Reference in New Issue
Block a user