Un widget se lit hors contexte, au milieu d'autres tuiles : sans titre,
« 0,3 L · 2 cafés » ne dit ni de quoi il s'agit, ni à quoi servent les boutons.
Le nom affiché dans la galerie de widgets est aligné sur ce titre — deux libellés
différents pour la même chose obligeraient à les rapprocher de tête.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Les deux liens utilisaient un schéma custom `coachapp://` que rien ne route :
le projet passe par les Universal Links (entitlement associated-domains), comme
les widgets Séance du jour et Score de forme, qui pointent tous deux sur des URL
https. L'app s'ouvrait donc sur sa dernière page consultée — le score de sommeil
en l'occurrence.
Les liens passent en https://coach.hypnotruck.ch/meals?photo=1 et ?scan=1, et le
schéma custom que j'avais ajouté à l'Info.plist est retiré : il ne servait à
rien et aurait laissé une fausse piste.
J'avais écrit ces URL sans lire comment les widgets voisins s'y prenaient — même
faute que pour `todayISO`, supposer un mécanisme au lieu de le vérifier.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Trois des étapes du runbook sont des fichiers texte, donc faisables hors Xcode :
* `CoachQuickWidget()` enregistré dans `CoachLiveActivityBundle`, sous
`if #available(iOS 17.0, *)` — le bundle sert aussi des cibles antérieures ;
* schéma `coachapp://` déclaré dans l'Info.plist de l'App. Il n'y était pas :
seul le schéma Google était présent, et les boutons Photo et Scanner du
widget n'auraient donc rien ouvert ;
* `CoachQuickSync.flush()` appelé depuis `applicationDidBecomeActive`, qui
était un corps vide.
Ne restent en manuel que les gestes qui touchent le projet Xcode lui-même :
Target Membership des trois fichiers Swift, puis le build.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Boutons d'App Intent (iOS 17+) pour l'eau et le café : ils s'exécutent dans
l'extension, écrivent dans l'App Group et rafraîchissent la timeline. Aucun
appel réseau — une extension n'a ni session authentifiée ni droit de tenir une
requête.
Photo et code-barres OUVRENT l'application, par `coachapp://meals?photo=1` et
`?scan=1` : la caméra exige le premier plan, aucun widget ne peut y échapper.
Le widget économise les navigations, pas le lancement.
`CoachQuickLog` : file d'attente partagée app ↔ widget ↔ montre. Les saisies
partent au serveur à la prochaine ouverture de l'app, et sont retirées PAR
IDENTIFIANT — vider la file perdrait une saisie faite pendant la
synchronisation, sans laisser de trace.
Le widget affiche son propre total du jour : les boissons déjà connues du
serveur (nouveaux champs `waterMlToday` / `coffeeCountToday` du snapshot, tous
deux optionnels pour rester lisibles depuis une version antérieure) PLUS ce qui
attend dans la file. Sans cela, il afficherait un total périmé juste après une
saisie et l'utilisateur douterait de ce qu'il vient de faire. Ce qui n'est pas
encore parti est signalé par une flèche, pas masqué.
Un échec d'écriture de l'App Group remonte en erreur d'intent : afficher
« ajouté » sur une saisie perdue est pire que ne rien afficher.
Runbook Mac complété — Target Membership, enregistrement dans le WidgetBundle,
schéma d'URL, iOS 17 minimum, et le câblage de synchronisation restant.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sur la Dynamic Island compact/minimal ET sur la bannière Lock Screen,
.widgetURL(https://coach.hypnotruck.ch/live) fait que le tap ouvre l'app
sur /live, qui appelle openNativeLive et présente CoachLiveView (Liquid
Glass plein écran) avec toutes les mesures.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>