From 09caca9ca61a4d516e1d95c0fda46e5b9cd57a11 Mon Sep 17 00:00:00 2001 From: Kai Lee Date: Wed, 25 Jun 2025 14:50:28 +0900 Subject: [PATCH 1/3] Refactors message fetching on reconnection --- .../OpenChannelMessageListUseCase.swift | 52 ++++++------------- 1 file changed, 17 insertions(+), 35 deletions(-) diff --git a/Modules/CommonModule/Sources/UseCase/OpenChannel/OpenChannelMessageListUseCase.swift b/Modules/CommonModule/Sources/UseCase/OpenChannel/OpenChannelMessageListUseCase.swift index 1312c4d..05421cf 100644 --- a/Modules/CommonModule/Sources/UseCase/OpenChannel/OpenChannelMessageListUseCase.swift +++ b/Modules/CommonModule/Sources/UseCase/OpenChannel/OpenChannelMessageListUseCase.swift @@ -242,49 +242,31 @@ extension OpenChannelMessageListUseCase: BaseChannelDelegate, OpenChannelDelegat // MARK: - ConnectionDelegate extension OpenChannelMessageListUseCase: ConnectionDelegate { - open func didSucceedReconnection() { hasNextMessages = true - - guard let timestamp = messages.last?.createdAt else { - return - } - - fetchChangeLogs(sinceTimestamp: timestamp) + fetchMessagesOnReconnect(sinceTimestamp: .max) } - private func fetchChangeLogs(sinceTimestamp timestamp: Int64) { - let params = MessageChangeLogsParams() + private func fetchMessagesOnReconnect(sinceTimestamp timestamp: Int64) { + let params = MessageListParams() + params.isInclusive = true + params.previousResultSize = Constant.previousResultSize - channel.getMessageChangeLogs(timestamp: timestamp, params: params) { [weak self] updatedMessages, deletedMessageIds, hasMore, token, error in - guard error == nil else { return } + channel.getMessagesByTimestamp(timestamp, params: params) { [weak self] messages, error in + guard let self = self else { return } - self?.handleChangeLogs(updatedMessages: updatedMessages, deletedMessageIds: deletedMessageIds, hasMore: hasMore, token: token) - } - } - - private func fetchChangeLogs(sinceToken token: String) { - let params = MessageChangeLogsParams() - - channel.getMessageChangeLogs(token: token, params: params) { [weak self] updatedMessages, deletedMessageIds, hasMore, token, error in - guard error == nil else { return } + if let error = error { + self.delegate?.openChannelMessageListUseCase(self, didReceiveError: error) + return + } - self?.handleChangeLogs(updatedMessages: updatedMessages, deletedMessageIds: deletedMessageIds, hasMore: hasMore, token: token) - } - } - - private func handleChangeLogs(updatedMessages: [BaseMessage]?, deletedMessageIds: [Int64]?, hasMore: Bool, token: String?) { - if let updatedMessages = updatedMessages { - replaceMessages(updatedMessages) - } - - if let deletedMessageIds = deletedMessageIds { - deleteMessages(byMessageIds: deletedMessageIds) - } - - if hasMore, let token = token { - fetchChangeLogs(sinceToken: token) + guard let messages = messages else { return } + + self.hasPreviousMessages = messages.count >= Constant.previousResultSize + self.messages = messages + self.delegate?.openChannelMessageListUseCase(self, didUpdateMessages: self.messages) } } } + From f1e60f0aaffd7dc048722f885b8d7e751393af70 Mon Sep 17 00:00:00 2001 From: Kai Lee Date: Wed, 25 Jun 2025 14:53:40 +0900 Subject: [PATCH 2/3] Improves message scrolling on channel load --- .../Channel/OpenChannelViewController.swift | 27 +++++++++++++++---- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/Apps/BasicOpenChannel/Sources/Channel/OpenChannelViewController.swift b/Apps/BasicOpenChannel/Sources/Channel/OpenChannelViewController.swift index 1d9a895..271a083 100644 --- a/Apps/BasicOpenChannel/Sources/Channel/OpenChannelViewController.swift +++ b/Apps/BasicOpenChannel/Sources/Channel/OpenChannelViewController.swift @@ -37,6 +37,7 @@ class OpenChannelViewController: UIViewController { private weak var messageInputBottomConstraint: NSLayoutConstraint? var targetMessageForScrolling: BaseMessage? + private var isInitialLoad = true let channel: OpenChannel @@ -169,6 +170,11 @@ extension OpenChannelViewController: UITableViewDelegate { func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) { if scrollView.contentOffset.y - Constant.loadMoreThreshold <= 0 { + if let visibleIndexPaths = tableView.indexPathsForVisibleRows, + let firstVisibleIndexPath = visibleIndexPaths.first, + firstVisibleIndexPath.row < messageListUseCase.messages.count { + targetMessageForScrolling = messageListUseCase.messages[firstVisibleIndexPath.row] + } messageListUseCase.loadPreviousMessages() } @@ -199,18 +205,29 @@ extension OpenChannelViewController: OpenChannelMessageListUseCaseDelegate { func openChannelMessageListUseCase(_ useCase: OpenChannelMessageListUseCase, didUpdateMessages messages: [BaseMessage]) { tableView.reloadData() + if isInitialLoad && !messages.isEmpty { + targetMessageForScrolling = messages.last + isInitialLoad = false + } scrollToFocusMessage() } - private func scrollToFocusMessage() { + private func scrollToFocusMessage() { defer { self.targetMessageForScrolling = nil } - guard let focusMessage = targetMessageForScrolling, - focusMessage.messageId == messageListUseCase.messages.last?.messageId else { return } + guard + let focusMessage = targetMessageForScrolling, + let messageIndex = messageListUseCase.messages.firstIndex(where: { $0.messageId == focusMessage.messageId }) + else { + return + } - let focusMessageIndexPath = IndexPath(row: messageListUseCase.messages.count - 1, section: 0) + let focusMessageIndexPath = IndexPath(row: messageIndex, section: 0) + let scrollPosition: UITableView.ScrollPosition = ( + messageIndex == messageListUseCase.messages.count - 1 + ) ? .bottom : .top - tableView.scrollToRow(at: focusMessageIndexPath, at: .bottom, animated: false) + tableView.scrollToRow(at: focusMessageIndexPath, at: scrollPosition, animated: false) } } From 9081f7269eb2a319af9b54bfd40b6ab1ab3380a8 Mon Sep 17 00:00:00 2001 From: Kai Lee Date: Wed, 25 Jun 2025 15:57:53 +0900 Subject: [PATCH 3/3] Improves message scrolling in other open channel projects --- .../Channel/OpenChannelViewController.swift | 22 +++++++++++++++---- .../Channel/OpenChannelViewController.swift | 22 +++++++++++++++---- .../Channel/OpenChannelViewController.swift | 22 +++++++++++++++---- ...nChannelPinnedMessagesViewController.swift | 22 +++++++++++++++---- .../Channel/OpenChannelViewController.swift | 22 +++++++++++++++---- .../Channel/OpenChannelViewController.swift | 22 +++++++++++++++---- .../Channel/OpenChannelViewController.swift | 22 +++++++++++++++---- .../Channel/OpenChannelViewController.swift | 22 +++++++++++++++---- .../Channel/OpenChannelViewController.swift | 22 +++++++++++++++---- .../Channel/OpenChannelViewController.swift | 22 +++++++++++++++---- .../Channel/OpenChannelViewController.swift | 22 +++++++++++++++---- .../Channel/OpenChannelViewController.swift | 22 +++++++++++++++---- .../Channel/OpenChannelViewController.swift | 22 +++++++++++++++---- .../Channel/OpenChannelViewController.swift | 21 +++++++++++++++--- .../Channel/OpenChannelViewController.swift | 21 +++++++++++++++--- 15 files changed, 270 insertions(+), 58 deletions(-) diff --git a/Apps/AddExtraDataMessageOpenChannel/Sources/Channel/OpenChannelViewController.swift b/Apps/AddExtraDataMessageOpenChannel/Sources/Channel/OpenChannelViewController.swift index 3c656c8..0a3c2a6 100644 --- a/Apps/AddExtraDataMessageOpenChannel/Sources/Channel/OpenChannelViewController.swift +++ b/Apps/AddExtraDataMessageOpenChannel/Sources/Channel/OpenChannelViewController.swift @@ -37,6 +37,7 @@ class OpenChannelViewController: UIViewController { private weak var messageInputBottomConstraint: NSLayoutConstraint? var targetMessageForScrolling: BaseMessage? + private var isInitialLoad = true let channel: OpenChannel @@ -171,6 +172,11 @@ extension OpenChannelViewController: UITableViewDelegate { func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) { if scrollView.contentOffset.y - Constant.loadMoreThreshold <= 0 { + if let visibleIndexPaths = tableView.indexPathsForVisibleRows, + let firstVisibleIndexPath = visibleIndexPaths.first, + firstVisibleIndexPath.row < messageListUseCase.messages.count { + targetMessageForScrolling = messageListUseCase.messages[firstVisibleIndexPath.row] + } messageListUseCase.loadPreviousMessages() } @@ -201,18 +207,26 @@ extension OpenChannelViewController: OpenChannelMessageListUseCaseDelegate { func openChannelMessageListUseCase(_ useCase: OpenChannelMessageListUseCase, didUpdateMessages messages: [BaseMessage]) { tableView.reloadData() + if isInitialLoad && !messages.isEmpty { + targetMessageForScrolling = messages.last + isInitialLoad = false + } scrollToFocusMessage() } private func scrollToFocusMessage() { defer { self.targetMessageForScrolling = nil } - guard let focusMessage = targetMessageForScrolling, - focusMessage.messageId == messageListUseCase.messages.last?.messageId else { return } + guard let focusMessage = targetMessageForScrolling else { return } + + guard let messageIndex = messageListUseCase.messages.firstIndex(where: { + $0.messageId == focusMessage.messageId || $0.requestId == focusMessage.requestId + }) else { return } - let focusMessageIndexPath = IndexPath(row: messageListUseCase.messages.count - 1, section: 0) + let focusMessageIndexPath = IndexPath(row: messageIndex, section: 0) - tableView.scrollToRow(at: focusMessageIndexPath, at: .bottom, animated: false) + let scrollPosition: UITableView.ScrollPosition = (messageIndex == messageListUseCase.messages.count - 1) ? .bottom : .top + tableView.scrollToRow(at: focusMessageIndexPath, at: scrollPosition, animated: false) } } diff --git a/Apps/AddStructuredDataMessageOpenChannel/Sources/Channel/OpenChannelViewController.swift b/Apps/AddStructuredDataMessageOpenChannel/Sources/Channel/OpenChannelViewController.swift index 98dbb55..035b441 100644 --- a/Apps/AddStructuredDataMessageOpenChannel/Sources/Channel/OpenChannelViewController.swift +++ b/Apps/AddStructuredDataMessageOpenChannel/Sources/Channel/OpenChannelViewController.swift @@ -37,6 +37,7 @@ class OpenChannelViewController: UIViewController { private weak var messageInputBottomConstraint: NSLayoutConstraint? var targetMessageForScrolling: BaseMessage? + private var isInitialLoad = true let channel: OpenChannel @@ -169,6 +170,11 @@ extension OpenChannelViewController: UITableViewDelegate { func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) { if scrollView.contentOffset.y - Constant.loadMoreThreshold <= 0 { + if let visibleIndexPaths = tableView.indexPathsForVisibleRows, + let firstVisibleIndexPath = visibleIndexPaths.first, + firstVisibleIndexPath.row < messageListUseCase.messages.count { + targetMessageForScrolling = messageListUseCase.messages[firstVisibleIndexPath.row] + } messageListUseCase.loadPreviousMessages() } @@ -199,18 +205,26 @@ extension OpenChannelViewController: OpenChannelMessageListUseCaseDelegate { func openChannelMessageListUseCase(_ useCase: OpenChannelMessageListUseCase, didUpdateMessages messages: [BaseMessage]) { tableView.reloadData() + if isInitialLoad && !messages.isEmpty { + targetMessageForScrolling = messages.last + isInitialLoad = false + } scrollToFocusMessage() } private func scrollToFocusMessage() { defer { self.targetMessageForScrolling = nil } - guard let focusMessage = targetMessageForScrolling, - focusMessage.messageId == messageListUseCase.messages.last?.messageId else { return } + guard let focusMessage = targetMessageForScrolling else { return } + + guard let messageIndex = messageListUseCase.messages.firstIndex(where: { + $0.messageId == focusMessage.messageId || $0.requestId == focusMessage.requestId + }) else { return } - let focusMessageIndexPath = IndexPath(row: messageListUseCase.messages.count - 1, section: 0) + let focusMessageIndexPath = IndexPath(row: messageIndex, section: 0) - tableView.scrollToRow(at: focusMessageIndexPath, at: .bottom, animated: false) + let scrollPosition: UITableView.ScrollPosition = (messageIndex == messageListUseCase.messages.count - 1) ? .bottom : .top + tableView.scrollToRow(at: focusMessageIndexPath, at: scrollPosition, animated: false) } } diff --git a/Apps/CategorizeMessageOpenChannel/Sources/Channel/OpenChannelViewController.swift b/Apps/CategorizeMessageOpenChannel/Sources/Channel/OpenChannelViewController.swift index f1ee1c3..d13d67c 100644 --- a/Apps/CategorizeMessageOpenChannel/Sources/Channel/OpenChannelViewController.swift +++ b/Apps/CategorizeMessageOpenChannel/Sources/Channel/OpenChannelViewController.swift @@ -37,6 +37,7 @@ class OpenChannelViewController: UIViewController { private weak var messageInputBottomConstraint: NSLayoutConstraint? var targetMessageForScrolling: BaseMessage? + private var isInitialLoad = true let channel: OpenChannel @@ -169,6 +170,11 @@ extension OpenChannelViewController: UITableViewDelegate { func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) { if scrollView.contentOffset.y - Constant.loadMoreThreshold <= 0 { + if let visibleIndexPaths = tableView.indexPathsForVisibleRows, + let firstVisibleIndexPath = visibleIndexPaths.first, + firstVisibleIndexPath.row < messageListUseCase.messages.count { + targetMessageForScrolling = messageListUseCase.messages[firstVisibleIndexPath.row] + } messageListUseCase.loadPreviousMessages() } @@ -199,18 +205,26 @@ extension OpenChannelViewController: OpenChannelMessageListUseCaseDelegate { func openChannelMessageListUseCase(_ useCase: OpenChannelMessageListUseCase, didUpdateMessages messages: [BaseMessage]) { tableView.reloadData() + if isInitialLoad && !messages.isEmpty { + targetMessageForScrolling = messages.last + isInitialLoad = false + } scrollToFocusMessage() } private func scrollToFocusMessage() { defer { self.targetMessageForScrolling = nil } - guard let focusMessage = targetMessageForScrolling, - focusMessage.messageId == messageListUseCase.messages.last?.messageId else { return } + guard let focusMessage = targetMessageForScrolling else { return } + + guard let messageIndex = messageListUseCase.messages.firstIndex(where: { + $0.messageId == focusMessage.messageId || $0.requestId == focusMessage.requestId + }) else { return } - let focusMessageIndexPath = IndexPath(row: messageListUseCase.messages.count - 1, section: 0) + let focusMessageIndexPath = IndexPath(row: messageIndex, section: 0) - tableView.scrollToRow(at: focusMessageIndexPath, at: .bottom, animated: false) + let scrollPosition: UITableView.ScrollPosition = (messageIndex == messageListUseCase.messages.count - 1) ? .bottom : .top + tableView.scrollToRow(at: focusMessageIndexPath, at: scrollPosition, animated: false) } } diff --git a/Apps/CategorizeMessageOpenChannel/Sources/PinnedMessages/OpenChannelPinnedMessagesViewController.swift b/Apps/CategorizeMessageOpenChannel/Sources/PinnedMessages/OpenChannelPinnedMessagesViewController.swift index f261a36..2641398 100644 --- a/Apps/CategorizeMessageOpenChannel/Sources/PinnedMessages/OpenChannelPinnedMessagesViewController.swift +++ b/Apps/CategorizeMessageOpenChannel/Sources/PinnedMessages/OpenChannelPinnedMessagesViewController.swift @@ -27,6 +27,7 @@ class OpenChannelPinnedMessagesViewController: UIViewController { }() var targetMessageForScrolling: BaseMessage? + private var isInitialLoad = true let channel: OpenChannel @@ -103,6 +104,11 @@ extension OpenChannelPinnedMessagesViewController: UITableViewDelegate { func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) { if scrollView.contentOffset.y - Constant.loadMoreThreshold <= 0 { + if let visibleIndexPaths = tableView.indexPathsForVisibleRows, + let firstVisibleIndexPath = visibleIndexPaths.first, + firstVisibleIndexPath.row < messageListUseCase.messages.count { + targetMessageForScrolling = messageListUseCase.messages[firstVisibleIndexPath.row] + } messageListUseCase.loadPreviousMessages() } @@ -133,18 +139,26 @@ extension OpenChannelPinnedMessagesViewController: OpenChannelMessageListUseCase func openChannelMessageListUseCase(_ useCase: OpenChannelMessageListUseCase, didUpdateMessages messages: [BaseMessage]) { tableView.reloadData() + if isInitialLoad && !messages.isEmpty { + targetMessageForScrolling = messages.last + isInitialLoad = false + } scrollToFocusMessage() } private func scrollToFocusMessage() { defer { self.targetMessageForScrolling = nil } - guard let focusMessage = targetMessageForScrolling, - focusMessage.messageId == messageListUseCase.messages.last?.messageId else { return } + guard let focusMessage = targetMessageForScrolling else { return } + + guard let messageIndex = messageListUseCase.messages.firstIndex(where: { + $0.messageId == focusMessage.messageId || $0.requestId == focusMessage.requestId + }) else { return } - let focusMessageIndexPath = IndexPath(row: messageListUseCase.messages.count - 1, section: 0) + let focusMessageIndexPath = IndexPath(row: messageIndex, section: 0) - tableView.scrollToRow(at: focusMessageIndexPath, at: .bottom, animated: false) + let scrollPosition: UITableView.ScrollPosition = (messageIndex == messageListUseCase.messages.count - 1) ? .bottom : .top + tableView.scrollToRow(at: focusMessageIndexPath, at: scrollPosition, animated: false) } } diff --git a/Apps/CategorizeWithCustomTypeOpenChannel/Sources/Channel/OpenChannelViewController.swift b/Apps/CategorizeWithCustomTypeOpenChannel/Sources/Channel/OpenChannelViewController.swift index 1d9a895..4e76371 100644 --- a/Apps/CategorizeWithCustomTypeOpenChannel/Sources/Channel/OpenChannelViewController.swift +++ b/Apps/CategorizeWithCustomTypeOpenChannel/Sources/Channel/OpenChannelViewController.swift @@ -37,6 +37,7 @@ class OpenChannelViewController: UIViewController { private weak var messageInputBottomConstraint: NSLayoutConstraint? var targetMessageForScrolling: BaseMessage? + private var isInitialLoad = true let channel: OpenChannel @@ -169,6 +170,11 @@ extension OpenChannelViewController: UITableViewDelegate { func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) { if scrollView.contentOffset.y - Constant.loadMoreThreshold <= 0 { + if let visibleIndexPaths = tableView.indexPathsForVisibleRows, + let firstVisibleIndexPath = visibleIndexPaths.first, + firstVisibleIndexPath.row < messageListUseCase.messages.count { + targetMessageForScrolling = messageListUseCase.messages[firstVisibleIndexPath.row] + } messageListUseCase.loadPreviousMessages() } @@ -199,18 +205,26 @@ extension OpenChannelViewController: OpenChannelMessageListUseCaseDelegate { func openChannelMessageListUseCase(_ useCase: OpenChannelMessageListUseCase, didUpdateMessages messages: [BaseMessage]) { tableView.reloadData() + if isInitialLoad && !messages.isEmpty { + targetMessageForScrolling = messages.last + isInitialLoad = false + } scrollToFocusMessage() } private func scrollToFocusMessage() { defer { self.targetMessageForScrolling = nil } - guard let focusMessage = targetMessageForScrolling, - focusMessage.messageId == messageListUseCase.messages.last?.messageId else { return } + guard let focusMessage = targetMessageForScrolling else { return } + + guard let messageIndex = messageListUseCase.messages.firstIndex(where: { + $0.messageId == focusMessage.messageId || $0.requestId == focusMessage.requestId + }) else { return } - let focusMessageIndexPath = IndexPath(row: messageListUseCase.messages.count - 1, section: 0) + let focusMessageIndexPath = IndexPath(row: messageIndex, section: 0) - tableView.scrollToRow(at: focusMessageIndexPath, at: .bottom, animated: false) + let scrollPosition: UITableView.ScrollPosition = (messageIndex == messageListUseCase.messages.count - 1) ? .bottom : .top + tableView.scrollToRow(at: focusMessageIndexPath, at: scrollPosition, animated: false) } } diff --git a/Apps/CopyMessageOpenChannel/Sources/Channel/OpenChannelViewController.swift b/Apps/CopyMessageOpenChannel/Sources/Channel/OpenChannelViewController.swift index 911b7ac..d73bc10 100644 --- a/Apps/CopyMessageOpenChannel/Sources/Channel/OpenChannelViewController.swift +++ b/Apps/CopyMessageOpenChannel/Sources/Channel/OpenChannelViewController.swift @@ -37,6 +37,7 @@ class OpenChannelViewController: UIViewController { private weak var messageInputBottomConstraint: NSLayoutConstraint? var targetMessageForScrolling: BaseMessage? + private var isInitialLoad = true let channel: OpenChannel @@ -175,6 +176,11 @@ extension OpenChannelViewController: UITableViewDelegate { func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) { if scrollView.contentOffset.y - Constant.loadMoreThreshold <= 0 { + if let visibleIndexPaths = tableView.indexPathsForVisibleRows, + let firstVisibleIndexPath = visibleIndexPaths.first, + firstVisibleIndexPath.row < messageListUseCase.messages.count { + targetMessageForScrolling = messageListUseCase.messages[firstVisibleIndexPath.row] + } messageListUseCase.loadPreviousMessages() } @@ -232,18 +238,26 @@ extension OpenChannelViewController: OpenChannelMessageListUseCaseDelegate { func openChannelMessageListUseCase(_ useCase: OpenChannelMessageListUseCase, didUpdateMessages messages: [BaseMessage]) { tableView.reloadData() + if isInitialLoad && !messages.isEmpty { + targetMessageForScrolling = messages.last + isInitialLoad = false + } scrollToFocusMessage() } private func scrollToFocusMessage() { defer { self.targetMessageForScrolling = nil } - guard let focusMessage = targetMessageForScrolling, - focusMessage.messageId == messageListUseCase.messages.last?.messageId else { return } + guard let focusMessage = targetMessageForScrolling else { return } + + guard let messageIndex = messageListUseCase.messages.firstIndex(where: { + $0.messageId == focusMessage.messageId || $0.requestId == focusMessage.requestId + }) else { return } - let focusMessageIndexPath = IndexPath(row: messageListUseCase.messages.count - 1, section: 0) + let focusMessageIndexPath = IndexPath(row: messageIndex, section: 0) - tableView.scrollToRow(at: focusMessageIndexPath, at: .bottom, animated: false) + let scrollPosition: UITableView.ScrollPosition = (messageIndex == messageListUseCase.messages.count - 1) ? .bottom : .top + tableView.scrollToRow(at: focusMessageIndexPath, at: scrollPosition, animated: false) } } diff --git a/Apps/DeleteMessageOpenChannel/Sources/Channel/OpenChannelViewController.swift b/Apps/DeleteMessageOpenChannel/Sources/Channel/OpenChannelViewController.swift index dec9dbb..2293c8b 100644 --- a/Apps/DeleteMessageOpenChannel/Sources/Channel/OpenChannelViewController.swift +++ b/Apps/DeleteMessageOpenChannel/Sources/Channel/OpenChannelViewController.swift @@ -37,6 +37,7 @@ class OpenChannelViewController: UIViewController { private weak var messageInputBottomConstraint: NSLayoutConstraint? var targetMessageForScrolling: BaseMessage? + private var isInitialLoad = true let channel: OpenChannel @@ -171,6 +172,11 @@ extension OpenChannelViewController: UITableViewDelegate { func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) { if scrollView.contentOffset.y - Constant.loadMoreThreshold <= 0 { + if let visibleIndexPaths = tableView.indexPathsForVisibleRows, + let firstVisibleIndexPath = visibleIndexPaths.first, + firstVisibleIndexPath.row < messageListUseCase.messages.count { + targetMessageForScrolling = messageListUseCase.messages[firstVisibleIndexPath.row] + } messageListUseCase.loadPreviousMessages() } @@ -201,18 +207,26 @@ extension OpenChannelViewController: OpenChannelMessageListUseCaseDelegate { func openChannelMessageListUseCase(_ useCase: OpenChannelMessageListUseCase, didUpdateMessages messages: [BaseMessage]) { tableView.reloadData() + if isInitialLoad && !messages.isEmpty { + targetMessageForScrolling = messages.last + isInitialLoad = false + } scrollToFocusMessage() } private func scrollToFocusMessage() { defer { self.targetMessageForScrolling = nil } - guard let focusMessage = targetMessageForScrolling, - focusMessage.messageId == messageListUseCase.messages.last?.messageId else { return } + guard let focusMessage = targetMessageForScrolling else { return } + + guard let messageIndex = messageListUseCase.messages.firstIndex(where: { + $0.messageId == focusMessage.messageId || $0.requestId == focusMessage.requestId + }) else { return } - let focusMessageIndexPath = IndexPath(row: messageListUseCase.messages.count - 1, section: 0) + let focusMessageIndexPath = IndexPath(row: messageIndex, section: 0) - tableView.scrollToRow(at: focusMessageIndexPath, at: .bottom, animated: false) + let scrollPosition: UITableView.ScrollPosition = (messageIndex == messageListUseCase.messages.count - 1) ? .bottom : .top + tableView.scrollToRow(at: focusMessageIndexPath, at: scrollPosition, animated: false) } } diff --git a/Apps/GenerateThumbnailForFileOpenChannel/Sources/Channel/OpenChannelViewController.swift b/Apps/GenerateThumbnailForFileOpenChannel/Sources/Channel/OpenChannelViewController.swift index 01d341a..2877d23 100644 --- a/Apps/GenerateThumbnailForFileOpenChannel/Sources/Channel/OpenChannelViewController.swift +++ b/Apps/GenerateThumbnailForFileOpenChannel/Sources/Channel/OpenChannelViewController.swift @@ -37,6 +37,7 @@ class OpenChannelViewController: UIViewController { private weak var messageInputBottomConstraint: NSLayoutConstraint? var targetMessageForScrolling: BaseMessage? + private var isInitialLoad = true let channel: OpenChannel @@ -169,6 +170,11 @@ extension OpenChannelViewController: UITableViewDelegate { func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) { if scrollView.contentOffset.y - Constant.loadMoreThreshold <= 0 { + if let visibleIndexPaths = tableView.indexPathsForVisibleRows, + let firstVisibleIndexPath = visibleIndexPaths.first, + firstVisibleIndexPath.row < messageListUseCase.messages.count { + targetMessageForScrolling = messageListUseCase.messages[firstVisibleIndexPath.row] + } messageListUseCase.loadPreviousMessages() } @@ -199,18 +205,26 @@ extension OpenChannelViewController: OpenChannelMessageListUseCaseDelegate { func openChannelMessageListUseCase(_ useCase: OpenChannelMessageListUseCase, didUpdateMessages messages: [BaseMessage]) { tableView.reloadData() + if isInitialLoad && !messages.isEmpty { + targetMessageForScrolling = messages.last + isInitialLoad = false + } scrollToFocusMessage() } private func scrollToFocusMessage() { defer { self.targetMessageForScrolling = nil } - guard let focusMessage = targetMessageForScrolling, - focusMessage.messageId == messageListUseCase.messages.last?.messageId else { return } + guard let focusMessage = targetMessageForScrolling else { return } + + guard let messageIndex = messageListUseCase.messages.firstIndex(where: { + $0.messageId == focusMessage.messageId || $0.requestId == focusMessage.requestId + }) else { return } - let focusMessageIndexPath = IndexPath(row: messageListUseCase.messages.count - 1, section: 0) + let focusMessageIndexPath = IndexPath(row: messageIndex, section: 0) - tableView.scrollToRow(at: focusMessageIndexPath, at: .bottom, animated: false) + let scrollPosition: UITableView.ScrollPosition = (messageIndex == messageListUseCase.messages.count - 1) ? .bottom : .top + tableView.scrollToRow(at: focusMessageIndexPath, at: scrollPosition, animated: false) } } diff --git a/Apps/MentionUsersInMessageOpenChannel/Sources/Channel/OpenChannelViewController.swift b/Apps/MentionUsersInMessageOpenChannel/Sources/Channel/OpenChannelViewController.swift index c078525..0908132 100644 --- a/Apps/MentionUsersInMessageOpenChannel/Sources/Channel/OpenChannelViewController.swift +++ b/Apps/MentionUsersInMessageOpenChannel/Sources/Channel/OpenChannelViewController.swift @@ -37,6 +37,7 @@ class OpenChannelViewController: UIViewController { private weak var messageInputBottomConstraint: NSLayoutConstraint? var targetMessageForScrolling: BaseMessage? + private var isInitialLoad = true let channel: OpenChannel @@ -171,6 +172,11 @@ extension OpenChannelViewController: UITableViewDelegate { func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) { if scrollView.contentOffset.y - Constant.loadMoreThreshold <= 0 { + if let visibleIndexPaths = tableView.indexPathsForVisibleRows, + let firstVisibleIndexPath = visibleIndexPaths.first, + firstVisibleIndexPath.row < messageListUseCase.messages.count { + targetMessageForScrolling = messageListUseCase.messages[firstVisibleIndexPath.row] + } messageListUseCase.loadPreviousMessages() } @@ -201,18 +207,26 @@ extension OpenChannelViewController: OpenChannelMessageListUseCaseDelegate { func openChannelMessageListUseCase(_ useCase: OpenChannelMessageListUseCase, didUpdateMessages messages: [BaseMessage]) { tableView.reloadData() + if isInitialLoad && !messages.isEmpty { + targetMessageForScrolling = messages.last + isInitialLoad = false + } scrollToFocusMessage() } private func scrollToFocusMessage() { defer { self.targetMessageForScrolling = nil } - guard let focusMessage = targetMessageForScrolling, - focusMessage.messageId == messageListUseCase.messages.last?.messageId else { return } + guard let focusMessage = targetMessageForScrolling else { return } + + guard let messageIndex = messageListUseCase.messages.firstIndex(where: { + $0.messageId == focusMessage.messageId || $0.requestId == focusMessage.requestId + }) else { return } - let focusMessageIndexPath = IndexPath(row: messageListUseCase.messages.count - 1, section: 0) + let focusMessageIndexPath = IndexPath(row: messageIndex, section: 0) - tableView.scrollToRow(at: focusMessageIndexPath, at: .bottom, animated: false) + let scrollPosition: UITableView.ScrollPosition = (messageIndex == messageListUseCase.messages.count - 1) ? .bottom : .top + tableView.scrollToRow(at: focusMessageIndexPath, at: scrollPosition, animated: false) } } diff --git a/Apps/MessageThreadingOpenChannel/Sources/Channel/OpenChannelViewController.swift b/Apps/MessageThreadingOpenChannel/Sources/Channel/OpenChannelViewController.swift index d029830..278f9a8 100644 --- a/Apps/MessageThreadingOpenChannel/Sources/Channel/OpenChannelViewController.swift +++ b/Apps/MessageThreadingOpenChannel/Sources/Channel/OpenChannelViewController.swift @@ -37,6 +37,7 @@ class OpenChannelViewController: UIViewController { private weak var messageInputBottomConstraint: NSLayoutConstraint? var targetMessageForScrolling: BaseMessage? + private var isInitialLoad = true let channel: OpenChannel @@ -171,6 +172,11 @@ extension OpenChannelViewController: UITableViewDelegate { func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) { if scrollView.contentOffset.y - Constant.loadMoreThreshold <= 0 { + if let visibleIndexPaths = tableView.indexPathsForVisibleRows, + let firstVisibleIndexPath = visibleIndexPaths.first, + firstVisibleIndexPath.row < messageListUseCase.messages.count { + targetMessageForScrolling = messageListUseCase.messages[firstVisibleIndexPath.row] + } messageListUseCase.loadPreviousMessages() } @@ -201,18 +207,26 @@ extension OpenChannelViewController: OpenChannelMessageListUseCaseDelegate { func openChannelMessageListUseCase(_ useCase: OpenChannelMessageListUseCase, didUpdateMessages messages: [BaseMessage]) { tableView.reloadData() + if isInitialLoad && !messages.isEmpty { + targetMessageForScrolling = messages.last + isInitialLoad = false + } scrollToFocusMessage() } private func scrollToFocusMessage() { defer { self.targetMessageForScrolling = nil } - guard let focusMessage = targetMessageForScrolling, - focusMessage.messageId == messageListUseCase.messages.last?.messageId else { return } + guard let focusMessage = targetMessageForScrolling else { return } + + guard let messageIndex = messageListUseCase.messages.firstIndex(where: { + $0.messageId == focusMessage.messageId || $0.requestId == focusMessage.requestId + }) else { return } - let focusMessageIndexPath = IndexPath(row: messageListUseCase.messages.count - 1, section: 0) + let focusMessageIndexPath = IndexPath(row: messageIndex, section: 0) - tableView.scrollToRow(at: focusMessageIndexPath, at: .bottom, animated: false) + let scrollPosition: UITableView.ScrollPosition = (messageIndex == messageListUseCase.messages.count - 1) ? .bottom : .top + tableView.scrollToRow(at: focusMessageIndexPath, at: scrollPosition, animated: false) } } diff --git a/Apps/MetaDataCounterOpenChannel/Sources/Channel/OpenChannelViewController.swift b/Apps/MetaDataCounterOpenChannel/Sources/Channel/OpenChannelViewController.swift index a489d2e..c9b4f85 100644 --- a/Apps/MetaDataCounterOpenChannel/Sources/Channel/OpenChannelViewController.swift +++ b/Apps/MetaDataCounterOpenChannel/Sources/Channel/OpenChannelViewController.swift @@ -37,6 +37,7 @@ class OpenChannelViewController: UIViewController { private weak var messageInputBottomConstraint: NSLayoutConstraint? var targetMessageForScrolling: BaseMessage? + private var isInitialLoad = true let channel: OpenChannel @@ -186,6 +187,11 @@ extension OpenChannelViewController: UITableViewDelegate { func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) { if scrollView.contentOffset.y - Constant.loadMoreThreshold <= 0 { + if let visibleIndexPaths = tableView.indexPathsForVisibleRows, + let firstVisibleIndexPath = visibleIndexPaths.first, + firstVisibleIndexPath.row < messageListUseCase.messages.count { + targetMessageForScrolling = messageListUseCase.messages[firstVisibleIndexPath.row] + } messageListUseCase.loadPreviousMessages() } @@ -216,18 +222,26 @@ extension OpenChannelViewController: OpenChannelMessageListUseCaseDelegate { func openChannelMessageListUseCase(_ useCase: OpenChannelMessageListUseCase, didUpdateMessages messages: [BaseMessage]) { tableView.reloadData() + if isInitialLoad && !messages.isEmpty { + targetMessageForScrolling = messages.last + isInitialLoad = false + } scrollToFocusMessage() } private func scrollToFocusMessage() { defer { self.targetMessageForScrolling = nil } - guard let focusMessage = targetMessageForScrolling, - focusMessage.messageId == messageListUseCase.messages.last?.messageId else { return } + guard let focusMessage = targetMessageForScrolling else { return } + + guard let messageIndex = messageListUseCase.messages.firstIndex(where: { + $0.messageId == focusMessage.messageId || $0.requestId == focusMessage.requestId + }) else { return } - let focusMessageIndexPath = IndexPath(row: messageListUseCase.messages.count - 1, section: 0) + let focusMessageIndexPath = IndexPath(row: messageIndex, section: 0) - tableView.scrollToRow(at: focusMessageIndexPath, at: .bottom, animated: false) + let scrollPosition: UITableView.ScrollPosition = (messageIndex == messageListUseCase.messages.count - 1) ? .bottom : .top + tableView.scrollToRow(at: focusMessageIndexPath, at: scrollPosition, animated: false) } } diff --git a/Apps/OpenGraphTagsOpenChannel/Sources/Channel/OpenChannelViewController.swift b/Apps/OpenGraphTagsOpenChannel/Sources/Channel/OpenChannelViewController.swift index 8e700c6..0153617 100644 --- a/Apps/OpenGraphTagsOpenChannel/Sources/Channel/OpenChannelViewController.swift +++ b/Apps/OpenGraphTagsOpenChannel/Sources/Channel/OpenChannelViewController.swift @@ -37,6 +37,7 @@ class OpenChannelViewController: UIViewController { private weak var messageInputBottomConstraint: NSLayoutConstraint? var targetMessageForScrolling: BaseMessage? + private var isInitialLoad = true let channel: OpenChannel @@ -169,6 +170,11 @@ extension OpenChannelViewController: UITableViewDelegate { func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) { if scrollView.contentOffset.y - Constant.loadMoreThreshold <= 0 { + if let visibleIndexPaths = tableView.indexPathsForVisibleRows, + let firstVisibleIndexPath = visibleIndexPaths.first, + firstVisibleIndexPath.row < messageListUseCase.messages.count { + targetMessageForScrolling = messageListUseCase.messages[firstVisibleIndexPath.row] + } messageListUseCase.loadPreviousMessages() } @@ -199,18 +205,26 @@ extension OpenChannelViewController: OpenChannelMessageListUseCaseDelegate { func openChannelMessageListUseCase(_ useCase: OpenChannelMessageListUseCase, didUpdateMessages messages: [BaseMessage]) { tableView.reloadData() + if isInitialLoad && !messages.isEmpty { + targetMessageForScrolling = messages.last + isInitialLoad = false + } scrollToFocusMessage() } private func scrollToFocusMessage() { defer { self.targetMessageForScrolling = nil } - guard let focusMessage = targetMessageForScrolling, - focusMessage.messageId == messageListUseCase.messages.last?.messageId else { return } + guard let focusMessage = targetMessageForScrolling else { return } + + guard let messageIndex = messageListUseCase.messages.firstIndex(where: { + $0.messageId == focusMessage.messageId || $0.requestId == focusMessage.requestId + }) else { return } - let focusMessageIndexPath = IndexPath(row: messageListUseCase.messages.count - 1, section: 0) + let focusMessageIndexPath = IndexPath(row: messageIndex, section: 0) - tableView.scrollToRow(at: focusMessageIndexPath, at: .bottom, animated: false) + let scrollPosition: UITableView.ScrollPosition = (messageIndex == messageListUseCase.messages.count - 1) ? .bottom : .top + tableView.scrollToRow(at: focusMessageIndexPath, at: scrollPosition, animated: false) } } diff --git a/Apps/ReportMessageUserOpenChannel/Sources/Channel/OpenChannelViewController.swift b/Apps/ReportMessageUserOpenChannel/Sources/Channel/OpenChannelViewController.swift index ca3abce..22e3961 100644 --- a/Apps/ReportMessageUserOpenChannel/Sources/Channel/OpenChannelViewController.swift +++ b/Apps/ReportMessageUserOpenChannel/Sources/Channel/OpenChannelViewController.swift @@ -37,6 +37,7 @@ class OpenChannelViewController: UIViewController { private weak var messageInputBottomConstraint: NSLayoutConstraint? var targetMessageForScrolling: BaseMessage? + private var isInitialLoad = true let channel: OpenChannel @@ -175,6 +176,11 @@ extension OpenChannelViewController: UITableViewDelegate { func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) { if scrollView.contentOffset.y - Constant.loadMoreThreshold <= 0 { + if let visibleIndexPaths = tableView.indexPathsForVisibleRows, + let firstVisibleIndexPath = visibleIndexPaths.first, + firstVisibleIndexPath.row < messageListUseCase.messages.count { + targetMessageForScrolling = messageListUseCase.messages[firstVisibleIndexPath.row] + } messageListUseCase.loadPreviousMessages() } @@ -225,18 +231,26 @@ extension OpenChannelViewController: OpenChannelMessageListUseCaseDelegate { func openChannelMessageListUseCase(_ useCase: OpenChannelMessageListUseCase, didUpdateMessages messages: [BaseMessage]) { tableView.reloadData() + if isInitialLoad && !messages.isEmpty { + targetMessageForScrolling = messages.last + isInitialLoad = false + } scrollToFocusMessage() } private func scrollToFocusMessage() { defer { self.targetMessageForScrolling = nil } - guard let focusMessage = targetMessageForScrolling, - focusMessage.messageId == messageListUseCase.messages.last?.messageId else { return } + guard let focusMessage = targetMessageForScrolling else { return } + + guard let messageIndex = messageListUseCase.messages.firstIndex(where: { + $0.messageId == focusMessage.messageId || $0.requestId == focusMessage.requestId + }) else { return } - let focusMessageIndexPath = IndexPath(row: messageListUseCase.messages.count - 1, section: 0) + let focusMessageIndexPath = IndexPath(row: messageIndex, section: 0) - tableView.scrollToRow(at: focusMessageIndexPath, at: .bottom, animated: false) + let scrollPosition: UITableView.ScrollPosition = (messageIndex == messageListUseCase.messages.count - 1) ? .bottom : .top + tableView.scrollToRow(at: focusMessageIndexPath, at: scrollPosition, animated: false) } } diff --git a/Apps/SendVariousTypesOfFileOpenChannel/Sources/Channel/OpenChannelViewController.swift b/Apps/SendVariousTypesOfFileOpenChannel/Sources/Channel/OpenChannelViewController.swift index 1d9a895..e11eb20 100644 --- a/Apps/SendVariousTypesOfFileOpenChannel/Sources/Channel/OpenChannelViewController.swift +++ b/Apps/SendVariousTypesOfFileOpenChannel/Sources/Channel/OpenChannelViewController.swift @@ -37,6 +37,7 @@ class OpenChannelViewController: UIViewController { private weak var messageInputBottomConstraint: NSLayoutConstraint? var targetMessageForScrolling: BaseMessage? + private var isInitialLoad = true let channel: OpenChannel @@ -169,6 +170,11 @@ extension OpenChannelViewController: UITableViewDelegate { func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) { if scrollView.contentOffset.y - Constant.loadMoreThreshold <= 0 { + if let visibleIndexPaths = tableView.indexPathsForVisibleRows, + let firstVisibleIndexPath = visibleIndexPaths.first, + firstVisibleIndexPath.row < messageListUseCase.messages.count { + targetMessageForScrolling = messageListUseCase.messages[firstVisibleIndexPath.row] + } messageListUseCase.loadPreviousMessages() } @@ -199,18 +205,27 @@ extension OpenChannelViewController: OpenChannelMessageListUseCaseDelegate { func openChannelMessageListUseCase(_ useCase: OpenChannelMessageListUseCase, didUpdateMessages messages: [BaseMessage]) { tableView.reloadData() + if isInitialLoad && !messages.isEmpty { + targetMessageForScrolling = messages.last + isInitialLoad = false + } scrollToFocusMessage() } private func scrollToFocusMessage() { defer { self.targetMessageForScrolling = nil } - guard let focusMessage = targetMessageForScrolling, - focusMessage.messageId == messageListUseCase.messages.last?.messageId else { return } + guard let focusMessage = targetMessageForScrolling else { return } + + guard let messageIndex = messageListUseCase.messages.firstIndex(where: { + $0.messageId == focusMessage.messageId || $0.requestId == focusMessage.requestId + }) else { return } - let focusMessageIndexPath = IndexPath(row: messageListUseCase.messages.count - 1, section: 0) + let focusMessageIndexPath = IndexPath(row: messageIndex, section: 0) tableView.scrollToRow(at: focusMessageIndexPath, at: .bottom, animated: false) + let scrollPosition: UITableView.ScrollPosition = (messageIndex == messageListUseCase.messages.count - 1) ? .bottom : .top + tableView.scrollToRow(at: focusMessageIndexPath, at: scrollPosition, animated: false) } } diff --git a/Apps/UpdateMessageOpenChannel/Sources/Channel/OpenChannelViewController.swift b/Apps/UpdateMessageOpenChannel/Sources/Channel/OpenChannelViewController.swift index d0d8906..a953eaa 100644 --- a/Apps/UpdateMessageOpenChannel/Sources/Channel/OpenChannelViewController.swift +++ b/Apps/UpdateMessageOpenChannel/Sources/Channel/OpenChannelViewController.swift @@ -37,6 +37,7 @@ class OpenChannelViewController: UIViewController { private weak var messageInputBottomConstraint: NSLayoutConstraint? var targetMessageForScrolling: BaseMessage? + private var isInitialLoad = true let channel: OpenChannel @@ -171,6 +172,11 @@ extension OpenChannelViewController: UITableViewDelegate { func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) { if scrollView.contentOffset.y - Constant.loadMoreThreshold <= 0 { + if let visibleIndexPaths = tableView.indexPathsForVisibleRows, + let firstVisibleIndexPath = visibleIndexPaths.first, + firstVisibleIndexPath.row < messageListUseCase.messages.count { + targetMessageForScrolling = messageListUseCase.messages[firstVisibleIndexPath.row] + } messageListUseCase.loadPreviousMessages() } @@ -201,18 +207,27 @@ extension OpenChannelViewController: OpenChannelMessageListUseCaseDelegate { func openChannelMessageListUseCase(_ useCase: OpenChannelMessageListUseCase, didUpdateMessages messages: [BaseMessage]) { tableView.reloadData() + if isInitialLoad && !messages.isEmpty { + targetMessageForScrolling = messages.last + isInitialLoad = false + } scrollToFocusMessage() } private func scrollToFocusMessage() { defer { self.targetMessageForScrolling = nil } - guard let focusMessage = targetMessageForScrolling, - focusMessage.messageId == messageListUseCase.messages.last?.messageId else { return } + guard let focusMessage = targetMessageForScrolling else { return } + + guard let messageIndex = messageListUseCase.messages.firstIndex(where: { + $0.messageId == focusMessage.messageId || $0.requestId == focusMessage.requestId + }) else { return } - let focusMessageIndexPath = IndexPath(row: messageListUseCase.messages.count - 1, section: 0) + let focusMessageIndexPath = IndexPath(row: messageIndex, section: 0) tableView.scrollToRow(at: focusMessageIndexPath, at: .bottom, animated: false) + let scrollPosition: UITableView.ScrollPosition = (messageIndex == messageListUseCase.messages.count - 1) ? .bottom : .top + tableView.scrollToRow(at: focusMessageIndexPath, at: scrollPosition, animated: false) } }