diff --git a/CHANGELOG.md b/CHANGELOG.md index 5964df96723..398ba929e03 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ _November 17, 2023_ ### 🐞 Fixed - Fix Message List UI not updated when message.updatedAt changes [#2884](https://github.com/GetStream/stream-chat-swift/pull/2884) - Fix jump to unread button showing "0" unread counts [#2894](https://github.com/GetStream/stream-chat-swift/pull/2894) +- Fix not able to mark channel read when isJumpToUnread is disabled [#2902](https://github.com/GetStream/stream-chat-swift/pull/2902) # [4.42.0](https://github.com/GetStream/stream-chat-swift/releases/tag/4.42.0) _November 14, 2023_ diff --git a/Sources/StreamChatUI/ChatChannel/ChatChannelVC.swift b/Sources/StreamChatUI/ChatChannel/ChatChannelVC.swift index 902e28b130c..ac1047dc327 100644 --- a/Sources/StreamChatUI/ChatChannel/ChatChannelVC.swift +++ b/Sources/StreamChatUI/ChatChannel/ChatChannelVC.swift @@ -91,7 +91,11 @@ open class ChatChannelVC: _ViewController, return false } - return isLastMessageVisibleOrSeen && hasSeenFirstUnreadMessage && channelController.hasLoadedAllNextMessages && !hasMarkedMessageAsUnread + guard components.isJumpToUnreadEnabled else { + return isLastMessageFullyVisible && isFirstPageLoaded + } + + return isLastMessageVisibleOrSeen && hasSeenFirstUnreadMessage && isFirstPageLoaded && !hasMarkedMessageAsUnread } private var isLastMessageVisibleOrSeen: Bool { diff --git a/Tests/StreamChatUITests/SnapshotTests/ChatChannel/ChatChannelVC_Tests.swift b/Tests/StreamChatUITests/SnapshotTests/ChatChannel/ChatChannelVC_Tests.swift index bda4276a703..799784ccfde 100644 --- a/Tests/StreamChatUITests/SnapshotTests/ChatChannel/ChatChannelVC_Tests.swift +++ b/Tests/StreamChatUITests/SnapshotTests/ChatChannel/ChatChannelVC_Tests.swift @@ -760,9 +760,22 @@ final class ChatChannelVC_Tests: XCTestCase { // MARK: Channel read - func test_shouldMarkChannelRead_viewIsVisible_remoteDataFetched_lastMessageVisible_hasLoadedAllNextMessages_hasNotMarkedMessageAsUnread_shouldReturnTrue() { + func test_shouldMarkChannelRead_jumpToUnreadDisabled_viewIsVisible_remoteDataFetched_lastMessageVisible_hasLoadedAllNextMessages_hasNotMarkedMessageAsUnread_shouldReturnTrue() { let mockedListView = makeMockMessageListView() vc.isViewVisible = { _ in true } + vc.components.isJumpToUnreadEnabled = false + channelControllerMock.state_mock = .remoteDataFetched + mockedListView.mockIsLastCellFullyVisible = true + channelControllerMock.hasLoadedAllNextMessages_mock = true + channelControllerMock.markedAsUnread_mock = false + + XCTAssertTrue(vc.shouldMarkChannelRead) + } + + func test_shouldMarkChannelRead_jumpToUnreadEnabled_viewIsVisible_remoteDataFetched_lastMessageVisible_hasLoadedAllNextMessages_hasNotMarkedMessageAsUnread_shouldReturnTrue() { + let mockedListView = makeMockMessageListView() + vc.isViewVisible = { _ in true } + vc.components.isJumpToUnreadEnabled = true channelControllerMock.state_mock = .remoteDataFetched mockedListView.mockIsLastCellFullyVisible = true channelControllerMock.hasLoadedAllNextMessages_mock = true @@ -775,6 +788,18 @@ final class ChatChannelVC_Tests: XCTestCase { XCTAssertTrue(vc.shouldMarkChannelRead) } + func test_shouldMarkChannelRead_jumpToUnreadEnabled_whenNotSeenLastMessage_whenNotSeenFirstUnreadMessage_shouldReturnFalse() { + let mockedListView = makeMockMessageListView() + vc.isViewVisible = { _ in true } + vc.components.isJumpToUnreadEnabled = true + channelControllerMock.state_mock = .remoteDataFetched + mockedListView.mockIsLastCellFullyVisible = true + channelControllerMock.hasLoadedAllNextMessages_mock = true + channelControllerMock.markedAsUnread_mock = false + + XCTAssertFalse(vc.shouldMarkChannelRead) + } + func test_shouldMarkChannelRead_viewIsNotVisible_remoteDataNotFetched_lastMessageNotVisible_hasNotLoadedAllNextMessages_hasMarkedMessageAsUnread_shouldReturnFalse() { let mockedListView = makeMockMessageListView() vc.isViewVisible = { _ in false } @@ -789,10 +814,15 @@ final class ChatChannelVC_Tests: XCTestCase { XCTAssertFalse(vc.shouldMarkChannelRead) } - func test_shouldMarkChannelRead_otherCombinations_shouldReturnFalse() { + func test_shouldMarkChannelRead_whenJumpToUnreadDisabled_otherCombinations_shouldReturnFalse() { struct MarkUnreadStatePreconditions { - let isViewVisible: Bool, state: DataController.State, isLastCellFullyVisible: Bool, hasLoadedAllNextMessages: Bool, markedAsUnread: Bool + let isViewVisible: Bool + let state: DataController.State + let isLastCellFullyVisible: Bool + let hasLoadedAllNextMessages: Bool + let markedAsUnread: Bool } + let options: [MarkUnreadStatePreconditions] = [ .init(isViewVisible: false, state: .remoteDataFetched, isLastCellFullyVisible: true, hasLoadedAllNextMessages: true, markedAsUnread: false), .init(isViewVisible: true, state: .initialized, isLastCellFullyVisible: true, hasLoadedAllNextMessages: true, markedAsUnread: false), @@ -806,9 +836,10 @@ final class ChatChannelVC_Tests: XCTestCase { let vc = ChatChannelVC() vc.isViewVisible = { _ in true } vc.components = self.vc.components + vc.components.isJumpToUnreadEnabled = true vc.channelController = self.vc.channelController - let mockedListView = makeMockMessageListView() + let mockedListView = makeMockMessageListView(channelVC: vc) vc.isViewVisible = { _ in option.isViewVisible } channelControllerMock.state_mock = option.state mockedListView.mockIsLastCellFullyVisible = option.isLastCellFullyVisible @@ -818,9 +849,44 @@ final class ChatChannelVC_Tests: XCTestCase { // Simulate display to update hasSeenLastMessage vc.chatMessageListVC(ChatMessageListVC_Mock(), willDisplayMessageAt: IndexPath(item: 0, section: 0)) + if vc.shouldMarkChannelRead { + debugPrint(option) + } XCTAssertFalse(vc.shouldMarkChannelRead) } } + + func test_shouldMarkChannelRead_whenJumpToUnreadDisabled_whenMarkedAsUnreadTrueOrFalse_shouldReturnTrue() { + struct MarkUnreadStatePreconditions { + let isViewVisible: Bool + let state: DataController.State + let isLastCellFullyVisible: Bool + let hasLoadedAllNextMessages: Bool + let markedAsUnread: Bool + } + + let options: [MarkUnreadStatePreconditions] = [ + .init(isViewVisible: true, state: .remoteDataFetched, isLastCellFullyVisible: true, hasLoadedAllNextMessages: true, markedAsUnread: false), + .init(isViewVisible: true, state: .remoteDataFetched, isLastCellFullyVisible: true, hasLoadedAllNextMessages: true, markedAsUnread: true) + ] + + options.forEach { option in + let vc = ChatChannelVC() + vc.isViewVisible = { _ in true } + vc.components = self.vc.components + vc.components.isJumpToUnreadEnabled = false + vc.channelController = self.vc.channelController + + let mockedListView = makeMockMessageListView(channelVC: vc) + vc.isViewVisible = { _ in option.isViewVisible } + channelControllerMock.state_mock = option.state + mockedListView.mockIsLastCellFullyVisible = option.isLastCellFullyVisible + channelControllerMock.hasLoadedAllNextMessages_mock = option.hasLoadedAllNextMessages + channelControllerMock.markedAsUnread_mock = option.markedAsUnread + + XCTAssertTrue(vc.shouldMarkChannelRead) + } + } func test_viewDidAppear_whenShouldMarkChannelRead_thenMarkRead() { let mockedListView = makeMockMessageListView() @@ -1300,7 +1366,8 @@ private extension ChatChannelVC_Tests { ) } - func makeMockMessageListView() -> ChatMessageListView_Mock { + func makeMockMessageListView(channelVC: ChatChannelVC? = nil) -> ChatMessageListView_Mock { + let vc = channelVC ?? self.vc! vc.messageListVC.components.messageListView = ChatMessageListView_Mock.self return vc.messageListVC.listView as! ChatMessageListView_Mock }