feat(exercice): modèle et migration pour l'auto-enchaînement des chronos d'étapes (ticket #75)

Étend le modèle Drift (migration schemaVersion 13→14, ADD COLUMN) et
la couche application (entités, use cases, repositories) pour
supporter l'auto-enchaînement des chronos d'étapes. flutter pub get
OK, build_runner OK, analyze propre (mêmes infos préexistantes),
141/141 tests verts, build APK debug validé. Premier ticket du
chantier "auto-enchaînement des chronos d'étapes" (#73).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-20 13:42:46 +02:00
parent f510053d55
commit e61365277b
8 changed files with 704 additions and 4 deletions

View File

@ -318,6 +318,7 @@ final class Exercise {
this.defaultTargetReps,
this.defaultTargetScore,
this.defaultTargetScoreTimeMs,
this.autoStartNextTimedStep = true,
List<ExerciseStep> steps = const [],
this.archivedAt,
}) : name = _nonBlank(name, 'Exercise name'),
@ -375,6 +376,7 @@ final class Exercise {
final int? defaultTargetReps;
final double? defaultTargetScore;
final int? defaultTargetScoreTimeMs;
final bool autoStartNextTimedStep;
final List<ExerciseStep> steps;
final DateTime? archivedAt;
@ -409,6 +411,7 @@ final class Exercise {
Object? defaultTargetReps = _unchanged,
Object? defaultTargetScore = _unchanged,
Object? defaultTargetScoreTimeMs = _unchanged,
bool? autoStartNextTimedStep,
Object? steps = _unchanged,
Object? archivedAt = _unchanged,
}) {
@ -456,6 +459,8 @@ final class Exercise {
defaultTargetScoreTimeMs: defaultTargetScoreTimeMs == _unchanged
? this.defaultTargetScoreTimeMs
: defaultTargetScoreTimeMs as int?,
autoStartNextTimedStep:
autoStartNextTimedStep ?? this.autoStartNextTimedStep,
steps: steps == _unchanged ? this.steps : steps as List<ExerciseStep>,
archivedAt: archivedAt == _unchanged
? this.archivedAt
@ -562,6 +567,8 @@ final class ProgramExercise {
List<String> exerciseImageMediaIdsSnapshot = const [],
this.exerciseVideoMediaIdSnapshot,
List<ExerciseStep> exerciseStepsSnapshot = const [],
this.autoStartNextTimedStepSnapshot = true,
this.autoStartNextTimedStepOverride,
this.exerciseArchivedSnapshot = false,
required this.availableTimeSnapshot,
required this.availableRepsSnapshot,
@ -628,6 +635,8 @@ final class ProgramExercise {
final List<String> exerciseImageMediaIdsSnapshot;
final String? exerciseVideoMediaIdSnapshot;
final List<ExerciseStep> exerciseStepsSnapshot;
final bool autoStartNextTimedStepSnapshot;
final bool? autoStartNextTimedStepOverride;
final bool exerciseArchivedSnapshot;
final bool availableTimeSnapshot;
final bool availableRepsSnapshot;
@ -675,6 +684,7 @@ final class ProgramExercise {
exerciseImageMediaIdsSnapshot: exercise.imageMediaIds,
exerciseVideoMediaIdSnapshot: exercise.videoMediaId,
exerciseStepsSnapshot: exercise.steps,
autoStartNextTimedStepSnapshot: exercise.autoStartNextTimedStep,
exerciseArchivedSnapshot: exercise.archivedAt != null,
availableTimeSnapshot: exercise.hasTimeMeasure,
availableRepsSnapshot: exercise.hasRepsMeasure,
@ -707,6 +717,8 @@ final class ProgramExercise {
'exerciseStepsSnapshot': exerciseStepsSnapshot
.map((step) => step.toSnapshotJson())
.toList(),
'autoStartNextTimedStepSnapshot': autoStartNextTimedStepSnapshot,
'autoStartNextTimedStepOverride': autoStartNextTimedStepOverride,
'exerciseArchivedSnapshot': exerciseArchivedSnapshot,
'availableTimeSnapshot': availableTimeSnapshot,
'availableRepsSnapshot': availableRepsSnapshot,
@ -802,6 +814,7 @@ final class WorkoutTemplateExerciseOverride {
this.targetRepsOverride,
this.targetScoreOverride,
this.targetScoreTimeMsOverride,
this.autoStartNextTimedStepOverride,
}) : snapshotProgramExerciseId = _nonBlank(
snapshotProgramExerciseId,
'Snapshot program exercise id',
@ -835,6 +848,7 @@ final class WorkoutTemplateExerciseOverride {
final int? targetRepsOverride;
final double? targetScoreOverride;
final int? targetScoreTimeMsOverride;
final bool? autoStartNextTimedStepOverride;
}
final class ActiveWorkoutSession {