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>
This commit is contained in:
530
.ideai/memory/gametime-ux-watch-companion.md
Normal file
530
.ideai/memory/gametime-ux-watch-companion.md
Normal file
@ -0,0 +1,530 @@
|
||||
---
|
||||
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.
|
||||
Reference in New Issue
Block a user