Skip to main content

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
2 files, 44 additions

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))
+    }
+}