merge(main): popup de confirmation d'ajout d'exercice (ticket #24)

Fusionne feature/#24-popup-exercice-ajoute — analyze propre, 43/43
tests verts, build APK debug validé. Ticket laissé en statut QA :
validation manuelle sur APK par l'utilisateur avant clôture.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-18 09:23:20 +02:00
5 changed files with 86 additions and 11 deletions

View File

@ -1,6 +1,9 @@
--- ---
issueRef: "#24" issueRef: "#24"
version: 5 version: 7
updatedBy: {"kind":"user"} updatedBy: {"kind":"agent","agent_id":"57695b92-24d0-4876-837c-76116e70a6ae"}
updatedAt: 1784329025027 updatedAt: 1784359379007
--- ---
Correctif : le SnackBar "Exercice ajouté" se ferme maintenant automatiquement après 3 secondes (Timer explicite, correctement annulé au dispose et avant chaque nouvel ajout pour éviter les fuites/conflits), ou immédiatement si l'utilisateur tape "Personnaliser". Vérifié : analyze propre, 43/43 tests verts, build APK réussi.
À tester sur le téléphone : ajouter un exercice à un programme, vérifier que le message disparaît tout seul après ~3s, et qu'il disparaît immédiatement si on tape "Personnaliser".

View File

@ -2,15 +2,15 @@
id: "3dbea39a-1466-47d9-b12a-95a601ec287d" id: "3dbea39a-1466-47d9-b12a-95a601ec287d"
number: 24 number: 24
title: "[Bug] Popup \"Exercie ajouté\" qui ne s'enlève pas quand on ajoute un exercice" title: "[Bug] Popup \"Exercie ajouté\" qui ne s'enlève pas quand on ajoute un exercice"
status: "open" status: "qa"
priority: "high" priority: "high"
sprint: "abc4f969-b169-45f7-988c-daeeab762201" sprint: "abc4f969-b169-45f7-988c-daeeab762201"
links: [] links: []
agentRefs: [{"agentId":"57695b92-24d0-4876-837c-76116e70a6ae","role":"assigned"}] agentRefs: [{"agentId":"57695b92-24d0-4876-837c-76116e70a6ae","role":"assigned"}]
createdBy: {"kind":"user"} createdBy: {"kind":"user"}
updatedBy: {"kind":"user"} updatedBy: {"kind":"agent","agent_id":"57695b92-24d0-4876-837c-76116e70a6ae"}
createdAt: 1784328185359 createdAt: 1784328185359
updatedAt: 1784329025027 updatedAt: 1784359379007
version: 5 version: 7
--- ---
Quand j'ajoute un exercice, la popup "Exercie ajouté" s'affiche mais ne s'enleve pas. Il faudrait qu'elle s'enleve au bout que 3 sec par exemple ou si on appuie sur Personnlaiser Quand j'ajoute un exercice, la popup "Exercie ajouté" s'affiche mais ne s'enleve pas. Il faudrait qu'elle s'enleve au bout que 3 sec par exemple ou si on appuie sur Personnlaiser

View File

@ -267,13 +267,13 @@
"issueRef": "#24", "issueRef": "#24",
"path": "24", "path": "24",
"title": "[Bug] Popup \"Exercie ajouté\" qui ne s'enlève pas quand on ajoute un exercice", "title": "[Bug] Popup \"Exercie ajouté\" qui ne s'enlève pas quand on ajoute un exercice",
"status": "open", "status": "qa",
"priority": "high", "priority": "high",
"sprint": "abc4f969-b169-45f7-988c-daeeab762201", "sprint": "abc4f969-b169-45f7-988c-daeeab762201",
"assignedAgentIds": [ "assignedAgentIds": [
"57695b92-24d0-4876-837c-76116e70a6ae" "57695b92-24d0-4876-837c-76116e70a6ae"
], ],
"updatedAt": 1784329025027 "updatedAt": 1784359379007
}, },
{ {
"issueRef": "#25", "issueRef": "#25",

View File

@ -1,3 +1,5 @@
import 'dart:async';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import '../application/application.dart'; import '../application/application.dart';
@ -121,6 +123,7 @@ final class _ProgramFormScreenState extends State<ProgramFormScreen> {
late final TextEditingController _nameController; late final TextEditingController _nameController;
late final TextEditingController _defaultRestController; late final TextEditingController _defaultRestController;
late final List<_ProgramExerciseDraft> _exercises; late final List<_ProgramExerciseDraft> _exercises;
Timer? _addedSnackBarTimer;
var _saving = false; var _saving = false;
bool get _isEditing => widget.program != null; bool get _isEditing => widget.program != null;
@ -145,6 +148,7 @@ final class _ProgramFormScreenState extends State<ProgramFormScreen> {
@override @override
void dispose() { void dispose() {
_addedSnackBarTimer?.cancel();
_nameController.dispose(); _nameController.dispose();
_defaultRestController.dispose(); _defaultRestController.dispose();
super.dispose(); super.dispose();
@ -253,12 +257,25 @@ final class _ProgramFormScreenState extends State<ProgramFormScreen> {
setState(() { setState(() {
_exercises.add(draft); _exercises.add(draft);
}); });
ScaffoldMessenger.of(context).showSnackBar( final messenger = ScaffoldMessenger.of(context);
_addedSnackBarTimer?.cancel();
_addedSnackBarTimer = Timer(const Duration(seconds: 3), () {
if (mounted) {
messenger.hideCurrentSnackBar();
}
});
messenger.showSnackBar(
SnackBar( SnackBar(
duration: const Duration(seconds: 3),
content: const Text('Exercice ajouté'), content: const Text('Exercice ajouté'),
action: SnackBarAction( action: SnackBarAction(
label: 'Personnaliser', label: 'Personnaliser',
onPressed: () => _customizeExercise(draft.key), onPressed: () {
_addedSnackBarTimer?.cancel();
_addedSnackBarTimer = null;
messenger.hideCurrentSnackBar();
_customizeExercise(draft.key);
},
), ),
), ),
); );

View File

@ -103,6 +103,61 @@ void main() {
}, },
); );
testWidgets(
'la popup exercice ajouté disparaît et se ferme à la personnalisation',
(tester) async {
final exerciseRepository = _FakeExerciseRepository()
..exercises.add(
Exercise(
metadata: _metadata('exercise-1'),
name: 'Squat',
hasTimeMeasure: true,
hasRepsMeasure: false,
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('Exercice ajouté'), findsOneWidget);
for (var i = 0; i < 5; i++) {
await tester.pump(const Duration(seconds: 1));
}
await tester.pump(const Duration(milliseconds: 500));
expect(find.text('Exercice ajouté'), findsNothing);
await tester.tap(find.text('Ajouter un exercice'));
await tester.pumpAndSettle();
await tester.tap(find.text('Squat').first);
await tester.pumpAndSettle();
expect(find.text('Exercice ajouté'), findsOneWidget);
await tester.tap(find.text('Personnaliser'));
await tester.pumpAndSettle();
expect(find.text('Exercice ajouté'), findsNothing);
expect(find.text("Personnaliser l'exercice"), findsOneWidget);
},
);
testWidgets('affiche lobjectif de chrono pour un score en mode chrono', ( testWidgets('affiche lobjectif de chrono pour un score en mode chrono', (
tester, tester,
) async { ) async {