-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathRemoteImage.swift
71 lines (59 loc) · 1.68 KB
/
RemoteImage.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
//
// RemoteImage.swift
//
// Created by Hovik Melikyan on 17.04.23.
//
import SwiftUI
import AsyncMux
struct RemoteImage<P: View, I: View>: View {
init(url: URL?, @ViewBuilder content: @escaping (Image) -> I, @ViewBuilder placeholder: @escaping (Error?) -> P) {
self.model = url.map { Model(url: $0) }
self.content = content
self.placeholder = placeholder
}
private let model: Model?
@ViewBuilder private let content: (Image) -> I
@ViewBuilder private let placeholder: (Error?) -> P
var body: some View {
if let image = model?.image {
content(image)
}
else if let error = model?.error {
placeholder(error)
}
else {
placeholder(nil)
}
}
@MainActor
@Observable final class Model {
var image: Image?
var error: Error?
init(url: URL) {
image = ImageCache.loadFromMemory(url)
if image == nil {
Task {
do {
self.image = try await ImageCache.request(url)
}
catch {
self.error = error
}
}
}
}
}
}
#Preview {
let url = URL(string: "https://images.unsplash.com/photo-1513051265668-0ebab31671ae")!
return RemoteImage(url: url) { image in
image
.resizable()
.aspectRatio(contentMode: .fill)
.ignoresSafeArea()
} placeholder: { error in
Text(error?.localizedDescription ?? "LOADING...")
.font(.caption)
.padding()
}
}