4struct ThumbnailImageInner: View {
5 @ObservedObject var assetImage: PHAssetImage
9 Image(nsImage: assetImage.image)
13 .frame(width: size, height: size, alignment: .center)
17/// Render a single thumbnail image in the thumbnail picker.
19/// Thumbnails are square, and they expand to fill the square. This may
20/// mean some information gets cropped out -- that's okay, these are only
21/// small previews, not complete images.
22struct ThumbnailImage: View {
24 // Implementation note: the reason we pass in a bunch of individual
25 // properties rather than the whole asset is because we need an
26 // @EnvironmentObject (the PhotosLibrary) to create the PHAssetImage,
27 // so we can stick the latter in an @ObservedObject.
29 // But EnvironmentObject values aren't passed down until you call the
30 // `body` method, which is too late! So instead we have the parent
31 // view call into PhotosLibrary and pass in the relevant values here.
33 // The `getAssetImage` is a callback so we can load those assets somewhat
34 // lazily; the ThumbnailImageInner is separate so it can subscribe to
35 // updates to the PHAssetImage.
36 @State var assetImage: PHAssetImage? = nil
39 var state: ReviewState?
42 private var getAssetImage: () -> PHAssetImage
44 init(index: Int, state: ReviewState?, isFavorite: Bool, isFocused: Bool, getAssetImage: @escaping () -> PHAssetImage) {
47 self.isFavorite = isFavorite
50 self.isFocused = isFocused
51 self.getAssetImage = getAssetImage
54 private func size() -> CGFloat {
58 private func cornerRadius() -> CGFloat {
63 if let thisAssetImage = assetImage {
64 ThumbnailImageInner(assetImage: thisAssetImage, size: size())
65 .cornerRadius(cornerRadius())
66 .reviewStateColor(isRejected: state == .Rejected)
67 .reviewStateBorder(for: state, with: cornerRadius())
68 .reviewStateIcon(for: state, isFocused)
69 .favoriteHeartIcon(isFavorite, isFocused)
74 self.assetImage = getAssetImage()