Files
GameTime/.ideai/tickets/131/carnet.md
Blomios 917777e18b chore(wip): consolidation intermédiaire multi-tickets (sprints Statistiques, UI, Bug resolution, Serveur-client)
Regroupe l'état de travail en cours réalisé dans un même worktree sur
plusieurs tickets/sprints (#85, #136, #145, #155-160, #162-164),
mélangeant des tickets QA et inProgress. Ne constitue pas une feature
terminée : commit de sauvegarde avant triage/split par ticket en
branches feature/* dédiées. Exclut les dossiers d'environnement de
build locaux et le heap dump parasite (.gitignore mis à jour).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-28 16:48:54 +02:00

32 lines
4.6 KiB
Markdown

---
issueRef: "#131"
version: 5
updatedBy: {"kind":"user"}
updatedAt: 1785216979125
---
## #131 — Cadrage technique Architect (2026-07-27)
**Root cause identifiée dans le code réel** — combinaison de contenu dense jamais rendue scrollable, dans une branche de layout spécifique.
L'écran d'exécution (`lib/presentation/workout_execution_screen.dart`) a **deux branches de layout** selon que l'exercice a des étapes (`hasStepSequence`, ligne 192-323) :
- Branche **sans étapes** (ligne 283-318) : le contenu (`SetMeasureInput`) est déjà enveloppé dans un `ListView` scrollable (ligne 300-317) — pas de risque d'overflow, quelle que soit la densité.
- Branche **avec étapes** (ligne 227-282, celle du scénario rapporté : exercice à 2 étapes) : empile un `_StepSequencePanel` (`Expanded`, non scrollable) puis, si activés, un bloc score de série `_StepSetResultSummary` (`SizedBox(height: 66)`) et/ou `_ScoreStopwatchInput` (`SizedBox(height: 96)`) — **aucun scroll nulle part dans cette branche**.
À l'intérieur, `_CurrentStepPane` (ligne 2321-2449) empile pour l'étape courante, dans un `Column` non scrollable : titre d'étape, nom, corps de l'étape (`Flexible(fit: FlexFit.tight)` — chrono ou reps), **puis** si `step.hasScore` (score au niveau de l'étape, ligne 2395-2409) un `_StepScoreInput` supplémentaire (`Flexible(fit: FlexFit.loose)`), puis la rangée de boutons "Passer l'étape". `Flexible.loose` ne force pas le contenu à rétrécir sous sa taille intrinsèque minimale (champ de score + boutons +/- + libellés) — il autorise seulement le widget à être plus petit que l'espace alloué, pas à comprimer son propre contenu.
**Le scénario rapporté combine trois blocs verticaux simultanément** : chrono d'étape (10s) + score d'étape ("panier", `step.hasScore`) + score de série ("panier" aussi, `_exercise.manualScoreEnabled` → déclenche le `SizedBox(height: 66)` supplémentaire en dehors de `_CurrentStepPane`). C'est une combinaison de configuration peu courante (score à la fois au niveau étape ET au niveau série, avec un chrono d'étape court) qui n'avait probablement jamais été testée sur petit écran — la somme des hauteurs minimales requises dépasse la hauteur réellement disponible, et comme rien n'est scrollable dans cette branche, Flutter rapporte l'overflow exact ("Bottom Overflowed by 82 pixels") au lieu de dégrader proprement.
### Correctif (contrat clair pour DevFrontend)
Rendre la branche `hasStepSequence` dégradable par scroll, symétriquement à ce que fait déjà la branche sans étapes :
- Option minimale et cohérente avec l'existant : envelopper le contenu de `_CurrentStepPane` (ligne 2356, le `Column` qui empile texte/corps d'étape/score d'étape/boutons) dans un `SingleChildScrollView` lorsque le contenu dépasse l'espace disponible — remplacer les `Flexible` internes qui n'ont plus de sens dans un contexte scrollable par leur contenu intrinsèque directement (un `ScrollView` donne une hauteur non bornée à son enfant, donc `Flexible`/`Expanded` y sont invalides et doivent être retirés à cet endroit précis).
- Alternative équivalente au niveau du parent : envelopper le `Column` de la branche `hasStepSequence` (ligne 228-281, qui empile `_StepSequencePanel` + blocs score de série) dans un `SingleChildScrollView`, en remplaçant l'`Expanded` du `_StepSequencePanel` (ligne 231) par une hauteur qui s'adapte à son contenu.
- Ne pas retirer le mode "tient sur un écran sans scroll" pour le cas courant (chrono seul, ou score seul) : le `SingleChildScrollView` ne change rien visuellement quand tout le contenu tient déjà — c'est un filet de sécurité pour les combinaisons denses, pas un changement de comportement pour le cas nominal.
- Ne pas retirer d'information ni de bouton pour "faire tenir" le contenu (pas de compromis produit ici) — c'est un problème de layout à corriger, pas un périmètre fonctionnel à réduire.
### Tests
- Widget test avec la configuration exacte du ticket (3 séries, 20 passages, 2 étapes, étape courante = chrono 10s + score d'étape "panier", score de série "panier") sur une hauteur d'écran réduite (ex. contrainte de test type Wear/petit téléphone) : aucune exception `RenderFlex overflowed`, le contenu doit rester scrollable jusqu'au bouton "Passer l'étape".
- Test de non-régression sur le cas nominal (chrono seul, pas de score d'étape ni de série) : layout identique à avant, pas de scroll visible si le contenu tient.
**Prêt pour implémentation directe, aucun arbitrage supplémentaire nécessaire. Priorité critique confirmée** (bloque l'affichage complet de l'écran d'exécution pour cette combinaison de configuration).