fix(programme): étapes d'exercice jamais affichées en séance (ticket #72)
_ProgramExerciseDraft dans program_screen.dart (état interne du formulaire de composition de programme) n'avait jamais de champ exerciseStepsSnapshot depuis sa création, avant le chantier "Exercice à plusieurs étapes" (#54). Les étapes d'un exercice étaient donc systématiquement perdues à chaque composition/édition de programme via l'écran réel, peu importe l'ordre des opérations — d'où l'absence totale d'étapes affichées en séance. Ajoute le champ manquant et 2 tests de non-régression exerçant le vrai flux UI ProgramFormScreen. flutter pub get OK, dart format appliqué (aucun changement), analyze propre (mêmes infos préexistantes), 135/135 tests verts, build APK debug validé. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@ -915,6 +915,7 @@ final class _ProgramExerciseDraft {
|
||||
this.exerciseImageMediaIdSnapshot,
|
||||
this.exerciseImageMediaIdsSnapshot = const [],
|
||||
this.exerciseVideoMediaIdSnapshot,
|
||||
this.exerciseStepsSnapshot = const [],
|
||||
this.exerciseArchivedSnapshot = false,
|
||||
required this.availableTimeSnapshot,
|
||||
required this.availableRepsSnapshot,
|
||||
@ -944,6 +945,7 @@ final class _ProgramExerciseDraft {
|
||||
exercise.iconMediaId ?? exercise.imageMediaId,
|
||||
exerciseImageMediaIdsSnapshot: exercise.imageMediaIds,
|
||||
exerciseVideoMediaIdSnapshot: exercise.videoMediaId,
|
||||
exerciseStepsSnapshot: exercise.steps,
|
||||
exerciseArchivedSnapshot: exercise.archivedAt != null,
|
||||
availableTimeSnapshot: exercise.hasTimeMeasure,
|
||||
availableRepsSnapshot: exercise.hasRepsMeasure,
|
||||
@ -975,6 +977,7 @@ final class _ProgramExerciseDraft {
|
||||
exerciseImageMediaIdSnapshot: exercise.exerciseImageMediaIdSnapshot,
|
||||
exerciseImageMediaIdsSnapshot: exercise.exerciseImageMediaIdsSnapshot,
|
||||
exerciseVideoMediaIdSnapshot: exercise.exerciseVideoMediaIdSnapshot,
|
||||
exerciseStepsSnapshot: exercise.exerciseStepsSnapshot,
|
||||
exerciseArchivedSnapshot: exercise.exerciseArchivedSnapshot,
|
||||
availableTimeSnapshot: exercise.availableTimeSnapshot,
|
||||
availableRepsSnapshot: exercise.availableRepsSnapshot,
|
||||
@ -1004,6 +1007,7 @@ final class _ProgramExerciseDraft {
|
||||
final String? exerciseImageMediaIdSnapshot;
|
||||
final List<String> exerciseImageMediaIdsSnapshot;
|
||||
final String? exerciseVideoMediaIdSnapshot;
|
||||
final List<ExerciseStep> exerciseStepsSnapshot;
|
||||
final bool exerciseArchivedSnapshot;
|
||||
final bool availableTimeSnapshot;
|
||||
final bool availableRepsSnapshot;
|
||||
@ -1029,6 +1033,7 @@ final class _ProgramExerciseDraft {
|
||||
exerciseImageMediaIdSnapshot: exerciseImageMediaIdSnapshot,
|
||||
exerciseImageMediaIdsSnapshot: exerciseImageMediaIdsSnapshot,
|
||||
exerciseVideoMediaIdSnapshot: exerciseVideoMediaIdSnapshot,
|
||||
exerciseStepsSnapshot: exerciseStepsSnapshot,
|
||||
exerciseArchivedSnapshot: exerciseArchivedSnapshot,
|
||||
availableTimeSnapshot: availableTimeSnapshot,
|
||||
availableRepsSnapshot: availableRepsSnapshot,
|
||||
@ -1057,6 +1062,7 @@ final class _ProgramExerciseDraft {
|
||||
exerciseImageMediaIdSnapshot: exerciseImageMediaIdSnapshot,
|
||||
exerciseImageMediaIdsSnapshot: exerciseImageMediaIdsSnapshot,
|
||||
exerciseVideoMediaIdSnapshot: exerciseVideoMediaIdSnapshot,
|
||||
exerciseStepsSnapshot: exerciseStepsSnapshot,
|
||||
exerciseArchivedSnapshot: exerciseArchivedSnapshot,
|
||||
availableTimeSnapshot: availableTimeSnapshot,
|
||||
availableRepsSnapshot: availableRepsSnapshot,
|
||||
|
||||
@ -164,6 +164,148 @@ void main() {
|
||||
},
|
||||
);
|
||||
|
||||
testWidgets(
|
||||
'ajouter un exercice avec étapes conserve le snapshot des étapes',
|
||||
(tester) async {
|
||||
final steps = [
|
||||
_step(
|
||||
id: 'step-1',
|
||||
position: 0,
|
||||
name: 'Course',
|
||||
type: ExerciseStepType.time,
|
||||
),
|
||||
_step(
|
||||
id: 'step-2',
|
||||
position: 1,
|
||||
name: 'Tirs',
|
||||
type: ExerciseStepType.reps,
|
||||
),
|
||||
];
|
||||
final programRepository = _FakeProgramRepository();
|
||||
final exerciseRepository = _FakeExerciseRepository()
|
||||
..exercises.add(
|
||||
Exercise(
|
||||
metadata: _metadata('exercise-steps'),
|
||||
name: 'Circuit tirs',
|
||||
hasTimeMeasure: false,
|
||||
hasRepsMeasure: true,
|
||||
hasScoreMeasure: false,
|
||||
defaultTargetReps: 2,
|
||||
steps: steps,
|
||||
),
|
||||
);
|
||||
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
home: ProgramFormScreen(
|
||||
programUseCases: _programUseCases(
|
||||
programRepository,
|
||||
exerciseRepository,
|
||||
),
|
||||
exerciseUseCases: _exerciseUseCases(exerciseRepository),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
await tester.enterText(
|
||||
find.widgetWithText(TextFormField, 'Nom'),
|
||||
'Programme étapes',
|
||||
);
|
||||
await tester.tap(find.text('Ajouter un exercice'));
|
||||
await tester.pumpAndSettle();
|
||||
await tester.tap(find.text('Circuit tirs'));
|
||||
await tester.pumpAndSettle();
|
||||
await tester.tap(find.text('Enregistrer'));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
final savedSteps = programRepository
|
||||
.programs
|
||||
.single
|
||||
.exercises
|
||||
.single
|
||||
.exerciseStepsSnapshot;
|
||||
expect(savedSteps, hasLength(2));
|
||||
expect(savedSteps.map((step) => step.name), ['Course', 'Tirs']);
|
||||
expect(savedSteps.map((step) => step.type), [
|
||||
ExerciseStepType.time,
|
||||
ExerciseStepType.reps,
|
||||
]);
|
||||
},
|
||||
);
|
||||
|
||||
testWidgets(
|
||||
'réenregistrer un programme existant conserve les étapes du snapshot',
|
||||
(tester) async {
|
||||
final steps = [
|
||||
_step(
|
||||
id: 'step-1',
|
||||
position: 0,
|
||||
name: 'Course',
|
||||
type: ExerciseStepType.time,
|
||||
),
|
||||
_step(
|
||||
id: 'step-2',
|
||||
position: 1,
|
||||
name: 'Tirs',
|
||||
type: ExerciseStepType.reps,
|
||||
),
|
||||
];
|
||||
final programRepository = _FakeProgramRepository()
|
||||
..programs.add(
|
||||
Program(
|
||||
metadata: _metadata('program-steps'),
|
||||
name: 'Programme étapes',
|
||||
defaultRestSeconds: 45,
|
||||
exercises: [
|
||||
ProgramExercise(
|
||||
metadata: _metadata('program-exercise-steps'),
|
||||
programId: 'program-steps',
|
||||
sourceExerciseId: 'exercise-steps',
|
||||
position: 0,
|
||||
exerciseNameSnapshot: 'Circuit tirs',
|
||||
exerciseStepsSnapshot: steps,
|
||||
availableTimeSnapshot: false,
|
||||
availableRepsSnapshot: true,
|
||||
availableScoreSnapshot: false,
|
||||
setsCount: 3,
|
||||
timeEnabled: false,
|
||||
repsEnabled: true,
|
||||
scoreEnabled: false,
|
||||
targetReps: 2,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
final exerciseRepository = _FakeExerciseRepository();
|
||||
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
home: ProgramFormScreen(
|
||||
programUseCases: _programUseCases(
|
||||
programRepository,
|
||||
exerciseRepository,
|
||||
),
|
||||
exerciseUseCases: _exerciseUseCases(exerciseRepository),
|
||||
program: programRepository.programs.single,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
await tester.tap(find.text('Enregistrer'));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
final savedSteps = programRepository
|
||||
.programs
|
||||
.single
|
||||
.exercises
|
||||
.single
|
||||
.exerciseStepsSnapshot;
|
||||
expect(savedSteps, hasLength(2));
|
||||
expect(savedSteps.map((step) => step.name), ['Course', 'Tirs']);
|
||||
expect(savedSteps.map((step) => step.position), [0, 1]);
|
||||
},
|
||||
);
|
||||
|
||||
testWidgets('affiche l’objectif de chrono pour un score en mode chrono', (
|
||||
tester,
|
||||
) async {
|
||||
@ -510,6 +652,21 @@ EntityMetadata _metadata(String id) {
|
||||
);
|
||||
}
|
||||
|
||||
ExerciseStep _step({
|
||||
required String id,
|
||||
required int position,
|
||||
required String name,
|
||||
required ExerciseStepType type,
|
||||
}) {
|
||||
return ExerciseStep(
|
||||
id: id,
|
||||
position: position,
|
||||
name: name,
|
||||
type: type,
|
||||
defaultTargetValue: type == ExerciseStepType.time ? 30 : 5,
|
||||
);
|
||||
}
|
||||
|
||||
final class _FakeClock implements Clock {
|
||||
const _FakeClock(this.value);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user