@@ -8,41 +8,47 @@ import StreamChat
8
8
import SwiftUI
9
9
10
10
public struct ImageAttachmentContainer : View {
11
+ @Injected ( \. colors) var colors
12
+
11
13
let message : ChatMessage
12
14
let width : CGFloat
13
15
let isFirst : Bool
14
- let isGiphy : Bool
15
16
16
17
public var body : some View {
17
18
if message. text. isEmpty {
18
19
ImageAttachmentView (
19
20
message: message,
20
- width: width,
21
- isGiphy: isGiphy
21
+ width: width
22
22
)
23
23
. messageBubble ( for: message, isFirst: isFirst)
24
24
} else {
25
25
VStack ( spacing: 0 ) {
26
- if hasAttachments {
27
- ImageAttachmentView (
28
- message: message,
29
- width: width,
30
- isGiphy: isGiphy
31
- )
32
- }
33
-
26
+ ImageAttachmentView (
27
+ message: message,
28
+ width: width
29
+ )
30
+
34
31
HStack {
35
32
Text ( message. text)
36
33
. standardPadding ( )
37
34
Spacer ( )
38
35
}
36
+ . background ( Color ( backgroundColor) )
39
37
}
40
38
. messageBubble ( for: message, isFirst: isFirst)
41
39
}
42
40
}
43
41
44
- private var hasAttachments : Bool {
45
- isGiphy ? !message. giphyAttachments. isEmpty : !message. imageAttachments. isEmpty
42
+ private var backgroundColor : UIColor {
43
+ if message. isSentByCurrentUser {
44
+ if message. type == . ephemeral {
45
+ return colors. background8
46
+ } else {
47
+ return colors. background6
48
+ }
49
+ } else {
50
+ return colors. background8
51
+ }
46
52
}
47
53
}
48
54
@@ -53,7 +59,6 @@ struct ImageAttachmentView: View {
53
59
54
60
let message : ChatMessage
55
61
let width : CGFloat
56
- let isGiphy : Bool
57
62
58
63
private let spacing : CGFloat = 2
59
64
private let maxDisplayedImages = 4
@@ -63,26 +68,11 @@ struct ImageAttachmentView: View {
63
68
}
64
69
65
70
private var sources : [ URL ] {
66
- if isGiphy {
67
- return message. giphyAttachments. map { attachment in
68
- if let state = attachment. uploadingState {
69
- return state. localFileURL
70
- } else {
71
- let url = imageCDN. thumbnailURL (
72
- originalURL: attachment. previewURL,
73
- preferredSize: CGSize ( width: width, height: width)
74
- )
75
-
76
- return url
77
- }
78
- }
79
- } else {
80
- return message. imageAttachments. map { attachment in
81
- if let state = attachment. uploadingState {
82
- return state. localFileURL
83
- } else {
84
- return attachment. imagePreviewURL
85
- }
71
+ message. imageAttachments. map { attachment in
72
+ if let state = attachment. uploadingState {
73
+ return state. localFileURL
74
+ } else {
75
+ return attachment. imagePreviewURL
86
76
}
87
77
}
88
78
}
@@ -99,13 +89,15 @@ struct ImageAttachmentView: View {
99
89
HStack ( spacing: spacing) {
100
90
MultiImageView (
101
91
source: sources [ 0 ] ,
102
- width: width / 2
92
+ width: width / 2 ,
93
+ height: width
103
94
)
104
95
. withUploadingStateIndicator ( for: uploadState ( for: 0 ) , url: sources [ 0 ] )
105
96
106
97
MultiImageView (
107
98
source: sources [ 1 ] ,
108
- width: width / 2
99
+ width: width / 2 ,
100
+ height: width
109
101
)
110
102
. withUploadingStateIndicator ( for: uploadState ( for: 1 ) , url: sources [ 1 ] )
111
103
}
@@ -114,20 +106,23 @@ struct ImageAttachmentView: View {
114
106
HStack ( spacing: spacing) {
115
107
MultiImageView (
116
108
source: sources [ 0 ] ,
117
- width: width / 2
109
+ width: width / 2 ,
110
+ height: width
118
111
)
119
112
. withUploadingStateIndicator ( for: uploadState ( for: 0 ) , url: sources [ 0 ] )
120
113
121
114
VStack ( spacing: spacing) {
122
115
MultiImageView (
123
116
source: sources [ 1 ] ,
124
- width: width / 2
117
+ width: width / 2 ,
118
+ height: width / 2
125
119
)
126
120
. withUploadingStateIndicator ( for: uploadState ( for: 1 ) , url: sources [ 1 ] )
127
121
128
122
MultiImageView (
129
123
source: sources [ 2 ] ,
130
- width: width / 2
124
+ width: width / 2 ,
125
+ height: width / 2
131
126
)
132
127
. withUploadingStateIndicator ( for: uploadState ( for: 2 ) , url: sources [ 2 ] )
133
128
}
@@ -138,28 +133,32 @@ struct ImageAttachmentView: View {
138
133
VStack ( spacing: spacing) {
139
134
MultiImageView (
140
135
source: sources [ 0 ] ,
141
- width: width / 2
136
+ width: width / 2 ,
137
+ height: width / 2
142
138
)
143
139
. withUploadingStateIndicator ( for: uploadState ( for: 0 ) , url: sources [ 0 ] )
144
140
145
141
MultiImageView (
146
142
source: sources [ 1 ] ,
147
- width: width / 2
143
+ width: width / 2 ,
144
+ height: width / 2
148
145
)
149
146
. withUploadingStateIndicator ( for: uploadState ( for: 1 ) , url: sources [ 1 ] )
150
147
}
151
148
152
149
VStack ( spacing: spacing) {
153
150
MultiImageView (
154
151
source: sources [ 2 ] ,
155
- width: width / 2
152
+ width: width / 2 ,
153
+ height: width / 2
156
154
)
157
155
. withUploadingStateIndicator ( for: uploadState ( for: 2 ) , url: sources [ 2 ] )
158
156
159
157
ZStack {
160
158
MultiImageView (
161
159
source: sources [ 3 ] ,
162
- width: width / 2
160
+ width: width / 2 ,
161
+ height: width / 2
163
162
)
164
163
. withUploadingStateIndicator ( for: uploadState ( for: 3 ) , url: sources [ 3 ] )
165
164
@@ -171,6 +170,7 @@ struct ImageAttachmentView: View {
171
170
. font ( fonts. title)
172
171
}
173
172
}
173
+ . frame ( width: width / 2 , height: width / 2 )
174
174
}
175
175
}
176
176
. aspectRatio ( 1 , contentMode: . fill)
@@ -184,11 +184,7 @@ struct ImageAttachmentView: View {
184
184
}
185
185
186
186
private func uploadState( for index: Int ) -> AttachmentUploadingState ? {
187
- if isGiphy {
188
- return message. giphyAttachments [ index] . uploadingState
189
- } else {
190
- return message. imageAttachments [ index] . uploadingState
191
- }
187
+ message. imageAttachments [ index] . uploadingState
192
188
}
193
189
}
194
190
@@ -198,29 +194,40 @@ struct SingleImageView: View {
198
194
199
195
var body : some View {
200
196
LazyLoadingImage ( source: source, width: width)
201
- . aspectRatio ( contentMode : . fit )
197
+ . frame ( width : width , height : 3 * width / 4 )
202
198
}
203
199
}
204
200
205
201
struct MultiImageView : View {
206
202
let source : URL
207
203
let width : CGFloat
204
+ let height : CGFloat
208
205
209
206
var body : some View {
210
207
LazyLoadingImage ( source: source, width: width)
211
- . frame ( width: width)
208
+ . frame ( width: width, height: height)
209
+ . clipped ( )
212
210
}
213
211
}
214
212
215
213
struct LazyLoadingImage : View {
214
+ @Injected ( \. utils) var utils
215
+
216
+ @State private var image : UIImage ?
217
+ @State private var error : Error ?
218
+
216
219
let source : URL
217
220
let width : CGFloat
218
221
219
222
var body : some View {
220
- LazyImage ( source: source) { state in
221
- if let imageContainer = state. imageContainer {
222
- Image ( imageContainer)
223
- } else if state. error != nil {
223
+ ZStack {
224
+ if let image = image {
225
+ Image ( uiImage: image)
226
+ . resizable ( )
227
+ . scaledToFill ( )
228
+ . aspectRatio ( contentMode: . fill)
229
+ . clipped ( )
230
+ } else if error != nil {
224
231
Color ( . secondarySystemBackground)
225
232
} else {
226
233
ZStack {
@@ -229,8 +236,26 @@ struct LazyLoadingImage: View {
229
236
}
230
237
}
231
238
}
232
- . onDisappear ( . reset)
233
- . processors ( [ ImageProcessors . Resize ( width: width) ] )
234
- . priority ( . high)
239
+ . onAppear {
240
+ if image != nil {
241
+ return
242
+ }
243
+
244
+ utils. imageLoader. loadImage (
245
+ url: source,
246
+ imageCDN: utils. imageCDN,
247
+ resize: true ,
248
+ preferredSize: CGSize ( width: width, height: 3 * width / 4 ) ,
249
+ completion: { result in
250
+ switch result {
251
+ case let . success( image) :
252
+ self . image = image
253
+ case let . failure( error) :
254
+ self . error = error
255
+ }
256
+ }
257
+ )
258
+ }
259
+ . clipped ( )
235
260
}
236
261
}
0 commit comments