Add loading indicator to conversation screen

This commit is contained in:
Shadowfacts 2023-01-21 13:17:11 -05:00
parent ccd1672e72
commit 63ed3b6e10
1 changed files with 31 additions and 4 deletions

View File

@ -94,6 +94,9 @@ class ConversationCollectionViewController: UIViewController, CollectionViewCont
let expandThreadCell = UICollectionView.CellRegistration<ExpandThreadCollectionViewCell, ([ConversationNode], Bool)> { cell, indexPath, item in let expandThreadCell = UICollectionView.CellRegistration<ExpandThreadCollectionViewCell, ([ConversationNode], Bool)> { cell, indexPath, item in
cell.updateUI(childThreads: item.0, inline: item.1) cell.updateUI(childThreads: item.0, inline: item.1)
} }
let loadingCell = UICollectionView.CellRegistration<LoadingCollectionViewCell, Void> { cell, indexPath, itemIdentifier in
cell.indicator.startAnimating()
}
return UICollectionViewDiffableDataSource(collectionView: collectionView) { [unowned self] collectionView, indexPath, itemIdentifier in return UICollectionViewDiffableDataSource(collectionView: collectionView) { [unowned self] collectionView, indexPath, itemIdentifier in
switch itemIdentifier { switch itemIdentifier {
case let .status(id: id, state: state, prevLink: prevLink, nextLink: nextLink): case let .status(id: id, state: state, prevLink: prevLink, nextLink: nextLink):
@ -104,17 +107,31 @@ class ConversationCollectionViewController: UIViewController, CollectionViewCont
} }
case .expandThread(childThreads: let childThreads, inline: let inline): case .expandThread(childThreads: let childThreads, inline: let inline):
return collectionView.dequeueConfiguredReusableCell(using: expandThreadCell, for: indexPath, item: (childThreads, inline)) return collectionView.dequeueConfiguredReusableCell(using: expandThreadCell, for: indexPath, item: (childThreads, inline))
case .loadingIndicator:
return collectionView.dequeueConfiguredReusableCell(using: loadingCell, for: indexPath, item: ())
} }
} }
} }
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
clearSelectionOnAppear(animated: animated)
}
func addMainStatus(_ status: StatusMO) { func addMainStatus(_ status: StatusMO) {
loadViewIfNeeded() loadViewIfNeeded()
var snapshot = NSDiffableDataSourceSnapshot<Section, Item>() var snapshot = NSDiffableDataSourceSnapshot<Section, Item>()
snapshot.appendSections([.statuses]) snapshot.appendSections([.statuses])
if status.inReplyToID != nil {
snapshot.appendItems([.loadingIndicator], toSection: .statuses)
}
let mainStatusItem = Item.status(id: mainStatusID, state: mainStatusState, prevLink: status.inReplyToID != nil, nextLink: false) let mainStatusItem = Item.status(id: mainStatusID, state: mainStatusState, prevLink: status.inReplyToID != nil, nextLink: false)
snapshot.appendItems([mainStatusItem], toSection: .statuses) snapshot.appendItems([mainStatusItem], toSection: .statuses)
dataSource.apply(snapshot, animatingDifferences: false) dataSource.apply(snapshot, animatingDifferences: false)
} }
@ -125,6 +142,7 @@ class ConversationCollectionViewController: UIViewController, CollectionViewCont
await mastodonController.persistentContainer.addAll(statuses: parentStatuses + context.descendants) await mastodonController.persistentContainer.addAll(statuses: parentStatuses + context.descendants)
var snapshot = dataSource.snapshot() var snapshot = dataSource.snapshot()
snapshot.deleteItems([.loadingIndicator])
let mainStatusItem = Item.status(id: mainStatusID, state: mainStatusState, prevLink: mainStatus.inReplyToID != nil, nextLink: false) let mainStatusItem = Item.status(id: mainStatusID, state: mainStatusState, prevLink: mainStatus.inReplyToID != nil, nextLink: false)
let parentItems = parentIDs.enumerated().map { index, id in let parentItems = parentIDs.enumerated().map { index, id in
Item.status(id: id, state: .unknown, prevLink: index > 0, nextLink: true) Item.status(id: id, state: .unknown, prevLink: index > 0, nextLink: true)
@ -299,6 +317,7 @@ extension ConversationCollectionViewController {
enum Item: Hashable { enum Item: Hashable {
case status(id: String, state: CollapseState, prevLink: Bool, nextLink: Bool) case status(id: String, state: CollapseState, prevLink: Bool, nextLink: Bool)
case expandThread(childThreads: [ConversationNode], inline: Bool) case expandThread(childThreads: [ConversationNode], inline: Bool)
case loadingIndicator
static func ==(lhs: Item, rhs: Item) -> Bool { static func ==(lhs: Item, rhs: Item) -> Bool {
switch (lhs, rhs) { switch (lhs, rhs) {
@ -306,6 +325,8 @@ extension ConversationCollectionViewController {
return a == b && aPrev == bPrev && aNext == bNext return a == b && aPrev == bPrev && aNext == bNext
case let (.expandThread(childThreads: a, inline: aInline), .expandThread(childThreads: b, inline: bInline)): case let (.expandThread(childThreads: a, inline: aInline), .expandThread(childThreads: b, inline: bInline)):
return a.count == b.count && zip(a, b).allSatisfy { $0.status.id == $1.status.id } && aInline == bInline return a.count == b.count && zip(a, b).allSatisfy { $0.status.id == $1.status.id } && aInline == bInline
case (.loadingIndicator, .loadingIndicator):
return true
default: default:
return false return false
} }
@ -324,6 +345,8 @@ extension ConversationCollectionViewController {
hasher.combine(thread.status.id) hasher.combine(thread.status.id)
} }
hasher.combine(inline) hasher.combine(inline)
case .loadingIndicator:
hasher.combine(2)
} }
} }
} }
@ -331,11 +354,13 @@ extension ConversationCollectionViewController {
extension ConversationCollectionViewController: UICollectionViewDelegate { extension ConversationCollectionViewController: UICollectionViewDelegate {
func collectionView(_ collectionView: UICollectionView, shouldSelectItemAt indexPath: IndexPath) -> Bool { func collectionView(_ collectionView: UICollectionView, shouldSelectItemAt indexPath: IndexPath) -> Bool {
if case .status(id: let id, _, _, _) = dataSource.itemIdentifier(for: indexPath), switch dataSource.itemIdentifier(for: indexPath) {
id == mainStatusID { case .status(id: let id, state: _, prevLink: _, nextLink: _):
return false return id != mainStatusID
} else { case .expandThread(childThreads: _, inline: _):
return true return true
default:
return false
} }
} }
@ -343,6 +368,8 @@ extension ConversationCollectionViewController: UICollectionViewDelegate {
switch dataSource.itemIdentifier(for: indexPath) { switch dataSource.itemIdentifier(for: indexPath) {
case nil: case nil:
break break
case .loadingIndicator:
break
case .status(id: let id, state: let state, _, _): case .status(id: let id, state: let state, _, _):
selected(status: id, state: state.copy()) selected(status: id, state: state.copy())
case .expandThread(childThreads: let childThreads, inline: _): case .expandThread(childThreads: let childThreads, inline: _):