--- issueRef: "#170" version: 6 updatedBy: {"kind":"agent","agent_id":"57695b92-24d0-4876-837c-76116e70a6ae"} updatedAt: 1785311597912 --- ## #170 — Cadrage UX (2026-07-28) Statut : **nouveau lot, cadrage exploitable, indépendant de #166/#167/#169.** ### Pourquoi ce n'est pas un doublon de #166/#167/#169 Ces trois tickets couvrent le cas **reps-only sans score manuel** sur la montre (branche `_ActiveContent` / `_DominantRepsLine` dans `watch_session_screen.dart`, déjà livrée). #170 décrit un **autre écran** : une étape qui combine `type = reps` **et** `hasScore` en mode manuel (`ScoreInputMode.manual`) — cette étape bascule sur `projection.hasManualScore == true` et rend `_ManualScoreContent` (watch_session_screen.dart:894), un layout entièrement différent qui n'a jamais affiché le nombre de répétitions cible. Vérifié en lecture directe : - `_watchManualScoreProjection` (lib/application/use_cases.dart:4285-4318) ne connaît que la **cible de score** (`targetValue`/`targetLabel: 'Cible'`), jamais `step.defaultTargetValue` (le nombre de répétitions). Le champ répétitions n'existe nulle part dans cette branche de données. - `_ManualScoreContent.build()` (watch_session_screen.dart:907-993) affiche : nom d'exercice, bande étape, puis **si `target != null`** une ligne caption `"$targetLabel : $target"` (ex. `Cible : 500`), puis le label `SCORE` et la ligne +/- score. Rien n'y référence `step.type` ni les répétitions. Donc le constat utilisateur est exact : sur une étape score-libre + répétitions, la montre affiche le score (incrémentable) mais **jamais** le nombre de répétitions à réaliser pendant ce score — contrairement au cas reps-only (#166/#167) qui, lui, a bien sa donnée dominante dédiée. ### Comportement attendu Réutiliser le gabarit caption déjà en place (`_ManualScoreContent`, juste au-dessus du label `SCORE`), sans ajouter de nouvelle ligne ni de nouveau composant : ```text Pompes tempo Répétitions : 10 ← nouvelle info, même style que "Cible : 500" SCORE − 42 + ♥ 118 ``` - Si l'étape a **aussi** une cible de score (`targetValue` non nul), joindre les deux informations sur la **même ligne**, séparées par `·` — même règle de mutualisation que les chronos secondaires (`secondaryTimers.join(' · ')`, déjà dans ce fichier) : `Répétitions : 10 · Cible : 500`. Ne jamais empiler deux lignes de caption : une étape à la fois ne doit montrer qu'une seule ligne d'info secondaire au-dessus du score, pour ne pas reproduire la densité déjà corrigée par #161. - Si l'étape n'a **pas** de cible de score, la ligne devient simplement `Répétitions : 10` (remplace l'espace aujourd'hui vide quand `target == null`). - Le score reste la donnée manipulable (boutons −/+ inchangés) : les répétitions ici sont une **cible informative**, pas un compteur actionnable — pas de bouton de validation à ajouter sur cette ligne (l'étape se termine via le flux existant de fin de score/étape, non modifié par ce ticket). - Style : reprendre exactement `Theme.of(context).textTheme.bodySmall` + couleur `#A7ADBA` + `fontSize: 11`, `maxLines: 1`, `overflow: ellipsis` — déjà le style de la ligne `Cible`, aucune nouvelle charte à définir. ### Ce qu'il faut pour Architect Donnée manquante à faire remonter dans `_WatchManualScoreProjectionData` / `WatchSessionProjection` : le nombre de répétitions cible de l'étape courante (`step.defaultTargetValue` quand `step.type == ExerciseStepType.reps`), à côté du `targetValue`/`targetLabel` de score existant. Recommandation : soit un champ dédié (`repsTargetValue`), soit généraliser la caption en une liste de segments texte assemblés côté UI — au choix d'Architect selon ce qui est le plus cohérent avec le modèle de projection existant. Le rendu attendu (label unique, jointure `·`, une seule ligne) est fixé ci-dessus et ne doit pas varier selon l'implémentation choisie.