import ManaCore import SwiftUI /// Top-Level-View: TabView mit drei Tabs. /// /// **Phase ζ-0 — Setup.** Tabs zeigen aktuell nur Placeholder-Views. /// Ab Phase ζ-1 wird der Lesen-Tab durch `WebShellView` ersetzt, /// der `zitare.com` im `WKWebView` rendert. struct RootView: View { @Environment(AuthClient.self) private var auth @State private var selectedTab: AppTab = .read @State private var healthStatus: HealthStatus = .unknown var body: some View { TabView(selection: $selectedTab) { placeholderView( title: "Lesen", subtitle: "ζ-1: WebShellView gegen zitare.com", systemImage: "book" ) .tabItem { Label("Lesen", systemImage: "book") } .tag(AppTab.read) placeholderView( title: "Erkunden", subtitle: "ζ-1: WebShell auf zitare.com/explore", systemImage: "sparkle.magnifyingglass" ) .tabItem { Label("Erkunden", systemImage: "sparkle.magnifyingglass") } .tag(AppTab.explore) AccountView(healthStatus: healthStatus) .tabItem { Label("Konto", systemImage: "person.circle") } .tag(AppTab.account) } .task { await probeHealth() } .onOpenURL { url in handle(url: url) } .onContinueUserActivity(NSUserActivityTypeBrowsingWeb) { activity in if let url = activity.webpageURL { handle(url: url) } } } /// Phase ζ-0 Probe: ein Aufruf gegen `/healthz` bei App-Start. /// Ab Phase ζ-1 wandert das in einen Service, der den Status global /// trackt und im AccountView anzeigt. private func probeHealth() async { let api = ZitareAPI(auth: auth) do { let ok = try await api.healthCheck() healthStatus = ok ? .ok : .down Log.api.info("Healthz: \(ok ? "OK" : "DOWN")") } catch { healthStatus = .down Log.api.warning( "Healthz fehlgeschlagen: \(String(describing: error), privacy: .public)" ) } } /// Deep-Link-Routing. Phase ζ-0: nur loggen. Phase ζ-1: in den /// passenden Tab + Pfad routen. private func handle(url: URL) { Log.app.info("Deep-Link empfangen: \(url.absoluteString, privacy: .public)") // ζ-1 TODO: parse zitare.com/q/, /a/, /c/ // und in WebShellView mit entsprechender URL laden. } private func placeholderView( title: String, subtitle: String, systemImage: String ) -> some View { VStack(spacing: 16) { Image(systemName: systemImage) .font(.system(size: 48)) .foregroundStyle(ZitareTheme.primary) Text(title) .font(.title2) .fontWeight(.semibold) Text(subtitle) .font(.callout) .foregroundStyle(ZitareTheme.mutedForeground) .multilineTextAlignment(.center) .padding(.horizontal, 32) } .frame(maxWidth: .infinity, maxHeight: .infinity) .background(ZitareTheme.background) } } enum AppTab: Hashable { case read case explore case account } enum HealthStatus { case unknown case ok case down }