Widget natif « Saisie rapide » : eau et café sans ouvrir l'app

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>
This commit is contained in:
Sylvain Bettinelli
2026-08-06 13:03:16 +00:00
parent f480c36dab
commit 9fda989afc
3 changed files with 296 additions and 0 deletions

View File

@@ -44,6 +44,15 @@ struct CoachWidgetSnapshot: Codable {
var today: TodaySession?
var forme: FormeScore?
/// Boissons du jour DÉJÀ connues du serveur, en millilitres et en nombre de
/// cafés. Le widget de saisie rapide y ajoute ce qui attend encore dans la
/// file locale : sans ces deux champs, il afficherait « 0,3 L » au lieu de
/// « 1,5 L » tant que l'app n'a pas resynchronisé, et l'utilisateur
/// douterait de saisies pourtant enregistrées.
/// Optionnels : un snapshot écrit par une version antérieure reste lisible.
var waterMlToday: Double?
var coffeeCountToday: Int?
/// Séance planifiée du jour (nil = jour OFF / pas de séance).
struct TodaySession: Codable {
var sport: String // running, cycling, strength, mobility, hiking, rest