feat(ui): integre affichage stats par scope et selection des types metier d'exercice cote telephone

UI telephone pour #179 (graphes/statistiques par etape, serie, exercice, seance) et #183 (choix des types metier d'exercice, hors pont Health Services).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-30 14:55:52 +02:00
parent fdaa518fa9
commit 36691643d7
8 changed files with 447 additions and 59 deletions

View File

@ -128,6 +128,54 @@ void main() {
expect(exerciseRepository.saved.single.tags, ['match']);
});
testWidgets('choisir des types métier les sauvegarde avec exercice', (
tester,
) async {
final exerciseRepository = _FakeExerciseRepository();
await tester.binding.setSurfaceSize(const Size(400, 1600));
addTearDown(() => tester.binding.setSurfaceSize(null));
await tester.pumpWidget(
MaterialApp(
home: ExerciseFormScreen(
exerciseUseCases: _exerciseUseCases(exerciseRepository),
mediaUseCases: _mediaUseCases(exerciseRepository),
),
),
);
await tester.enterText(find.widgetWithText(TextFormField, 'Nom'), 'Départ');
await tester.ensureVisible(find.text('Type dexercice'));
await tester.dragUntilVisible(
find.widgetWithText(FilterChip, 'Dribble'),
find.byType(SingleChildScrollView).last,
const Offset(-180, 0),
);
await tester.tap(find.widgetWithText(FilterChip, 'Dribble'));
await tester.dragUntilVisible(
find.widgetWithText(FilterChip, 'Haute intensité'),
find.byType(SingleChildScrollView).last,
const Offset(-250, 0),
);
await tester.tap(find.widgetWithText(FilterChip, 'Haute intensité'));
await tester.ensureVisible(
find.widgetWithText(TextFormField, 'Durée par défaut (s)'),
);
await tester.enterText(
find.widgetWithText(TextFormField, 'Durée par défaut (s)'),
'30',
);
await tester.ensureVisible(find.text('Enregistrer'));
await tester.tap(find.text('Enregistrer'));
await tester.pumpAndSettle();
expect(exerciseRepository.saved.single.businessTypes, [
BusinessExerciseType.dribble,
BusinessExerciseType.highIntensity,
]);
});
testWidgets('filtre les exercices par tag et efface tous les filtres', (
tester,
) async {
@ -414,7 +462,7 @@ void main() {
await _pumpExerciseForm(tester, exerciseRepository);
await tester.enterText(find.widgetWithText(TextFormField, 'Nom'), 'Tirs');
await tester.enterText(
find.widgetWithText(TextFormField, 'Temps par défaut (s)'),
find.widgetWithText(TextFormField, 'Durée par défaut (s)'),
'30',
);
await tester.tap(find.widgetWithText(SwitchListTile, 'Score'));
@ -614,7 +662,7 @@ void main() {
await _pumpExerciseForm(tester, exerciseRepository);
await tester.enterText(find.widgetWithText(TextFormField, 'Nom'), 'Combo');
await tester.enterText(
find.widgetWithText(TextFormField, 'Temps par défaut (s)'),
find.widgetWithText(TextFormField, 'Durée par défaut (s)'),
'30',
);
await tester.tap(
@ -655,7 +703,7 @@ void main() {
await _pumpExerciseForm(tester, exerciseRepository);
await tester.enterText(find.widgetWithText(TextFormField, 'Nom'), 'Combo');
await tester.enterText(
find.widgetWithText(TextFormField, 'Temps par défaut (s)'),
find.widgetWithText(TextFormField, 'Durée par défaut (s)'),
'30',
);

View File

@ -940,6 +940,19 @@ final class _FakeWorkoutTelemetryRepository
return const [];
}
@override
Future<List<WorkoutTelemetrySample>> listSamplesForScope({
required String sessionId,
required WorkoutTelemetryAggregateScope scope,
int? programIndex,
int? exerciseIndex,
int? setIndex,
int? passageIndex,
int? stepIndex,
}) async {
return const [];
}
@override
Future<void> replaceAggregatesForSession({
required String sessionId,

View File

@ -237,7 +237,7 @@ void main() {
expect(find.text('186 kcal'), findsOneWidget);
});
testWidgets('naffiche aucun indicateur capteur sans donnée FC', (
testWidgets('affiche les états capteur explicites avant la première mesure', (
tester,
) async {
final now = DateTime.now().toUtc();
@ -272,10 +272,10 @@ void main() {
),
);
expect(find.textContaining('bpm'), findsNothing);
expect(find.textContaining('kcal'), findsNothing);
expect(find.byIcon(Icons.favorite), findsNothing);
expect(find.byIcon(Icons.local_fire_department), findsNothing);
expect(find.text('Mesure en attente'), findsNWidgets(3));
expect(find.byIcon(Icons.favorite), findsOneWidget);
expect(find.byIcon(Icons.directions_run), findsOneWidget);
expect(find.byIcon(Icons.local_fire_department), findsOneWidget);
});
testWidgets('ne fabrique pas de calories sans mesure montre native', (
@ -331,6 +331,7 @@ void main() {
expect(find.text('FC 124 bpm'), findsOneWidget);
expect(find.textContaining('kcal'), findsNothing);
expect(find.text('Donnée indisponible'), findsNWidgets(2));
});
testWidgets('atténue la fréquence cardiaque périmée', (tester) async {