Skip to main content

try using PHFetchResult

ID
e155f99
date
2023-06-09 17:15:37+00:00
author
Alex Chan <alex@alexwlchan.net>
parent
e4fabe6
message
try using PHFetchResult

keep fiddling

wip
changed files
6 files, 93 additions, 49 deletions

Changed files

BlinkReviewer/BlinkReviewer/BlinkReviewerApp.swift (388) → BlinkReviewer/BlinkReviewer/BlinkReviewerApp.swift (389)

diff --git a/BlinkReviewer/BlinkReviewer/BlinkReviewerApp.swift b/BlinkReviewer/BlinkReviewer/BlinkReviewerApp.swift
index 199819d..47c80db 100644
--- a/BlinkReviewer/BlinkReviewer/BlinkReviewerApp.swift
+++ b/BlinkReviewer/BlinkReviewer/BlinkReviewerApp.swift
@@ -13,7 +13,7 @@ struct BlinkReviewerApp: App {
     
     var body: some Scene {
         WindowGroup {
-            PhotoReviewer(selectedAssetIndex: photosLibrary.assets.count - 1)
+            PhotoReviewer(selectedAssetIndex: photosLibrary.assets2.count - 1)
                 .environmentObject(photosLibrary)
         }
     }

BlinkReviewer/BlinkReviewer/Photos/PhotosLibrary.swift (2737) → BlinkReviewer/BlinkReviewer/Photos/PhotosLibrary.swift (3213)

diff --git a/BlinkReviewer/BlinkReviewer/Photos/PhotosLibrary.swift b/BlinkReviewer/BlinkReviewer/Photos/PhotosLibrary.swift
index e4b4046..459cdd2 100644
--- a/BlinkReviewer/BlinkReviewer/Photos/PhotosLibrary.swift
+++ b/BlinkReviewer/BlinkReviewer/Photos/PhotosLibrary.swift
@@ -10,9 +10,11 @@ import Photos
 
 class PhotosLibrary: NSObject, ObservableObject, PHPhotoLibraryChangeObserver {
 
-    @Published var assets = getAllPhotos()
+//    @Published var assets = getAllPhotos()
     @Published var isPhotoLibraryAuthorized = false
     
+    @Published var assets2: PHFetchResult<PHAsset> = PHFetchResult()
+    
     @Published var approvedAssets: PHFetchResult<PHAsset> = PHFetchResult()
     @Published var rejectedAssets: PHFetchResult<PHAsset> = PHFetchResult()
     @Published var needsActionAssets: PHFetchResult<PHAsset> = PHFetchResult()
@@ -28,7 +30,7 @@ class PhotosLibrary: NSObject, ObservableObject, PHPhotoLibraryChangeObserver {
     }
     
     func updateAsset(atIndex index: Int) {
-        self.assets[index] = PHAsset.fetchAssets(withLocalIdentifiers: [self.assets[index].localIdentifier], options: nil).firstObject!
+//        self.assets[index] = PHAsset.fetchAssets(withLocalIdentifiers: [self.assets[index].localIdentifier], options: nil).firstObject!
     }
 
     func photoLibraryDidChange(_ changeInstance: PHChange) {
@@ -53,7 +55,13 @@ class PhotosLibrary: NSObject, ObservableObject, PHPhotoLibraryChangeObserver {
               print("Time to \(label):\n  \(elapsedInterval) seconds (\(totalInterval) total)")
             }
             
-            self.assets = getAllPhotos()
+//            self.assets = getAllPhotos()
+            
+            let options = PHFetchOptions()
+            options.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: true)]
+//            options.fetchLimit = 50
+            
+            self.assets2 = PHAsset.fetchAssets(with: PHAssetMediaType.image, options: options)
             
             self.approvedAssets = PHAsset.fetchAssets(in: self.approved, options: nil)
             self.rejectedAssets = PHAsset.fetchAssets(in: self.rejected, options: nil)
@@ -61,6 +69,8 @@ class PhotosLibrary: NSObject, ObservableObject, PHPhotoLibraryChangeObserver {
             
             self.isPhotoLibraryAuthorized = PHPhotoLibrary.authorizationStatus() == .authorized
             
+            print("self.isPhotoLibraryAuthorized = \(self.isPhotoLibraryAuthorized)")
+            
             printElapsed("get photos library data")
         }
     }

BlinkReviewer/BlinkReviewer/Views/PHAssetImage.swift (4458) → BlinkReviewer/BlinkReviewer/Views/PHAssetImage.swift (4533)

diff --git a/BlinkReviewer/BlinkReviewer/Views/PHAssetImage.swift b/BlinkReviewer/BlinkReviewer/Views/PHAssetImage.swift
index a938b88..1bff24e 100644
--- a/BlinkReviewer/BlinkReviewer/Views/PHAssetImage.swift
+++ b/BlinkReviewer/BlinkReviewer/Views/PHAssetImage.swift
@@ -67,6 +67,9 @@ class PHAssetImage: NSObject, ObservableObject {
                 self.image = nsImage
                 return
             }
+
+            print("regenerating image for \(thisAsset.localIdentifier)")
+
             
             // This implementation is based on code in a Stack Overflow answer
             // by Francois Nadeau: https://stackoverflow.com/a/48755517/1558022

BlinkReviewer/BlinkReviewer/Views/PhotoReviewer.swift (5814) → BlinkReviewer/BlinkReviewer/Views/PhotoReviewer.swift (5926)

diff --git a/BlinkReviewer/BlinkReviewer/Views/PhotoReviewer.swift b/BlinkReviewer/BlinkReviewer/Views/PhotoReviewer.swift
index d30ce4c..05d9c11 100644
--- a/BlinkReviewer/BlinkReviewer/Views/PhotoReviewer.swift
+++ b/BlinkReviewer/BlinkReviewer/Views/PhotoReviewer.swift
@@ -28,20 +28,20 @@ struct PhotoReviewer: View {
                         .environmentObject(photosLibrary)
                         .background(.gray.opacity(0.3))
                     
-                    FullSizeImage(image: fullSizeImage)
-                        .background(.black)
+//                    FullSizeImage(image: fullSizeImage)
+//                        .background(.black)
                 }
                 .background(.black)
-                .onAppear {
-                    fullSizeImage.asset = photosLibrary.assets[selectedAssetIndex]
-                    
-                    NSEvent.addLocalMonitorForEvents(matching: .keyDown) { event in
-                        handleKeyEvent(event)
-                        return event
-                    }
-                }.onChange(of: selectedAssetIndex, perform: { newIndex in
-                    fullSizeImage.asset = photosLibrary.assets[newIndex]
-                })
+//                .onAppear {
+//                    fullSizeImage.asset = photosLibrary.assets2.object(at: selectedAssetIndex)
+//
+//                    NSEvent.addLocalMonitorForEvents(matching: .keyDown) { event in
+//                        handleKeyEvent(event)
+//                        return event
+//                    }
+//                }.onChange(of: selectedAssetIndex, perform: { newIndex in
+//                    fullSizeImage.asset = photosLibrary.assets2.object(at: newIndex)
+//                })
                 
                 if showStatistics {
                     HStack {
@@ -62,7 +62,7 @@ struct PhotoReviewer: View {
     }
     
     private func handleKeyEvent(_ event: NSEvent) {
-        let asset = photosLibrary.assets[selectedAssetIndex]
+        let asset = photosLibrary.assets2.object(at: selectedAssetIndex)
         
         switch event.keyCode {
             case 123: // Left arrow key
@@ -71,7 +71,7 @@ struct PhotoReviewer: View {
                 }
             
             case 124: // Right arrow key
-                if selectedAssetIndex < photosLibrary.assets.count - 1 {
+                if selectedAssetIndex < photosLibrary.assets2.count - 1 {
                     selectedAssetIndex += 1
                 }
             
@@ -137,15 +137,18 @@ struct PhotoReviewer: View {
                 photosLibrary.updateAsset(atIndex: selectedAssetIndex)
 
             case 32: // "u"
-                if photosLibrary.state(for: asset) != nil {
-                    let lastUnreviewed = photosLibrary.assets[0..<selectedAssetIndex].lastIndex(where: { asset in
-                        photosLibrary.state(for: asset) == nil
-                    })
-                    
-                    if let theIndex = lastUnreviewed {
-                        selectedAssetIndex = theIndex
-                    }
-                }
+                print("not implemented yet!")
+//                if photosLibrary.state(for: asset) != nil {
+//                    let lastUnreviewed = photosLibrary.assets2
+//
+//                    [0..<selectedAssetIndex].lastIndex(where: { asset in
+//                        photosLibrary.state(for: asset) == nil
+//                    })
+//
+//                    if let theIndex = lastUnreviewed {
+//                        selectedAssetIndex = theIndex
+//                    }
+//                }
             
             case 1: // "s"
                 showStatistics.toggle()

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

diff --git a/BlinkReviewer/BlinkReviewer/Views/Statistics.swift b/BlinkReviewer/BlinkReviewer/Views/Statistics.swift
index f45b082..7376d80 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.approvedAssets.count) approved, \(photosLibrary.rejectedAssets.count) rejected, \(photosLibrary.needsActionAssets.count) need action")
+        Text("\(photosLibrary.assets2.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 (3094) → BlinkReviewer/BlinkReviewer/Views/ThumbnailList.swift (3600)

diff --git a/BlinkReviewer/BlinkReviewer/Views/ThumbnailList.swift b/BlinkReviewer/BlinkReviewer/Views/ThumbnailList.swift
index d89022b..b13f254 100644
--- a/BlinkReviewer/BlinkReviewer/Views/ThumbnailList.swift
+++ b/BlinkReviewer/BlinkReviewer/Views/ThumbnailList.swift
@@ -8,39 +8,67 @@
 import SwiftUI
 import Photos
 
+// https://stackoverflow.com/q/62745595/1558022
+struct PHFetchResultCollection: RandomAccessCollection, Equatable {
+    typealias Element = PHAsset
+    typealias Index = Int
+
+    let fetchResult: PHFetchResult<PHAsset>
+
+    var startIndex: Int { 0 }
+    var endIndex: Int { fetchResult.count }
+
+    subscript(position: Int) -> PHAsset {
+        fetchResult.object(at: position)
+    }
+}
+
 struct ThumbnailList: View {
     @EnvironmentObject var photosLibrary: PhotosLibrary
 
     @Binding var selectedAssetIndex: Int
     
-    func displaySelectedAssetIndex() -> Int {
-        photosLibrary.assets.count - 1 - selectedAssetIndex
-    }
+//    func displaySelectedAssetIndex() -> Int {
+//        photosLibrary.assets2.count - 1 - selectedAssetIndex
+//    }
+//
+//    func displayAssets() -> [PHAsset] {
+//        photosLibrary.assets2.reversed()
+//    }
     
-    func displayAssets() -> [PHAsset] {
-        photosLibrary.assets.reversed()
+    private var assets: PHFetchResultCollection {
+        print(PHFetchResultCollection(fetchResult: photosLibrary.assets2).indices)
+        return PHFetchResultCollection(fetchResult: photosLibrary.assets2)
     }
     
+    
+    private var thumbnails: some View {
+        // Implementation note: we use the localIdentifier rather than the
+        // array index as the id here, because the app gets way slower if
+        // you use the array index -- it tries to regenerate a bunch of
+        // the thumbnails every time you change position.
+        ForEach(
+            Array(zip(assets.indices, assets)), id: \.1.localIdentifier) { index, asset in
+//                Text("asset \(index)")
+                ThumbnailImage(
+                    thumbnail: PHAssetImage(asset, size: CGSize(width: 70, height: 70), deliveryMode: .opportunistic),
+                    state: photosLibrary.state(for: asset),
+                    isFavorite: asset.isFavorite,
+                    isSelected: photosLibrary.assets2.count - 1 - index == selectedAssetIndex
+                ).onTapGesture {
+                    selectedAssetIndex = photosLibrary.assets2.count - 1 - index
+                }
+        }
+    }
+
     var body: some View {
         ScrollViewReader { proxy in
             ScrollView(.horizontal) {
                 LazyHStack(spacing: 5) {
                     // TODO: placeholder images for start/end
                     
-                    // Implementation note: we use the localIdentifier rather than the
-                    // array index as the id here, because the app gets way slower if
-                    // you use the array index -- it tries to regenerate a bunch of
-                    // the thumbnails every time you change position.
-                    ForEach(Array(displayAssets().enumerated()), id: \.element.localIdentifier) { index, asset in
-                        ThumbnailImage(
-                            thumbnail: PHAssetImage(asset, size: CGSize(width: 70, height: 70), deliveryMode: .opportunistic),
-                            state: photosLibrary.state(for: asset),
-                            isFavorite: asset.isFavorite,
-                            isSelected: displayAssets()[displaySelectedAssetIndex()].localIdentifier == asset.localIdentifier
-                        ).onTapGesture {
-                            selectedAssetIndex = photosLibrary.assets.count - 1 - index
-                        }
-                    }
+                    thumbnails
+
                     // Note: these two uses of RTL direction are a way to get the LazyHStack
                     // to start on the right-hand side (i.e. the newest image) without loading
                     // everything else in the view.
@@ -58,11 +86,11 @@ struct ThumbnailList: View {
                 .environment(\.layoutDirection, .rightToLeft)
                 .onChange(of: selectedAssetIndex, perform: { newIndex in
                     withAnimation {
-                        proxy.scrollTo(displayAssets()[displaySelectedAssetIndex()].localIdentifier, anchor: .center)
+                        proxy.scrollTo(selectedAssetIndex, anchor: .center)
                     }
                 })
                 .onAppear {
-                    proxy.scrollTo(displayAssets()[displaySelectedAssetIndex()].localIdentifier, anchor: .center)
+                    proxy.scrollTo(selectedAssetIndex, anchor: .center)
                 }
         }
     }