import SwiftUI // MARK: - App Delegate (Background Upload Session) class AppDelegate: NSObject, UIApplicationDelegate { func application( _ application: UIApplication, handleEventsForBackgroundURLSession identifier: String, completionHandler: @escaping () -> Void ) { if identifier == "com.navidromeplayer.batchupload" { ZipImportManager.shared.setBackgroundCompletionHandler(completionHandler) DebugLogger.shared.log("Background session woke app: \(identifier)", category: "Upload") } } } @main struct NavidromePlayerApp: App { @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate @StateObject private var serverManager = ServerManager.shared @StateObject private var audioPlayer = AudioPlayer.shared @StateObject private var offlineManager = OfflineManager.shared // Initialize WatchConnectivity so sync works immediately private let watchConnectivity = WatchConnectivityManager.shared init() { // Dismiss keyboard when scrolling any scroll view UIScrollView.appearance().keyboardDismissMode = .interactive } var body: some Scene { WindowGroup { RootView() .environmentObject(serverManager) .environmentObject(audioPlayer) .environmentObject(offlineManager) .tint(Color(red: 1.0, green: 0.176, blue: 0.333)) // iOS 8 Music pink } } } struct RootView: View { @EnvironmentObject var serverManager: ServerManager var body: some View { Group { if serverManager.servers.isEmpty { // No servers configured — show login LoginView() } else { // Servers exist — show main UI immediately (connects in background) MainTabView() } } .dismissKeyboardOnTap() .task { ImageCache.shared.trimDiskCache() AudioPreFetcher.shared.cleanOldPrefetches(keeping: AudioPlayer.shared.queue) if serverManager.activeServer != nil { await serverManager.connectToActive() // Background sync — fills LibraryCache so UI never waits for network SyncEngine.shared.syncIfNeeded() // Flush any pending optimistic actions (star/unstar that failed offline) OptimisticActionQueue.shared.flush() } // Connect Companion push client if enabled if CompanionSettings.shared.isEnabled { CompanionPushClient.shared.connect() } } } }