Skip to main content

Track the asset identifiers in the HStack

ID
d7fb0ab
date
2023-06-15 06:51:47+00:00
author
Alex Chan <alex@alexwlchan.net>
parent
7495512
message
Track the asset identifiers in the HStack
changed files
4 files, 69 additions, 34 deletions

Changed files

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

diff --git a/BlinkReviewer/Blink.xcodeproj/project.pbxproj b/BlinkReviewer/Blink.xcodeproj/project.pbxproj
index 1617cc2..2caaedb 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 = 3;
+				CURRENT_PROJECT_VERSION = 10;
 				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 = 3;
+				CURRENT_PROJECT_VERSION = 10;
 				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 = 3;
+				CURRENT_PROJECT_VERSION = 10;
 				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 = 3;
+				CURRENT_PROJECT_VERSION = 10;
 				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 = 3;
+				CURRENT_PROJECT_VERSION = 10;
 				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 = 3;
+				CURRENT_PROJECT_VERSION = 10;
 				GENERATE_INFOPLIST_FILE = YES;
 				MARKETING_VERSION = 1.0;
 				PRODUCT_BUNDLE_IDENTIFIER = net.alexwlchan.BlinkReviewerUITests;

BlinkReviewer/Blink/Photos/PhotosLibrary.swift (8979) → BlinkReviewer/Blink/Photos/PhotosLibrary.swift (9492)

diff --git a/BlinkReviewer/Blink/Photos/PhotosLibrary.swift b/BlinkReviewer/Blink/Photos/PhotosLibrary.swift
index 89660a3..d4e0fa9 100644
--- a/BlinkReviewer/Blink/Photos/PhotosLibrary.swift
+++ b/BlinkReviewer/Blink/Photos/PhotosLibrary.swift
@@ -11,6 +11,7 @@ class PhotosLibrary: NSObject, ObservableObject, PHPhotoLibraryChangeObserver {
     @Published var isPhotoLibraryAuthorized = false
     
     @Published var assets: PHFetchResult<PHAsset> = PHFetchResult()
+    @Published var assetIdentifiers: [String] = []
     
     @Published var approvedAssets: PHFetchResult<PHAsset> = PHFetchResult()
     @Published var rejectedAssets: PHFetchResult<PHAsset> = PHFetchResult()
@@ -69,6 +70,7 @@ class PhotosLibrary: NSObject, ObservableObject, PHPhotoLibraryChangeObserver {
             
             if let assetsChangeDetails = changeInstance.changeDetails(for: self.assets) {
                 self.assets = assetsChangeDetails.fetchResultAfterChanges
+                self.regenerateAssetIdentifiers()
                 self.latestChangeDetails = assetsChangeDetails
             }
             
@@ -113,6 +115,7 @@ class PhotosLibrary: NSObject, ObservableObject, PHPhotoLibraryChangeObserver {
             
             if (self.isPhotoLibraryAuthorized) {
                 self.assets = PHAsset.fetchAssets(with: PHAssetMediaType.image, options: options)
+                self.regenerateAssetIdentifiers()
 
                 self.approvedAssets = PHAsset.fetchAssets(in: self.approved, options: nil)
                 self.rejectedAssets = PHAsset.fetchAssets(in: self.rejected, options: nil)
@@ -183,14 +186,15 @@ class PhotosLibrary: NSObject, ObservableObject, PHPhotoLibraryChangeObserver {
     //
     // On my M2 MacBook Air, these numbers mean the app peaks at ~250MB of memory,
     // which seems pretty reasonable.
-    private var thumbnailCache = LRUCache<PHAsset, PHAssetImage>(withMaxSize: 100)
+    private var thumbnailCache = LRUCache<PHAsset, PHAssetImage>(withMaxSize: 500)
     
     func getThumbnail(for asset: PHAsset) -> PHAssetImage {
         if thumbnailCache[asset] == nil {
             let newImage = PHAssetImage(
                 asset,
                 size: CGSize(width: 70, height: 70),
-                deliveryMode: .opportunistic
+                deliveryMode: .opportunistic,
+                regenerateImmediately: false
             )
             
             thumbnailCache[asset] = newImage
@@ -214,7 +218,8 @@ class PhotosLibrary: NSObject, ObservableObject, PHPhotoLibraryChangeObserver {
             let newImage = PHAssetImage(
                 asset,
                 size: PHImageManagerMaximumSize,
-                deliveryMode: .opportunistic
+                deliveryMode: .opportunistic,
+                regenerateImmediately: true
             )
             
             fullSizeImageCache[asset] = newImage
@@ -222,4 +227,14 @@ class PhotosLibrary: NSObject, ObservableObject, PHPhotoLibraryChangeObserver {
 
         return fullSizeImageCache[asset]!
     }
+    
+    private func regenerateAssetIdentifiers() -> Void {
+        var result: [String] = []
+        
+        self.assets.enumerateObjects { asset, _, _ in
+            result.append(asset.localIdentifier)
+        }
+        
+        self.assetIdentifiers = result
+    }
 }

BlinkReviewer/Blink/Views/Helpers/PHAssetHStack.swift (4391) → BlinkReviewer/Blink/Views/Helpers/PHAssetHStack.swift (4975)

diff --git a/BlinkReviewer/Blink/Views/Helpers/PHAssetHStack.swift b/BlinkReviewer/Blink/Views/Helpers/PHAssetHStack.swift
index d80cea0..46a2762 100644
--- a/BlinkReviewer/Blink/Views/Helpers/PHAssetHStack.swift
+++ b/BlinkReviewer/Blink/Views/Helpers/PHAssetHStack.swift
@@ -1,6 +1,21 @@
 import SwiftUI
 import Photos
 
+struct AssetIdentifiersCollection: RandomAccessCollection, Equatable {
+    typealias Element = (Int, String)
+    typealias Index = Int
+    
+    let assetIdentifiers: [String]
+
+    var startIndex: Int { 0 }
+    var endIndex: Int { assetIdentifiers.count }
+
+    subscript(position: Int) -> Element {
+        (position, assetIdentifiers[position])
+    }
+}
+
+
 /// Creates an HStack of PHAssets that fills in right-to-left.
 ///
 /// This provides lazy loading to the left-hand side, and assumes you're
@@ -23,15 +38,18 @@ import Photos
 ///
 struct PHAssetHStack<Content: View>: View {
     var subview: (PHAsset, Int) -> Content
-    var collection: PHFetchResultCollection
+    var fetchResult: PHFetchResult<PHAsset>
+    var assetIdentifiers: [String]
     
     init(
         _ fetchResult: PHFetchResult<PHAsset>,
+        assetIdentifiers: [String],
         @ViewBuilder subview: @escaping (PHAsset, Int) -> Content
     ) {
         print("--> creating PHAssetHStack")
         self.subview = subview
-        self.collection = PHFetchResultCollection(fetchResult)
+        self.fetchResult = fetchResult
+        self.assetIdentifiers = assetIdentifiers
     }
     
     var body: some View {
@@ -55,8 +73,10 @@ struct PHAssetHStack<Content: View>: View {
                 // creating the entire Array, which is quite expensive.  I switched the
                 // PHFetchResultCollection to vend a struct with both the asset and the
                 // position, but now it does it by random access -- this seems faster.
-                ForEach(self.collection, id: \.asset.localIdentifier) { indexedAsset in
-                    subview(indexedAsset.asset, indexedAsset.position)
+                //
+                // Note: enumerated is okay
+                ForEach(AssetIdentifiersCollection(assetIdentifiers: self.assetIdentifiers), id: \.1) { index, localIdentifier in
+                    subview(self.fetchResult.object(at: index), index)
                 }
                 
                 // Note: these two uses of RTL direction are a way to get the LazyHStack
@@ -78,23 +98,23 @@ struct PHAssetHStack<Content: View>: View {
             .environment(\.layoutDirection, .rightToLeft)
     }
 }
-
-struct PHAssetHStack_Previews: PreviewProvider {
-    static var fetchResult: PHFetchResult<PHAsset> {
-        let options = PHFetchOptions()
-        options.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)]
-        options.fetchLimit = 25
-        
-        return PHAsset.fetchAssets(with: options)
-    }
-    
-    static var previews: some View {
-        PHAssetHStack(fetchResult) { asset, index in
-            VStack {
-                Text("view index = \(index)")
-                Text("asset ID =\n\(asset.localIdentifier)")
-                Text("fetchResult.object(at: \(index)) =\n\(fetchResult.object(at: index).localIdentifier)")
-            }
-        }
-    }
-}
+//
+//struct PHAssetHStack_Previews: PreviewProvider {
+//    static var fetchResult: PHFetchResult<PHAsset> {
+//        let options = PHFetchOptions()
+//        options.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)]
+//        options.fetchLimit = 25
+//
+//        return PHAsset.fetchAssets(with: options)
+//    }
+//
+//    static var previews: some View {
+//        PHAssetHStack(fetchResult) { asset, index in
+//            VStack {
+//                Text("view index = \(index)")
+//                Text("asset ID =\n\(asset.localIdentifier)")
+//                Text("fetchResult.object(at: \(index)) =\n\(fetchResult.object(at: index).localIdentifier)")
+//            }
+//        }
+//    }
+//}

BlinkReviewer/Blink/Views/Thumbnails/ThumbnailList.swift (1075) → BlinkReviewer/Blink/Views/Thumbnails/ThumbnailList.swift (1125)

diff --git a/BlinkReviewer/Blink/Views/Thumbnails/ThumbnailList.swift b/BlinkReviewer/Blink/Views/Thumbnails/ThumbnailList.swift
index efcc95b..a8ba73e 100644
--- a/BlinkReviewer/Blink/Views/Thumbnails/ThumbnailList.swift
+++ b/BlinkReviewer/Blink/Views/Thumbnails/ThumbnailList.swift
@@ -13,7 +13,7 @@ struct ThumbnailList: View {
     
     var body: some View {
         ScrollViewReader { proxy in
-            PHAssetHStack(photosLibrary.assets) { asset, index in
+            PHAssetHStack(photosLibrary.assets, assetIdentifiers: photosLibrary.assetIdentifiers) { asset, index in
                 ThumbnailImage(
                     assetImage: photosLibrary.getThumbnail(for: asset),
                     state: photosLibrary.state(of: asset),