mirror of
https://github.com/element-hq/element-x-ios.git
synced 2025-03-10 21:39:12 +00:00
Fix back pagination (#432)
* Use pagination and start items for view state. isBackPaginating and canBackPaginate are updated each time the timeline is rebuilt * Update some timeline snapshots The top section has gone, which has altered the layout slightly.
This commit is contained in:
parent
3d1266ca25
commit
08b333839a
@ -49,6 +49,7 @@ struct RoomScreenViewState: BindableState {
|
||||
var roomTitle = ""
|
||||
var roomAvatar: UIImage?
|
||||
var items: [RoomTimelineViewProvider] = []
|
||||
var canBackPaginate = true
|
||||
var isBackPaginating = false
|
||||
var showLoading = false
|
||||
var bindings: RoomScreenViewStateBindings
|
||||
|
@ -61,10 +61,14 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
|
||||
}
|
||||
|
||||
self.state.items[viewIndex] = timelineViewFactory.buildTimelineViewFor(timelineItem: timelineItem)
|
||||
case .startedBackPaginating:
|
||||
self.state.isBackPaginating = true
|
||||
case .finishedBackPaginating:
|
||||
self.state.isBackPaginating = false
|
||||
case .canBackPaginate(let canBackPaginate):
|
||||
if self.state.canBackPaginate != canBackPaginate {
|
||||
self.state.canBackPaginate = canBackPaginate
|
||||
}
|
||||
case .isBackPaginating(let isBackPaginating):
|
||||
if self.state.isBackPaginating != isBackPaginating {
|
||||
self.state.isBackPaginating = isBackPaginating
|
||||
}
|
||||
}
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
|
@ -61,6 +61,9 @@ class TimelineTableViewController: UIViewController {
|
||||
}
|
||||
}
|
||||
|
||||
/// Whether or not the timeline has more messages to back paginate.
|
||||
var canBackPaginate = true
|
||||
|
||||
/// Whether or not the timeline is waiting for more messages to be added to the top.
|
||||
var isBackPaginating = false {
|
||||
didSet {
|
||||
@ -334,7 +337,8 @@ class TimelineTableViewController: UIViewController {
|
||||
///
|
||||
/// Prefer not to call this directly, instead using ``paginateBackwardsPublisher`` to throttle requests.
|
||||
private func paginateBackwardsIfNeeded() {
|
||||
guard !isBackPaginating,
|
||||
guard canBackPaginate,
|
||||
!isBackPaginating,
|
||||
!hasPendingUpdates,
|
||||
tableView.contentOffset.y < tableView.visibleSize.height * 2.0
|
||||
else { return }
|
||||
|
@ -59,6 +59,9 @@ struct TimelineView: UIViewControllerRepresentable {
|
||||
if tableViewController.timelineItems != context.viewState.items {
|
||||
tableViewController.timelineItems = context.viewState.items
|
||||
}
|
||||
if tableViewController.canBackPaginate != context.viewState.canBackPaginate {
|
||||
tableViewController.canBackPaginate = context.viewState.canBackPaginate
|
||||
}
|
||||
if tableViewController.isBackPaginating != context.viewState.isBackPaginating {
|
||||
tableViewController.isBackPaginating = context.viewState.isBackPaginating
|
||||
}
|
||||
|
@ -19,8 +19,6 @@ import Combine
|
||||
struct MockRoomTimelineProvider: RoomTimelineProviderProtocol {
|
||||
var itemsPublisher = CurrentValueSubject<[TimelineItemProxy], Never>([])
|
||||
|
||||
var backPaginationPublisher = CurrentValueSubject<Bool, Never>(false)
|
||||
|
||||
private var itemProxies = [TimelineItemProxy]()
|
||||
|
||||
func paginateBackwards(requestSize: UInt, untilNumberOfItems: UInt) async -> Result<Void, RoomTimelineProviderError> {
|
||||
|
@ -32,15 +32,10 @@ class RoomTimelineProvider: RoomTimelineProviderProtocol {
|
||||
private var cancellables = Set<AnyCancellable>()
|
||||
|
||||
let itemsPublisher = CurrentValueSubject<[TimelineItemProxy], Never>([])
|
||||
let backPaginationPublisher = CurrentValueSubject<Bool, Never>(false)
|
||||
|
||||
private var itemProxies: [TimelineItemProxy] {
|
||||
didSet {
|
||||
itemsPublisher.send(itemProxies)
|
||||
|
||||
if backPaginationPublisher.value == true {
|
||||
backPaginationPublisher.send(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -69,9 +64,6 @@ class RoomTimelineProvider: RoomTimelineProviderProtocol {
|
||||
}
|
||||
|
||||
func paginateBackwards(requestSize: UInt, untilNumberOfItems: UInt) async -> Result<Void, RoomTimelineProviderError> {
|
||||
// Set this back to false after actually updating the items or if failed
|
||||
backPaginationPublisher.send(true)
|
||||
|
||||
MXLog.info("Started back pagination request")
|
||||
switch await roomProxy.paginateBackwards(requestSize: requestSize, untilNumberOfItems: untilNumberOfItems) {
|
||||
case .success:
|
||||
@ -79,7 +71,6 @@ class RoomTimelineProvider: RoomTimelineProviderProtocol {
|
||||
return .success(())
|
||||
case .failure(let error):
|
||||
MXLog.error("Failed back pagination request with error: \(error)")
|
||||
backPaginationPublisher.send(false)
|
||||
|
||||
if error == .noMoreMessagesToBackPaginate {
|
||||
return .failure(.noMoreMessagesToBackPaginate)
|
||||
|
@ -29,8 +29,6 @@ enum RoomTimelineProviderError: Error {
|
||||
protocol RoomTimelineProviderProtocol {
|
||||
var itemsPublisher: CurrentValueSubject<[TimelineItemProxy], Never> { get }
|
||||
|
||||
var backPaginationPublisher: CurrentValueSubject<Bool, Never> { get }
|
||||
|
||||
func paginateBackwards(requestSize: UInt, untilNumberOfItems: UInt) async -> Result<Void, RoomTimelineProviderError>
|
||||
|
||||
func sendMessage(_ message: String, inReplyToItemId: String?) async -> Result<Void, RoomTimelineProviderError>
|
||||
|
@ -42,20 +42,7 @@ class MockRoomTimelineController: RoomTimelineControllerProtocol {
|
||||
}
|
||||
|
||||
func paginateBackwards(requestSize: UInt, untilNumberOfItems: UInt) async -> Result<Void, RoomTimelineControllerError> {
|
||||
callbacks.send(.startedBackPaginating)
|
||||
|
||||
guard !backPaginationResponses.isEmpty else {
|
||||
callbacks.send(.finishedBackPaginating)
|
||||
return .failure(.generic)
|
||||
}
|
||||
|
||||
let newItems = backPaginationResponses.removeFirst()
|
||||
|
||||
try? await Task.sleep(for: backPaginationDelay)
|
||||
timelineItems.insert(contentsOf: newItems, at: 0)
|
||||
callbacks.send(.updatedTimelineItems)
|
||||
callbacks.send(.finishedBackPaginating)
|
||||
|
||||
callbacks.send(.canBackPaginate(false))
|
||||
return .success(())
|
||||
}
|
||||
|
||||
@ -125,11 +112,12 @@ class MockRoomTimelineController: RoomTimelineControllerProtocol {
|
||||
/// Prepends the next chunk of items to the `timelineItems` array.
|
||||
private func simulateBackPagination() async throws {
|
||||
guard !backPaginationResponses.isEmpty else { return }
|
||||
callbacks.send(.isBackPaginating(true))
|
||||
|
||||
let newItems = backPaginationResponses.removeFirst()
|
||||
timelineItems.insert(contentsOf: newItems, at: 0)
|
||||
callbacks.send(.updatedTimelineItems)
|
||||
callbacks.send(.finishedBackPaginating)
|
||||
callbacks.send(.isBackPaginating(false))
|
||||
|
||||
try? await connection?.send(.success)
|
||||
}
|
||||
|
@ -61,18 +61,6 @@ class RoomTimelineController: RoomTimelineControllerProtocol {
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
|
||||
self.timelineProvider
|
||||
.backPaginationPublisher
|
||||
.receive(on: DispatchQueue.main)
|
||||
.sink { [weak self] value in
|
||||
if value {
|
||||
self?.callbacks.send(.startedBackPaginating)
|
||||
} else {
|
||||
self?.callbacks.send(.finishedBackPaginating)
|
||||
}
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
|
||||
updateTimelineItems()
|
||||
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(contentSizeCategoryDidChange), name: UIContentSizeCategory.didChangeNotification, object: nil)
|
||||
@ -230,6 +218,8 @@ class RoomTimelineController: RoomTimelineControllerProtocol {
|
||||
// swiftlint:disable:next cyclomatic_complexity
|
||||
private func asyncUpdateTimelineItems() async {
|
||||
var newTimelineItems = [RoomTimelineItemProtocol]()
|
||||
var canBackPaginate = true
|
||||
var isBackPaginating = false
|
||||
|
||||
for (index, itemProxy) in timelineProvider.itemsPublisher.value.enumerated() {
|
||||
if Task.isCancelled {
|
||||
@ -262,8 +252,10 @@ class RoomTimelineController: RoomTimelineControllerProtocol {
|
||||
}
|
||||
case .loadingIndicator:
|
||||
newTimelineItems.append(PaginationIndicatorRoomTimelineItem())
|
||||
isBackPaginating = true
|
||||
case .timelineStart:
|
||||
newTimelineItems.append(TimelineStartRoomTimelineItem(name: roomProxy.displayName ?? roomProxy.name))
|
||||
canBackPaginate = false
|
||||
}
|
||||
default:
|
||||
break
|
||||
@ -277,6 +269,8 @@ class RoomTimelineController: RoomTimelineControllerProtocol {
|
||||
timelineItems = newTimelineItems
|
||||
|
||||
callbacks.send(.updatedTimelineItems)
|
||||
callbacks.send(.canBackPaginate(canBackPaginate))
|
||||
callbacks.send(.isBackPaginating(isBackPaginating))
|
||||
}
|
||||
|
||||
private func computeGroupState(for itemProxy: TimelineItemProxy,
|
||||
|
@ -21,8 +21,8 @@ import UIKit
|
||||
enum RoomTimelineControllerCallback {
|
||||
case updatedTimelineItems
|
||||
case updatedTimelineItem(_ itemId: String)
|
||||
case startedBackPaginating
|
||||
case finishedBackPaginating
|
||||
case canBackPaginate(Bool)
|
||||
case isBackPaginating(Bool)
|
||||
}
|
||||
|
||||
enum RoomTimelineControllerAction {
|
||||
|
BIN
UITests/Sources/__Snapshots__/Application/de-DE-iPad-9th-generation.roomLayoutMiddle-0.png
(Stored with Git LFS)
BIN
UITests/Sources/__Snapshots__/Application/de-DE-iPad-9th-generation.roomLayoutMiddle-0.png
(Stored with Git LFS)
Binary file not shown.
BIN
UITests/Sources/__Snapshots__/Application/de-DE-iPad-9th-generation.roomLayoutMiddle-1.png
(Stored with Git LFS)
BIN
UITests/Sources/__Snapshots__/Application/de-DE-iPad-9th-generation.roomLayoutMiddle-1.png
(Stored with Git LFS)
Binary file not shown.
BIN
UITests/Sources/__Snapshots__/Application/de-DE-iPad-9th-generation.roomLayoutTop.png
(Stored with Git LFS)
BIN
UITests/Sources/__Snapshots__/Application/de-DE-iPad-9th-generation.roomLayoutTop.png
(Stored with Git LFS)
Binary file not shown.
BIN
UITests/Sources/__Snapshots__/Application/de-DE-iPhone-14.roomLayoutMiddle-0.png
(Stored with Git LFS)
BIN
UITests/Sources/__Snapshots__/Application/de-DE-iPhone-14.roomLayoutMiddle-0.png
(Stored with Git LFS)
Binary file not shown.
BIN
UITests/Sources/__Snapshots__/Application/de-DE-iPhone-14.roomLayoutMiddle-1.png
(Stored with Git LFS)
BIN
UITests/Sources/__Snapshots__/Application/de-DE-iPhone-14.roomLayoutMiddle-1.png
(Stored with Git LFS)
Binary file not shown.
BIN
UITests/Sources/__Snapshots__/Application/de-DE-iPhone-14.roomLayoutTop.png
(Stored with Git LFS)
BIN
UITests/Sources/__Snapshots__/Application/de-DE-iPhone-14.roomLayoutTop.png
(Stored with Git LFS)
Binary file not shown.
BIN
UITests/Sources/__Snapshots__/Application/en-GB-iPad-9th-generation.roomLayoutMiddle-0.png
(Stored with Git LFS)
BIN
UITests/Sources/__Snapshots__/Application/en-GB-iPad-9th-generation.roomLayoutMiddle-0.png
(Stored with Git LFS)
Binary file not shown.
BIN
UITests/Sources/__Snapshots__/Application/en-GB-iPad-9th-generation.roomLayoutMiddle-1.png
(Stored with Git LFS)
BIN
UITests/Sources/__Snapshots__/Application/en-GB-iPad-9th-generation.roomLayoutMiddle-1.png
(Stored with Git LFS)
Binary file not shown.
BIN
UITests/Sources/__Snapshots__/Application/en-GB-iPad-9th-generation.roomLayoutTop.png
(Stored with Git LFS)
BIN
UITests/Sources/__Snapshots__/Application/en-GB-iPad-9th-generation.roomLayoutTop.png
(Stored with Git LFS)
Binary file not shown.
BIN
UITests/Sources/__Snapshots__/Application/en-GB-iPhone-14.roomLayoutMiddle-0.png
(Stored with Git LFS)
BIN
UITests/Sources/__Snapshots__/Application/en-GB-iPhone-14.roomLayoutMiddle-0.png
(Stored with Git LFS)
Binary file not shown.
BIN
UITests/Sources/__Snapshots__/Application/en-GB-iPhone-14.roomLayoutMiddle-1.png
(Stored with Git LFS)
BIN
UITests/Sources/__Snapshots__/Application/en-GB-iPhone-14.roomLayoutMiddle-1.png
(Stored with Git LFS)
Binary file not shown.
BIN
UITests/Sources/__Snapshots__/Application/en-GB-iPhone-14.roomLayoutTop.png
(Stored with Git LFS)
BIN
UITests/Sources/__Snapshots__/Application/en-GB-iPhone-14.roomLayoutTop.png
(Stored with Git LFS)
Binary file not shown.
@ -58,7 +58,7 @@ targets:
|
||||
- path: ../SupportingFiles
|
||||
- path: ../../Tools/Scripts/Templates/SimpleScreenExample/Tests/UI
|
||||
- path: ../../ElementX/Sources/UITests/UITestScreenIdentifier.swift
|
||||
- path: ../../ElementX/Sources/UITests/UITestSignalling.swift
|
||||
- path: ../../ElementX/Sources/UITests/UITestsSignalling.swift
|
||||
- path: ../../ElementX/Sources/Generated/Strings.swift
|
||||
- path: ../../ElementX/Sources/Generated/Strings+Untranslated.swift
|
||||
- path: ../../ElementX/Resources
|
||||
|
1
changelog.d/pr-432.bugfix
Normal file
1
changelog.d/pr-432.bugfix
Normal file
@ -0,0 +1 @@
|
||||
Use pagination indicators and start of room timeline items to update the view's pagination state.
|
Loading…
x
Reference in New Issue
Block a user