From ab926e67bd9152625cd5fd761034950f4680c27b Mon Sep 17 00:00:00 2001 From: martinmitrevski Date: Sun, 26 Nov 2023 23:31:10 +0100 Subject: [PATCH] Small updates --- CHANGELOG.md | 5 +++ .../ChatChannel/ChatChannelDataSource.swift | 7 +++++ .../ChatChannel/ChatChannelView.swift | 4 +-- .../ChatChannel/ChatChannelViewModel.swift | 13 ++++---- .../Utils/MessageCachingUtils.swift | 1 + .../ChatChannelDataSource_Tests.swift | 31 +++++++++++++++++++ 6 files changed, 52 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f0181464..fec6e9b8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). # Upcoming +### ✅ Added +- Jump to a message that is not on the first page +- Jump to a message in a thread +- Bi-directional scrolling of the message list + ### 🐞 Fixed - Some links not being rendered correctly diff --git a/Sources/StreamChatSwiftUI/ChatChannel/ChatChannelDataSource.swift b/Sources/StreamChatSwiftUI/ChatChannel/ChatChannelDataSource.swift index 699be412..c0841664 100644 --- a/Sources/StreamChatSwiftUI/ChatChannel/ChatChannelDataSource.swift +++ b/Sources/StreamChatSwiftUI/ChatChannel/ChatChannelDataSource.swift @@ -71,6 +71,8 @@ protocol ChannelDataSource: AnyObject { completion: ((Error?) -> Void)? ) + /// Loads the first page of the channel. + /// - Parameter completion: called when the initial page is loaded. func loadFirstPage(_ completion: ((_ error: Error?) -> Void)?) } @@ -79,9 +81,11 @@ class ChatChannelDataSource: ChannelDataSource, ChatChannelControllerDelegate { let controller: ChatChannelController weak var delegate: MessagesDataSource? + var messages: LazyCachedMapCollection { controller.messages } + var hasLoadedAllNextMessages: Bool { controller.hasLoadedAllNextMessages } @@ -146,10 +150,13 @@ class MessageThreadDataSource: ChannelDataSource, ChatMessageControllerDelegate let channelController: ChatChannelController let messageController: ChatMessageController + weak var delegate: MessagesDataSource? + var messages: LazyCachedMapCollection { messageController.replies } + var hasLoadedAllNextMessages: Bool { messageController.hasLoadedAllNextReplies } diff --git a/Sources/StreamChatSwiftUI/ChatChannel/ChatChannelView.swift b/Sources/StreamChatSwiftUI/ChatChannel/ChatChannelView.swift index 52f739b0..0647ad9a 100644 --- a/Sources/StreamChatSwiftUI/ChatChannel/ChatChannelView.swift +++ b/Sources/StreamChatSwiftUI/ChatChannel/ChatChannelView.swift @@ -54,8 +54,8 @@ public struct ChatChannelView: View, KeyboardReadable { currentDateString: viewModel.currentDateString, listId: viewModel.listId, isMessageThread: viewModel.isMessageThread, - shouldShowTypingIndicator: viewModel.shouldShowTypingIndicator, - scrollPosition: $viewModel.scrollPosition, + shouldShowTypingIndicator: viewModel.shouldShowTypingIndicator, + scrollPosition: $viewModel.scrollPosition, loadingNextMessages: viewModel.loadingNextMessages, onMessageAppear: viewModel.handleMessageAppear(index:scrollDirection:), onScrollToBottom: viewModel.scrollToLastMessage, diff --git a/Sources/StreamChatSwiftUI/ChatChannel/ChatChannelViewModel.swift b/Sources/StreamChatSwiftUI/ChatChannel/ChatChannelViewModel.swift index a114f624..56d86304 100644 --- a/Sources/StreamChatSwiftUI/ChatChannel/ChatChannelViewModel.swift +++ b/Sources/StreamChatSwiftUI/ChatChannel/ChatChannelViewModel.swift @@ -25,6 +25,7 @@ open class ChatChannelViewModel: ObservableObject, MessagesDataSource { return 5 } }() + private var timer: Timer? private var currentDate: Date? { didSet { @@ -106,7 +107,7 @@ open class ChatChannelViewModel: ObservableObject, MessagesDataSource { @Published public var shouldShowTypingIndicator = false @Published public var scrollPosition: String? - @Published public private(set)var loadingNextMessages: Bool = false + @Published public private(set) var loadingNextMessages: Bool = false public var channel: ChatChannel? { channelController.channel @@ -140,9 +141,7 @@ open class ChatChannelViewModel: ObservableObject, MessagesDataSource { messages = channelDataSource.messages DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { [weak self] in - if let scrollToMessage, - let parentMessageId = scrollToMessage.parentMessageId, - messageController == nil { + if let scrollToMessage, let parentMessageId = scrollToMessage.parentMessageId, messageController == nil { let message = channelController.dataStore.message(id: parentMessageId) self?.threadMessage = message self?.threadMessageShown = true @@ -206,7 +205,7 @@ open class ChatChannelViewModel: ObservableObject, MessagesDataSource { if channelDataSource.hasLoadedAllNextMessages { updateScrolledIdToNewestMessage() } else { - channelDataSource.loadFirstPage { [weak self] error in + channelDataSource.loadFirstPage { [weak self] _ in self?.scrolledId = self?.messages.first?.messageId } } @@ -424,8 +423,8 @@ open class ChatChannelViewModel: ObservableObject, MessagesDataSource { } loadingNextMessages = true - if scrollPosition != self.messages.first?.messageId { - scrollPosition = self.messages[index].messageId + if scrollPosition != messages.first?.messageId { + scrollPosition = messages[index].messageId } channelDataSource.loadNextMessages(limit: newerMessagesLimit) { [weak self] _ in diff --git a/Sources/StreamChatSwiftUI/Utils/MessageCachingUtils.swift b/Sources/StreamChatSwiftUI/Utils/MessageCachingUtils.swift index ce7a87d8..f6fbd2d3 100644 --- a/Sources/StreamChatSwiftUI/Utils/MessageCachingUtils.swift +++ b/Sources/StreamChatSwiftUI/Utils/MessageCachingUtils.swift @@ -24,6 +24,7 @@ class MessageCachingUtils { } } } + var jumpToReplyId: String? func authorId(for message: ChatMessage) -> String { diff --git a/StreamChatSwiftUITests/Tests/ChatChannel/ChatChannelDataSource_Tests.swift b/StreamChatSwiftUITests/Tests/ChatChannel/ChatChannelDataSource_Tests.swift index f2a00075..b001d1ce 100644 --- a/StreamChatSwiftUITests/Tests/ChatChannel/ChatChannelDataSource_Tests.swift +++ b/StreamChatSwiftUITests/Tests/ChatChannel/ChatChannelDataSource_Tests.swift @@ -81,6 +81,37 @@ class ChatChannelDataSource_Tests: StreamChatTestCase { XCTAssert(channelCall == true) XCTAssert(noChannelCall == false) } + + func test_channelDataSource_hasLoadedAllNextMessages() { + // Given + let expected: [ChatMessage] = [message] + let channelDataSource = makeChannelDataSource(messages: expected) + + // When + let messages = channelDataSource.messages + channelDataSource.loadFirstPage(nil) + + // Then + XCTAssert(messages[0] == expected[0]) + XCTAssert(messages.count == expected.count) + XCTAssert(channelDataSource.hasLoadedAllNextMessages == true) + } + + func test_channelDataSource_loadPageAroundMessageId() { + // Given + let handler = MockMessagesDataSourceHandler() + let expected: [ChatMessage] = [message] + let controller = makeChannelController(messages: expected) + let channelDataSource = ChatChannelDataSource(controller: controller) + channelDataSource.delegate = handler + + // When + channelDataSource.loadPageAroundMessageId(.unique, completion: nil) + let loadPageCall = controller.loadPageAroundMessageIdCallCount + + // Then + XCTAssert(loadPageCall == 1) + } func test_messageThreadDataSource_messages() { // Given