--- name: gametime-ux-watch-companion description: memory note gametime-ux-watch-companion metadata: type: project --- # GameTime — UX interface montre synchronisée (ticket #91, UX 2026-07-25) Conception UX d'une app compagnon Wear OS synchronisée avec l'app téléphone pour piloter une séance en cours depuis le poignet. Références à respecter : - `gametime-session-execution-timer-refactor` - `gametime-ux-step-chaining-override` - `gametime-architecture-step-chaining-override` - `gametime-ux-score-chrono` - `gametime-online-layer-philosophy` ## Décision produit structurante La montre est une **surface compagnon de pilotage**, pas une deuxième app autonome de séance. - **Téléphone = source de vérité de l'exécution**. - **Montre = télécommande + miroir d'état**. - Toute action lancée sur la montre est une **intention utilisateur** envoyée au téléphone, puis confirmée par le retour d'état. - La montre ne doit jamais exposer un modèle d'exécution différent de celui du téléphone. Justification : - la logique de séance, des chronos, des overrides d'étapes et du repos existe déjà côté téléphone ; - cela évite les divergences de calcul entre deux appareils ; - cela rend la cohérence UX compréhensible : un seul état réel, visible sur deux surfaces. ## Principe de surface Sur montre, la hiérarchie doit être radicale : 1. **où j'en suis** : série, exercice, étape/passage si nécessaire ; 2. **ce qui se passe maintenant** : chrono dominant ou état dominant ; 3. **l'action unique la plus probable** ; 4. **les actions de contournement** dans une surface secondaire. La montre ne doit pas tenter de reproduire toute l'interface téléphone. Pas de médias, pas d'édition, pas de paramètres, pas de détails historiques. ## Surfaces montre ## 1. État sans séance active Écran affiché si aucune séance n'est en cours côté téléphone. Contenu : ```text Aucune séance en cours Lance une séance sur le téléphone. ``` CTA optionnel si le système le permet : ```text [Actualiser] ``` Règles : - aucun contrôle d'exécution affiché ; - pas de faux bouton `Démarrer` ; - si la montre n'est pas connectée au téléphone, le message devient : ```text Téléphone indisponible Rouvre GameTime sur le téléphone. ``` ## 2. Écran principal `Séance active` Écran par défaut dès qu'une séance en cours existe. C'est la surface centrale de la feature. Structure recommandée sur écran rond : ```text SÉRIE 2 / 5 Pompes tempo Passage 1 / 3 · Étape 2 / 4 00:18 Chrono étape Série 01:42 · Score 00:51 [Pause] ``` ### Hiérarchie d'information L'ordre visuel doit être fixe : 1. `SÉRIE X / Y` toujours en haut. 2. Nom de l'exercice sur 1 à 2 lignes max. 3. Ligne contextuelle compacte : - `Passage A / B` seulement si l'exercice en a ; - `Étape C / D` seulement si l'exercice en a ; - si les deux existent, les concaténer sur une seule ligne. 4. **Chrono dominant** en très grand. 5. Libellé du chrono dominant ou de l'état. 6. Ligne compacte des autres chronos simultanés, si utile. 7. Bouton principal pleine largeur. ### Règle du chrono dominant La montre ne doit afficher qu'un seul chrono en grand. Ordre de priorité UX : 1. `Repos` si un repos est en cours. 2. `Étape` si une étape temps est active ou en état `Chrono suivant prêt`. 3. `Score chrono` s'il est actif et qu'aucune étape temps n'est prioritaire. 4. `Temps de série` si actif. 5. Sinon, l'état dominant remplace le chrono. Les autres chronos actifs restent en secondaire sur une seule ligne compacte, par exemple : ```text Série 03:12 · Score 01:08 ``` But : rester lisible pendant l'effort tout en respectant le modèle multi-chronos existant. ### Bouton principal contextuel Le bas de l'écran porte **une seule action primaire** dont le libellé dépend de l'état : - `Démarrer l'exercice` - `Pause` - `Reprendre` - `Démarrer le chrono` - `Passer le repos` Cette action unique est le raccourci du cas d'usage le plus probable à cet instant. ## 3. Écran `Actions` Surface secondaire accessible depuis `Séance active` par swipe horizontal ou tap sur un affordance discret `Actions`. Cette surface contient les actions moins fréquentes, sous forme de gros boutons verticaux scrollables. Ordre des actions : ```text [Passer l'étape] // seulement si applicable [Passer le passage] // seulement si applicable [Terminer la série] [Passer la série] [Passer le repos] // seulement pendant le repos ``` Règles : - n'afficher que les actions réellement applicables à l'état courant ; - ne pas afficher d'action impossible ou déjà satisfaite ; - pendant un chrono en cours, `Passer la série` doit demander une confirmation ; - pendant un repos, `Terminer la série` disparaît car la série est déjà terminée. ### Confirmations montre Deux confirmations seulement, pour éviter les erreurs grossières pendant l'effort : 1. `Passer la série ?` `Le chrono en cours sera ignoré.` `[Annuler] [Passer]` 2. `Passer le passage ?` `L'étape en cours sera ignorée.` `[Annuler] [Passer]` `Passer l'étape` peut être immédiat : coût faible, fréquence plus élevée. ## 4. Écran `Repos` Quand le repos est en cours, l'écran principal change de nature et devient un écran repos, pas un simple bandeau. Structure : ```text REPOS Après série 2 / 5 00:37 Repos en cours Exercice suivant Fentes sautées [Pause] ``` Actions secondaires sur l'écran `Actions` : ```text [Passer le repos] ``` Si le repos est en pause : ```text REPOS 00:37 Repos en pause [Reprendre] ``` ## États à couvrir ## 1. Séance pas encore lancée / début de série Cas : la série existe, mais aucun chrono qui démarre au début de série n'a encore été lancé. Affichage : ```text SÉRIE 1 / 4 Burpees Étape 1 / 3 00:20 Prêt à démarrer [Démarrer l'exercice] ``` Règle obligatoire : - si l'exercice est sous chrono **et** que la première étape est une étape `Temps`, le bouton reste **unique** : ```text [Démarrer l'exercice] ``` Cette action démarre à la fois : - le timer de série si `timeEnabled` ; - le chrono de la première étape ; - le score chrono si `scoreInputMode == stopwatch`. La montre ne doit jamais afficher deux boutons concurrents du type `Démarrer l'exercice` et `Démarrer l'étape`. ## 2. Chrono running Cas nominal pendant l'effort. Affichage : - chrono dominant animé visuellement ; - libellé `En cours` ou libellé du chrono (`Chrono étape`, `Score chrono`, `Temps de série`) ; - bouton principal `Pause`. Effet du bouton : - met la séance en pause ; - la pause suspend tous les chronos running, y compris le repos. ## 3. Séance en pause Affichage : ```text SÉRIE 2 / 5 Pompes tempo 00:18 Séance en pause [Reprendre] ``` Règles : - l'état doit être explicite ; - aucun chrono ne doit sembler continuer ; - si l'utilisateur reprend depuis le téléphone, la montre revient automatiquement à l'état running. ## 4. `Chrono suivant prêt` Cas imposé par `autoStartNextTimedStep = false` après une étape temps suivie d'une autre étape temps. Affichage : ```text SÉRIE 2 / 5 Pompes tempo Passage 1 / 3 · Étape 3 / 4 00:15 Chrono suivant prêt [Démarrer le chrono] ``` Règles : - ne pas réutiliser `Démarrer l'exercice` ; - ne pas auto-démarrer ; - conserver l'état après pause/reprise ; - l'écran doit rendre évident qu'on est déjà avancé dans la séquence, mais en attente d'un lancement manuel. ## 5. Entre les séries Deux cas distincts : 1. repos configuré et lancé ; 2. pas de repos en cours, prochaine série prête. Si pas de repos : ```text SÉRIE 3 / 5 Pompes tempo Prêt pour la série suivante [Démarrer l'exercice] ``` L'utilisateur comprend qu'il redémarre une nouvelle série, pas la séance depuis zéro. ## 6. Repos running / repos en pause Voir surface `Repos`. Le repos doit être traité comme un état de premier rang, car c'est souvent le seul moment où l'utilisateur regarde la montre entre deux séries. ## 7. Pas de séance active Voir surface `État sans séance active`. ## 8. Téléphone temporairement indisponible Cas spécifique à la cohabitation téléphone/montre. La montre peut afficher le dernier état connu, mais il doit être clairement marqué comme potentiellement obsolète : ```text Connexion perdue Dernier état reçu il y a quelques secondes [Réessayer] ``` Règles : - désactiver les actions de pilotage tant que la connexion n'est pas rétablie ; - ne pas laisser croire qu'un tap local a réellement modifié la séance sans confirmation ; - au retour de connexion, la montre remplace entièrement son affichage par l'état confirmé du téléphone. ## Mapping des contrôles ## Gestes retenus - **Tap** sur le bouton principal : action primaire contextuelle. - **Swipe horizontal** : bascule entre `Séance active` et `Actions`. - **Scroll vertical / couronne** : parcours des actions si la liste dépasse. - **Bouton système / retour système** : navigation système uniquement. Décision UX : ne pas attribuer de commande métier obligatoire à un bouton physique matériel. Les montres Wear OS n'offrent pas toutes la même ergonomie matérielle. ## Mapping détaillé ### Sur `Séance active` - `Démarrer l'exercice` - déclenche tous les chronos de début de série applicables ; - couvre explicitement le cas exercice chrono + première étape chrono. - `Pause` - met la séance en pause ; - suspend série, étape, score chrono, repos. - `Reprendre` - reprend exactement l'état suspendu. - `Démarrer le chrono` - démarre l'étape temps prête après un enchaînement manuel. - `Passer le repos` - raccourci contextuel possible si UX test montre que c'est plus utile que `Pause` pendant le repos ; - sinon garder `Pause` en primaire et déplacer `Passer le repos` dans `Actions`. Décision recommandée pour v1 : - pendant le repos, **bouton principal = `Pause`**, pour garder la cohérence avec le reste de la séance ; - `Passer le repos` reste en action secondaire. ### Sur `Actions` - `Passer l'étape` - disponible seulement si une étape courante existe. - `Passer le passage` - disponible seulement si l'exercice a plusieurs passages/séquences et si le passage courant n'est pas déjà terminé. - `Terminer la série` - finalise la série et arrête/enregistre les chronos actifs selon les règles existantes. - `Passer la série` - ignore la série courante avec confirmation si un chrono ou une séquence est en cours. - `Passer le repos` - disponible seulement si repos en cours. ## Cohérence téléphone ↔ montre ## Source de vérité Décision UX ferme : - l'état autoritaire de séance vit sur le téléphone ; - la montre affiche une **projection compacte** de cet état ; - la montre n'invente jamais un état final seule. ## Modèle d'interaction Cycle UX attendu pour une action montre : 1. l'utilisateur tape sur la montre ; 2. la montre passe brièvement le bouton en état `Envoi...` ; 3. le téléphone applique la commande ; 4. la montre reçoit l'état confirmé et remplace l'affichage. Si l'état confirmé diffère de l'intention initiale parce que le téléphone a déjà changé entre-temps, c'est **le dernier état confirmé** qui gagne visuellement. Exemple : - l'utilisateur tape `Pause` sur la montre ; - presque au même moment, il a déjà repris sur le téléphone ; - la montre ne doit pas essayer de "corriger" localement ; elle se recale sur le dernier snapshot confirmé. ## Règle de conflit UX En cas d'actions quasi simultanées téléphone/montre : - le système applique un ordre réel côté source de vérité ; - la montre n'affiche jamais un dialogue de conflit ; - elle se contente d'afficher le résultat réel le plus récent. Autrement dit : **pas de résolution de conflit visible par l'utilisateur**, seulement un réalignement rapide de l'UI. ## Règle de latence La montre doit distinguer trois cas UX : 1. **latence courte** - simple état `Envoi...` sur le bouton. 2. **latence perceptible** - texte discret `En attente du téléphone`. 3. **absence de réponse** - état `Connexion perdue` et actions désactivées. Les seuils temporels exacts sont laissés à Architect, mais la surface doit prévoir ces trois états distincts. ## Signaux sonores et haptiques ## Principe Pour respecter #92, la montre doit privilégier **l'haptique**. L'audio montre n'est pas requis pour le MVP. Décisions UX : - par défaut, **pas de son obligatoire côté montre** ; - retour principal = vibration ; - si un son est ajouté plus tard, il doit être bref, non intrusif, et ne jamais prendre le focus audio au détriment de la musique de fond. ## Patterns recommandés - démarrage/pause/reprise confirmé : **impulsion courte** ; - fin d'un chrono ou fin de repos : **double impulsion** ; - état `Chrono suivant prêt` : **double impulsion** au moment où l'état est atteint, puis silence ; - perte de connexion après action utilisateur : **impulsion lourde unique** optionnelle. Règles : - pas de bip de décompte 3-2-1 imposé sur la montre au MVP ; - pas de répétition haptique continue ; - éviter la duplication agressive téléphone + montre sur le même événement. ## Exigences de donnée pour Architect La montre a besoin d'un view model compact, orienté exécution, pas de tout le snapshot séance brut. Minimum UX requis : - présence ou absence d'une séance active ; - statut de connexion téléphone↔montre ; - `seriesIndex`, `seriesTotal` ; - `exerciseName` ; - contexte séquence : - `sequenceIndex?`, `sequenceTotal?` - `stepIndex?`, `stepTotal?` - `stepName?` - type et valeur du **chrono dominant** ; - liste compacte des autres chronos actifs visibles ; - état global : - `ready` - `running` - `paused` - `nextTimerReady` - `restRunning` - `restPaused` - `noActiveSession` - `phoneUnavailable` - libellé de l'action primaire autorisée ; - liste des actions secondaires autorisées ; - indicateur `commandPending`. ## Hypothèses techniques laissées à Architect Points explicitement non tranchés par UX, à valider techniquement : 1. faisabilité et coût d'une app Wear OS Flutter dédiée ou module compagnon séparé ; 2. capacité à exposer côté téléphone un flux d'état d'exécution suffisamment compact et fréquent pour la montre ; 3. stratégie de mise à jour du chrono affiché sur la montre : - push fréquent depuis le téléphone ; - ou interpolation locale à partir d'horodatages autoritaires ; 4. transport exact téléphone↔montre et garanties d'acknowledgement pour les commandes ; 5. comportement si le téléphone est verrouillé, en arrière-plan, ou si le process principal est suspendu ; 6. possibilité de déclencher des vibrations montre sans prise de focus audio ; 7. capacité à rendre idempotentes les commandes utilisateur (`pause`, `resume`, `skipStep`, `finishSet`, etc.) ; 8. découpage des use cases côté téléphone pour exposer uniquement les commandes compatibles montre ; 9. gestion exacte des timeouts et des seuils de latence visibles dans l'UI ; 10. politique de duplication ou non des signaux entre téléphone et montre sur un même événement. ## Synthèse décisionnelle pour la suite La montre doit rester une surface extrêmement simple : - un écran principal `Séance active` ; - un écran secondaire `Actions` ; - un écran dédié `Repos` quand le repos est l'état dominant ; - des états explicites pour pause, `Chrono suivant prêt`, absence de séance et perte de connexion ; - une seule action primaire contextuelle à la fois ; - téléphone autoritaire, montre suiveuse interactive. Cette forme couvre l'objectif utilisateur réel : piloter entièrement la séance sans sortir le téléphone, tout en conservant la logique d'exécution déjà stabilisée dans GameTime.