import SwiftUI struct ContentView: View { @StateObject private var dataManager = ClimbingDataManager() @State private var selectedTab = 0 @Environment(\.scenePhase) private var scenePhase @State private var notificationObservers: [NSObjectProtocol] = [] var body: some View { TabView(selection: $selectedTab) { SessionsView() .tabItem { Image(systemName: "play.fill") Text("Sessions") } .tag(0) ProblemsView() .tabItem { Image(systemName: "star.fill") Text("Problems") } .tag(1) AnalyticsView() .tabItem { Image(systemName: "chart.bar.fill") Text("Analytics") } .tag(2) GymsView() .tabItem { Image(systemName: "location.fill") Text("Gyms") } .tag(3) SettingsView() .tabItem { Image(systemName: "gear") Text("Settings") } .tag(4) } .environmentObject(dataManager) .onChange(of: scenePhase) { oldPhase, newPhase in if newPhase == .active { // Add slight delay to ensure app is fully loaded Task { try? await Task.sleep(nanoseconds: 200_000_000) // 0.2 seconds dataManager.onAppBecomeActive() } } else if newPhase == .background { dataManager.onAppEnterBackground() } } .onAppear { setupNotificationObservers() // Trigger auto-sync on app launch dataManager.syncService.triggerAutoSync(dataManager: dataManager) } .onDisappear { removeNotificationObservers() } .overlay(alignment: .top) { if let message = dataManager.successMessage { SuccessMessageView(message: message) .transition(.move(edge: .top).combined(with: .opacity)) .animation(.easeInOut, value: dataManager.successMessage) } if let error = dataManager.errorMessage { ErrorMessageView(message: error) .transition(.move(edge: .top).combined(with: .opacity)) .animation(.easeInOut, value: dataManager.errorMessage) } } } private func setupNotificationObservers() { // Listen for when the app will enter foreground let willEnterForegroundObserver = NotificationCenter.default.addObserver( forName: UIApplication.willEnterForegroundNotification, object: nil, queue: .main ) { _ in print("App will enter foreground - preparing Live Activity check") Task { // Small delay to ensure app is fully active try? await Task.sleep(nanoseconds: 800_000_000) // 0.8 seconds await dataManager.onAppBecomeActive() } } // Listen for when the app becomes active let didBecomeActiveObserver = NotificationCenter.default.addObserver( forName: UIApplication.didBecomeActiveNotification, object: nil, queue: .main ) { _ in print("App did become active - checking Live Activity status") Task { try? await Task.sleep(nanoseconds: 300_000_000) // 0.3 seconds await dataManager.onAppBecomeActive() // Trigger auto-sync when app becomes active await dataManager.syncService.triggerAutoSync(dataManager: dataManager) } } notificationObservers = [willEnterForegroundObserver, didBecomeActiveObserver] } private func removeNotificationObservers() { for observer in notificationObservers { NotificationCenter.default.removeObserver(observer) } notificationObservers.removeAll() } } struct SuccessMessageView: View { let message: String var body: some View { HStack { Image(systemName: "checkmark.circle.fill") .foregroundColor(.green) Text(message) .font(.subheadline) .foregroundColor(.primary) } .padding() .background( RoundedRectangle(cornerRadius: 12) .fill(.regularMaterial) .shadow(radius: 4) ) .padding(.horizontal) .padding(.top, 8) } } struct ErrorMessageView: View { let message: String var body: some View { HStack { Image(systemName: "exclamationmark.triangle.fill") .foregroundColor(.red) Text(message) .font(.subheadline) .foregroundColor(.primary) } .padding() .background( RoundedRectangle(cornerRadius: 12) .fill(.regularMaterial) .shadow(radius: 4) ) .padding(.horizontal) .padding(.top, 8) } } #Preview { ContentView() }