Fixes #351 - Replace Syncing toast indicator with an in-timeline loading activity indicator (#378)

This commit is contained in:
Stefan Ceriu
2022-12-19 16:25:41 +02:00
committed by GitHub
parent 1a47fd1a8d
commit e0e2d26b4b
3 changed files with 48 additions and 41 deletions
@@ -22,7 +22,6 @@ typealias RoomScreenViewModelType = StateStoreViewModel<RoomScreenViewState, Roo
class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol {
private enum Constants {
static let backPaginationPageSize: UInt = 20
static let backPaginationIndicatorID = "RoomBackPagination"
}
private let timelineController: RoomTimelineControllerProtocol
@@ -30,11 +29,7 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
private let mediaProvider: MediaProviderProtocol
// MARK: - Setup
deinit {
ServiceLocator.shared.userNotificationController.retractNotificationWithId(Constants.backPaginationIndicatorID)
}
init(timelineController: RoomTimelineControllerProtocol,
timelineViewFactory: RoomTimelineViewFactoryProtocol,
mediaProvider: MediaProviderProtocol,
@@ -66,13 +61,8 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
self.state.items[viewIndex] = timelineViewFactory.buildTimelineViewFor(timelineItem: timelineItem)
case .startedBackPaginating:
self.state.isBackPaginating = true
ServiceLocator.shared.userNotificationController.submitNotification(UserNotification(id: Constants.backPaginationIndicatorID,
type: .toast,
title: ElementL10n.roomTimelineSyncing,
persistent: true))
case .finishedBackPaginating:
self.state.isBackPaginating = false
ServiceLocator.shared.userNotificationController.retractNotificationWithId(Constants.backPaginationIndicatorID)
}
}
.store(in: &cancellables)
@@ -66,6 +66,7 @@ class TimelineTableViewController: UIViewController {
didSet {
// Paginate again if the threshold hasn't been satisfied.
paginateBackwardsPublisher.send(())
applySnapshot()
}
}
@@ -197,37 +198,41 @@ class TimelineTableViewController: UIViewController {
cell.item = timelineItem
cell.contentConfiguration = UIHostingConfiguration {
VStack {
if displayReactionsMenuForItemId == timelineItem.id {
TimelineItemReactionsMenuView { emoji in
coordinator.send(viewAction: .emojiTapped(emoji: emoji, itemId: timelineItem.id))
} onDisplayEmojiPicker: {
coordinator.send(viewAction: .displayEmojiPicker(itemId: timelineItem.id))
}
}
if case .backPaginationIndicator = timelineItem {
timelineItem
.frame(maxWidth: .infinity, alignment: .leading)
.opacity(opacity)
.contextMenu {
contextMenuBuilder?(timelineItem.id)
}
.onAppear {
coordinator.send(viewAction: .itemAppeared(id: timelineItem.id))
}
.onDisappear {
coordinator.send(viewAction: .itemDisappeared(id: timelineItem.id))
}
.environment(\.openURL, OpenURLAction { url in
coordinator.send(viewAction: .linkClicked(url: url))
return .systemAction
})
.onTapGesture(count: 2) {
coordinator.send(viewAction: .displayReactionsMenuForItemId(itemId: timelineItem.id))
}
.onTapGesture {
coordinator.send(viewAction: .itemTapped(id: timelineItem.id))
} else {
VStack {
if displayReactionsMenuForItemId == timelineItem.id {
TimelineItemReactionsMenuView { emoji in
coordinator.send(viewAction: .emojiTapped(emoji: emoji, itemId: timelineItem.id))
} onDisplayEmojiPicker: {
coordinator.send(viewAction: .displayEmojiPicker(itemId: timelineItem.id))
}
}
timelineItem
.frame(maxWidth: .infinity, alignment: .leading)
.opacity(opacity)
.contextMenu {
contextMenuBuilder?(timelineItem.id)
}
.onAppear {
coordinator.send(viewAction: .itemAppeared(id: timelineItem.id))
}
.onDisappear {
coordinator.send(viewAction: .itemDisappeared(id: timelineItem.id))
}
.environment(\.openURL, OpenURLAction { url in
coordinator.send(viewAction: .linkClicked(url: url))
return .systemAction
})
.onTapGesture(count: 2) {
coordinator.send(viewAction: .displayReactionsMenuForItemId(itemId: timelineItem.id))
}
.onTapGesture {
coordinator.send(viewAction: .itemTapped(id: timelineItem.id))
}
}
}
}
.margins(.all, self.timelineStyle.rowInsets)
@@ -248,6 +253,8 @@ class TimelineTableViewController: UIViewController {
let previousLayout = layout()
var snapshot = NSDiffableDataSourceSnapshot<TimelineSection, RoomTimelineViewProvider>()
snapshot.appendSections([.loadingIndicator])
snapshot.appendItems([.backPaginationIndicator(isBackPaginating)])
snapshot.appendSections([.main])
snapshot.appendItems(timelineItems)
dataSource.apply(snapshot, animatingDifferences: false)
@@ -409,7 +416,10 @@ extension TimelineTableViewController: UITableViewDelegate {
extension TimelineTableViewController {
/// The sections of the table view used in the diffable data source.
enum TimelineSection { case main }
enum TimelineSection {
case loadingIndicator
case main
}
/// A description of the timeline's layout.
struct LayoutDescriptor {
@@ -27,6 +27,7 @@ enum RoomTimelineViewProvider: Identifiable, Hashable {
case notice(NoticeRoomTimelineItem)
case redacted(RedactedRoomTimelineItem)
case encrypted(EncryptedRoomTimelineItem)
case backPaginationIndicator(Bool)
var id: String {
switch self {
@@ -48,6 +49,8 @@ enum RoomTimelineViewProvider: Identifiable, Hashable {
return item.id
case .encrypted(let item):
return item.id
case .backPaginationIndicator:
return "BackpaginationLoadingIndicator"
}
}
}
@@ -73,6 +76,10 @@ extension RoomTimelineViewProvider: View {
RedactedRoomTimelineView(timelineItem: item)
case .encrypted(let item):
EncryptedRoomTimelineView(timelineItem: item)
case .backPaginationIndicator(let isBackPaginating):
ProgressView()
.frame(maxWidth: .infinity)
.opacity(isBackPaginating ? 1.0 : 0.0)
}
}
}