perf: eliminate full rescans with local caches; add queue tracking, notifications, SyncView redesign
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>
This commit is contained in:
@@ -38,7 +38,16 @@ final class GalleryViewModel: ObservableObject {
|
||||
isLoading = true
|
||||
nasError = nil
|
||||
|
||||
let manifestEntries = statusService.lastManifest?.entries ?? []
|
||||
// Prefer the in-memory lastManifest (most recent reconcile), fall back to
|
||||
// disk-cached NASManifestCache (survives launches without NAS connection).
|
||||
let manifestEntries: [ManifestEntry]
|
||||
if let m = statusService.lastManifest {
|
||||
manifestEntries = m.entries
|
||||
} else if let cached = await NASManifestCache.shared.manifest {
|
||||
manifestEntries = cached.entries
|
||||
} else {
|
||||
manifestEntries = []
|
||||
}
|
||||
|
||||
let phoneAssets = await Task.detached(priority: .userInitiated) {
|
||||
Self.fetchPhoneAssets()
|
||||
|
||||
Reference in New Issue
Block a user