From 486fcd501cde5afd601dc415444492dc1b01ebf0 Mon Sep 17 00:00:00 2001 From: Nuno Vieira Date: Tue, 21 Oct 2025 10:28:31 +0100 Subject: [PATCH 1/7] Hide commands overlay when keyboard disappears --- .../ChatChannel/Composer/MessageComposerView.swift | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Sources/StreamChatSwiftUI/ChatChannel/Composer/MessageComposerView.swift b/Sources/StreamChatSwiftUI/ChatChannel/Composer/MessageComposerView.swift index 1d5a6add..c47b9ed7 100644 --- a/Sources/StreamChatSwiftUI/ChatChannel/Composer/MessageComposerView.swift +++ b/Sources/StreamChatSwiftUI/ChatChannel/Composer/MessageComposerView.swift @@ -9,6 +9,7 @@ import SwiftUI public struct MessageComposerView: View, KeyboardReadable { @Injected(\.colors) private var colors @Injected(\.fonts) private var fonts + @Injected(\.utils) private var utils // Initial popup size, before the keyboard is shown. @State private var popupSize: CGFloat = 350 @@ -186,6 +187,8 @@ public struct MessageComposerView: View, KeyboardReadable // If the attachment picker is open, we should dismiss it. viewModel.pickerTypeState = .expanded(.none) } + } else if !visible && keyboardShown && utils.messageListConfig.hidesCommandsOverlayOnMessageListTap { + viewModel.composerCommand = nil } keyboardShown = visible editedMessageWillShow = false From 9687846d44a5127dfb5c13ca53976388f592ffc2 Mon Sep 17 00:00:00 2001 From: Nuno Vieira Date: Tue, 21 Oct 2025 10:31:57 +0100 Subject: [PATCH 2/7] Allow hiding keyboard attachments picker when tapping the message list --- .../ChatChannel/ChatChannelView.swift | 13 ++++++++++++- .../Composer/MessageComposerView.swift | 16 ++++++++++++++++ .../MessageList/MessageListConfig.swift | 16 +++++++++++++++- .../MessageList/MessageListView.swift | 1 - .../Utils/KeyboardHandling.swift | 2 +- 5 files changed, 44 insertions(+), 4 deletions(-) diff --git a/Sources/StreamChatSwiftUI/ChatChannel/ChatChannelView.swift b/Sources/StreamChatSwiftUI/ChatChannel/ChatChannelView.swift index 5a6e50b3..f81e9978 100644 --- a/Sources/StreamChatSwiftUI/ChatChannel/ChatChannelView.swift +++ b/Sources/StreamChatSwiftUI/ChatChannel/ChatChannelView.swift @@ -73,6 +73,12 @@ public struct ChatChannelView: View, KeyboardReadable { }, onJumpToMessage: viewModel.jumpToMessage(messageId:) ) + .dismissKeyboardOnTap(enabled: true) { + NotificationCenter.default.post( + name: .overridePickerTypeState, + object: PickerTypeState.expanded(.none) + ) + } .overlay( viewModel.currentDateString != nil ? factory.makeDateIndicatorView(dateString: viewModel.currentDateString!) @@ -81,7 +87,12 @@ public struct ChatChannelView: View, KeyboardReadable { } else { ZStack { factory.makeEmptyMessagesView(for: channel, colors: colors) - .dismissKeyboardOnTap(enabled: keyboardShown) + .dismissKeyboardOnTap(enabled: keyboardShown) { + NotificationCenter.default.post( + name: .overridePickerTypeState, + object: PickerTypeState.collapsed + ) + } if viewModel.shouldShowTypingIndicator { factory.makeTypingIndicatorBottomView( channel: channel, diff --git a/Sources/StreamChatSwiftUI/ChatChannel/Composer/MessageComposerView.swift b/Sources/StreamChatSwiftUI/ChatChannel/Composer/MessageComposerView.swift index c47b9ed7..946e032a 100644 --- a/Sources/StreamChatSwiftUI/ChatChannel/Composer/MessageComposerView.swift +++ b/Sources/StreamChatSwiftUI/ChatChannel/Composer/MessageComposerView.swift @@ -231,6 +231,15 @@ public struct MessageComposerView: View, KeyboardReadable viewModel.updateDraftMessage(quotedMessage: quotedMessage) } }) + .onReceive(NotificationCenter.default.publisher(for: .overridePickerTypeState)) { notification in + guard utils.messageListConfig.hidesAttachmentsPickersOnMessageListTap else { + return + } + guard let pickerTypeState = notification.object as? PickerTypeState else { + return + } + viewModel.pickerTypeState = pickerTypeState + } .accessibilityElement(children: .contain) } } @@ -447,3 +456,10 @@ public struct ComposerInputView: View, KeyboardReadable { isInCooldown || isChannelFrozen } } + +// MARK: - Notification Names + +extension Notification.Name { + /// Notification sent when the picker type state should be overridden. + static let overridePickerTypeState = Notification.Name("overridePickerTypeState") +} diff --git a/Sources/StreamChatSwiftUI/ChatChannel/MessageList/MessageListConfig.swift b/Sources/StreamChatSwiftUI/ChatChannel/MessageList/MessageListConfig.swift index e0dba4bc..57c94a6e 100644 --- a/Sources/StreamChatSwiftUI/ChatChannel/MessageList/MessageListConfig.swift +++ b/Sources/StreamChatSwiftUI/ChatChannel/MessageList/MessageListConfig.swift @@ -36,7 +36,9 @@ public struct MessageListConfig { bouncedMessagesAlertActionsEnabled: Bool = true, skipEditedMessageLabel: @escaping (ChatMessage) -> Bool = { _ in false }, draftMessagesEnabled: Bool = false, - downloadFileAttachmentsEnabled: Bool = false + downloadFileAttachmentsEnabled: Bool = false, + hidesCommandsOverlayOnMessageListTap: Bool = true, + hidesAttachmentsPickersOnMessageListTap: Bool = false ) { self.messageListType = messageListType self.typingIndicatorPlacement = typingIndicatorPlacement @@ -66,6 +68,8 @@ public struct MessageListConfig { self.skipEditedMessageLabel = skipEditedMessageLabel self.draftMessagesEnabled = draftMessagesEnabled self.downloadFileAttachmentsEnabled = downloadFileAttachmentsEnabled + self.hidesCommandsOverlayOnMessageListTap = hidesCommandsOverlayOnMessageListTap + self.hidesAttachmentsPickersOnMessageListTap = hidesAttachmentsPickersOnMessageListTap } public let messageListType: MessageListType @@ -93,6 +97,16 @@ public struct MessageListConfig { public let markdownSupportEnabled: Bool public let userBlockingEnabled: Bool + /// A boolean to enable hiding the commands overlay when tapping the message list. + /// + /// It is enabled by default. + public let hidesCommandsOverlayOnMessageListTap: Bool + + /// A boolean to enable collapsing the attachments keyboard picker when tapping the message list. + /// + /// IT is disabled by default. + public let hidesAttachmentsPickersOnMessageListTap: Bool + /// A boolean to enable the alert actions for bounced messages. /// /// By default it is true and the bounced actions are displayed as an alert instead of a context menu. diff --git a/Sources/StreamChatSwiftUI/ChatChannel/MessageList/MessageListView.swift b/Sources/StreamChatSwiftUI/ChatChannel/MessageList/MessageListView.swift index 0696eeb7..2bfe8a96 100644 --- a/Sources/StreamChatSwiftUI/ChatChannel/MessageList/MessageListView.swift +++ b/Sources/StreamChatSwiftUI/ChatChannel/MessageList/MessageListView.swift @@ -313,7 +313,6 @@ public struct MessageListView: View, KeyboardReadable { ) : nil ) .modifier(factory.makeMessageListContainerModifier()) - .dismissKeyboardOnTap(enabled: keyboardShown) .onDisappear { messageRenderingUtil.update(previousTopMessage: nil) } diff --git a/Sources/StreamChatSwiftUI/Utils/KeyboardHandling.swift b/Sources/StreamChatSwiftUI/Utils/KeyboardHandling.swift index ec483dbf..5a21e9dc 100644 --- a/Sources/StreamChatSwiftUI/Utils/KeyboardHandling.swift +++ b/Sources/StreamChatSwiftUI/Utils/KeyboardHandling.swift @@ -63,7 +63,7 @@ extension View { /// - enabled: If true, tapping on the view dismisses the view, otherwise keyboard stays visible. /// - onTapped: A closure which is triggered when keyboard is dismissed after tapping the view. func dismissKeyboardOnTap(enabled: Bool, onKeyboardDismissed: (() -> Void)? = nil) -> some View { - modifier(HideKeyboardOnTapGesture(shouldAdd: enabled)) + modifier(HideKeyboardOnTapGesture(shouldAdd: enabled, onTapped: onKeyboardDismissed)) } } From b7f5a3b5de79bf8c4faf8b5cbd2f276488dca9f0 Mon Sep 17 00:00:00 2001 From: Nuno Vieira Date: Tue, 21 Oct 2025 10:53:51 +0100 Subject: [PATCH 3/7] Update CHANGELOG.md --- CHANGELOG.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3389424a..b39b4b83 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,11 +3,12 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). # Upcoming +### ✅ Added +- Allow dismissing commands overlay when tapping the message list [#1024](https://github.com/GetStream/stream-chat-swiftui/pull/1024) +- Allows dismissing the keyboard attachments picker when tapping the message list [#1024](https://github.com/GetStream/stream-chat-swiftui/pull/1024) ### 🐞 Fixed - Fix composer not being locked after the channel was frozen [#1015](https://github.com/GetStream/stream-chat-swiftui/pull/1015) -### 🔄 Changed - # [4.90.0](https://github.com/GetStream/stream-chat-swiftui/releases/tag/4.90.0) _October 08, 2025_ From 307708ece2c73a40ecab47c756898e5605b1c134 Mon Sep 17 00:00:00 2001 From: Nuno Vieira Date: Tue, 21 Oct 2025 11:01:11 +0100 Subject: [PATCH 4/7] Use the same implementation strategy for the commands overlay --- .../ChatChannel/ChatChannelView.swift | 21 ++++++++++++------- .../Composer/MessageComposerView.swift | 11 ++++++++-- 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/Sources/StreamChatSwiftUI/ChatChannel/ChatChannelView.swift b/Sources/StreamChatSwiftUI/ChatChannel/ChatChannelView.swift index f81e9978..1a878bc0 100644 --- a/Sources/StreamChatSwiftUI/ChatChannel/ChatChannelView.swift +++ b/Sources/StreamChatSwiftUI/ChatChannel/ChatChannelView.swift @@ -74,10 +74,7 @@ public struct ChatChannelView: View, KeyboardReadable { onJumpToMessage: viewModel.jumpToMessage(messageId:) ) .dismissKeyboardOnTap(enabled: true) { - NotificationCenter.default.post( - name: .overridePickerTypeState, - object: PickerTypeState.expanded(.none) - ) + hideComposerCommandsAndAttachmentsPicker() } .overlay( viewModel.currentDateString != nil ? @@ -88,10 +85,7 @@ public struct ChatChannelView: View, KeyboardReadable { ZStack { factory.makeEmptyMessagesView(for: channel, colors: colors) .dismissKeyboardOnTap(enabled: keyboardShown) { - NotificationCenter.default.post( - name: .overridePickerTypeState, - object: PickerTypeState.collapsed - ) + hideComposerCommandsAndAttachmentsPicker() } if viewModel.shouldShowTypingIndicator { factory.makeTypingIndicatorBottomView( @@ -224,4 +218,15 @@ public struct ChatChannelView: View, KeyboardReadable { let bottomPadding = topVC()?.view.safeAreaInsets.bottom ?? 0 return bottomPadding } + + private func hideComposerCommandsAndAttachmentsPicker() { + NotificationCenter.default.post( + name: .overridePickerTypeState, + object: PickerTypeState.expanded(.none) + ) + NotificationCenter.default.post( + name: .overrideCommandsOverlayVisibility, + object: nil + ) + } } diff --git a/Sources/StreamChatSwiftUI/ChatChannel/Composer/MessageComposerView.swift b/Sources/StreamChatSwiftUI/ChatChannel/Composer/MessageComposerView.swift index 946e032a..b96f0c11 100644 --- a/Sources/StreamChatSwiftUI/ChatChannel/Composer/MessageComposerView.swift +++ b/Sources/StreamChatSwiftUI/ChatChannel/Composer/MessageComposerView.swift @@ -187,8 +187,6 @@ public struct MessageComposerView: View, KeyboardReadable // If the attachment picker is open, we should dismiss it. viewModel.pickerTypeState = .expanded(.none) } - } else if !visible && keyboardShown && utils.messageListConfig.hidesCommandsOverlayOnMessageListTap { - viewModel.composerCommand = nil } keyboardShown = visible editedMessageWillShow = false @@ -231,6 +229,12 @@ public struct MessageComposerView: View, KeyboardReadable viewModel.updateDraftMessage(quotedMessage: quotedMessage) } }) + .onReceive(NotificationCenter.default.publisher(for: .overrideCommandsOverlayVisibility)) { _ in + guard utils.messageListConfig.hidesCommandsOverlayOnMessageListTap else { + return + } + viewModel.composerCommand = nil + } .onReceive(NotificationCenter.default.publisher(for: .overridePickerTypeState)) { notification in guard utils.messageListConfig.hidesAttachmentsPickersOnMessageListTap else { return @@ -462,4 +466,7 @@ public struct ComposerInputView: View, KeyboardReadable { extension Notification.Name { /// Notification sent when the picker type state should be overridden. static let overridePickerTypeState = Notification.Name("overridePickerTypeState") + + /// Notification sent when the commands overlay visibility should be overridden. + static let overrideCommandsOverlayVisibility = Notification.Name("overrideCommandsOverlayVisibility") } From c01d0203848f342f1cd272674e3a10c3f78e40d0 Mon Sep 17 00:00:00 2001 From: Nuno Vieira Date: Tue, 21 Oct 2025 11:06:55 +0100 Subject: [PATCH 5/7] Rename the notifications names to be more consistent with the rest of the codebase --- .../ChatChannel/ChatChannelView.swift | 6 ++---- .../Composer/MessageComposerView.swift | 17 +++++++---------- 2 files changed, 9 insertions(+), 14 deletions(-) diff --git a/Sources/StreamChatSwiftUI/ChatChannel/ChatChannelView.swift b/Sources/StreamChatSwiftUI/ChatChannel/ChatChannelView.swift index 1a878bc0..47ff4277 100644 --- a/Sources/StreamChatSwiftUI/ChatChannel/ChatChannelView.swift +++ b/Sources/StreamChatSwiftUI/ChatChannel/ChatChannelView.swift @@ -221,12 +221,10 @@ public struct ChatChannelView: View, KeyboardReadable { private func hideComposerCommandsAndAttachmentsPicker() { NotificationCenter.default.post( - name: .overridePickerTypeState, - object: PickerTypeState.expanded(.none) + name: .attachmentPickerHiddenNotification, object: nil ) NotificationCenter.default.post( - name: .overrideCommandsOverlayVisibility, - object: nil + name: .commandsOverlayHiddenNotification, object: nil ) } } diff --git a/Sources/StreamChatSwiftUI/ChatChannel/Composer/MessageComposerView.swift b/Sources/StreamChatSwiftUI/ChatChannel/Composer/MessageComposerView.swift index b96f0c11..c4712a21 100644 --- a/Sources/StreamChatSwiftUI/ChatChannel/Composer/MessageComposerView.swift +++ b/Sources/StreamChatSwiftUI/ChatChannel/Composer/MessageComposerView.swift @@ -229,20 +229,17 @@ public struct MessageComposerView: View, KeyboardReadable viewModel.updateDraftMessage(quotedMessage: quotedMessage) } }) - .onReceive(NotificationCenter.default.publisher(for: .overrideCommandsOverlayVisibility)) { _ in + .onReceive(NotificationCenter.default.publisher(for: .commandsOverlayHiddenNotification)) { _ in guard utils.messageListConfig.hidesCommandsOverlayOnMessageListTap else { return } viewModel.composerCommand = nil } - .onReceive(NotificationCenter.default.publisher(for: .overridePickerTypeState)) { notification in + .onReceive(NotificationCenter.default.publisher(for: .attachmentPickerHiddenNotification)) { _ in guard utils.messageListConfig.hidesAttachmentsPickersOnMessageListTap else { return } - guard let pickerTypeState = notification.object as? PickerTypeState else { - return - } - viewModel.pickerTypeState = pickerTypeState + viewModel.pickerTypeState = .expanded(.none) } .accessibilityElement(children: .contain) } @@ -464,9 +461,9 @@ public struct ComposerInputView: View, KeyboardReadable { // MARK: - Notification Names extension Notification.Name { - /// Notification sent when the picker type state should be overridden. - static let overridePickerTypeState = Notification.Name("overridePickerTypeState") + /// Notification sent when the attachments picker should be hidden. + static let attachmentPickerHiddenNotification = Notification.Name("attachmentPickerHiddenNotification") - /// Notification sent when the commands overlay visibility should be overridden. - static let overrideCommandsOverlayVisibility = Notification.Name("overrideCommandsOverlayVisibility") + /// Notification sent when the commands overlay should be hidden. + static let commandsOverlayHiddenNotification = Notification.Name("commandsOverlayHiddenNotification") } From e62b4ad0ac9cdadccfc246adab04763d1b7d8af3 Mon Sep 17 00:00:00 2001 From: Nuno Vieira Date: Tue, 21 Oct 2025 11:15:10 +0100 Subject: [PATCH 6/7] Allow the attachments picker by default as well --- .../ChatChannel/MessageList/MessageListConfig.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Sources/StreamChatSwiftUI/ChatChannel/MessageList/MessageListConfig.swift b/Sources/StreamChatSwiftUI/ChatChannel/MessageList/MessageListConfig.swift index 57c94a6e..b03d8550 100644 --- a/Sources/StreamChatSwiftUI/ChatChannel/MessageList/MessageListConfig.swift +++ b/Sources/StreamChatSwiftUI/ChatChannel/MessageList/MessageListConfig.swift @@ -38,7 +38,7 @@ public struct MessageListConfig { draftMessagesEnabled: Bool = false, downloadFileAttachmentsEnabled: Bool = false, hidesCommandsOverlayOnMessageListTap: Bool = true, - hidesAttachmentsPickersOnMessageListTap: Bool = false + hidesAttachmentsPickersOnMessageListTap: Bool = true ) { self.messageListType = messageListType self.typingIndicatorPlacement = typingIndicatorPlacement @@ -102,9 +102,9 @@ public struct MessageListConfig { /// It is enabled by default. public let hidesCommandsOverlayOnMessageListTap: Bool - /// A boolean to enable collapsing the attachments keyboard picker when tapping the message list. + /// A boolean to enable hiding the attachments keyboard picker when tapping the message list. /// - /// IT is disabled by default. + /// It is enabled by default. public let hidesAttachmentsPickersOnMessageListTap: Bool /// A boolean to enable the alert actions for bounced messages. From 809539fbc20bc4f1e690e066487d08436b3074f1 Mon Sep 17 00:00:00 2001 From: Nuno Vieira Date: Tue, 21 Oct 2025 15:44:36 +0100 Subject: [PATCH 7/7] Add test coverage to the view --- .../TestTools/ViewFrameUtils.swift | 11 ++ .../MessageComposerView_Tests.swift | 160 ++++++++++++++++++ 2 files changed, 171 insertions(+) diff --git a/StreamChatSwiftUITests/Infrastructure/TestTools/ViewFrameUtils.swift b/StreamChatSwiftUITests/Infrastructure/TestTools/ViewFrameUtils.swift index c9186bbe..77a7130d 100644 --- a/StreamChatSwiftUITests/Infrastructure/TestTools/ViewFrameUtils.swift +++ b/StreamChatSwiftUITests/Infrastructure/TestTools/ViewFrameUtils.swift @@ -15,4 +15,15 @@ extension View { func applySize(_ size: CGSize) -> some View { frame(width: size.width, height: size.height) } + + @discardableResult + /// Add SwiftUI View to a fake hierarchy so that it can receive UI events. + func addToViewHierarchy() -> some View { + let window = UIWindow(frame: CGRect(x: 0, y: 0, width: 400, height: 400)) + let hostingController = UIHostingController(rootView: self) + window.rootViewController = hostingController + window.makeKeyAndVisible() + hostingController.view.layoutIfNeeded() + return self + } } diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/MessageComposerView_Tests.swift b/StreamChatSwiftUITests/Tests/ChatChannel/MessageComposerView_Tests.swift index 7fe459f5..34663602 100644 --- a/StreamChatSwiftUITests/Tests/ChatChannel/MessageComposerView_Tests.swift +++ b/StreamChatSwiftUITests/Tests/ChatChannel/MessageComposerView_Tests.swift @@ -894,6 +894,166 @@ class MessageComposerView_Tests: StreamChatTestCase { onMessageSent: {} ) } + + // MARK: - Notification Tests + + func test_commandsOverlayHiddenNotification_hidesCommandsOverlay() { + // Given + let utils = Utils( + messageListConfig: MessageListConfig( + hidesCommandsOverlayOnMessageListTap: true + ) + ) + streamChat = StreamChat(chatClient: chatClient, utils: utils) + + let factory = DefaultViewFactory.shared + let channelController = ChatChannelTestHelpers.makeChannelController(chatClient: chatClient) + let viewModel = MessageComposerViewModel(channelController: channelController, messageController: nil) + + // Set up a command to be shown + viewModel.composerCommand = ComposerCommand( + id: "testCommand", + typingSuggestion: TypingSuggestion.empty, + displayInfo: nil + ) + + let view = MessageComposerView( + viewFactory: factory, + viewModel: viewModel, + channelController: channelController, + messageController: nil, + quotedMessage: .constant(nil), + editedMessage: .constant(nil), + onMessageSent: {} + ) + view.addToViewHierarchy() + + // When + NotificationCenter.default.post( + name: .commandsOverlayHiddenNotification, + object: nil + ) + + // Then + XCTAssertNil(viewModel.composerCommand) + } + + func test_commandsOverlayHiddenNotification_respectsConfigSetting() { + // Given + let utils = Utils( + messageListConfig: MessageListConfig( + hidesCommandsOverlayOnMessageListTap: false + ) + ) + streamChat = StreamChat(chatClient: chatClient, utils: utils) + + let factory = DefaultViewFactory.shared + let channelController = ChatChannelTestHelpers.makeChannelController(chatClient: chatClient) + let viewModel = MessageComposerViewModel(channelController: channelController, messageController: nil) + + // Set up a command to be shown + let testCommand = ComposerCommand( + id: "testCommand", + typingSuggestion: TypingSuggestion.empty, + displayInfo: nil + ) + viewModel.composerCommand = testCommand + + let view = MessageComposerView( + viewFactory: factory, + viewModel: viewModel, + channelController: channelController, + messageController: nil, + quotedMessage: .constant(nil), + editedMessage: .constant(nil), + onMessageSent: {} + ) + view.addToViewHierarchy() + + // When + NotificationCenter.default.post( + name: .commandsOverlayHiddenNotification, + object: nil + ) + + // Then + XCTAssertNotNil(viewModel.composerCommand) + XCTAssertEqual(viewModel.composerCommand?.id, testCommand.id) + } + + func test_attachmentPickerHiddenNotification_hidesAttachmentPicker() { + // Given + let utils = Utils( + messageListConfig: MessageListConfig( + hidesAttachmentsPickersOnMessageListTap: true + ) + ) + streamChat = StreamChat(chatClient: chatClient, utils: utils) + + let factory = DefaultViewFactory.shared + let channelController = ChatChannelTestHelpers.makeChannelController(chatClient: chatClient) + let viewModel = MessageComposerViewModel(channelController: channelController, messageController: nil) + + // Set up attachment picker to be shown + viewModel.pickerTypeState = .expanded(.media) + + let view = MessageComposerView( + viewFactory: factory, + viewModel: viewModel, + channelController: channelController, + messageController: nil, + quotedMessage: .constant(nil), + editedMessage: .constant(nil), + onMessageSent: {} + ) + view.addToViewHierarchy() + + // When + NotificationCenter.default.post( + name: .attachmentPickerHiddenNotification, + object: nil + ) + + // Then + XCTAssertEqual(viewModel.pickerTypeState, .expanded(.none)) + } + + func test_attachmentPickerHiddenNotification_respectsConfigSetting() { + // Given + let utils = Utils( + messageListConfig: MessageListConfig( + hidesAttachmentsPickersOnMessageListTap: false + ) + ) + streamChat = StreamChat(chatClient: chatClient, utils: utils) + + let factory = DefaultViewFactory.shared + let channelController = ChatChannelTestHelpers.makeChannelController(chatClient: chatClient) + let viewModel = MessageComposerViewModel(channelController: channelController, messageController: nil) + + // Set up attachment picker to be shown + viewModel.pickerTypeState = .expanded(.media) + + let view = MessageComposerView( + viewFactory: factory, + viewModel: viewModel, + channelController: channelController, + messageController: nil, + quotedMessage: .constant(nil), + editedMessage: .constant(nil), + onMessageSent: {} + ) + view.addToViewHierarchy() + + // When + NotificationCenter.default.post( + name: .attachmentPickerHiddenNotification, + object: nil + ) + + // Then + XCTAssertEqual(viewModel.pickerTypeState, .expanded(.media)) + } } class SynchronousAttachmentsConverter: MessageAttachmentsConverter {