add a loading indicator overlay
- ID
c0fd3f4- date
2023-06-09 23:58:31+00:00- author
Alex Chan <alex@alexwlchan.net>- parent
035b996- message
add a loading indicator overlay- changed files
Changed files
BlinkReviewer/BlinkReviewer/Views/FocusedImage/FocusedImage.swift (825) → BlinkReviewer/BlinkReviewer/Views/FocusedImage/FocusedImage.swift (889)
diff --git a/BlinkReviewer/BlinkReviewer/Views/FocusedImage/FocusedImage.swift b/BlinkReviewer/BlinkReviewer/Views/FocusedImage/FocusedImage.swift
index 05ff4a3..a6e92d5 100644
--- a/BlinkReviewer/BlinkReviewer/Views/FocusedImage/FocusedImage.swift
+++ b/BlinkReviewer/BlinkReviewer/Views/FocusedImage/FocusedImage.swift
@@ -18,5 +18,6 @@ struct FocusedImage: View {
Image(nsImage: assetImage.image)
.resizable()
.aspectRatio(contentMode: .fit)
+ .loadingIndicator(isLoading: assetImage.isDegraded)
}
}
BlinkReviewer/BlinkReviewer/Views/FocusedImage/LoadingIndicatorOverlay.swift (0) → BlinkReviewer/BlinkReviewer/Views/FocusedImage/LoadingIndicatorOverlay.swift (1731)
diff --git a/BlinkReviewer/BlinkReviewer/Views/FocusedImage/LoadingIndicatorOverlay.swift b/BlinkReviewer/BlinkReviewer/Views/FocusedImage/LoadingIndicatorOverlay.swift
new file mode 100644
index 0000000..5f30374
--- /dev/null
+++ b/BlinkReviewer/BlinkReviewer/Views/FocusedImage/LoadingIndicatorOverlay.swift
@@ -0,0 +1,43 @@
+import SwiftUI
+import Photos
+
+/// Renders a progress indicator if we're waiting for the image to load.
+///
+/// This is for when Photos is taking a while to load the high-quality version
+/// of a photo; see the comment on `PHAssetImage`.
+struct LoadingIndicatorOverlay: ViewModifier {
+ let isLoading: Bool
+
+ func body(content: Content) -> some View {
+ if (isLoading) {
+ content.overlay(alignment: Alignment(horizontal: .trailing, vertical: .bottom)) {
+
+ // `ProgressView` does have a `tint` modifier, but that doesn't seem to
+ // work on macOS 13 -- this uses some code from a Stack Overflow answer
+ // by aheze: https://stackoverflow.com/a/66568704/1558022
+ ProgressView()
+ .colorInvert()
+ .brightness(1)
+ .padding()
+ .deferredRendering(
+ // Note: even if the image is already cached locally, the
+ // image caching manager typically sends two images: a low-res
+ // version comes immediately, then a higher-res version within
+ // a second or two. This causes the progress indicator to
+ // "flash" -- it appears then almost instantly disappears.
+ //
+ // Deferring the rendering by a second avoids this "flash".
+ for: .seconds(1)
+ )
+ }
+ } else {
+ content
+ }
+ }
+}
+
+extension View {
+ func loadingIndicator(isLoading: Bool) -> some View {
+ modifier(LoadingIndicatorOverlay(isLoading: isLoading))
+ }
+}