feat(exercice): état d'exécution Chrono suivant prêt (ticket #78)
Ajoute l'état "Chrono suivant prêt" sur workout_execution_screen.dart pour l'auto-enchaînement des chronos d'étapes. Corrige _startCurrentStepTimerIfNeeded() qui forçait à tort startTimer() : il se contente maintenant de rafraîchir le ticker d'affichage, laissant le backend (#76) seul décisionnaire du démarrage automatique ou de l'attente du chrono suivant. flutter pub get OK, dart format appliqué (aucun changement), analyze propre (mêmes infos préexistantes), 153/153 tests verts (dont le test de non-régression pour l'enchaînement automatique activé par défaut), build APK debug validé. Dernier ticket de développement du chantier "auto-enchaînement des chronos d'étapes" (#73) — il ne reste que la QA finale (#79). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@ -1202,7 +1202,7 @@ void main() {
|
||||
|
||||
await tester.tap(find.text('Démarrer la séquence'));
|
||||
await tester.pump();
|
||||
clock.value = DateTime.utc(2026, 7, 17, 12, 0, 1);
|
||||
clock.value = DateTime.utc(2026, 7, 17, 12, 0, 1, 200);
|
||||
await tester.pump(const Duration(milliseconds: 200));
|
||||
await tester.pump();
|
||||
|
||||
@ -1211,9 +1211,86 @@ void main() {
|
||||
expect(find.text('ÉTAPE 2 / 2'), findsOneWidget);
|
||||
expect(find.text('Droite'), findsOneWidget);
|
||||
expect(find.text('00:02'), findsOneWidget);
|
||||
expect(
|
||||
repository.stepProgressStates.single.status,
|
||||
ActiveExerciseStepProgressStatus.runningTimer,
|
||||
);
|
||||
expect(audio.longBeeps, 1);
|
||||
});
|
||||
|
||||
testWidgets(
|
||||
'chrono suivant prêt attend un démarrage manuel quand l’enchaînement est désactivé',
|
||||
(tester) async {
|
||||
await tester.binding.setSurfaceSize(const Size(400, 1600));
|
||||
addTearDown(() => tester.binding.setSurfaceSize(null));
|
||||
|
||||
final clock = _FakeClock(DateTime.utc(2026, 7, 17, 12));
|
||||
final repository = _FakeActiveSessionRepository();
|
||||
final session = ActiveWorkoutSession(
|
||||
metadata: _metadata('session-1'),
|
||||
sourceWorkoutTemplateId: 'template-1',
|
||||
status: ActiveWorkoutStatus.running,
|
||||
startedAt: DateTime.utc(2026, 7, 17, 12),
|
||||
lastPersistedAt: DateTime.utc(2026, 7, 17, 12),
|
||||
elapsedActiveMs: 0,
|
||||
currentProgramIndex: 0,
|
||||
currentExerciseIndex: 0,
|
||||
currentSetIndex: 0,
|
||||
resolvedTemplateSnapshotJson: _sessionSnapshot(
|
||||
targetReps: 1,
|
||||
autoStartNextTimedStep: false,
|
||||
exerciseSteps: [
|
||||
_step('step-1', 0, 'Gauche', ExerciseStepType.time, 1),
|
||||
_step('step-2', 1, 'Droite', ExerciseStepType.time, 2),
|
||||
],
|
||||
),
|
||||
);
|
||||
repository.session = session;
|
||||
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
home: WorkoutExecutionScreen(
|
||||
initialSession: session,
|
||||
activeUseCases: _activeUseCases(repository, clock),
|
||||
stepUseCases: _stepUseCases(repository, clock),
|
||||
stepAudioCuePlayer: _FakeStepAudioCuePlayer(),
|
||||
closeUseCase: _closeUseCase(repository, clock),
|
||||
historyUseCases: _historyUseCases(clock),
|
||||
workoutTemplateUseCases: _workoutTemplateUseCases(),
|
||||
),
|
||||
),
|
||||
);
|
||||
await tester.pump();
|
||||
|
||||
await tester.tap(find.text('Démarrer la séquence'));
|
||||
await tester.pump();
|
||||
clock.value = DateTime.utc(2026, 7, 17, 12, 0, 1, 200);
|
||||
await tester.pump(const Duration(milliseconds: 200));
|
||||
await tester.pump();
|
||||
|
||||
expect(repository.stepResults.single.stepIndex, 0);
|
||||
expect(find.text('ÉTAPE 2 / 2'), findsOneWidget);
|
||||
expect(find.text('Droite'), findsOneWidget);
|
||||
expect(find.text('00:02'), findsOneWidget);
|
||||
expect(find.text('Chrono suivant prêt'), findsOneWidget);
|
||||
expect(find.text('Démarrer le chrono'), findsOneWidget);
|
||||
expect(
|
||||
repository.stepProgressStates.single.status,
|
||||
ActiveExerciseStepProgressStatus.stoppedTimer,
|
||||
);
|
||||
expect(repository.stepProgressStates.single.startedAt, isNull);
|
||||
|
||||
await tester.tap(find.text('Démarrer le chrono'));
|
||||
await tester.pump();
|
||||
|
||||
expect(
|
||||
repository.stepProgressStates.single.status,
|
||||
ActiveExerciseStepProgressStatus.runningTimer,
|
||||
);
|
||||
expect(repository.stepProgressStates.single.startedAt, clock.value);
|
||||
},
|
||||
);
|
||||
|
||||
testWidgets('la séquence passe au deuxième passage si répétitions > 1', (
|
||||
tester,
|
||||
) async {
|
||||
@ -1460,6 +1537,7 @@ String _sessionSnapshot({
|
||||
ScoreInputMode scoreInputMode = ScoreInputMode.manual,
|
||||
List<String> imageMediaIds = const [],
|
||||
List<Map<String, Object?>> exerciseSteps = const [],
|
||||
bool autoStartNextTimedStep = true,
|
||||
String? videoMediaId,
|
||||
}) {
|
||||
return jsonEncode({
|
||||
@ -1490,6 +1568,7 @@ String _sessionSnapshot({
|
||||
'exerciseVideoMediaIdSnapshot': videoMediaId,
|
||||
'videoMediaIdSnapshot': videoMediaId,
|
||||
'exerciseStepsSnapshot': exerciseSteps,
|
||||
'autoStartNextTimedStepSnapshot': autoStartNextTimedStep,
|
||||
},
|
||||
],
|
||||
}),
|
||||
|
||||
Reference in New Issue
Block a user