// JQCApp.swift // ------------ // App entry point. import SwiftUI import SwiftData import BackgroundTasks import UserNotifications @main struct JanitorialQCApp: App { @StateObject private var auth = AuthManager.shared @StateObject private var sync = SyncManager.shared init() { registerBackgroundTasks() requestNotificationPermission() } var body: some Scene { WindowGroup { ContentView() .environmentObject(auth) .environmentObject(sync) } .modelContainer(for: [ LocalFacility.self, LocalArea.self, LocalTemplate.self, LocalInspection.self, LocalIssue.self, PendingPhoto.self, SyncQueueEntry.self, ], isUndoEnabled: false) { result in switch result { case .success(let container): // Only set the model context here — do NOT await anything. // Session restore and sync are triggered by ContentView.task{} // which runs on the MainActor inside the SwiftUI lifecycle, // guaranteeing isLoading changes are seen by the view immediately. SyncManager.shared.modelContext = container.mainContext case .failure(let error): fatalError("SwiftData container failed: \(error)") } } } // ── Local notification permission ───────────────────────────────────── // Request permission for local notifications (used by the polling poller // to alert inspectors of new assignments and follow-up requests). // Called at init — iOS caches the grant; subsequent calls are no-ops. private func requestNotificationPermission() { UNUserNotificationCenter.current().requestAuthorization( options: [.alert, .sound, .badge] ) { granted, error in if let error { print("[JQC] Notification permission error: \(error)") } } } private func registerBackgroundTasks() { BGTaskScheduler.shared.register( forTaskWithIdentifier: "com.jqc.sync", using: nil ) { task in guard let processingTask = task as? BGProcessingTask else { task.setTaskCompleted(success: false) return } handleBackgroundSync(task: processingTask) } } private func handleBackgroundSync(task: BGProcessingTask) { scheduleBackgroundSync() let syncTask = Task { await SyncManager.shared.triggerSync() } task.expirationHandler = { syncTask.cancel() } Task { await syncTask.value task.setTaskCompleted(success: !syncTask.isCancelled) } } } func scheduleBackgroundSync() { let request = BGProcessingTaskRequest(identifier: "com.jqc.sync") request.requiresNetworkConnectivity = true request.requiresExternalPower = false try? BGTaskScheduler.shared.submit(request) }