Skip to main content

Push some setState stuff into PhotosLibrary for snappier UI

ID
fd49963
date
2023-06-15 13:35:55+00:00
author
Alex Chan <alex@alexwlchan.net>
parent
3bba5d9
message
Push some setState stuff into PhotosLibrary for snappier UI
changed files
3 files, 83 additions, 42 deletions

Changed files

BlinkReviewer/Blink.xcodeproj/project.pbxproj (34154) → BlinkReviewer/Blink.xcodeproj/project.pbxproj (34154)

diff --git a/BlinkReviewer/Blink.xcodeproj/project.pbxproj b/BlinkReviewer/Blink.xcodeproj/project.pbxproj
index 8b267a5..82cfc5a 100644
--- a/BlinkReviewer/Blink.xcodeproj/project.pbxproj
+++ b/BlinkReviewer/Blink.xcodeproj/project.pbxproj
@@ -588,7 +588,7 @@
 				CODE_SIGN_ENTITLEMENTS = Blink/Blink.entitlements;
 				CODE_SIGN_STYLE = Automatic;
 				COMBINE_HIDPI_IMAGES = YES;
-				CURRENT_PROJECT_VERSION = 30;
+				CURRENT_PROJECT_VERSION = 42;
 				DEVELOPMENT_ASSET_PATHS = "\"Blink/Preview Content\"";
 				ENABLE_PREVIEWS = YES;
 				GENERATE_INFOPLIST_FILE = YES;
@@ -615,7 +615,7 @@
 				CODE_SIGN_ENTITLEMENTS = Blink/Blink.entitlements;
 				CODE_SIGN_STYLE = Automatic;
 				COMBINE_HIDPI_IMAGES = YES;
-				CURRENT_PROJECT_VERSION = 30;
+				CURRENT_PROJECT_VERSION = 42;
 				DEVELOPMENT_ASSET_PATHS = "\"Blink/Preview Content\"";
 				ENABLE_PREVIEWS = YES;
 				GENERATE_INFOPLIST_FILE = YES;
@@ -640,7 +640,7 @@
 				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
 				BUNDLE_LOADER = "$(TEST_HOST)";
 				CODE_SIGN_STYLE = Automatic;
-				CURRENT_PROJECT_VERSION = 30;
+				CURRENT_PROJECT_VERSION = 42;
 				GENERATE_INFOPLIST_FILE = YES;
 				MACOSX_DEPLOYMENT_TARGET = 13.3;
 				MARKETING_VERSION = 1.0;
@@ -658,7 +658,7 @@
 				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
 				BUNDLE_LOADER = "$(TEST_HOST)";
 				CODE_SIGN_STYLE = Automatic;
-				CURRENT_PROJECT_VERSION = 30;
+				CURRENT_PROJECT_VERSION = 42;
 				GENERATE_INFOPLIST_FILE = YES;
 				MACOSX_DEPLOYMENT_TARGET = 13.3;
 				MARKETING_VERSION = 1.0;
@@ -675,7 +675,7 @@
 			buildSettings = {
 				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
 				CODE_SIGN_STYLE = Automatic;
-				CURRENT_PROJECT_VERSION = 30;
+				CURRENT_PROJECT_VERSION = 42;
 				GENERATE_INFOPLIST_FILE = YES;
 				MARKETING_VERSION = 1.0;
 				PRODUCT_BUNDLE_IDENTIFIER = net.alexwlchan.BlinkReviewerUITests;
@@ -691,7 +691,7 @@
 			buildSettings = {
 				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
 				CODE_SIGN_STYLE = Automatic;
-				CURRENT_PROJECT_VERSION = 30;
+				CURRENT_PROJECT_VERSION = 42;
 				GENERATE_INFOPLIST_FILE = YES;
 				MARKETING_VERSION = 1.0;
 				PRODUCT_BUNDLE_IDENTIFIER = net.alexwlchan.BlinkReviewerUITests;

BlinkReviewer/Blink/Photos/PhotosLibrary.swift (12709) → BlinkReviewer/Blink/Photos/PhotosLibrary.swift (14943)

diff --git a/BlinkReviewer/Blink/Photos/PhotosLibrary.swift b/BlinkReviewer/Blink/Photos/PhotosLibrary.swift
index fece0a4..0d69662 100644
--- a/BlinkReviewer/Blink/Photos/PhotosLibrary.swift
+++ b/BlinkReviewer/Blink/Photos/PhotosLibrary.swift
@@ -308,6 +308,61 @@ class PhotosLibrary: NSObject, ObservableObject, PHPhotoLibraryChangeObserver {
         self.assetIdentifiers = assetIdentifiers
         self.favoriteAssetIdentifiers = favoriteAssetIdentifiers
     }
+    
+    func setState(ofAsset asset: PHAsset, to newState: ReviewState) -> Void {
+        let existingState = self.state(of: asset)
+    
+        try! PHPhotoLibrary.shared().performChangesAndWait {
+            // The first condition is a combination of two:
+            //
+            //      -- the photo is already approved and you hit the "approve" hotkey,
+            //      -- so un-approve it
+            //      state == .Approved && e.characters == "1"
+            //
+            //      -- the photo is already approved and you selected a different review
+            //      -- state, so unapprove it
+            //      state == .Approved && e.characters != "1"
+            //
+            // We can optimise it into a single case, but it does make sense!
+            //
+            // Similar logic applies for all three conditions.
+            if existingState == .Approved {
+                asset.remove(fromAlbum: self.approved)
+            } else if newState == .Approved {
+                asset.add(toAlbum: self.approved)
+            }
+
+            if existingState == .Rejected {
+                asset.remove(fromAlbum: self.rejected)
+            } else if newState == .Rejected {
+                asset.add(toAlbum: self.rejected)
+            }
+
+            if existingState == .NeedsAction {
+                asset.remove(fromAlbum: self.needsAction)
+            } else if newState == .NeedsAction {
+                asset.add(toAlbum: self.needsAction)
+            }
+        }
+        
+        if existingState == .Approved {
+            self.approvedAssetIdentifiers.remove(asset.localIdentifier)
+        } else if newState == .Approved {
+            self.approvedAssetIdentifiers.insert(asset.localIdentifier)
+        }
+
+        if existingState == .Rejected {
+            self.rejectedAssetIdentifiers.remove(asset.localIdentifier)
+        } else if newState == .Rejected {
+            self.rejectedAssetIdentifiers.insert(asset.localIdentifier)
+        }
+
+        if existingState == .NeedsAction {
+            self.needsActionAssetIdentifiers.remove(asset.localIdentifier)
+        } else if newState == .NeedsAction {
+            self.needsActionAssetIdentifiers.insert(asset.localIdentifier)
+        }
+    }
 }
 
 func getSetOfIdentifiers(fetchResult: PHFetchResult<PHAsset>) -> Set<String> {

BlinkReviewer/Blink/Views/PhotoReviewer.swift (14002) → BlinkReviewer/Blink/Views/PhotoReviewer.swift (13085)

diff --git a/BlinkReviewer/Blink/Views/PhotoReviewer.swift b/BlinkReviewer/Blink/Views/PhotoReviewer.swift
index ecc434f..8d972a4 100644
--- a/BlinkReviewer/Blink/Views/PhotoReviewer.swift
+++ b/BlinkReviewer/Blink/Views/PhotoReviewer.swift
@@ -224,49 +224,35 @@ struct PhotoReviewer: View {
                 return nil
             
             case let e where e.characters == "1" || e.characters == "2" || e.characters == "3":
-                print("time to review!")
-                let state = photosLibrary.state(of: focusedAsset)
+                let oldState = photosLibrary.state(of: focusedAsset)
             
-                let approved = getAlbum(withName: "Approved")
-                let rejected = getAlbum(withName: "Rejected")
-                let needsAction = getAlbum(withName: "Needs Action")
+                let newState: ReviewState =
+                    e.characters == "1" ? .Approved :
+                    e.characters == "2" ? .Rejected : .NeedsAction
             
-                try! PHPhotoLibrary.shared().performChangesAndWait {
-                    // The first condition is a combination of two:
-                    //
-                    //      -- the photo is already approved and you hit the "approve" hotkey,
-                    //      -- so un-approve it
-                    //      state == .Approved && e.characters == "1"
-                    //
-                    //      -- the photo is already approved and you selected a different review
-                    //      -- state, so unapprove it
-                    //      state == .Approved && e.characters != "1"
-                    //
-                    // We can optimise it into a single case, but it does make sense!
-                    //
-                    // Similar logic applies for all three conditions.
-                    if state == .Approved {
-                        focusedAsset.remove(fromAlbum: approved)
-                    } else if e.characters == "1" {
-                        focusedAsset.add(toAlbum: approved)
-                    }
-
-                    if state == .Rejected {
-                        focusedAsset.remove(fromAlbum: rejected)
-                    } else if e.characters == "2" {
-                        focusedAsset.add(toAlbum: rejected)
-                    }
-
-                    if state == .NeedsAction {
-                        focusedAsset.remove(fromAlbum: needsAction)
-                    } else if e.characters == "3" {
-                        focusedAsset.add(toAlbum: needsAction)
-                    }
+                photosLibrary.setState(ofAsset: focusedAsset, to: newState)
+            
+                if focusedAssetIndex < photosLibrary.assets.count - 1 {
+                    focusedAssetIndex += 1
                 }
+                
+                return nil
+            
+            case let e where e.characters == "2":
+                photosLibrary.setState(ofAsset: focusedAsset, to: .Rejected)
             
                 if focusedAssetIndex < photosLibrary.assets.count - 1 {
                     focusedAssetIndex += 1
                 }
+                
+                return nil
+            
+            case let e where e.characters == "3":
+                photosLibrary.setState(ofAsset: focusedAsset, to: .NeedsAction)
+
+                if focusedAssetIndex < photosLibrary.assets.count - 1 {
+                    focusedAssetIndex += 1
+                }
                 return nil
             
             case let e where e.characters == "c":