import SwiftUI struct WatchRootView: View { @EnvironmentObject private var model: WatchAppModel var body: some View { Group { if model.hasCompletedOnboarding { WatchHomeView() } else { WatchOnboardingView() } } .preferredColorScheme(.dark) } } struct WatchOnboardingView: View { @EnvironmentObject private var model: WatchAppModel @State private var page = 0 @State private var authorizationError: String? var body: some View { VStack(spacing: 8) { TabView(selection: $page) { onboardingPage(icon: "hand.raised.fill", title: "Vos données", text: "Les mesures restent sur vos appareils et se synchronisent avec votre iPhone appairé.").tag(0) onboardingPage(icon: "heart.text.square.fill", title: "Bien-être, pas diagnostic", text: "Haptika n’est pas un dispositif médical. Consultez un professionnel en cas de symptôme.").tag(1) onboardingPage(icon: "waveform.path.ecg", title: "Mesurer sans vibrer", text: "La Watch mesure le pouls optique. Les vibrations sont toujours arrêtées pendant cette phase.").tag(2) } .tabViewStyle(.verticalPage) if let authorizationError { Text(authorizationError).font(.caption2).foregroundStyle(.orange) } Button(page < 2 ? "Continuer" : "Autoriser Santé") { if page < 2 { withAnimation { page += 1 } } else { Task { do { try await model.measurement.requestAuthorization() model.hasCompletedOnboarding = true } catch { authorizationError = error.localizedDescription } } } } .buttonStyle(.borderedProminent) } .padding(.horizontal, 6) .background(WatchTheme.background.ignoresSafeArea()) } private func onboardingPage(icon: String, title: String, text: String) -> some View { VStack(spacing: 10) { Image(systemName: icon).font(.system(size: 34)).foregroundStyle(WatchTheme.accent) Text(title).font(.headline).multilineTextAlignment(.center) Text(text).font(.caption).foregroundStyle(WatchTheme.secondary).multilineTextAlignment(.center) } } } struct WatchHomeView: View { @EnvironmentObject private var model: WatchAppModel var body: some View { NavigationStack { List { Section { NavigationLink(value: WatchHomeDestination.measure) { homeRow("Mesurer", "waveform.path.ecg", WatchTheme.mint) } NavigationLink(value: WatchHomeDestination.coherence) { homeRow("Ma Cohérence", "circle.dotted", WatchTheme.accent) } NavigationLink(value: WatchHomeDestination.exercises) { homeRow("Exercices", "wind", .cyan) } NavigationLink(value: WatchHomeDestination.cardiacMirror) { homeRow("Miroir cardiaque", "heart.circle", .pink) } NavigationLink(value: WatchHomeDestination.history) { homeRow("Historique", "chart.xyaxis.line", .indigo) } } header: { VStack(alignment: .leading, spacing: 2) { Text("HAPTIKA").font(.caption2).foregroundStyle(WatchTheme.accent) Text("Prendre un temps").font(.headline).foregroundStyle(.white) } .textCase(nil) } Section { HStack { Circle().fill(model.connectivity.isReachable ? WatchTheme.mint : .gray).frame(width: 7, height: 7) Text(model.connectivity.isReachable ? "iPhone joignable" : "Mode autonome") } .font(.caption2) .foregroundStyle(WatchTheme.secondary) } } .navigationDestination(for: WatchHomeDestination.self) { destination in switch destination { case .measure: WatchMeasurementView() case .coherence: WatchCoherenceView() case .exercises: WatchExerciseListView() case .cardiacMirror: WatchCardiacMirrorView() case .history: WatchHistoryView() } } .haptikaScreen() } } private func homeRow(_ title: String, _ icon: String, _ color: Color) -> some View { Label { Text(title).font(.subheadline.weight(.semibold)) } icon: { Image(systemName: icon).foregroundStyle(color) } } }