feat(exercice): exécution persistante des étapes et éditeur d'étapes (tickets #58, #59)

Ajoute la persistance de l'exécution par étapes avec résultats par
passage (ports, use cases, entités, modèle Drift avec migration) et
l'éditeur d'exercice avec séquence d'étapes sur
exercise_library_screen.dart. Développés dans le même worktree
partagé par DevBackend et DevFrontend ; commit combiné plutôt que
séparé car les fakes de repository de test corrigés (nouvelles
interfaces #58) touchent plusieurs écrans sans lien avec l'éditeur
lui-même (historique, accueil, exécution, séance-modèle). Corrige au
passage un ListTile sans ancêtre Material dans le nouvel éditeur
d'étapes (Material(type: MaterialType.transparency)). flutter pub get
OK, build_runner OK, analyze propre (mêmes infos préexistantes),
93/93 tests verts, build APK debug validé.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-19 19:52:43 +02:00
parent 4731a257a1
commit ebba22db56
14 changed files with 11371 additions and 2 deletions

View File

@ -7,6 +7,8 @@ part 'app_database.g.dart';
@DriftDatabase(
tables: [
ActiveExerciseStepProgressStates,
ActiveExerciseStepResults,
ActiveRestStates,
ActiveScoreStopwatchStates,
ActiveSetResults,
@ -20,6 +22,7 @@ part 'app_database.g.dart';
Programs,
WorkoutHistories,
WorkoutHistorySetResults,
WorkoutHistoryStepResults,
WorkoutTemplateExerciseOverrides,
WorkoutTemplatePrograms,
WorkoutTemplates,
@ -38,7 +41,7 @@ final class AppDatabase extends _$AppDatabase {
}
@override
int get schemaVersion => 8;
int get schemaVersion => 9;
@override
MigrationStrategy get migration {
@ -77,6 +80,9 @@ final class AppDatabase extends _$AppDatabase {
if (from < 8) {
await _migrateToSchema8(migrator);
}
if (from < 9) {
await _migrateToSchema9(migrator);
}
await _createIndexes();
},
beforeOpen: (details) async {
@ -133,6 +139,15 @@ final class AppDatabase extends _$AppDatabase {
'CREATE INDEX IF NOT EXISTS idx_active_rest_states_session_id '
'ON active_rest_states (active_workout_session_id)',
);
await customStatement(
'CREATE INDEX IF NOT EXISTS '
'idx_active_exercise_step_progress_states_session_id '
'ON active_exercise_step_progress_states (active_workout_session_id)',
);
await customStatement(
'CREATE INDEX IF NOT EXISTS idx_active_exercise_step_results_session_id '
'ON active_exercise_step_results (active_workout_session_id)',
);
await customStatement(
'CREATE UNIQUE INDEX IF NOT EXISTS '
'idx_active_workout_sessions_single_open '
@ -148,6 +163,10 @@ final class AppDatabase extends _$AppDatabase {
'CREATE INDEX IF NOT EXISTS idx_workout_history_set_results_history_id '
'ON workout_history_set_results (workout_history_id)',
);
await customStatement(
'CREATE INDEX IF NOT EXISTS idx_workout_history_step_results_history_id '
'ON workout_history_step_results (workout_history_id)',
);
await customStatement(
'CREATE INDEX IF NOT EXISTS idx_change_log_entity '
'ON change_log (entity_type, entity_id)',
@ -164,6 +183,8 @@ final class AppDatabase extends _$AppDatabase {
}
const _syncableTableNames = [
'active_exercise_step_progress_states',
'active_exercise_step_results',
'active_rest_states',
'active_score_stopwatch_states',
'active_set_results',
@ -176,6 +197,7 @@ const _syncableTableNames = [
'programs',
'workout_history',
'workout_history_set_results',
'workout_history_step_results',
'workout_template_exercise_overrides',
'workout_template_programs',
'workout_templates',
@ -287,4 +309,10 @@ extension on AppDatabase {
'exercise_steps_snapshot_json TEXT',
);
}
Future<void> _migrateToSchema9(Migrator migrator) async {
await migrator.createTable(activeExerciseStepProgressStates);
await migrator.createTable(activeExerciseStepResults);
await migrator.createTable(workoutHistoryStepResults);
}
}