feat(ui): réglages auto-enchaînement exercice, programme et séance (ticket #77)
Ajoute les réglages d'auto-enchaînement des chronos d'étapes sur exercise_library_screen.dart, program_screen.dart et workout_template_screen.dart, s'appuyant sur la résolution du ticket #76. Propagation du nouveau champ vérifiée exhaustivement sur les 5 points d'impact de _ProgramExerciseDraft (constructeur, fromExercise, fromProgramExercise, copy(), toConfig()) — pas de répétition du bug #72. flutter pub get OK, dart format appliqué (7 fichiers reformatés), analyze propre (mêmes infos préexistantes), 152/152 tests verts, build APK debug validé. Développés dans le même worktree partagé par DevBackend et DevFrontend ; feature/step-chaining-77-ui-settings restée vide, jamais divergée. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@ -44,6 +44,117 @@ void main() {
|
||||
},
|
||||
);
|
||||
|
||||
testWidgets(
|
||||
'personnaliser l’enchaînement automatique transmet l’override séance',
|
||||
(tester) async {
|
||||
final program = WorkoutTemplateProgramDraft(
|
||||
clientKey: 'program-1',
|
||||
programNameSnapshot: 'Circuit',
|
||||
defaultRestSecondsSnapshot: 60,
|
||||
programSnapshotJson: '{}',
|
||||
exercises: [
|
||||
WorkoutTemplateExerciseDraft(
|
||||
snapshotExerciseId: 'exercise-1',
|
||||
exerciseNameSnapshot: 'Navettes',
|
||||
setsCount: 3,
|
||||
timeEnabled: true,
|
||||
repsEnabled: false,
|
||||
scoreEnabled: false,
|
||||
exerciseStepsSnapshot: [
|
||||
_step(
|
||||
id: 'step-1',
|
||||
position: 0,
|
||||
name: 'Course',
|
||||
type: ExerciseStepType.time,
|
||||
),
|
||||
_step(
|
||||
id: 'step-2',
|
||||
position: 1,
|
||||
name: 'Retour',
|
||||
type: ExerciseStepType.time,
|
||||
),
|
||||
],
|
||||
autoStartNextTimedStepSnapshot: true,
|
||||
targetTimeSeconds: 30,
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
await tester.binding.setSurfaceSize(const Size(400, 1400));
|
||||
addTearDown(() => tester.binding.setSurfaceSize(null));
|
||||
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(home: WorkoutTemplateProgramDetailScreen(program: program)),
|
||||
);
|
||||
|
||||
await tester.tap(
|
||||
find.widgetWithText(
|
||||
SwitchListTile,
|
||||
'Enchaîner automatiquement les chronos consécutifs',
|
||||
),
|
||||
);
|
||||
await tester.pump();
|
||||
|
||||
expect(
|
||||
find.textContaining('Personnalisé pour cette séance'),
|
||||
findsOneWidget,
|
||||
);
|
||||
final override = program.toOverrides().single;
|
||||
expect(override.autoStartNextTimedStepOverride, isFalse);
|
||||
},
|
||||
);
|
||||
|
||||
testWidgets(
|
||||
'revenir au réglage du programme remet l’override séance à null',
|
||||
(tester) async {
|
||||
final program = WorkoutTemplateProgramDraft(
|
||||
clientKey: 'program-1',
|
||||
programNameSnapshot: 'Circuit',
|
||||
defaultRestSecondsSnapshot: 60,
|
||||
programSnapshotJson: '{}',
|
||||
exercises: [
|
||||
WorkoutTemplateExerciseDraft(
|
||||
snapshotExerciseId: 'exercise-1',
|
||||
exerciseNameSnapshot: 'Navettes',
|
||||
setsCount: 3,
|
||||
timeEnabled: true,
|
||||
repsEnabled: false,
|
||||
scoreEnabled: false,
|
||||
exerciseStepsSnapshot: [
|
||||
_step(
|
||||
id: 'step-1',
|
||||
position: 0,
|
||||
name: 'Course',
|
||||
type: ExerciseStepType.time,
|
||||
),
|
||||
],
|
||||
autoStartNextTimedStepSnapshot: false,
|
||||
autoStartNextTimedStepOverride: true,
|
||||
targetTimeSeconds: 30,
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
await tester.binding.setSurfaceSize(const Size(400, 1400));
|
||||
addTearDown(() => tester.binding.setSurfaceSize(null));
|
||||
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(home: WorkoutTemplateProgramDetailScreen(program: program)),
|
||||
);
|
||||
|
||||
expect(
|
||||
find.textContaining('Personnalisé pour cette séance'),
|
||||
findsOneWidget,
|
||||
);
|
||||
|
||||
await tester.tap(find.text('Revenir au réglage du programme'));
|
||||
await tester.pump();
|
||||
|
||||
expect(find.textContaining('Réglage du programme'), findsOneWidget);
|
||||
expect(program.toOverrides(), isEmpty);
|
||||
},
|
||||
);
|
||||
|
||||
testWidgets(
|
||||
'lancer une séance alors qu’une autre est en cours affiche un message',
|
||||
(tester) async {
|
||||
@ -308,6 +419,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