RootView.swift
128 lignes · 4427 octets
import SwiftUI // Port of ui/nav/Card2vcfNavHost.kt — NavigationStack + Carnet | Projets tabs. // Deep flows: scan → draft → fiche, fiche → edit → rescan, duplicates → merge // → fiche, carnet → import. enum AppRoute: Hashable { case fiche(contactId: Int64, sort: ContactSort) case edit(contactId: Int64) case duplicates(contactId: Int64) case scan(editId: Int64?) case manual case importVcf case settings case projetDetail(serverId: String) } struct RootView: View { @State private var path: [AppRoute] = [] @State private var tab: MainTab = .carnet // Long-lived view models (Android scoped them to the NavHost). @StateObject private var carnetVm = CarnetViewModel() @StateObject private var projetsVm = ProjetsViewModel() @StateObject private var scanVm = ScanCarteViewModel() @StateObject private var settingsVm = SettingsViewModel() @StateObject private var syncVm = SyncChromeViewModel() var body: some View { NavigationStack(path: $path) { rootTab .navigationDestination(for: AppRoute.self) { route in destination(route) } } .tint(C2VColor.ink) } @ViewBuilder private var rootTab: some View { switch tab { case .carnet: CarnetScreen( viewModel: carnetVm, onOpenContact: { id, sort in path.append(.fiche(contactId: id, sort: sort)) }, onScan: { path.append(.scan(editId: nil)) }, onManual: { path.append(.manual) }, onImportVcf: { path.append(.importVcf) }, onSettings: { path.append(.settings) }, onOpenProjets: { tab = .projets }, syncViewModel: syncVm ) case .projets: ProjetsListScreen( viewModel: projetsVm, onOpenCarnet: { tab = .carnet }, onOpenProjet: { serverId in path.append(.projetDetail(serverId: serverId)) }, onSettings: { path.append(.settings) }, syncViewModel: syncVm ) } } @ViewBuilder private func destination(_ route: AppRoute) -> some View { switch route { case .fiche(let contactId, let sort): ContactPagerScreen( contactId: contactId, sort: sort, onBack: { pop() }, onEdit: { id in path.append(.edit(contactId: id)) }, onDuplicates: { id in path.append(.duplicates(contactId: id)) }, onDeleted: { path = [] } ) case .edit(let contactId): ContactEditScreen( contactId: contactId, onBack: { pop() }, onSaved: { pop() }, onRescan: { id in path.append(.scan(editId: id)) } ) case .duplicates(let contactId): DuplicateReviewScreen( contactId: contactId, onBack: { pop() }, onMerged: { keepId in // Kotlin: navigate fiche(keepId) popUpTo(carnet). path = [.fiche(contactId: keepId, sort: .lastName)] } ) case .scan(let editId): ScanCarteScreen( viewModel: scanVm, onBack: { pop() }, onContactSaved: { id in scanVm.editingContactId = nil scanVm.reset() path = [.fiche(contactId: id, sort: .lastName)] } ) .onAppear { // Kotlin LaunchedEffect(editId). scanVm.editingContactId = editId scanVm.reset() } case .manual: ManualContactScreen( onBack: { pop() }, onSaved: { id in path = [.fiche(contactId: id, sort: .lastName)] } ) case .importVcf: VcfImportScreen(onBack: { pop() }) case .settings: SettingsScreen(viewModel: settingsVm, onBack: { pop() }) case .projetDetail(let serverId): ProjetDetailScreen(serverId: serverId, onBack: { pop() }) } } private func pop() { if !path.isEmpty { path.removeLast() } } }
GitRust