import SwiftUI import CocotteCockpitKit import CocottePlatformModels import CocottePlatformAPIClient // Stream 2 — the iOS cockpit. TabView shell (navigation lives here, not the Kit): // Drops · Assets · Fleet · Activity · Insights, reusing the shared model + views. @main struct CocotteCockpitiOSApp: App { var body: some Scene { WindowGroup { RootView() } } } struct RootView: View { @State private var model = RootView.makeModel() @State private var theme: Theme = .dark /// Build the data source. With `--api-base ` + `--user-id ` /// (and optional `--token `, `--org-id `) the cockpit talks to the live /// platform.api via the shared client; without them, the mock dataset. /// `--api-base` is the host root (e.g. `http://black:3060`) — the client adds `/api/v1`. private static func makeModel() -> CockpitModel { let args = ProcessInfo.processInfo.arguments func value(_ flag: String) -> String? { guard let i = args.firstIndex(of: flag), i + 1 < args.count else { return nil } return args[i + 1] } guard let base = value("--api-base"), let url = URL(string: base), let userIdStr = value("--user-id"), let userId = UUID(uuidString: userIdStr) else { return CockpitModel() } let scope = TenantScope(userId: userId, orgId: value("--org-id").flatMap { UUID(uuidString: $0) }) let auth = InMemoryAuthProvider(token: value("--token")) return CockpitModel(api: LiveCockpitAPI(baseURL: url, auth: auth, scope: scope)) } @State private var selection: Int = { let args = ProcessInfo.processInfo.arguments if let i = args.firstIndex(of: "--tab"), i + 1 < args.count, let n = Int(args[i + 1]) { return n } return 0 }() private var tokens: Tokens { Tokens.make(theme, .regular) } var body: some View { TabView(selection: $selection) { DropsTab(model: model, theme: $theme) .tabItem { Label("Drops", systemImage: "tray.full") }.tag(0) AssetsTab(model: model) .tabItem { Label("Assets", systemImage: "photo.on.rectangle") }.tag(1) FleetTab(model: model) .tabItem { Label("Fleet", systemImage: "person.3") }.tag(2) ActivityTab(model: model) .tabItem { Label("Activity", systemImage: "bolt.horizontal") }.tag(3) InsightsTab(model: model) .tabItem { Label("Insights", systemImage: "chart.bar") }.tag(4) } .environment(\.tokens, tokens) .preferredColorScheme(theme == .dark ? .dark : .light) .tint(tokens.accent) .task { await model.refresh() } } } private struct DropsTab: View { var model: CockpitModel @Binding var theme: Theme @State private var path: [UUID] = [] @State private var composing = ProcessInfo.processInfo.arguments.contains("--composer") var body: some View { NavigationStack(path: $path) { ContentDropsView(model: model, onSelectDrop: { path.append($0.id) }) .navigationTitle("CocotteAI · social") .navigationBarTitleDisplayMode(.inline) .toolbar { ToolbarItem(placement: .topBarLeading) { Button { theme = (theme == .dark ? .light : .dark) } label: { Image(systemName: "circle.lefthalf.filled") } } ToolbarItem(placement: .topBarTrailing) { Button { composing = true } label: { Image(systemName: "plus") } } } .navigationDestination(for: UUID.self) { id in if let drop = model.drop(id) { DropDetailView(drop: drop) .navigationTitle(drop.displayTitle) .navigationBarTitleDisplayMode(.inline) } } .sheet(isPresented: $composing) { ComposerView(model: model, onClose: { composing = false }) } } } } private struct AssetsTab: View { var model: CockpitModel var body: some View { NavigationStack { AssetLibraryView(model: model) .navigationTitle("Assets") .navigationBarTitleDisplayMode(.inline) } } } private struct FleetTab: View { var model: CockpitModel @State private var path: [UUID] = [] var body: some View { NavigationStack(path: $path) { FleetListView(model: model, onSelect: { path.append($0.id) }) .navigationTitle("Fleet · content") .navigationBarTitleDisplayMode(.inline) .navigationDestination(for: UUID.self) { id in if let s = model.specialist(id) { SpecialistDetailView(specialist: s) .navigationTitle(s.displayName) .navigationBarTitleDisplayMode(.inline) } } } } } private struct ActivityTab: View { var model: CockpitModel var body: some View { NavigationStack { ActivityView(model: model) .navigationTitle("Activity") .navigationBarTitleDisplayMode(.inline) } } } private struct InsightsTab: View { var model: CockpitModel var body: some View { NavigationStack { AnalyticsView(model: model) .navigationTitle("Insights") .navigationBarTitleDisplayMode(.inline) } } }