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
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),