import SwiftUI struct CachedCapImage: View where Content: View, T: Equatable { @State private var phase: AsyncImagePhase let id: T let check: () -> UIImage? let fetch: () async -> UIImage? private let transaction: Transaction private let content: (AsyncImagePhase) -> Content var body: some View { content(phase) .task(id: id, load) } init(_ id: T, _ image: CapImage, cache: ImageCache, @ViewBuilder content: @escaping (Image) -> I, @ViewBuilder placeholder: @escaping () -> P) where Content == _ConditionalContent, I : View, P : View { self.init(id, image: image, cache: cache) { phase in if let image = phase.image { content(image) } else { placeholder() } } } init(_ id: T, image: CapImage, cache: ImageCache, transaction: Transaction = Transaction(), @ViewBuilder content: @escaping (AsyncImagePhase) -> Content) { self.init(id, check: { cache.cachedImage(image) }, fetch: { await cache.image(image) }, transaction: transaction, content: content) } init(_ id: T, check: @escaping () -> UIImage?, fetch: @escaping () async -> UIImage?, @ViewBuilder content: @escaping (Image) -> I, @ViewBuilder placeholder: @escaping () -> P) where Content == _ConditionalContent, I : View, P : View { self.init(id, check: check, fetch: fetch) { phase in if let image = phase.image { content(image) } else { placeholder() } } } init(_ id: T, check: @escaping () -> UIImage?, fetch: @escaping () async -> UIImage?, transaction: Transaction = Transaction(), @ViewBuilder content: @escaping (AsyncImagePhase) -> Content) { self.id = id self.check = check self.fetch = fetch self.transaction = transaction self.content = content self._phase = State(wrappedValue: .empty) guard let image = check() else { return } let wrapped = Image(uiImage: image) self._phase = State(wrappedValue: .success(wrapped)) } @Sendable private func load() async { guard let image = await fetch() else { withAnimation(transaction.animation) { phase = .empty } return } let wrapped = Image(uiImage: image) withAnimation(transaction.animation) { phase = .success(wrapped) } } }