85 lines
2.1 KiB
Swift
85 lines
2.1 KiB
Swift
//
|
|
// CachedAsyncImage.swift
|
|
// Mobile Music Assistant
|
|
//
|
|
// Created by Sven Hanold on 26.03.26.
|
|
//
|
|
|
|
import SwiftUI
|
|
|
|
/// AsyncImage with URLCache support for album covers
|
|
struct CachedAsyncImage<Content: View, Placeholder: View>: View {
|
|
let url: URL?
|
|
let content: (Image) -> Content
|
|
let placeholder: () -> Placeholder
|
|
|
|
@State private var image: UIImage?
|
|
@State private var isLoading = false
|
|
|
|
init(
|
|
url: URL?,
|
|
@ViewBuilder content: @escaping (Image) -> Content,
|
|
@ViewBuilder placeholder: @escaping () -> Placeholder
|
|
) {
|
|
self.url = url
|
|
self.content = content
|
|
self.placeholder = placeholder
|
|
}
|
|
|
|
var body: some View {
|
|
Group {
|
|
if let image {
|
|
content(Image(uiImage: image))
|
|
} else {
|
|
placeholder()
|
|
.task {
|
|
await loadImage()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private func loadImage() async {
|
|
guard let url, !isLoading else { return }
|
|
|
|
isLoading = true
|
|
defer { isLoading = false }
|
|
|
|
// Configure URLCache if needed
|
|
configureURLCache()
|
|
|
|
do {
|
|
let (data, _) = try await URLSession.shared.data(from: url)
|
|
if let uiImage = UIImage(data: data) {
|
|
await MainActor.run {
|
|
image = uiImage
|
|
}
|
|
}
|
|
} catch {
|
|
print("Failed to load image: \(error.localizedDescription)")
|
|
}
|
|
}
|
|
|
|
private func configureURLCache() {
|
|
let cache = URLCache.shared
|
|
if cache.diskCapacity < 50_000_000 {
|
|
URLCache.shared = URLCache(
|
|
memoryCapacity: 10_000_000, // 10 MB
|
|
diskCapacity: 50_000_000 // 50 MB
|
|
)
|
|
}
|
|
}
|
|
}
|
|
|
|
// MARK: - Convenience Initializers
|
|
|
|
extension CachedAsyncImage where Content == Image, Placeholder == Color {
|
|
init(url: URL?) {
|
|
self.init(
|
|
url: url,
|
|
content: { $0.resizable() },
|
|
placeholder: { Color.gray.opacity(0.2) }
|
|
)
|
|
}
|
|
}
|