---
issueRef: "#176"
version: 5
updatedBy: {"kind":"agent","agent_id":"57695b92-24d0-4876-837c-76116e70a6ae"}
updatedAt: 1785321673401
---

## #176 — Cadrage UX (2026-07-29)

Statut : **cadrage exploitable, nouveau lot**, app téléphone, `lib/presentation/workout_execution_screen.dart`, widget `_TimedStepBody` (L2907-2963), rendu dans `_CurrentStepPane` (branche générale, L2811-2838, `Expanded(child: step.type == time ? _TimedStepBody(...) : ...)`).

### Constat, vérifié en lecture directe
`_TimedStepBody` est placé dans un `Expanded` par son parent (toute la hauteur disponible lui est allouée), mais **à l'intérieur** de ce widget rien n'exploite cet espace :

```dart
Column(  // pas de mainAxisAlignment.center, pas de Expanded interne, pas de FittedBox
  children: [
    Text('Objectif : Xs'),
    Center(child: Text(remainingLabel, style: displayMedium)),  // taille fixe, non scalable
    if (!running) [...'Chrono prêt'..., FilledButton 'Lancer'],
  ],
)
```

Le `Text(remainingLabel)` a une taille de police fixe (`displayMedium`), la `Column` s'aligne en haut (comportement par défaut) : tout l'espace du `Expanded` non consommé par le contenu à taille naturelle reste vide en bas. Résultat : le chrono reste petit que le bouton `Lancer` soit visible ou non, et une fois le chrono démarré (`running == true`, le bloc `Lancer`/`Chrono prêt` disparaît), l'espace libéré n'est récupéré par personne — comportement exactement décrit par le ticket.

À comparer avec `_RepsWithStopwatchScoreStepBody` (L2965+) et le bloc `Expanded → LayoutBuilder → FittedBox(scaleDown) → SizedBox(hauteur de référence fixe)` déjà utilisé en L2740-2772 pour dimensionner un contenu à une zone variable : ce pattern existe déjà dans ce fichier, `_TimedStepBody` ne le reprend pas.

### Comportement attendu
Le chrono (et le bouton `Lancer` quand il est visible) doivent occuper **tout** l'espace vertical disponible dans le `Expanded` parent, dans les deux états :

- **Avant démarrage** (`!running`) : chrono + `Chrono prêt` (si prêt) + bouton `Lancer`, empilés et **centrés**, mis à l'échelle ensemble pour remplir la zone disponible (largeur et hauteur).
- **Après démarrage** (`running`) : le bloc `Chrono prêt`/`Lancer` disparaît (inchangé), et le chrono seul se remet à l'échelle pour **regrandir** et occuper tout l'espace libéré — pas de saut brutal de layout, juste une nouvelle mise à l'échelle du même mécanisme.

### Implémentation recommandée
Réutiliser le mécanisme `FittedBox(fit: BoxFit.contain)` déjà présent dans ce fichier (au lieu de `BoxFit.scaleDown` utilisé ailleurs, qui ne permet que de rétrécir — ici on veut aussi agrandir) :

```dart
Column(
  crossAxisAlignment: CrossAxisAlignment.stretch,
  children: [
    Text('Objectif : ${_formatShortSeconds(step.defaultTargetValue)}'),  // inchangé, taille fixe
    const SizedBox(height: 4),
    Expanded(                                    // NOUVEAU : réclame tout l'espace restant
      child: LayoutBuilder(
        builder: (context, c) => FittedBox(
          fit: BoxFit.contain,                    // scale up ET down, contrairement à scaleDown
          child: SizedBox(
            width: c.maxWidth,
            child: Column(
              mainAxisSize: MainAxisSize.min,
              children: [
                Text(remainingLabel, style: /* displayMedium, référence */),
                if (!running) ...[
                  const SizedBox(height: 8),
                  if (readyToStart) Text('Chrono prêt', ...),
                  const SizedBox(height: 4),
                  FilledButton.icon(onPressed: onStartTimer, icon: Icons.play_arrow, label: 'Lancer'),
                ],
              ],
            ),
          ),
        ),
      ),
    ),
  ],
)
```

- Le `FittedBox(BoxFit.contain)` prend le bloc de référence (chrono seul, ou chrono + libellé + bouton selon l'état) et le met à l'échelle pour remplir exactement la largeur ET la hauteur du `Expanded` — c'est ce même mécanisme qui fait automatiquement grandir le chrono quand le bouton disparaît : le bloc de référence devient plus petit (moins d'enfants), donc le facteur d'échelle appliqué par `FittedBox` augmente pour combler le même espace disponible.
- Le bouton `Lancer` grandit avec le reste (proportionnellement) tant qu'il est visible — cohérent avec la demande explicite du ticket (« chrono + bouton commencer prennent la place disponible »).
- Point de vigilance dev : choisir une taille de référence (police du `Text(remainingLabel)`, hauteur du bouton) qui donne un **rendu correct au repos** (échelle ≈ 1) sur la taille d'écran de référence du projet, quitte à ajuster ces valeurs empiriquement — le `FittedBox` absorbe l'écart, mais des proportions de référence déséquilibrées donneraient un mauvais rendu même mis à l'échelle. Ne pas plafonner l'échelle maximale (pas de `scaleDown`) : la demande explicite est que ça puisse grandir au-delà de la taille actuelle.
- Ne touche pas au cas `hasTimedWithManualScore` (L2725-2809, `_TimedStepWithManualScoreBody`) : ce lot ne concerne que le chrono seul, sans score manuel, branche générale de `_CurrentStepPane`.
