Files
JQC_iOS_App/JanitorialQC/JanitorialQCApp.swift
T

81 lines
2.4 KiB
Swift

// JQCApp.swift
// ------------
// App entry point.
import SwiftUI
import SwiftData
import BackgroundTasks
@main
struct JanitorialQCApp: App {
@StateObject private var auth = AuthManager.shared
@StateObject private var sync = SyncManager.shared
init() {
registerBackgroundTasks()
}
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)")
}
}
}
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)
}