Skip to content

Commit b89dec2

Browse files
Align video attachments' bubble corner radius and corner shape with image attachments (#1260)
1 parent a100bd4 commit b89dec2

12 files changed

+95
-45
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
66
### ✅ Added
77
- `AddedAsset` now has `originalWidth`, `originalHeight`, and `duration` (videos), set at selection time and passed into image/video attachment payloads for custom CDN uploads [#1255](https://github.com/GetStream/stream-chat-swiftui/pull/1255)
88

9+
### 🐞 Fixed
10+
- Align video attachments' bubble corner radius and corner shape with image attachments [#1260](https://github.com/GetStream/stream-chat-swiftui/pull/1260)
11+
912
# [4.98.0](https://github.com/GetStream/stream-chat-swiftui/releases/tag/4.98.0)
1013
_February 26, 2026_
1114

Sources/StreamChatSwiftUI/ChatChannel/MessageList/VideoAttachmentView.swift

Lines changed: 24 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -10,44 +10,37 @@ public struct VideoAttachmentsContainer<Factory: ViewFactory>: View {
1010
var factory: Factory
1111
let message: ChatMessage
1212
let width: CGFloat
13+
let isFirst: Bool
1314
@Binding var scrolledId: String?
1415

1516
public init(
1617
factory: Factory,
1718
message: ChatMessage,
1819
width: CGFloat,
20+
isFirst: Bool = true,
1921
scrolledId: Binding<String?>
2022
) {
2123
self.factory = factory
2224
self.message = message
2325
self.width = width
26+
self.isFirst = isFirst
2427
_scrolledId = scrolledId
2528
}
2629

2730
public var body: some View {
2831
VStack(spacing: 0) {
2932
if let quotedMessage = message.quotedMessage {
30-
VStack {
31-
factory.makeQuotedMessageView(
32-
quotedMessage: quotedMessage,
33-
fillAvailableSpace: !message.attachmentCounts.isEmpty,
34-
isInComposer: false,
35-
scrolledId: $scrolledId
36-
)
37-
38-
VideoAttachmentsList(
39-
factory: factory,
40-
message: message,
41-
width: width
42-
)
43-
}
44-
.modifier(
45-
factory.makeMessageViewModifier(
46-
for: MessageModifierInfo(
47-
message: message,
48-
isFirst: false
49-
)
50-
)
33+
factory.makeQuotedMessageView(
34+
quotedMessage: quotedMessage,
35+
fillAvailableSpace: !message.attachmentCounts.isEmpty,
36+
isInComposer: false,
37+
scrolledId: $scrolledId
38+
)
39+
40+
VideoAttachmentsList(
41+
factory: factory,
42+
message: message,
43+
width: width
5144
)
5245
} else {
5346
VideoAttachmentsList(
@@ -62,17 +55,14 @@ public struct VideoAttachmentsContainer<Factory: ViewFactory>: View {
6255
.frame(width: width)
6356
}
6457
}
65-
.if(!message.text.isEmpty, transform: { view in
66-
view.modifier(
67-
factory.makeMessageViewModifier(
68-
for: MessageModifierInfo(
69-
message: message,
70-
isFirst: true,
71-
cornerRadius: 24
72-
)
58+
.modifier(
59+
factory.makeMessageViewModifier(
60+
for: MessageModifierInfo(
61+
message: message,
62+
isFirst: isFirst
7363
)
7464
)
75-
})
65+
)
7666
.accessibilityIdentifier("VideoAttachmentsContainer")
7767
}
7868
}
@@ -116,15 +106,15 @@ public struct VideoAttachmentView<Factory: ViewFactory>: View {
116106
let message: ChatMessage
117107
let width: CGFloat
118108
var ratio: CGFloat = 0.75
119-
var cornerRadius: CGFloat = 24
109+
var cornerRadius: CGFloat = 18
120110

121111
public init(
122112
factory: Factory = DefaultViewFactory.shared,
123113
attachment: ChatMessageVideoAttachment,
124114
message: ChatMessage,
125115
width: CGFloat,
126116
ratio: CGFloat = 0.75,
127-
cornerRadius: CGFloat = 24
117+
cornerRadius: CGFloat = 18
128118
) {
129119
self.factory = factory
130120
self.attachment = attachment
@@ -164,7 +154,7 @@ struct VideoAttachmentContentView<Factory: ViewFactory>: View {
164154
let message: ChatMessage
165155
let width: CGFloat
166156
var ratio: CGFloat = 0.75
167-
var cornerRadius: CGFloat = 24
157+
var cornerRadius: CGFloat = 18
168158

169159
@State var previewImage: UIImage?
170160
@State var error: Error?
@@ -176,6 +166,7 @@ struct VideoAttachmentContentView<Factory: ViewFactory>: View {
176166
Image(uiImage: previewImage)
177167
.resizable()
178168
.scaledToFill()
169+
.frame(width: width, height: width * ratio)
179170
.clipped()
180171
.allowsHitTesting(false)
181172
.accessibilityHidden(true)
@@ -204,7 +195,6 @@ struct VideoAttachmentContentView<Factory: ViewFactory>: View {
204195
}
205196
}
206197
.frame(width: width, height: width * ratio)
207-
.cornerRadius(cornerRadius)
208198
.fullScreenCover(isPresented: $fullScreenShown) {
209199
factory.makeVideoPlayerView(
210200
attachment: attachment,

Sources/StreamChatSwiftUI/DefaultViewFactory.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -451,6 +451,7 @@ extension ViewFactory {
451451
factory: self,
452452
message: message,
453453
width: availableWidth,
454+
isFirst: isFirst,
454455
scrolledId: scrolledId
455456
)
456457
}

StreamChatSwiftUITests/Tests/ChatChannel/MessageContainerView_Tests.swift

Lines changed: 67 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -196,21 +196,24 @@ class MessageContainerView_Tests: StreamChatTestCase {
196196

197197
func test_videoAttachment_snapshotNoText() {
198198
// Given
199-
let attachment = ChatChannelTestHelpers.videoAttachment
200199
let message = ChatMessage.mock(
201200
id: .unique,
202201
cid: .unique,
203202
text: "",
204-
author: .mock(id: .unique)
203+
author: .mock(id: .unique),
204+
attachments: ChatChannelTestHelpers.videoAttachments
205205
)
206206

207207
// When
208-
let view = VideoAttachmentView(
209-
attachment: attachment,
208+
let view = VideoAttachmentsContainer(
209+
factory: DefaultViewFactory.shared,
210210
message: message,
211-
width: 2 * defaultScreenSize.width / 3
211+
width: 2 * defaultScreenSize.width / 3,
212+
isFirst: true,
213+
scrolledId: .constant(nil)
212214
)
213-
.applyDefaultSize()
215+
.frame(width: 200)
216+
.padding()
214217

215218
// Then
216219
assertSnapshot(matching: view, as: .image(perceptualPrecision: precision))
@@ -231,6 +234,57 @@ class MessageContainerView_Tests: StreamChatTestCase {
231234
factory: DefaultViewFactory.shared,
232235
message: message,
233236
width: 2 * defaultScreenSize.width / 3,
237+
isFirst: true,
238+
scrolledId: .constant(nil)
239+
)
240+
.frame(width: 200)
241+
.padding()
242+
243+
// Then
244+
assertSnapshot(matching: view, as: .image(perceptualPrecision: precision))
245+
}
246+
247+
func test_videoAttachmentsContainer_isFirstFalse_snapshot() {
248+
// Given
249+
let message = ChatMessage.mock(
250+
id: .unique,
251+
cid: .unique,
252+
text: "Test message",
253+
author: .mock(id: .unique),
254+
attachments: ChatChannelTestHelpers.videoAttachments
255+
)
256+
257+
// When
258+
let view = VideoAttachmentsContainer(
259+
factory: DefaultViewFactory.shared,
260+
message: message,
261+
width: 2 * defaultScreenSize.width / 3,
262+
isFirst: false,
263+
scrolledId: .constant(nil)
264+
)
265+
.frame(width: 200)
266+
.padding()
267+
268+
// Then
269+
assertSnapshot(matching: view, as: .image(perceptualPrecision: precision))
270+
}
271+
272+
func test_videoAttachment_noText_isFirstFalse_snapshot() {
273+
// Given
274+
let message = ChatMessage.mock(
275+
id: .unique,
276+
cid: .unique,
277+
text: "",
278+
author: .mock(id: .unique),
279+
attachments: ChatChannelTestHelpers.videoAttachments
280+
)
281+
282+
// When
283+
let view = VideoAttachmentsContainer(
284+
factory: DefaultViewFactory.shared,
285+
message: message,
286+
width: 2 * defaultScreenSize.width / 3,
287+
isFirst: false,
234288
scrolledId: .constant(nil)
235289
)
236290
.frame(width: 200)
@@ -625,20 +679,22 @@ class MessageContainerView_Tests: StreamChatTestCase {
625679
message: ChatMessage,
626680
channel: ChatChannel? = nil,
627681
messageViewModel: MessageViewModel? = nil,
628-
highlightedMessageId: String? = nil
682+
highlightedMessageId: String? = nil,
683+
showsAllInfo: Bool = true
629684
) -> some View {
630-
MessageContainerView(
685+
let channelOrMock = channel ?? .mockDMChannel()
686+
return MessageContainerView(
631687
factory: DefaultViewFactory.shared,
632-
channel: channel ?? .mockDMChannel(),
688+
channel: channelOrMock,
633689
message: message,
634690
width: defaultScreenSize.width,
635-
showsAllInfo: true,
691+
showsAllInfo: showsAllInfo,
636692
isInThread: false,
637693
isLast: false,
638694
scrolledId: .constant(nil),
639695
quotedMessage: .constant(nil),
640696
onLongPress: { _ in },
641-
viewModel: messageViewModel ?? MessageViewModel(message: message, channel: channel)
697+
viewModel: messageViewModel ?? MessageViewModel(message: message, channel: channelOrMock)
642698
)
643699
.environment(\.highlightedMessageId, highlightedMessageId)
644700
.frame(width: 375, height: 200)
14.7 KB
Loading
Loading
11.2 KB
Loading
Loading
-116 KB
Loading
950 Bytes
Loading

0 commit comments

Comments
 (0)