feat(exercice): exécution de séance avec module séquence et bips (ticket #60)

Ajoute le lecteur de bips d'étapes (presentation/exercise_step_audio.dart,
port ExerciseStepAudioCuePlayer injectable en test, jamais le vrai
audioplayers en test) et les fichiers audio associés
(assets/audio/step_countdown_short.wav, step_completion_long.wav).
Câble ActiveExerciseStepUseCases dans app_bootstrap.dart et l'expose à
WorkoutExecutionScreen. Les appels audio réels sont protégés par un
try/catch qui log sans jamais bloquer la progression d'étape. flutter
pub get OK (ajout audioplayers), analyze propre (mêmes infos
préexistantes + 2 nouvelles use_build_context_synchronously, non
bloquantes), 100/100 tests verts, build APK debug validé.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-19 20:07:56 +02:00
parent 83c87d9a42
commit 6947cee30c
13 changed files with 1459 additions and 0 deletions

View File

@ -0,0 +1,49 @@
import 'package:audioplayers/audioplayers.dart';
abstract interface class ExerciseStepAudioCuePlayer {
Future<void> playShortCountdownBeep();
Future<void> playLongCompletionBeep();
Future<void> dispose();
}
final class AudioplayersExerciseStepAudioCuePlayer
implements ExerciseStepAudioCuePlayer {
AudioplayersExerciseStepAudioCuePlayer();
final AudioPlayer _player = AudioPlayer();
@override
Future<void> playShortCountdownBeep() {
return _play('audio/step_countdown_short.wav');
}
@override
Future<void> playLongCompletionBeep() {
return _play('audio/step_completion_long.wav');
}
Future<void> _play(String assetPath) async {
await _player.stop();
await _player.play(AssetSource(assetPath));
}
@override
Future<void> dispose() {
return _player.dispose();
}
}
final class NoOpExerciseStepAudioCuePlayer implements ExerciseStepAudioCuePlayer {
const NoOpExerciseStepAudioCuePlayer();
@override
Future<void> playShortCountdownBeep() async {}
@override
Future<void> playLongCompletionBeep() async {}
@override
Future<void> dispose() async {}
}