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 deletionsBlinkReviewer/BlinkReviewer/BlinkReviewerApp.swiftBlinkReviewer/BlinkReviewer/Photos/PhotosLibrary.swiftBlinkReviewer/BlinkReviewer/Views/PHAssetImage.swiftBlinkReviewer/BlinkReviewer/Views/PhotoReviewer.swiftBlinkReviewer/BlinkReviewer/Views/Statistics.swiftBlinkReviewer/BlinkReviewer/Views/ThumbnailList.swift
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)
}
}
}