Skip to content

Instantly share code, notes, and snippets.

@moto0000
Last active June 22, 2024 02:13
Show Gist options
  • Save moto0000/b79cc9782618210824acb545dd31cb91 to your computer and use it in GitHub Desktop.
Save moto0000/b79cc9782618210824acb545dd31cb91 to your computer and use it in GitHub Desktop.
Mockable SwiftUI.AsyncImage
import SwiftUI
public struct AsyncImage<Content>: View where Content: View {
private var content: (ImageProvider) -> _ConditionalContent<
SwiftUI.AsyncImage<Content>, Content
>
@Environment(\.imageProvider) var imageProvider
public init(
url: URL?,
scale: CGFloat = 1
) where Content == Image {
self.content = { imageProvider in
if let uiImage = url.flatMap(imageProvider) {
return ViewBuilder.buildEither(
second: Image(uiImage: uiImage)
)
} else {
return ViewBuilder.buildEither(
first: SwiftUI.AsyncImage(
url: url,
scale: scale
)
)
}
}
}
public init<I, P>(
url: URL?,
scale: CGFloat = 1,
@ViewBuilder content: @escaping (Image) -> I,
@ViewBuilder placeholder: @escaping () -> P
) where Content == _ConditionalContent<I, P>, I: View, P: View {
self.content = { imageProvider in
if let uiImage = url.flatMap(imageProvider) {
return ViewBuilder.buildEither(
second: ViewBuilder.buildEither(
first: content(Image(uiImage: uiImage))
)
)
} else {
return ViewBuilder.buildEither(
first: SwiftUI.AsyncImage(
url: url,
scale: scale,
content: content,
placeholder: placeholder
)
)
}
}
}
public init(
url: URL?,
scale: CGFloat = 1,
transaction: Transaction = Transaction(),
@ViewBuilder content: @escaping (AsyncImagePhase) -> Content
) {
self.content = { imageProvider in
if let uiImage = url.flatMap(imageProvider) {
return ViewBuilder.buildEither(
second: content(.success(Image(uiImage: uiImage)))
)
} else {
return ViewBuilder.buildEither(
first: SwiftUI.AsyncImage(
url: url,
scale: scale,
transaction: transaction,
content: content
)
)
}
}
}
public var body: some View {
self.content(self.imageProvider)
}
}
public typealias ImageProvider = (URL) -> UIImage?
private struct Key: EnvironmentKey {
static var defaultValue: ImageProvider = { _ in nil }
}
extension EnvironmentValues {
public var imageProvider: ImageProvider {
get { self[Key.self] }
set { self[Key.self] = newValue }
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment