feat(watch): routine quotidienne cochable sur l'Apple Watch

Pendant natif du backend coach_sportif (commit 772385b, déjà en prod).

- CoachRoutineBridge (target App) : pousse blocs + état du jour vers la Watch
  via updateApplicationContext, relaie les coches Watch vers /api/routine/day
  puis notifie la WebView (event routineUpdated)
- CoachWatch/RoutineStore : état persisté en UserDefaults, reset au changement
  de jour. Les blocs viennent de l'iPhone — rien codé en dur côté watchOS, donc
  modifier la routine côté web ne demande aucun rebuild
- CoachWatch/RoutineView : liste cochable, progression, haptique, bouton de
  renvoi si la synchro a échoué
- ConnectivityManager (watch) : sendRoutine() en sendMessage avec repli
  transferUserInfo (coche faite iPhone hors de portée -> livraison différée)

⚠️ CoachLiveBridge touché : routeIfNotLiveSample() aiguille les messages
routineDone vers NotificationCenter. WCSession.delegate est unique côté iPhone,
impossible d'en ajouter un second. Le flux live workout n'est pas modifié mais
doit être re-vérifié au build.

Les 3 nouveaux fichiers sont référencés dans project.pbxproj (bonne target) :
aucun "Add Files" à faire sur le Mac. Runbook : docs/routine-watch-runbook-mac.md

NON COMPILÉ — nécessite une session Xcode sur le Mac mini.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Sylvain Bettinelli
2026-08-03 14:22:33 +00:00
parent 5f8f3edcd9
commit caeac37f38
10 changed files with 639 additions and 0 deletions

View File

@@ -24,6 +24,7 @@ struct ContentView: View {
struct ActivityPickerView: View {
@EnvironmentObject private var workout: WorkoutManager
@State private var showRoutine = false
private struct Activity: Identifiable {
let id = UUID()
@@ -54,6 +55,14 @@ struct ActivityPickerView: View {
.frame(maxWidth: .infinity, alignment: .leading)
}
}
Button {
showRoutine = true
} label: {
Label("Routine du jour", systemImage: "figure.cooldown")
.frame(maxWidth: .infinity, alignment: .leading)
}
.tint(.cyan)
Button {
workout.startSimulation()
} label: {
@@ -71,6 +80,9 @@ struct ActivityPickerView: View {
.padding(.horizontal, 4)
}
.navigationTitle("Coach")
.sheet(isPresented: $showRoutine) {
RoutineView()
}
}
}