Skip to content

Commit dc717fc

Browse files
authored
Fix v5 QA issues: navigation headers, member view renames, media viewer, and swipe-to-reply (#1402)
* Fix swipe to reply icon for outgoing message not shifted to the right * Fix swipe to reply gesture for RTL * Update MediaViewer design according to Figma * Add support for customizing Media Viewer footer * Re-record snapshots * Fix border in Edit button in ChannelInfoView * Update AddUsersView navigation bar to be consistent with the rest of the SDK * Update the navigation bar on the MemberListView as well * Rename member views * Update changelog * Update the stream-chat commit to remote LLC develop * PR Feedback changes
1 parent ddc0279 commit dc717fc

71 files changed

Lines changed: 533 additions & 303 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
1212
- Redesign the thread replies divider in the message replies list [#1354](https://github.com/GetStream/stream-chat-swiftui/pull/1354)
1313

1414
### 🐞 Fixed
15+
- Fix swipe-to-reply icon layout for outgoing messages and RTL [#1402](https://github.com/GetStream/stream-chat-swiftui/pull/1402)
16+
- Fix unwanted border on the Edit button in Channel Info [#1402](https://github.com/GetStream/stream-chat-swiftui/pull/1402)
1517
- Fix send button icon not mirroring in RTL layouts [#1397](https://github.com/GetStream/stream-chat-swiftui/pull/1397)
1618
- Fix composer attachment picker prompt views layout to center all content vertically [#1397](https://github.com/GetStream/stream-chat-swiftui/pull/1397)
1719
- Fix poll icon inconsistency in the attachment type picker and attachment previews [#1397](https://github.com/GetStream/stream-chat-swiftui/pull/1397)
@@ -37,6 +39,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
3739
- Fix spacings in message annotations [#1403](https://github.com/GetStream/stream-chat-swiftui/pull/1403)
3840

3941
### 🔄 Changed
42+
- Rename `AddUsersView`/`AddUsersViewModel` to `MemberAddView`/`MemberAddViewModel` [#1402](https://github.com/GetStream/stream-chat-swiftui/pull/1402)
43+
- Unify Channel Info navigation headers styling [#1402](https://github.com/GetStream/stream-chat-swiftui/pull/1402)
4044
- Renamed the `onMessageSent` callback to `willSendMessage` in `MessageComposerViewModel`, `ViewModelsFactory`, and `ComposerViewFactoryOptions` [#1327](https://github.com/GetStream/stream-chat-swiftui/pull/1327)
4145
- Remove `InjectedChannelInfo` from `ChatChannelListItemView` [#1338](https://github.com/GetStream/stream-chat-swiftui/pull/1338)
4246
- Rename empty state views from `No` prefix to `Empty` prefix [#1345](https://github.com/GetStream/stream-chat-swiftui/pull/1345)

Sources/StreamChatSwiftUI/ChatChannel/ChannelInfo/ChatChannelInfoHelperViews.swift

Lines changed: 0 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -257,94 +257,6 @@ public struct ChannelInfoItemView<TrailingView: View>: View {
257257
}
258258
}
259259

260-
// MARK: - Member List View
261-
262-
/// A view that displays the full member list for a group channel, presented as a sheet.
263-
public struct MemberListView<Factory: ViewFactory>: View {
264-
@Injected(\.colors) private var colors
265-
@Injected(\.fonts) private var fonts
266-
@Injected(\.tokens) private var tokens
267-
@Injected(\.images) private var images
268-
@Injected(\.chatClient) private var chatClient
269-
270-
let factory: Factory
271-
@ObservedObject var viewModel: ChatChannelInfoViewModel
272-
@State private var selectedParticipant: ParticipantInfo?
273-
@State private var addUsersShown = false
274-
275-
public init(factory: Factory = DefaultViewFactory.shared, viewModel: ChatChannelInfoViewModel) {
276-
self.factory = factory
277-
self.viewModel = viewModel
278-
}
279-
280-
public var body: some View {
281-
NavigationView {
282-
ScrollView {
283-
LazyVStack(spacing: 0) {
284-
ForEach(viewModel.allParticipants) { participant in
285-
ChatInfoMemberView(
286-
factory: factory,
287-
participant: participant,
288-
backgroundColor: colors.backgroundCoreApp,
289-
onAppear: { viewModel.onMemberAppear(participant) },
290-
onTap: {
291-
selectedParticipant = participant
292-
}
293-
)
294-
}
295-
}
296-
}
297-
.background(Color(colors.backgroundCoreApp).edgesIgnoringSafeArea(.all))
298-
.toolbarThemed {
299-
ToolbarItem(placement: .principal) {
300-
Text(L10n.ChatInfo.Members.count(viewModel.channel.memberCount))
301-
.font(fonts.bodyBold)
302-
.foregroundColor(Color(colors.navigationBarTitle))
303-
}
304-
ToolbarItem(placement: .navigationBarLeading) {
305-
Button {
306-
viewModel.memberListSheetShown = false
307-
} label: {
308-
Image(uiImage: images.close)
309-
.foregroundColor(Color(colors.textSecondary))
310-
}
311-
}
312-
ToolbarItem(placement: .navigationBarTrailing) {
313-
if viewModel.shouldShowAddUserButton {
314-
StreamIconButton(role: .primary, style: .solid, size: .small) {
315-
addUsersShown = true
316-
} icon: {
317-
Image(systemName: "person.badge.plus")
318-
}
319-
}
320-
}
321-
}
322-
.navigationBarTitleDisplayMode(.inline)
323-
}
324-
.sheet(item: $selectedParticipant) { participant in
325-
ParticipantInfoView(
326-
factory: factory,
327-
participant: participant,
328-
actions: viewModel.participantActions(for: participant)
329-
) {
330-
selectedParticipant = nil
331-
}
332-
.modifier(PresentationDetentsModifier(sheetSizes: [.custom(280), .medium]))
333-
}
334-
.sheet(isPresented: $addUsersShown) {
335-
factory.makeAddUsersView(
336-
options: AddUsersViewOptions(
337-
options: .init(loadedUserIds: viewModel.allMemberIds),
338-
onConfirm: { users in
339-
viewModel.addUsersTapped(users)
340-
addUsersShown = false
341-
}
342-
)
343-
)
344-
}
345-
}
346-
}
347-
348260
public final class ParticipantInfo: Identifiable {
349261
public var id: String {
350262
chatUser.id

Sources/StreamChatSwiftUI/ChatChannel/ChannelInfo/ChatChannelInfoView.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,8 @@ public struct ChatChannelInfoView<Factory: ViewFactory>: View, KeyboardReadable
8282
EditGroupView(factory: factory, viewModel: viewModel)
8383
}
8484
.sheet(isPresented: $viewModel.addUsersShown) {
85-
factory.makeAddUsersView(
86-
options: AddUsersViewOptions(
85+
factory.makeMemberAddView(
86+
options: MemberAddViewOptions(
8787
options: .init(loadedUserIds: viewModel.allMemberIds),
8888
onConfirm: viewModel.addUsersTapped(_:)
8989
)
@@ -216,7 +216,7 @@ public struct ChatChannelInfoView<Factory: ViewFactory>: View, KeyboardReadable
216216

217217
Spacer()
218218

219-
if viewModel.shouldShowAddUserButton {
219+
if viewModel.shouldShowAddMemberButton {
220220
StreamTextButton(role: .secondary, style: .outline, size: .small) {
221221
viewModel.addUsersShown = true
222222
} text: {
@@ -378,7 +378,7 @@ struct ChatChannelInfoViewHeaderViewModifier: ViewModifier {
378378
Text(L10n.ChatInfo.edit)
379379
.font(fonts.bodyBold)
380380
}
381-
.modifier(LiquidGlassModifier(shape: Capsule(), isInteractive: true))
381+
.modifier(LiquidGlassBorderlessModifier(shape: Capsule(), isInteractive: true))
382382
} else {
383383
StreamTextButton(role: .secondary, style: .outline, size: .medium) {
384384
viewModel.editGroupShown = true

Sources/StreamChatSwiftUI/ChatChannel/ChannelInfo/ChatChannelInfoViewModel.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ import SwiftUI
7272
channel.ownCapabilities.contains(.updateChannel)
7373
}
7474

75-
open var shouldShowAddUserButton: Bool {
75+
open var shouldShowAddMemberButton: Bool {
7676
if channel.isDirectMessageChannel {
7777
false
7878
} else {

Sources/StreamChatSwiftUI/ChatChannel/ChannelInfo/MediaAttachmentsView.swift

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ struct MediaAttachmentsGridView<Factory: ViewFactory>: View {
7272
let mediaItems: [MediaItem]?
7373
let showAvatars: Bool
7474
let onItemAppear: ((Int) -> Void)?
75+
let onItemSelected: ((Int) -> Void)?
7576

7677
private let targetItemWidth: CGFloat = 120
7778

@@ -80,13 +81,15 @@ struct MediaAttachmentsGridView<Factory: ViewFactory>: View {
8081
attachments: [MediaAttachment],
8182
mediaItems: [MediaItem]? = nil,
8283
showAvatars: Bool = true,
83-
onItemAppear: ((Int) -> Void)? = nil
84+
onItemAppear: ((Int) -> Void)? = nil,
85+
onItemSelected: ((Int) -> Void)? = nil
8486
) {
8587
self.factory = factory
8688
self.attachments = attachments
8789
self.mediaItems = mediaItems
8890
self.showAvatars = showAvatars
8991
self.onItemAppear = onItemAppear
92+
self.onItemSelected = onItemSelected
9093
}
9194

9295
public var body: some View {
@@ -156,6 +159,19 @@ struct MediaAttachmentsGridView<Factory: ViewFactory>: View {
156159
}
157160
}
158161
)
162+
} else if let onItemSelected {
163+
Button {
164+
onItemSelected(index)
165+
} label: {
166+
LazyLoadingImage(
167+
source: attachments[index],
168+
width: itemWidth,
169+
height: itemWidth,
170+
showVideoIcon: false
171+
)
172+
.frame(width: itemWidth, height: itemWidth)
173+
.clipped()
174+
}
159175
} else {
160176
LazyLoadingImage(
161177
source: attachments[index],

Sources/StreamChatSwiftUI/ChatChannel/ChannelInfo/AddUsersView.swift renamed to Sources/StreamChatSwiftUI/ChatChannel/ChannelInfo/MemberAddView.swift

Lines changed: 36 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,13 @@ import SwiftUI
77

88
/// Full-sheet view for adding members to a channel.
99
/// Supports search, pagination, and multi-select with a batch confirm action.
10-
public struct AddUsersView<Factory: ViewFactory>: View {
10+
public struct MemberAddView<Factory: ViewFactory>: View {
1111
@Injected(\.colors) private var colors
1212

1313
@Environment(\.presentationMode) private var presentationMode
1414

1515
private let factory: Factory
16-
@StateObject private var viewModel: AddUsersViewModel
16+
@StateObject private var viewModel: MemberAddViewModel
1717
var onConfirm: @MainActor ([ChatUser]) -> Void
1818

1919
public init(
@@ -22,15 +22,15 @@ public struct AddUsersView<Factory: ViewFactory>: View {
2222
onConfirm: @escaping @MainActor ([ChatUser]) -> Void
2323
) {
2424
_viewModel = StateObject(
25-
wrappedValue: AddUsersViewModel(loadedUserIds: loadedUserIds)
25+
wrappedValue: MemberAddViewModel(loadedUserIds: loadedUserIds)
2626
)
2727
self.onConfirm = onConfirm
2828
self.factory = factory
2929
}
3030

3131
init(
3232
factory: Factory = DefaultViewFactory.shared,
33-
viewModel: AddUsersViewModel,
33+
viewModel: MemberAddViewModel,
3434
onConfirm: @escaping @MainActor ([ChatUser]) -> Void
3535
) {
3636
_viewModel = StateObject(wrappedValue: viewModel)
@@ -62,7 +62,8 @@ public struct AddUsersView<Factory: ViewFactory>: View {
6262
))
6363
.background(Color(colors.backgroundCoreApp).edgesIgnoringSafeArea(.all))
6464
.modifier(
65-
AddMembersToolbarModifier(
65+
MemberAddToolbarModifier(
66+
factory: factory,
6667
viewModel: viewModel,
6768
onConfirm: { onConfirm(viewModel.selectedUsers) },
6869
onDismiss: { presentationMode.wrappedValue.dismiss() }
@@ -73,8 +74,8 @@ public struct AddUsersView<Factory: ViewFactory>: View {
7374
}
7475
}
7576

76-
/// Options used in the add users view.
77-
public final class AddUsersOptions: Sendable {
77+
/// Options used in the member add view.
78+
public final class MemberAddOptions: Sendable {
7879
public let loadedUserIds: [String]
7980

8081
public init(loadedUserIds: [String]) {
@@ -155,54 +156,51 @@ private struct AddMembersUserRow<Factory: ViewFactory>: View {
155156

156157
// MARK: - Toolbar
157158

158-
private struct AddMembersToolbarModifier: ViewModifier {
159+
private struct MemberAddToolbarModifier<Factory: ViewFactory>: ViewModifier {
159160
@Injected(\.colors) private var colors
160161
@Injected(\.fonts) private var fonts
161-
@Injected(\.images) private var images
162162
@Injected(\.tokens) private var tokens
163163

164-
@ObservedObject var viewModel: AddUsersViewModel
164+
let factory: Factory
165+
@ObservedObject var viewModel: MemberAddViewModel
165166
let onConfirm: () -> Void
166167
let onDismiss: () -> Void
167168

168169
func body(content: Content) -> some View {
169-
if #available(iOS 26.0, *) {
170-
content
171-
.toolbarThemed {
172-
toolbarContent()
173-
#if compiler(>=6.2)
174-
.sharedBackgroundVisibility(.hidden)
175-
#endif
176-
}
177-
} else {
178-
content
179-
.toolbarThemed {
180-
toolbarContent()
181-
}
182-
}
170+
content
171+
.toolbarThemed {
172+
toolbarContent()
173+
}
183174
}
184175

185176
@ToolbarContentBuilder private func toolbarContent() -> some ToolbarContent {
177+
ToolbarItem(placement: .navigationBarLeading) {
178+
Button(action: onDismiss) {
179+
Image(systemName: "xmark")
180+
.renderingMode(.template)
181+
.font(.system(size: 12))
182+
.foregroundColor(Color(colors.buttonSecondaryText))
183+
}
184+
}
185+
186186
ToolbarItem(placement: .principal) {
187187
Text(L10n.ChatInfo.Members.addMembersTitle)
188188
.font(fonts.bodyBold)
189189
.foregroundColor(Color(colors.navigationBarTitle))
190190
}
191-
ToolbarItem(placement: .navigationBarLeading) {
192-
Button(action: onDismiss) {
193-
Image(uiImage: images.close)
194-
.foregroundColor(Color(colors.textSecondary))
195-
}
191+
192+
ToolbarItem(placement: .topBarTrailing) {
193+
confirmButton
196194
}
197-
ToolbarItem(placement: .navigationBarTrailing) {
198-
Button(action: onConfirm) {
199-
Image(uiImage: images.selectionBadgeIcon)
200-
.customizable()
201-
.frame(width: tokens.iconSizeSm)
202-
.foregroundColor(Color(colors.buttonPrimaryTextOnAccent))
203-
}
204-
.frame(width: tokens.buttonVisualHeightMd)
205-
.background(Circle().fill(Color(colors.accentPrimary)))
195+
}
196+
197+
private var confirmButton: some View {
198+
Button(action: onConfirm) {
199+
Image(systemName: "checkmark")
200+
.renderingMode(.template)
201+
.font(.system(size: 16))
202+
.foregroundColor(Color(colors.buttonPrimaryTextOnAccent))
206203
}
204+
.modifier(factory.styles.makeToolbarConfirmActionModifier(options: .init()))
207205
}
208206
}

Sources/StreamChatSwiftUI/ChatChannel/ChannelInfo/AddUsersViewModel.swift renamed to Sources/StreamChatSwiftUI/ChatChannel/ChannelInfo/MemberAddViewModel.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ import Combine
66
import StreamChat
77
import SwiftUI
88

9-
/// View model for the `AddUsersView`.
10-
@MainActor class AddUsersViewModel: ObservableObject {
9+
/// View model for the `MemberAddView`.
10+
@MainActor class MemberAddViewModel: ObservableObject {
1111
@Injected(\.chatClient) private var chatClient
1212

1313
@Published var users = [ChatUser]()

0 commit comments

Comments
 (0)