feat(ui): écran Création/édition de programme
Ajoute l'écran de programme (presentation/program_screen.dart) et un écran d'accueil (presentation/home_screen.dart) pour la navigation, avec les ajustements application/domaine/repositories nécessaires. flutter analyze propre, 11/11 tests verts, build APK debug validé. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@ -109,6 +109,12 @@ final class _FakeProgramRepository implements ProgramRepository {
|
||||
@override
|
||||
Future<Program?> findById(String id) async => null;
|
||||
|
||||
@override
|
||||
Future<List<Program>> listActive() async => const [];
|
||||
|
||||
@override
|
||||
Future<void> replaceExercises(Program program, DateTime deletedAt) async {}
|
||||
|
||||
@override
|
||||
Future<void> save(Program program) async {}
|
||||
|
||||
|
||||
198
test/presentation/program_screen_test.dart
Normal file
198
test/presentation/program_screen_test.dart
Normal file
@ -0,0 +1,198 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:gametime/application/application.dart';
|
||||
import 'package:gametime/domain/domain.dart';
|
||||
import 'package:gametime/presentation/presentation.dart';
|
||||
|
||||
void main() {
|
||||
testWidgets(
|
||||
'ajoute un exercice au programme avec sa configuration par défaut',
|
||||
(tester) async {
|
||||
final exerciseRepository = _FakeExerciseRepository()
|
||||
..exercises.add(
|
||||
Exercise(
|
||||
metadata: _metadata('exercise-1'),
|
||||
name: 'Squat',
|
||||
hasTimeMeasure: true,
|
||||
hasRepsMeasure: true,
|
||||
hasScoreMeasure: false,
|
||||
),
|
||||
);
|
||||
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
home: ProgramFormScreen(
|
||||
programUseCases: _programUseCases(
|
||||
_FakeProgramRepository(),
|
||||
exerciseRepository,
|
||||
),
|
||||
exerciseUseCases: _exerciseUseCases(exerciseRepository),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
await tester.tap(find.text('Ajouter un exercice'));
|
||||
await tester.pumpAndSettle();
|
||||
await tester.tap(find.text('Squat'));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.text('Squat'), findsOneWidget);
|
||||
expect(
|
||||
find.text('3 séries · Temps + Répétitions · Repos 60 s'),
|
||||
findsOneWidget,
|
||||
);
|
||||
expect(find.widgetWithText(CheckboxListTile, 'Temps'), findsOneWidget);
|
||||
expect(
|
||||
find.widgetWithText(CheckboxListTile, 'Répétitions'),
|
||||
findsOneWidget,
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
testWidgets(
|
||||
'limite les mesures aux mesures autorisées par l’exercice source',
|
||||
(tester) async {
|
||||
final exerciseRepository = _FakeExerciseRepository()
|
||||
..exercises.add(
|
||||
Exercise(
|
||||
metadata: _metadata('exercise-1'),
|
||||
name: 'Pompes',
|
||||
hasTimeMeasure: false,
|
||||
hasRepsMeasure: true,
|
||||
hasScoreMeasure: false,
|
||||
),
|
||||
);
|
||||
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
home: ProgramFormScreen(
|
||||
programUseCases: _programUseCases(
|
||||
_FakeProgramRepository(),
|
||||
exerciseRepository,
|
||||
),
|
||||
exerciseUseCases: _exerciseUseCases(exerciseRepository),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
await tester.tap(find.text('Ajouter un exercice'));
|
||||
await tester.pumpAndSettle();
|
||||
await tester.tap(find.text('Pompes'));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(
|
||||
find.widgetWithText(CheckboxListTile, 'Répétitions'),
|
||||
findsOneWidget,
|
||||
);
|
||||
expect(find.widgetWithText(CheckboxListTile, 'Temps'), findsNothing);
|
||||
expect(find.widgetWithText(CheckboxListTile, 'Score'), findsNothing);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
ExerciseUseCases _exerciseUseCases(_FakeExerciseRepository repository) {
|
||||
return ExerciseUseCases(
|
||||
repository: repository,
|
||||
clock: _FakeClock(DateTime.utc(2026, 7, 17, 12)),
|
||||
ids: _FakeIds(),
|
||||
originDeviceId: 'device-1',
|
||||
);
|
||||
}
|
||||
|
||||
ProgramUseCases _programUseCases(
|
||||
_FakeProgramRepository programRepository,
|
||||
_FakeExerciseRepository exerciseRepository,
|
||||
) {
|
||||
return ProgramUseCases(
|
||||
programRepository: programRepository,
|
||||
exerciseRepository: exerciseRepository,
|
||||
clock: _FakeClock(DateTime.utc(2026, 7, 17, 12)),
|
||||
ids: _FakeIds(),
|
||||
originDeviceId: 'device-1',
|
||||
);
|
||||
}
|
||||
|
||||
EntityMetadata _metadata(String id) {
|
||||
return EntityMetadata(
|
||||
id: id,
|
||||
createdAt: DateTime.utc(2026, 7, 17),
|
||||
updatedAt: DateTime.utc(2026, 7, 17),
|
||||
originDeviceId: 'device-1',
|
||||
);
|
||||
}
|
||||
|
||||
final class _FakeClock implements Clock {
|
||||
const _FakeClock(this.value);
|
||||
|
||||
final DateTime value;
|
||||
|
||||
@override
|
||||
DateTime now() => value;
|
||||
}
|
||||
|
||||
final class _FakeIds implements IdGenerator {
|
||||
var _next = 0;
|
||||
|
||||
@override
|
||||
String newId() {
|
||||
_next += 1;
|
||||
return 'id-$_next';
|
||||
}
|
||||
}
|
||||
|
||||
final class _FakeExerciseRepository implements ExerciseRepository {
|
||||
final exercises = <Exercise>[];
|
||||
final saved = <Exercise>[];
|
||||
|
||||
@override
|
||||
Future<Exercise?> findById(String id) async {
|
||||
for (final exercise in exercises) {
|
||||
if (exercise.metadata.id == id) {
|
||||
return exercise;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<bool> isReferencedByProgram(String id) async => false;
|
||||
|
||||
@override
|
||||
Future<List<Exercise>> listActive() async => exercises;
|
||||
|
||||
@override
|
||||
Future<void> save(Exercise exercise) async {
|
||||
saved.add(exercise);
|
||||
}
|
||||
}
|
||||
|
||||
final class _FakeProgramRepository implements ProgramRepository {
|
||||
final programs = <Program>[];
|
||||
|
||||
@override
|
||||
Future<Program?> findById(String id) async {
|
||||
for (final program in programs) {
|
||||
if (program.metadata.id == id) {
|
||||
return program;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<Program>> listActive() async => programs;
|
||||
|
||||
@override
|
||||
Future<void> replaceExercises(Program program, DateTime deletedAt) async {
|
||||
programs.removeWhere((item) => item.metadata.id == program.metadata.id);
|
||||
programs.add(program);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> save(Program program) async {
|
||||
programs.add(program);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> saveExercise(ProgramExercise exercise) async {}
|
||||
}
|
||||
Reference in New Issue
Block a user