From 8fd5ea2089ebff2731aa918ab2010431d87f049d Mon Sep 17 00:00:00 2001 From: Carson Katri Date: Tue, 6 May 2025 14:13:00 -0400 Subject: [PATCH] Use Nuke LazyImage for AsyncImage implementation --- Package.resolved | 11 ++- Package.swift | 6 +- .../Views/Images/AsyncImage.swift | 71 +++++++++++++------ 3 files changed, 63 insertions(+), 25 deletions(-) diff --git a/Package.resolved b/Package.resolved index c7c09f8a6..39606a485 100644 --- a/Package.resolved +++ b/Package.resolved @@ -1,5 +1,5 @@ { - "originHash" : "a1b1e06fbdf5f90d2817b4e4ba491ff6fc177e87dad20844f45d67caa0b58193", + "originHash" : "0c8c3e8458ec9c2f13f4c7fdaf35ecaf0763b299e8b3f598c64384f5561619e0", "pins" : [ { "identity" : "liveview-native-core", @@ -10,6 +10,15 @@ "version" : "0.4.1-rc-5" } }, + { + "identity" : "nuke", + "kind" : "remoteSourceControl", + "location" : "https://github.com/kean/Nuke", + "state" : { + "revision" : "0ead44350d2737db384908569c012fe67c421e4d", + "version" : "12.8.0" + } + }, { "identity" : "swift-argument-parser", "kind" : "remoteSourceControl", diff --git a/Package.swift b/Package.swift index 5d85bb652..f2f1f3a26 100644 --- a/Package.swift +++ b/Package.swift @@ -30,6 +30,8 @@ let package = Package( .package(url: "https://github.com/apple/swift-argument-parser", from: "1.5.0"), .package(url: "https://github.com/swiftlang/swift-syntax.git", from: "600.0.1"), + + .package(url: "https://github.com/kean/Nuke", from: "12.8.0"), ], targets: [ // Targets are the basic building blocks of a package. A target can define a module or a test suite. @@ -38,9 +40,11 @@ let package = Package( name: "LiveViewNative", dependencies: [ .product(name: "AsyncAlgorithms", package: "swift-async-algorithms"), + .product(name: "Nuke", package: "Nuke"), + .product(name: "NukeUI", package: "Nuke"), .product(name: "LiveViewNativeCore", package: "liveview-native-core"), "LiveViewNativeMacros", - "LiveViewNativeStylesheet" + "LiveViewNativeStylesheet", ], plugins: [ .plugin(name: "BuiltinRegistryGeneratorPlugin"), diff --git a/Sources/LiveViewNative/Views/Images/AsyncImage.swift b/Sources/LiveViewNative/Views/Images/AsyncImage.swift index b94954243..7e83ece5f 100644 --- a/Sources/LiveViewNative/Views/Images/AsyncImage.swift +++ b/Sources/LiveViewNative/Views/Images/AsyncImage.swift @@ -6,6 +6,10 @@ // import SwiftUI +#if canImport(Nuke) && canImport(NukeUI) +import Nuke +import NukeUI +#endif /// Displays an image asynchronously loaded from a URL. /// @@ -69,37 +73,58 @@ struct AsyncImage: View { } var asyncImage: some View { + #if canImport(Nuke) && canImport(NukeUI) + LazyImage( + url: url.flatMap({ URL(string: $0, relativeTo: context.url) }), + transaction: transaction + ) { state in + let phase = switch state.result { + case .none: + AsyncImagePhase.empty + case .some(.success(let response)): + AsyncImagePhase.success(Image(uiImage: response.image)) + case .some(.failure(let error)): + AsyncImagePhase.failure(error) + } + asyncImageContent(phase) + } + #else SwiftUI.AsyncImage( url: url.flatMap({ URL(string: $0, relativeTo: context.url) }), scale: scale, transaction: transaction ) { phase in - SwiftUI.Group { - switch phase { - case .empty: - if $liveElement.hasTemplate(.asyncImagePhase(.empty)) { - $liveElement.children(in: .asyncImagePhase(.empty)) - } else { - SwiftUI.ProgressView().progressViewStyle(.circular) - } - case .success(let image): - if $liveElement.hasTemplate(.asyncImagePhase(.success)) { - $liveElement.children(in: .asyncImagePhase(.success)) - } else { - image - } - case .failure(let error): - if $liveElement.hasTemplate(.asyncImagePhase(.failure)) { - $liveElement.children(in: .asyncImagePhase(.failure)) - } else { - SwiftUI.Text(error.localizedDescription) - } - @unknown default: - EmptyView() + asyncImageContent(phase) + } + #endif + } + + func asyncImageContent(_ phase: AsyncImagePhase) -> some View { + SwiftUI.Group { + switch phase { + case .empty: + if $liveElement.hasTemplate(.asyncImagePhase(.empty)) { + $liveElement.children(in: .asyncImagePhase(.empty)) + } else { + SwiftUI.ProgressView().progressViewStyle(.circular) + } + case .success(let image): + if $liveElement.hasTemplate(.asyncImagePhase(.success)) { + $liveElement.children(in: .asyncImagePhase(.success)) + } else { + image + } + case .failure(let error): + if $liveElement.hasTemplate(.asyncImagePhase(.failure)) { + $liveElement.children(in: .asyncImagePhase(.failure)) + } else { + SwiftUI.Text(error.localizedDescription) } + @unknown default: + EmptyView() } - .environment(\.asyncImagePhase, phase) } + .environment(\.asyncImagePhase, phase) } }