Files
omnivore/apple/OmnivoreKit/Sources/Views/AsyncImage.swift
2022-02-11 09:24:33 -08:00

88 lines
2.1 KiB
Swift

import Combine
import Foundation
import SwiftUI
import Utils
struct AsyncImage: View {
let isResizable: Bool
@ObservedObject private var imageLoader = ImageLoader()
init(url: URL?, isResizable: Bool = true) {
self.isResizable = isResizable
if let url = url {
imageLoader.load(fromUrl: url)
}
}
var body: some View {
#if os(iOS)
if isResizable {
Image(uiImage: imageLoader.image ?? imageLoader.placeholder)
.resizable()
} else {
Image(uiImage: imageLoader.image ?? imageLoader.placeholder)
}
#elseif os(macOS)
if isResizable {
Image(nsImage: imageLoader.image ?? imageLoader.placeholder)
.resizable()
} else {
Image(nsImage: imageLoader.image ?? imageLoader.placeholder)
}
#endif
}
}
#if os(iOS)
private final class ImageLoader: ObservableObject {
@Published var image: UIImage?
let placeholder = UIImage()
private var cancellable: AnyCancellable?
func load(fromUrl url: URL) {
if let cachedImage = ImageCache.shared[url] {
image = cachedImage
return
}
cancellable = URLSession.shared
.dataTaskPublisher(for: url)
.map { UIImage(data: $0.data) }
.handleEvents(receiveOutput: {
ImageCache.shared[url] = $0
})
.replaceError(with: nil)
.receive(on: DispatchQueue.main)
.assign(to: \.image, on: self)
}
}
#elseif os(macOS)
private final class ImageLoader: ObservableObject {
@Published var image: NSImage?
let placeholder = NSImage(systemSymbolName: "photo", accessibilityDescription: "photo-placeholder")!
private var cancellable: AnyCancellable?
func load(fromUrl url: URL) {
if let cachedImage = ImageCache.shared[url] {
image = cachedImage
return
}
cancellable = URLSession.shared
.dataTaskPublisher(for: url)
.map { NSImage(data: $0.data) }
.handleEvents(receiveOutput: {
ImageCache.shared[url] = $0
})
.replaceError(with: nil)
.receive(on: DispatchQueue.main)
.assign(to: \.image, on: self)
}
}
#endif