| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130 |
- import SwiftUI
- import SwiftData
- // MARK: - ContentView
- /// Root navigation container for the CelestiaTrace app.
- /// Uses a TabView with three tabs: Home, Field Records, and Settings.
- struct ContentView: View {
- @Environment(\.modelContext) private var modelContext
- @Environment(\.scenePhase) private var scenePhase
- @Query(sort: \CelestiaSession.startTime, order: .reverse) private var sessions: [CelestiaSession]
- @ObservedObject private var authManager = AuthManager.shared
- @AppStorage(DeveloperLogStore.enabledKey) private var isDeveloperModeEnabled = false
- /// Currently selected tab.
- @State private var selectedTab: Tab = .home
- /// Session selected for detail playback navigation in Field Records tab.
- @State private var fieldRecordsSelectedSession: CelestiaSession?
- var body: some View {
- ZStack(alignment: .bottomTrailing) {
- TabView(selection: $selectedTab) {
- HomeView { session in
- fieldRecordsSelectedSession = session
- selectedTab = .fieldRecords
- }
- .tabItem {
- Label(Tab.home.title, systemImage: Tab.home.icon)
- }
- .tag(Tab.home)
- SessionListView(
- selectedSession: $fieldRecordsSelectedSession,
- onStartRecording: {
- selectedTab = .home
- }
- )
- .tabItem {
- Label(Tab.fieldRecords.title, systemImage: Tab.fieldRecords.icon)
- }
- .tag(Tab.fieldRecords)
- SettingsView()
- .tabItem {
- Label(Tab.settings.title, systemImage: Tab.settings.icon)
- }
- .tag(Tab.settings)
- }
- .tint(.celestiaCyan)
- if isDeveloperModeEnabled {
- DeveloperLogOverlay()
- .transition(.scale(scale: 0.92, anchor: .bottomTrailing).combined(with: .opacity))
- .zIndex(20)
- }
- }
- .animation(.easeInOut(duration: 0.2), value: isDeveloperModeEnabled)
- .onAppear {
- if isDeveloperModeEnabled {
- DeveloperLogStore.log("App", "开发者模式已启用,开始记录本次运行日志", level: .success)
- }
- if RecordingRecoveryStore.activeSessionID != nil
- || RecordingLiveActivityManager.shared.recoverableSessionID != nil {
- selectedTab = .home
- }
- }
- .task(id: authManager.currentUser?.id) {
- await synchronizeFieldRecords()
- }
- .onChange(of: scenePhase) { _, newPhase in
- guard newPhase == .active else { return }
- Task {
- await synchronizeFieldRecords()
- }
- }
- .onOpenURL { url in
- guard RecordingLiveActivityRoute(url: url) != nil else { return }
- selectedTab = .home
- }
- .onChange(of: isDeveloperModeEnabled) { _, enabled in
- if enabled {
- DeveloperLogStore.log("App", "开发者模式已开启", level: .success)
- }
- }
- }
- @MainActor
- private func synchronizeFieldRecords() async {
- guard let userID = authManager.currentUser?.id else { return }
- _ = await SyncManager.shared.sync(
- sessions: sessions,
- modelContext: modelContext,
- userID: userID
- )
- }
- }
- // MARK: - Tab Definition
- extension ContentView {
- /// Defines the available tabs in the app's root navigation.
- enum Tab: Hashable {
- case home
- case fieldRecords
- case settings
- var title: String {
- switch self {
- case .home: "首页"
- case .fieldRecords: "现场记录"
- case .settings: "设置"
- }
- }
- var icon: String {
- switch self {
- case .home: "house.fill"
- case .fieldRecords: "waveform.path.ecg"
- case .settings: "gearshape.fill"
- }
- }
- }
- }
- // MARK: - Preview
- #Preview {
- ContentView()
- .modelContainer(for: CelestiaSession.self, inMemory: true)
- }
|