@@ -10,11 +10,13 @@ import SwiftUI
1010struct PaneImageViewer : View {
1111 let selectedImage : URL ?
1212 @State private var loadedImage : NSImage ?
13+ @State private var currentLoadingURL : URL ?
14+ @State private var loadingTask : Task < Void , Never > ?
1315
1416 var body : some View {
1517 Group {
1618 if selectedImage != nil {
17- if let loadedImage = loadedImage {
19+ if let loadedImage = loadedImage, currentLoadingURL == selectedImage {
1820 ScrollView ( [ . horizontal, . vertical] ) {
1921 Image ( nsImage: loadedImage)
2022 . resizable ( )
@@ -41,26 +43,50 @@ struct PaneImageViewer: View {
4143 . background ( Color ( NSColor . controlBackgroundColor) )
4244 }
4345 }
44- // Load when the view appears and whenever the selectedImage changes.
45- // .task(id:) runs initially and on every change of the id, so it
46- // covers both the initial-selection case and subsequent changes.
47- . task ( id : selectedImage ) {
46+ . onChange ( of : selectedImage ) { _ , newValue in
47+ loadImage ( from : newValue )
48+ }
49+ . onAppear {
4850 loadImage ( from: selectedImage)
4951 }
5052 }
5153
5254 private func loadImage( from url: URL ? ) {
53- // Clear current image immediately to show loading state.
54- // Ensure state changes happen on the main actor.
55- DispatchQueue . main. async {
56- self . loadedImage = nil
55+ // Cancel any existing loading task
56+ loadingTask? . cancel ( )
57+
58+ guard let url = url else {
59+ loadedImage = nil
60+ currentLoadingURL = nil
61+ return
62+ }
63+
64+ // Don't reload if it's the exact same URL and we already have the image loaded for it
65+ if currentLoadingURL == url && loadedImage != nil {
66+ return
5767 }
5868
59- guard let url = url else { return }
69+ // Set the new loading URL and clear image if switching URLs
70+ let previousURL = currentLoadingURL
71+ currentLoadingURL = url
72+
73+ // Clear the loaded image if we're switching to a different URL
74+ if previousURL != url {
75+ loadedImage = nil
76+ }
77+
78+ loadingTask = Task {
79+ let image = await withTaskCancellationHandler {
80+ return await Task . detached ( priority: . userInitiated) {
81+ NSImage ( contentsOf: url)
82+ } . value
83+ } onCancel: {
84+ // Handle cancellation if needed
85+ }
6086
61- DispatchQueue . global ( qos : . userInitiated ) . async {
62- if let image = NSImage ( contentsOf : url) {
63- DispatchQueue . main . async {
87+ // Only update if this task wasn't cancelled and we're still loading the same URL
88+ if !Task . isCancelled && currentLoadingURL == url {
89+ await MainActor . run {
6490 self . loadedImage = image
6591 }
6692 }
0 commit comments