mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-04 10:33:45 +00:00
Rewrote timeline back pagination on top of direct access to the underlying UITableView.
This commit is contained in:
@@ -13,14 +13,13 @@ class MockRoomTimelineController: RoomTimelineControllerProtocol {
|
||||
|
||||
let callbacks = PassthroughSubject<RoomTimelineControllerCallback, Never>()
|
||||
|
||||
let timelineItems: [RoomTimelineViewProvider] =
|
||||
[RoomTimelineViewProvider.separator(.init(id: UUID().uuidString, text: "Yesterday")),
|
||||
RoomTimelineViewProvider.text(.init(id: UUID().uuidString, senderDisplayName: "Alice", text: "You rock!", timestamp: "10:10 AM", shouldShowSenderDetails: true)),
|
||||
RoomTimelineViewProvider.text(.init(id: UUID().uuidString, senderDisplayName: "Alice", text: "You also rule!", timestamp: "10:11 AM", shouldShowSenderDetails: false)),
|
||||
RoomTimelineViewProvider.separator(.init(id: UUID().uuidString, text: "Today")),
|
||||
RoomTimelineViewProvider.text(.init(id: UUID().uuidString, senderDisplayName: "Bob", text: "You too!", timestamp: "5 PM", shouldShowSenderDetails: true))]
|
||||
var timelineItems: [RoomTimelineViewProvider] = [RoomTimelineViewProvider.separator(.init(id: UUID().uuidString, text: "Yesterday")),
|
||||
RoomTimelineViewProvider.text(.init(id: UUID().uuidString, senderDisplayName: "Alice", text: "You rock!", timestamp: "10:10 AM", shouldShowSenderDetails: true)),
|
||||
RoomTimelineViewProvider.text(.init(id: UUID().uuidString, senderDisplayName: "Alice", text: "You also rule!", timestamp: "10:11 AM", shouldShowSenderDetails: false)),
|
||||
RoomTimelineViewProvider.separator(.init(id: UUID().uuidString, text: "Today")),
|
||||
RoomTimelineViewProvider.text(.init(id: UUID().uuidString, senderDisplayName: "Bob", text: "You too!", timestamp: "5 PM", shouldShowSenderDetails: true))]
|
||||
|
||||
func paginateBackwards(_ count: UInt) {
|
||||
|
||||
func paginateBackwards(_ count: UInt, callback: ((Result<Void, RoomTimelineControllerError>) -> Void)) {
|
||||
callbacks.send(.updatedTimelineItems)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,10 +10,6 @@ import Foundation
|
||||
import Combine
|
||||
import MatrixRustSDK
|
||||
|
||||
enum RoomTimelineControllerCallback {
|
||||
case updatedTimelineItems
|
||||
}
|
||||
|
||||
class RoomTimelineController: RoomTimelineControllerProtocol {
|
||||
private let timelineProvider: RoomTimelineProvider
|
||||
private var cancellables = Set<AnyCancellable>()
|
||||
@@ -29,50 +25,62 @@ class RoomTimelineController: RoomTimelineControllerProtocol {
|
||||
guard let self = self else { return }
|
||||
|
||||
switch callback {
|
||||
case .updatedMessages:
|
||||
var newTimelineItems = [RoomTimelineViewProvider]()
|
||||
|
||||
var previousMessage: Message?
|
||||
for message in self.timelineProvider.messages {
|
||||
let timestamp = Date(timeIntervalSince1970: TimeInterval(message.originServerTs()))
|
||||
|
||||
let areMessagesFromTheSameDay = self.haveSameDay(lhs: previousMessage, rhs: message)
|
||||
let shouldAddSectionHeader = !areMessagesFromTheSameDay
|
||||
|
||||
if shouldAddSectionHeader {
|
||||
let item = SeparatorRoomTimelineItem(id: timestamp.ISO8601Format(),
|
||||
text: timestamp.formatted(date: .long, time: .omitted))
|
||||
|
||||
newTimelineItems.append(RoomTimelineViewProvider.separator(item))
|
||||
}
|
||||
|
||||
let areMessagesFromTheSameSender = (previousMessage?.sender() == message.sender())
|
||||
let shouldShowSenderDetails = !areMessagesFromTheSameSender || !areMessagesFromTheSameDay
|
||||
|
||||
let item = TextRoomTimelineItem(id: message.id(),
|
||||
senderDisplayName: message.sender(),
|
||||
text: message.content(),
|
||||
timestamp: timestamp.formatted(date: .omitted, time: .shortened),
|
||||
shouldShowSenderDetails: shouldShowSenderDetails)
|
||||
|
||||
newTimelineItems.append(RoomTimelineViewProvider.text(item))
|
||||
|
||||
previousMessage = message
|
||||
}
|
||||
|
||||
self.timelineItems = newTimelineItems
|
||||
|
||||
self.callbacks.send(.updatedTimelineItems)
|
||||
case .addedMessage:
|
||||
self.rebuildTimeline()
|
||||
}
|
||||
}.store(in: &cancellables)
|
||||
}
|
||||
|
||||
func paginateBackwards(_ count: UInt) {
|
||||
timelineProvider.paginateBackwards(count)
|
||||
func paginateBackwards(_ count: UInt, callback: @escaping ((Result<Void, RoomTimelineControllerError>) -> Void)) {
|
||||
timelineProvider.paginateBackwards(count) { [weak self] result in
|
||||
switch result {
|
||||
case .success:
|
||||
callback(.success(()))
|
||||
self?.rebuildTimeline()
|
||||
case .failure:
|
||||
callback(.failure(.generic))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
private func rebuildTimeline() {
|
||||
var newTimelineItems = [RoomTimelineViewProvider]()
|
||||
|
||||
var previousMessage: Message?
|
||||
for message in self.timelineProvider.messages {
|
||||
let timestamp = Date(timeIntervalSince1970: TimeInterval(message.originServerTs()))
|
||||
|
||||
let areMessagesFromTheSameDay = self.haveSameDay(lhs: previousMessage, rhs: message)
|
||||
let shouldAddSectionHeader = !areMessagesFromTheSameDay
|
||||
|
||||
if shouldAddSectionHeader {
|
||||
let item = SeparatorRoomTimelineItem(id: timestamp.ISO8601Format(),
|
||||
text: timestamp.formatted(date: .long, time: .omitted))
|
||||
|
||||
newTimelineItems.append(RoomTimelineViewProvider.separator(item))
|
||||
}
|
||||
|
||||
let areMessagesFromTheSameSender = (previousMessage?.sender() == message.sender())
|
||||
let shouldShowSenderDetails = !areMessagesFromTheSameSender || !areMessagesFromTheSameDay
|
||||
|
||||
let item = TextRoomTimelineItem(id: message.id(),
|
||||
senderDisplayName: message.sender(),
|
||||
text: message.content(),
|
||||
timestamp: timestamp.formatted(date: .omitted, time: .shortened),
|
||||
shouldShowSenderDetails: shouldShowSenderDetails)
|
||||
|
||||
newTimelineItems.append(RoomTimelineViewProvider.text(item))
|
||||
|
||||
previousMessage = message
|
||||
}
|
||||
|
||||
self.timelineItems = newTimelineItems
|
||||
|
||||
self.callbacks.send(.updatedTimelineItems)
|
||||
}
|
||||
|
||||
private func haveSameDay(lhs: Message?, rhs: Message?) -> Bool {
|
||||
guard let lhs = lhs, let rhs = rhs else {
|
||||
return false
|
||||
|
||||
@@ -9,9 +9,17 @@
|
||||
import Foundation
|
||||
import Combine
|
||||
|
||||
enum RoomTimelineControllerCallback {
|
||||
case updatedTimelineItems
|
||||
}
|
||||
|
||||
enum RoomTimelineControllerError: Error {
|
||||
case generic
|
||||
}
|
||||
|
||||
protocol RoomTimelineControllerProtocol {
|
||||
var timelineItems: [RoomTimelineViewProvider] { get }
|
||||
var callbacks: PassthroughSubject<RoomTimelineControllerCallback, Never> { get }
|
||||
|
||||
func paginateBackwards(_ count: UInt)
|
||||
func paginateBackwards(_ count: UInt, callback: @escaping ((Result<Void, RoomTimelineControllerError>) -> Void))
|
||||
}
|
||||
|
||||
@@ -11,15 +11,17 @@ import Combine
|
||||
import MatrixRustSDK
|
||||
|
||||
enum RoomTimelineCallback {
|
||||
case updatedMessages
|
||||
case addedMessage
|
||||
}
|
||||
|
||||
enum RoomTimelineError: Error {
|
||||
case generic
|
||||
}
|
||||
|
||||
class RoomTimelineProvider {
|
||||
private let roomProxy: RoomProxyProtocol
|
||||
private var cancellables = Set<AnyCancellable>()
|
||||
|
||||
private var paginationCounter: UInt = 0
|
||||
|
||||
let callbacks = PassthroughSubject<RoomTimelineCallback, Never>()
|
||||
private(set) var messages = [Message]()
|
||||
|
||||
@@ -32,24 +34,21 @@ class RoomTimelineProvider {
|
||||
switch callback {
|
||||
case .addedMessage(let message):
|
||||
self.messages.append(message)
|
||||
self.callbacks.send(.addedMessage)
|
||||
case .updatedLastMessage:
|
||||
break
|
||||
}
|
||||
|
||||
self.callbacks.send(.updatedMessages)
|
||||
|
||||
}.store(in: &cancellables)
|
||||
}
|
||||
|
||||
func paginateBackwards(_ count: UInt) {
|
||||
func paginateBackwards(_ count: UInt, callback: ((Result<([Message]), RoomTimelineError>) -> Void)?) {
|
||||
self.roomProxy.paginateBackwards(count: count) { result in
|
||||
switch result {
|
||||
case .success(let messages):
|
||||
self.messages.insert(contentsOf: messages.reversed(), at: 0)
|
||||
self.callbacks.send(.updatedMessages)
|
||||
case .failure(let error):
|
||||
MXLog.debug("Failed paginating backwards with error: \(error)")
|
||||
self.callbacks.send(.updatedMessages)
|
||||
callback?(.success((self.messages)))
|
||||
case .failure:
|
||||
callback?(.failure(.generic))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user