fix(exercice): suppression d'exercice ne casse plus les programmes (ticket #62)
Corrige ExerciseUseCases.delete() qui cascadait à tort vers les ProgramExercise référents, violant le pattern snapshot (un exercice supprimé ne doit jamais affecter les programmes déjà composés). Ajoute le test de régression associé. Met à jour le texte de confirmation _confirmDelete dans exercise_library_screen.dart, devenu incohérent avec ce fix (il affirmait à tort que la suppression retirerait l'exercice des programmes). Trouvé pendant la QA finale du chantier "Exercice à plusieurs étapes" (#54). flutter analyze propre (mêmes infos préexistantes), 103/103 tests verts, build APK debug validé. Dernier ticket du chantier (#56/#58/#59/#60/#61/#62 tous faits). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@ -220,7 +220,8 @@ final class _ExerciseLibraryScreenState extends State<ExerciseLibraryScreen> {
|
||||
content: Text(
|
||||
used
|
||||
? 'Cet exercice est utilisé dans un ou plusieurs programmes. '
|
||||
'Le supprimer le retirera de ces programmes. Continuer ?'
|
||||
'Il sera retiré de la bibliothèque. '
|
||||
'Les programmes existants restent inchangés. Continuer ?'
|
||||
: 'Cette action est irréversible.',
|
||||
),
|
||||
actions: [
|
||||
@ -885,8 +886,9 @@ final class _ExerciseFormScreenState extends State<ExerciseFormScreen> {
|
||||
controller: draft.targetController,
|
||||
decoration: InputDecoration(labelText: targetLabel),
|
||||
keyboardType: TextInputType.number,
|
||||
validator: (value) =>
|
||||
_stepsEnabled ? _positiveIntValidator(value, targetMessage) : null,
|
||||
validator: (value) => _stepsEnabled
|
||||
? _positiveIntValidator(value, targetMessage)
|
||||
: null,
|
||||
onChanged: (_) => setState(() {}),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
@ -898,7 +900,10 @@ final class _ExerciseFormScreenState extends State<ExerciseFormScreen> {
|
||||
onChanged: (value) => setState(() => draft.hasScore = value),
|
||||
),
|
||||
if (draft.hasScore) ...[
|
||||
Text('Mode de score', style: Theme.of(context).textTheme.titleSmall),
|
||||
Text(
|
||||
'Mode de score',
|
||||
style: Theme.of(context).textTheme.titleSmall,
|
||||
),
|
||||
RadioListTile<ScoreInputMode>(
|
||||
contentPadding: EdgeInsets.zero,
|
||||
title: const Text('Saisie libre'),
|
||||
@ -922,7 +927,9 @@ final class _ExerciseFormScreenState extends State<ExerciseFormScreen> {
|
||||
if (draft.scoreInputMode == ScoreInputMode.manual) ...[
|
||||
TextFormField(
|
||||
controller: draft.scoreLabelController,
|
||||
decoration: const InputDecoration(labelText: 'Score à saisir'),
|
||||
decoration: const InputDecoration(
|
||||
labelText: 'Score à saisir',
|
||||
),
|
||||
validator: (value) {
|
||||
if (!_stepsEnabled || !draft.hasScore) return null;
|
||||
if (draft.scoreInputMode != ScoreInputMode.manual) {
|
||||
@ -1081,9 +1088,10 @@ final class _ExerciseFormScreenState extends State<ExerciseFormScreen> {
|
||||
}
|
||||
setState(() {
|
||||
_stepError = null;
|
||||
_stepDrafts.insert(index + 1, _stepDrafts[index].duplicate(
|
||||
'step-draft-${_nextStepDraftId++}',
|
||||
));
|
||||
_stepDrafts.insert(
|
||||
index + 1,
|
||||
_stepDrafts[index].duplicate('step-draft-${_nextStepDraftId++}'),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@ -1143,8 +1151,8 @@ final class _ExerciseFormScreenState extends State<ExerciseFormScreen> {
|
||||
for (var index = 0; index < _stepDrafts.length; index++)
|
||||
_stepDrafts[index].toExerciseStep(
|
||||
position: index,
|
||||
defaultTargetScoreTimeMs: _stepDrafts[index].scoreInputMode ==
|
||||
ScoreInputMode.stopwatch
|
||||
defaultTargetScoreTimeMs:
|
||||
_stepDrafts[index].scoreInputMode == ScoreInputMode.stopwatch
|
||||
? _optionalSecondsToMilliseconds(
|
||||
_stepDrafts[index].scoreTargetController.text,
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user