diff --git a/Sources/StreamChat/Controllers/ChannelController/ChannelController.swift b/Sources/StreamChat/Controllers/ChannelController/ChannelController.swift index db9f27e01f9..d7b31463a47 100644 --- a/Sources/StreamChat/Controllers/ChannelController/ChannelController.swift +++ b/Sources/StreamChat/Controllers/ChannelController/ChannelController.swift @@ -1161,7 +1161,8 @@ public class ChatChannelController: DataController, DelegateCallable, DataStoreP /// Returns the current cooldown time for the channel. Returns 0 in case there is no cooldown active. public func currentCooldownTime() -> Int { guard let cooldownDuration = channel?.cooldownDuration, cooldownDuration > 0, - let currentUserLastMessage = channel?.lastMessageFromCurrentUser else { + let currentUserLastMessage = channel?.lastMessageFromCurrentUser, + channel?.ownCapabilities.contains(.skipSlowMode) == false else { return 0 } diff --git a/Sources/StreamChat/Models/Channel.swift b/Sources/StreamChat/Models/Channel.swift index a9a6620f530..d63945d66f4 100644 --- a/Sources/StreamChat/Models/Channel.swift +++ b/Sources/StreamChat/Models/Channel.swift @@ -359,6 +359,8 @@ public struct ChannelCapability: RawRepresentable, ExpressibleByStringLiteral, H public static var typingEvents: Self = "typing-events" /// Indicates that channel slow mode is active. public static var slowMode: Self = "slow-mode" + /// Ability to skip the slow mode when it's active. + public static var skipSlowMode: Self = "skip-slow-mode" /// Ability to join a call. public static var joinCall: Self = "join-call" /// Ability to create a call. diff --git a/Sources/StreamChatUI/Composer/ComposerVC.swift b/Sources/StreamChatUI/Composer/ComposerVC.swift index 61e32b7ee76..7376828e2dd 100644 --- a/Sources/StreamChatUI/Composer/ComposerVC.swift +++ b/Sources/StreamChatUI/Composer/ComposerVC.swift @@ -617,7 +617,9 @@ open class ComposerVC: _ViewController, } else { createNewMessage(text: text) - if !content.hasCommand, let cooldownDuration = channelController?.channel?.cooldownDuration { + let channel = channelController?.channel + let skipSlowMode = channel?.ownCapabilities.contains(.skipSlowMode) == true + if !content.hasCommand, !skipSlowMode, let cooldownDuration = channel?.cooldownDuration { cooldownTracker.start(with: cooldownDuration) } diff --git a/TestTools/StreamChatTestTools/Mocks/Models + Extensions/ChatChannel_Mock.swift b/TestTools/StreamChatTestTools/Mocks/Models + Extensions/ChatChannel_Mock.swift index 9c05fa8a034..39778283175 100644 --- a/TestTools/StreamChatTestTools/Mocks/Models + Extensions/ChatChannel_Mock.swift +++ b/TestTools/StreamChatTestTools/Mocks/Models + Extensions/ChatChannel_Mock.swift @@ -84,6 +84,7 @@ public extension ChatChannel { watcherCount: Int = 0, memberCount: Int = 0, reads: [ChatChannelRead] = [], + cooldownDuration: Int = 0, extraData: [String: RawJSON] = [:], latestMessages: [ChatMessage] = [], muteDetails: MuteDetails? = nil, @@ -110,6 +111,7 @@ public extension ChatChannel { watcherCount: watcherCount, memberCount: memberCount, reads: reads, + cooldownDuration: cooldownDuration, extraData: extraData, latestMessages: { latestMessages }, muteDetails: { muteDetails }, diff --git a/Tests/StreamChatUITests/SnapshotTests/Composer/ComposerVC_Tests.swift b/Tests/StreamChatUITests/SnapshotTests/Composer/ComposerVC_Tests.swift index 951e28486be..cd44c1cf2d9 100644 --- a/Tests/StreamChatUITests/SnapshotTests/Composer/ComposerVC_Tests.swift +++ b/Tests/StreamChatUITests/SnapshotTests/Composer/ComposerVC_Tests.swift @@ -302,6 +302,18 @@ final class ComposerVC_Tests: XCTestCase { AssertSnapshot(composerVC) } + func test_channelWithSlowModeActive_messageIsSent_SkipSlowModeIsOnWithCountdownShown() { + let channel = ChatChannel.mock(cid: .unique, ownCapabilities: [.skipSlowMode, .sendMessage], cooldownDuration: 10) + mockedChatChannelController.channel_mock = channel + composerVC.channelController = mockedChatChannelController + composerVC.appearance = Appearance.default + composerVC.publishMessage(sender: UIButton()) + composerVC.content.text = "Test text" + composerVC.composerView.inputMessageView.textView.placeholderLabel.isHidden = true + + AssertSnapshot(composerVC, variants: [.defaultLight]) + } + func test_didUpdateMessages_startsCooldown() { let mockedCooldownTracker = CooldownTracker_Mock(timer: ScheduledStreamTimer_Mock()) composerVC.cooldownTracker = mockedCooldownTracker diff --git a/Tests/StreamChatUITests/SnapshotTests/Composer/__Snapshots__/ComposerVC_Tests/test_channelWithSlowModeActive_messageIsSent_SkipSlowModeIsOnWithCountdownShown.default-light.png b/Tests/StreamChatUITests/SnapshotTests/Composer/__Snapshots__/ComposerVC_Tests/test_channelWithSlowModeActive_messageIsSent_SkipSlowModeIsOnWithCountdownShown.default-light.png new file mode 100644 index 00000000000..af0fdfead06 Binary files /dev/null and b/Tests/StreamChatUITests/SnapshotTests/Composer/__Snapshots__/ComposerVC_Tests/test_channelWithSlowModeActive_messageIsSent_SkipSlowModeIsOnWithCountdownShown.default-light.png differ