feat(gestion): suppression en cascade exercice/programme/séance-modèle (ticket #37)

Ajoute la suppression avec gestion des dépendances en cascade sur les
écrans bibliothèque d'exercices, programme et séance-modèle, avec les
use cases et le bootstrap applicatif associés. flutter analyze propre,
58/58 tests verts, build APK debug validé.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-18 10:33:06 +02:00
parent 7434790da2
commit 1a0d01f038
10 changed files with 881 additions and 26 deletions

View File

@ -69,7 +69,17 @@ final class _ProgramListScreenState extends State<ProgramListScreen> {
return ListTile(
title: Text(program.name),
subtitle: Text(_programSummary(program)),
trailing: const Icon(Icons.chevron_right),
trailing: Wrap(
spacing: 8,
children: [
IconButton(
tooltip: 'Supprimer le programme',
icon: const Icon(Icons.delete_outline),
onPressed: () => _confirmDelete(program),
),
const Icon(Icons.chevron_right),
],
),
onTap: () => _openForm(program: program),
);
},
@ -100,6 +110,51 @@ final class _ProgramListScreenState extends State<ProgramListScreen> {
_reload();
}
}
Future<void> _confirmDelete(Program program) async {
final used = await widget.programUseCases.isUsedInWorkoutTemplates(
program.metadata.id,
);
if (!mounted) return;
final confirmed = await showDialog<bool>(
context: context,
builder: (context) => AlertDialog(
title: Text('Supprimer ${program.name} ?'),
content: Text(
used
? 'Ce programme est utilisé dans une ou plusieurs séances. '
'Le supprimer le retirera de ces séances. Continuer ?'
: 'Cette action est irréversible.',
),
actions: [
TextButton(
onPressed: () => Navigator.of(context).pop(false),
child: const Text('Annuler'),
),
FilledButton.icon(
onPressed: () => Navigator.of(context).pop(true),
icon: const Icon(Icons.delete_outline),
label: const Text('Supprimer'),
),
],
),
);
if (confirmed != true) return;
try {
await widget.programUseCases.delete(program.metadata.id);
if (!mounted) return;
_reload();
} on Exception catch (error) {
_showSnackBar(error.toString());
}
}
void _showSnackBar(String message) {
if (!mounted) return;
ScaffoldMessenger.of(
context,
).showSnackBar(SnackBar(content: Text(message)));
}
}
final class ProgramFormScreen extends StatefulWidget {