Skip to main content

Blink/Views/Thumbnails/ThumbnailImage.swift

1import SwiftUI
2import Photos
4struct ThumbnailImageInner: View {
5 @ObservedObject var assetImage: PHAssetImage
6 var size: CGFloat
7
8 var body: some View {
9 Image(nsImage: assetImage.image)
10 .resizable()
11 .scaledToFill()
12 .clipped()
13 .frame(width: size, height: size, alignment: .center)
14 }
17/// Render a single thumbnail image in the thumbnail picker.
18///
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.
28 //
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.
32 //
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
38 var index: Int
39 var state: ReviewState?
40 var isFocused: Bool
41 var isFavorite: Bool
42 private var getAssetImage: () -> PHAssetImage
44 init(index: Int, state: ReviewState?, isFavorite: Bool, isFocused: Bool, getAssetImage: @escaping () -> PHAssetImage) {
45 self.index = index
47 self.isFavorite = isFavorite
48 self.state = state
50 self.isFocused = isFocused
51 self.getAssetImage = getAssetImage
52 }
54 private func size() -> CGFloat {
55 isFocused ? 70 : 50
56 }
58 private func cornerRadius() -> CGFloat {
59 isFocused ? 7 : 5
60 }
62 var body: some View {
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)
71 } else {
72 ProgressView()
73 .onAppear {
74 self.assetImage = getAssetImage()
75 }
76 }
78 }