Cached indexes: - NASManifestCache: actor-based disk cache for the NAS manifest (kisani_manifest_cache.json) Avoids NAS network round-trip when cache < 5 min old. Updated after every manifest download. - LocalPhotoIndex: actor-based disk cache of phone asset metadata (kisani_local_index.json) Built once on first launch, then updated incrementally via PHPhotoLibraryChangeObserver. O(1) countSafe via in-memory dict (vs PHFetchResult batch enumeration + CoreData calls). Fast path reconcile: When both caches are warm, reconcile() skips NAS connection + PHFetchResult enumeration entirely and returns in microseconds. Falls through to full NAS path only when stale. AutoBackupCoordinator.onActive(): Changed force: true → force: false so the 30-second debounce prevents expensive rescans on rapid app foreground/background cycles. Dashboard appears instantly from cached snapshot. BackupQueueItem + queue tracking: BackupEngine publishes queueItems: [BackupQueueItem] with per-file status, progress, speed, error details. Queue is persisted to disk and reloaded on next launch so SyncView always has data to show even after restart. NotificationService: Centralised local notification sender replacing the inline UNMutableNotificationContent blocks. Sends for: backup started, completed, failed, paused, NAS offline. Uses category identifiers so same-type notifications replace each other. SyncView redesign: - Removed pill/chip around NAS IP — replaced with plain "Online/Offline/Checking" dot+text - No live NAS directory listing (was expensive NAS connection on every tab open) - Shows engine.queueItems grouped into Active / Failed / Completed sections - Per-file rows with inline progress bar + bytes/speed for uploading items, error text for failed - Idle state shows archive count from statusService snapshot GalleryViewModel: NAS tab and All tab now use NASManifestCache as fallback when statusService.lastManifest is nil (offline launch). Gallery shows NAS items even when NAS is unreachable. AppDelegate: Bootstraps LocalPhotoIndex.loadOrBuild() in background on launch (non-blocking). Co-Authored-By: Kutesir <kutesir@provoc.ug> Co-Authored-By: Sentry <sentry@provoc.ug>
41 lines
1.4 KiB
Swift
41 lines
1.4 KiB
Swift
import UIKit
|
|
import BackgroundTasks
|
|
import UserNotifications
|
|
|
|
final class AppDelegate: NSObject, UIApplicationDelegate {
|
|
func application(
|
|
_ application: UIApplication,
|
|
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
|
|
) -> Bool {
|
|
UIDevice.current.isBatteryMonitoringEnabled = true
|
|
BackgroundTaskManager.registerTasks()
|
|
requestNotificationPermission()
|
|
setupLANMonitor()
|
|
// Bootstrap local indexes in the background — non-blocking.
|
|
// After first build they're loaded from disk in microseconds.
|
|
Task(priority: .utility) {
|
|
await LocalPhotoIndex.shared.loadOrBuild()
|
|
}
|
|
return true
|
|
}
|
|
|
|
private func requestNotificationPermission() {
|
|
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) { _, _ in }
|
|
}
|
|
|
|
private func setupLANMonitor() {
|
|
let monitor = LANMonitor.shared
|
|
monitor.onTrustedNetworkJoined = { ssid in
|
|
let store = ConnectionStore.shared
|
|
guard store.lanTriggerEnabled, !store.isInQuietHours else { return }
|
|
let delay = TimeInterval(store.startDelaySeconds)
|
|
BackgroundTaskManager.scheduleBackup(delay: delay)
|
|
}
|
|
monitor.start()
|
|
}
|
|
|
|
func applicationDidEnterBackground(_ application: UIApplication) {
|
|
BackgroundTaskManager.scheduleAppRefresh()
|
|
}
|
|
}
|