feat(ui): écran Composition de séance-modèle

Ajoute l'écran de composition de séance-modèle
(presentation/workout_template_screen.dart), avec les ajustements
application/domaine/repositories nécessaires et la navigation depuis
l'accueil. flutter analyze propre, 12/12 tests verts, build APK debug
validé.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-17 18:59:59 +02:00
parent be02bbfeea
commit 89d89a3005
9 changed files with 1029 additions and 7 deletions

View File

@ -191,21 +191,33 @@ final class DriftWorkoutTemplateRepository
@override
Future<domain.WorkoutTemplate?> findById(String id) async {
final row = await (database.select(
database.workoutTemplates,
)..where((table) => table.id.equals(id))).getSingleOrNull();
final row =
await (database.select(
database.workoutTemplates,
)..where((table) => table.id.equals(id) & table.deletedAt.isNull()))
.getSingleOrNull();
if (row == null) {
return null;
}
final programs =
await (database.select(database.workoutTemplatePrograms)
..where((table) => table.workoutTemplateId.equals(id))
..where(
(table) =>
table.workoutTemplateId.equals(id) &
table.deletedAt.isNull(),
)
..orderBy([(table) => OrderingTerm.asc(table.position)]))
.get();
final programIds = programs.map((program) => program.id).toSet();
final overrides = await (database.select(
database.workoutTemplateExerciseOverrides,
)..where((table) => table.workoutTemplateProgramId.isIn(programIds))).get();
final overrides = programIds.isEmpty
? <db.WorkoutTemplateExerciseOverride>[]
: await (database.select(database.workoutTemplateExerciseOverrides)
..where(
(table) =>
table.workoutTemplateProgramId.isIn(programIds) &
table.deletedAt.isNull(),
))
.get();
return _workoutTemplateFromRow(
row,
programs.map(_workoutTemplateProgramFromRow).toList(),
@ -213,6 +225,23 @@ final class DriftWorkoutTemplateRepository
);
}
@override
Future<List<domain.WorkoutTemplate>> listActive() async {
final rows =
await (database.select(database.workoutTemplates)
..where((table) => table.deletedAt.isNull())
..orderBy([(table) => OrderingTerm.asc(table.name)]))
.get();
final templates = <domain.WorkoutTemplate>[];
for (final row in rows) {
final template = await findById(row.id);
if (template != null) {
templates.add(template);
}
}
return templates;
}
@override
Future<void> save(domain.WorkoutTemplate template) async {
await database
@ -243,6 +272,81 @@ final class DriftWorkoutTemplateRepository
_workoutTemplateExerciseOverrideCompanion(override),
);
}
@override
Future<void> replaceComposition(
domain.WorkoutTemplate template,
DateTime deletedAt,
) async {
await database.transaction(() async {
final previousPrograms =
await (database.select(database.workoutTemplatePrograms)..where(
(table) =>
table.workoutTemplateId.equals(template.metadata.id) &
table.deletedAt.isNull(),
))
.get();
final previousProgramIds = previousPrograms
.map((program) => program.id)
.toSet();
await save(template);
final activeProgramIds = template.programs
.map((program) => program.metadata.id)
.toSet();
final programUpdate = database.update(database.workoutTemplatePrograms);
if (activeProgramIds.isEmpty) {
programUpdate.where(
(table) =>
table.workoutTemplateId.equals(template.metadata.id) &
table.deletedAt.isNull(),
);
} else {
programUpdate.where(
(table) =>
table.workoutTemplateId.equals(template.metadata.id) &
table.deletedAt.isNull() &
table.id.isNotIn(activeProgramIds),
);
}
await programUpdate.write(
db.WorkoutTemplateProgramsCompanion(
deletedAt: Value(deletedAt),
updatedAt: Value(deletedAt),
),
);
final activeOverrideIds = template.overrides
.map((override) => override.metadata.id)
.toSet();
final relevantProgramIds = {...previousProgramIds, ...activeProgramIds};
if (relevantProgramIds.isEmpty) {
return;
}
final overrideUpdate = database.update(
database.workoutTemplateExerciseOverrides,
);
if (activeOverrideIds.isEmpty) {
overrideUpdate.where(
(table) =>
table.workoutTemplateProgramId.isIn(relevantProgramIds) &
table.deletedAt.isNull(),
);
} else {
overrideUpdate.where(
(table) =>
table.workoutTemplateProgramId.isIn(relevantProgramIds) &
table.deletedAt.isNull() &
table.id.isNotIn(activeOverrideIds),
);
}
await overrideUpdate.write(
db.WorkoutTemplateExerciseOverridesCompanion(
deletedAt: Value(deletedAt),
updatedAt: Value(deletedAt),
),
);
});
}
}
final class DriftActiveSessionRepository implements ActiveSessionRepository {