Skip to main content

Cache the list of approved/rejected/needs action assets

ID
2942f9f
date
2023-06-09 16:57:18+00:00
author
Alex Chan <alex@alexwlchan.net>
parent
1d67a77
message
Cache the list of approved/rejected/needs action assets

This means the app takes slightly longer every time it needs to fetch
new data from the photos library, but now the state lookup for thumbnail
annotations should be quicker.
changed files
5 files, 33 additions, 34 deletions

Changed files

BlinkReviewer/BlinkReviewer/Photos/AssetHelpers.swift (4937) → BlinkReviewer/BlinkReviewer/Photos/AssetHelpers.swift (4429)

diff --git a/BlinkReviewer/BlinkReviewer/Photos/AssetHelpers.swift b/BlinkReviewer/BlinkReviewer/Photos/AssetHelpers.swift
index 9fd36ad..60f3c92 100644
--- a/BlinkReviewer/BlinkReviewer/Photos/AssetHelpers.swift
+++ b/BlinkReviewer/BlinkReviewer/Photos/AssetHelpers.swift
@@ -38,25 +38,6 @@ extension PHAsset {
         return result
     }
     
-    func state() -> ReviewState? {
-        var result: ReviewState? = nil
-        
-        self.albums().forEach { album in
-            switch (album.localizedTitle) {
-                case "Approved":
-                    result = .Approved
-                case "Rejected":
-                    result = .Rejected
-                case "Needs Action":
-                    result = .NeedsAction
-                default:
-                    break
-            }
-        }
-        
-        return result
-    }
-    
     private func getImageForSize(size: CGSize) -> NSImage {
         // This implementation is based on code in a Stack Overflow answer
         // by Francois Nadeau: https://stackoverflow.com/a/48755517/1558022

BlinkReviewer/BlinkReviewer/Photos/PhotosLibrary.swift (1447) → BlinkReviewer/BlinkReviewer/Photos/PhotosLibrary.swift (2105)

diff --git a/BlinkReviewer/BlinkReviewer/Photos/PhotosLibrary.swift b/BlinkReviewer/BlinkReviewer/Photos/PhotosLibrary.swift
index 0fa8aa4..9a09244 100644
--- a/BlinkReviewer/BlinkReviewer/Photos/PhotosLibrary.swift
+++ b/BlinkReviewer/BlinkReviewer/Photos/PhotosLibrary.swift
@@ -12,6 +12,10 @@ class PhotosLibrary: NSObject, ObservableObject, PHPhotoLibraryChangeObserver {
 
     @Published var assets = getAllPhotos()
     @Published var isPhotoLibraryAuthorized = false
+    
+    @Published var approvedAssets: Set<PHAsset> = Set()
+    @Published var rejectedAssets: Set<PHAsset> = Set()
+    @Published var needsActionAssets: Set<PHAsset> = Set()
 
     override init() {
         super.init()
@@ -30,25 +34,39 @@ class PhotosLibrary: NSObject, ObservableObject, PHPhotoLibraryChangeObserver {
     private func updateStatus() {
         DispatchQueue.main.async {
             self.assets = getAllPhotos()
+            
+            self.approvedAssets = self.getPhotosIn(album: getAlbum(withName: "Approved"))
+            self.rejectedAssets = self.getPhotosIn(album: getAlbum(withName: "Rejected"))
+            self.needsActionAssets = self.getPhotosIn(album: getAlbum(withName: "Needs Action"))
+            
             self.isPhotoLibraryAuthorized = PHPhotoLibrary.authorizationStatus() == .authorized
         }
     }
     
-    func countApproved() -> Int {
-        let album = getAlbum(withName: "Approved")
+    private func getPhotosIn(album: PHAssetCollection) -> Set<PHAsset> {
+        var result: Set<PHAsset> = Set()
         
-        return PHAsset.fetchAssets(in: album, options: nil).count
-    }
-    
-    func countRejected() -> Int {
-        let album = getAlbum(withName: "Rejected")
+        PHAsset.fetchAssets(in: album, options: nil)
+            .enumerateObjects({ (asset, _, _) in
+                result.insert(asset)
+            })
         
-        return PHAsset.fetchAssets(in: album, options: nil).count
+        return result
     }
     
-    func countNeedsAction() -> Int {
-        let album = getAlbum(withName: "Needs Action")
+    func state(for asset: PHAsset) -> ReviewState? {
+        if self.rejectedAssets.contains(asset) {
+            return .Rejected
+        }
+        
+        if self.needsActionAssets.contains(asset) {
+            return .NeedsAction
+        }
+        
+        if self.approvedAssets.contains(asset) {
+            return .Approved
+        }
         
-        return PHAsset.fetchAssets(in: album, options: nil).count
+        return nil
     }
 }

BlinkReviewer/BlinkReviewer/Views/PhotoReviewer.swift (5694) → BlinkReviewer/BlinkReviewer/Views/PhotoReviewer.swift (5730)

diff --git a/BlinkReviewer/BlinkReviewer/Views/PhotoReviewer.swift b/BlinkReviewer/BlinkReviewer/Views/PhotoReviewer.swift
index 7058682..42221d3 100644
--- a/BlinkReviewer/BlinkReviewer/Views/PhotoReviewer.swift
+++ b/BlinkReviewer/BlinkReviewer/Views/PhotoReviewer.swift
@@ -135,9 +135,9 @@ struct PhotoReviewer: View {
                 photosLibrary.updateAsset(atIndex: selectedAssetIndex)
 
             case 32: // "u"
-                if asset.state() != nil {
+                if photosLibrary.state(for: asset) != nil {
                     let lastUnreviewed = photosLibrary.assets[0..<selectedAssetIndex].lastIndex(where: { asset in
-                        asset.state() == nil
+                        photosLibrary.state(for: asset) == nil
                     })
                     
                     if let theIndex = lastUnreviewed {

BlinkReviewer/BlinkReviewer/Views/Statistics.swift (611) → BlinkReviewer/BlinkReviewer/Views/Statistics.swift (626)

diff --git a/BlinkReviewer/BlinkReviewer/Views/Statistics.swift b/BlinkReviewer/BlinkReviewer/Views/Statistics.swift
index 4b2059c..f45b082 100644
--- a/BlinkReviewer/BlinkReviewer/Views/Statistics.swift
+++ b/BlinkReviewer/BlinkReviewer/Views/Statistics.swift
@@ -11,7 +11,7 @@ struct Statistics: View {
     @EnvironmentObject var photosLibrary: PhotosLibrary
     
     var body: some View {
-        Text("\(photosLibrary.assets.count) photos, \(photosLibrary.countApproved()) approved, \(photosLibrary.countRejected()) rejected, \(photosLibrary.countNeedsAction()) need action")
+        Text("\(photosLibrary.assets.count) photos, \(photosLibrary.approvedAssets.count) approved, \(photosLibrary.rejectedAssets.count) rejected, \(photosLibrary.needsActionAssets.count) need action")
             .font(.title)
             .padding(10)
             .foregroundColor(.white)

BlinkReviewer/BlinkReviewer/Views/ThumbnailList.swift (3076) → BlinkReviewer/BlinkReviewer/Views/ThumbnailList.swift (3094)

diff --git a/BlinkReviewer/BlinkReviewer/Views/ThumbnailList.swift b/BlinkReviewer/BlinkReviewer/Views/ThumbnailList.swift
index 4bf01aa..d89022b 100644
--- a/BlinkReviewer/BlinkReviewer/Views/ThumbnailList.swift
+++ b/BlinkReviewer/BlinkReviewer/Views/ThumbnailList.swift
@@ -34,7 +34,7 @@ struct ThumbnailList: View {
                     ForEach(Array(displayAssets().enumerated()), id: \.element.localIdentifier) { index, asset in
                         ThumbnailImage(
                             thumbnail: PHAssetImage(asset, size: CGSize(width: 70, height: 70), deliveryMode: .opportunistic),
-                            state: asset.state(),
+                            state: photosLibrary.state(for: asset),
                             isFavorite: asset.isFavorite,
                             isSelected: displayAssets()[displaySelectedAssetIndex()].localIdentifier == asset.localIdentifier
                         ).onTapGesture {