feat(watch): complications Apple Watch (Forme + Séance du jour)

L'App Group n'étant pas partagé entre appareils, le snapshot transite par
WatchConnectivity : iPhone CoachWidgetBridge.pushToWatch (updateApplicationContext)
-> CoachWatch/ConnectivityManager reçoit -> App Group de la montre + reload des
complications. Nouvelles complications (CoachWatchWidgets/CoachWatchComplications.swift) :
Forme (accessoryCircular/corner, Gauge) + Séance du jour (accessoryRectangular/inline).

⚠️ Reste Mac : créer la target widget watchOS + App Group/capability + Target
Membership. Runbook complet dans docs/widgets-runbook-mac.md.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Sylvain Bettinelli
2026-06-29 05:50:29 +00:00
parent a6bdebcfc8
commit cc88431f6b
5 changed files with 280 additions and 5 deletions

View File

@@ -1,5 +1,6 @@
import Foundation
import WatchConnectivity
import WidgetKit
import os
private let connLog = Logger(subsystem: "ch.hypnotruck.coach.watchkitapp", category: "connectivity")
@@ -78,4 +79,26 @@ extension ConnectivityManager: WCSessionDelegate {
queue.async { [weak self] in self?.flushLocked() }
}
}
// Réception du snapshot widget (iPhone Watch)
// L'iPhone (CoachWidgetBridge) pousse les données du jour ; on les persiste
// dans l'App Group de CETTE montre et on recharge les complications.
func session(_ session: WCSession, didReceiveApplicationContext applicationContext: [String: Any]) {
storeWidgetSnapshot(applicationContext)
}
func session(_ session: WCSession, didReceiveUserInfo userInfo: [String: Any] = [:]) {
storeWidgetSnapshot(userInfo)
}
private func storeWidgetSnapshot(_ dict: [String: Any]) {
guard let data = dict["widgetSnapshot"] as? Data,
let snapshot = try? JSONDecoder().decode(CoachWidgetSnapshot.self, from: data) else { return }
CoachWidgetStore.save(snapshot)
connLog.info("widgetSnapshot reçu de l'iPhone -> complications rechargées")
DispatchQueue.main.async {
WidgetCenter.shared.reloadAllTimelines()
}
}
}