feat(ui): écran Exécution de séance

Ajoute l'écran d'exécution de séance (presentation/workout_execution_screen.dart),
avec les ajustements application/domaine/repositories nécessaires et la
navigation depuis l'accueil et l'écran séance-modèle. flutter analyze
propre, 15/15 tests verts, build APK debug validé.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-17 19:08:23 +02:00
parent 6bc09fe1ca
commit bfd727a6a2
9 changed files with 1159 additions and 8 deletions

View File

@ -590,6 +590,8 @@ final class ActiveWorkoutSessionUseCases {
final IdGenerator ids;
final String originDeviceId;
Future<ActiveWorkoutSession?> findOpen() => sessionRepository.findOpen();
Future<ActiveWorkoutSession> startFromTemplate(String templateId) async {
final template = await templateRepository.findById(templateId);
if (template == null) {
@ -659,6 +661,97 @@ final class ActiveWorkoutSessionUseCases {
return result;
}
Future<ActiveSetResult> recordCurrentSetResult({
required String sessionId,
required String programSnapshotId,
required String exerciseSnapshotId,
required int programIndex,
required int exerciseIndex,
required int setIndex,
int? actualTimeMs,
int? actualReps,
double? actualScore,
String? scoreLabelSnapshot,
String? scoreUnitSnapshot,
}) async {
final now = clock.now();
final result = ActiveSetResult(
metadata: _newMetadata(ids, originDeviceId, now),
activeWorkoutSessionId: sessionId,
programSnapshotId: programSnapshotId,
exerciseSnapshotId: exerciseSnapshotId,
programIndex: programIndex,
exerciseIndex: exerciseIndex,
setIndex: setIndex,
completedAt: now,
actualTimeMs: actualTimeMs,
actualReps: actualReps,
actualScore: actualScore,
scoreLabelSnapshot: scoreLabelSnapshot,
scoreUnitSnapshot: scoreUnitSnapshot,
);
await sessionRepository.saveSetResult(result);
return result;
}
Future<ActiveWorkoutSession> updateProgress({
required String sessionId,
required int programIndex,
required int exerciseIndex,
required int setIndex,
}) async {
final session = await _requiredSession(sessionId);
final updated = session.copyWith(
currentProgramIndex: programIndex,
currentExerciseIndex: exerciseIndex,
currentSetIndex: setIndex,
metadata: session.metadata.touch(clock.now()),
);
await sessionRepository.save(updated);
return updated;
}
Future<ActiveWorkoutSession> quitAndSave(String sessionId) async {
final session = await _requiredSession(sessionId);
final now = clock.now();
final saved = session.copyWith(
status: ActiveWorkoutStatus.savedExit,
lastPersistedAt: now,
elapsedActiveMs: session.elapsedActiveMillisecondsAt(now),
metadata: session.metadata.touch(now),
);
await sessionRepository.save(saved);
return saved;
}
Future<ActiveWorkoutSession> abandon(String sessionId) async {
final session = await _requiredSession(sessionId);
final now = clock.now();
final abandoned = session.copyWith(
status: ActiveWorkoutStatus.abandoned,
endedAt: now,
lastPersistedAt: now,
elapsedActiveMs: session.elapsedActiveMillisecondsAt(now),
metadata: session.metadata.touch(now),
);
await sessionRepository.save(abandoned);
return abandoned;
}
Future<ActiveWorkoutSession> complete(String sessionId) async {
final session = await _requiredSession(sessionId);
final now = clock.now();
final completed = session.copyWith(
status: ActiveWorkoutStatus.completed,
endedAt: now,
lastPersistedAt: now,
elapsedActiveMs: session.elapsedActiveMillisecondsAt(now),
metadata: session.metadata.touch(now),
);
await sessionRepository.save(completed);
return completed;
}
Future<ActiveRestState> startRestAfterSet({
required String sessionId,
required int afterProgramIndex,