From b1d83f2746946f6819e17ad5274d2dbe22648227 Mon Sep 17 00:00:00 2001 From: Shadowfacts Date: Tue, 1 Nov 2022 21:06:06 -0400 Subject: [PATCH] Switch hashtag/instance/list timelines to use new collection view impl --- .../Lists/ListTimelineViewController.swift | 9 ++++++--- .../HashtagTimelineViewController.swift | 2 +- .../InstanceTimelineViewController.swift | 17 +++++++---------- .../Timeline/TimelineViewController.swift | 17 ++++++++++++----- Tusker/TimelineLikeController.swift | 6 +++--- .../Views/Status/StatusCollectionViewCell.swift | 3 +-- .../TimelineStatusCollectionViewCell.swift | 2 ++ 7 files changed, 32 insertions(+), 24 deletions(-) diff --git a/Tusker/Screens/Lists/ListTimelineViewController.swift b/Tusker/Screens/Lists/ListTimelineViewController.swift index 02341e27..ab97ce29 100644 --- a/Tusker/Screens/Lists/ListTimelineViewController.swift +++ b/Tusker/Screens/Lists/ListTimelineViewController.swift @@ -9,7 +9,7 @@ import UIKit import Pachyderm -class ListTimelineViewController: TimelineTableViewController { +class ListTimelineViewController: TimelineViewController { let list: List @@ -57,8 +57,11 @@ class ListTimelineViewController: TimelineTableViewController { @objc func editListDoneButtonPressed() { dismiss(animated: true) - // todo: show loading indicator - reloadInitial() + // TODO: only reload if there were changes + Task { + applyInitialSnapshot() + await controller.loadInitial() + } } } diff --git a/Tusker/Screens/Timeline/HashtagTimelineViewController.swift b/Tusker/Screens/Timeline/HashtagTimelineViewController.swift index d860c500..acfebb41 100644 --- a/Tusker/Screens/Timeline/HashtagTimelineViewController.swift +++ b/Tusker/Screens/Timeline/HashtagTimelineViewController.swift @@ -9,7 +9,7 @@ import UIKit import Pachyderm -class HashtagTimelineViewController: TimelineTableViewController { +class HashtagTimelineViewController: TimelineViewController { let hashtag: Hashtag diff --git a/Tusker/Screens/Timeline/InstanceTimelineViewController.swift b/Tusker/Screens/Timeline/InstanceTimelineViewController.swift index 4c9dafbd..929ebc5a 100644 --- a/Tusker/Screens/Timeline/InstanceTimelineViewController.swift +++ b/Tusker/Screens/Timeline/InstanceTimelineViewController.swift @@ -7,13 +7,14 @@ // import UIKit +import Pachyderm protocol InstanceTimelineViewControllerDelegate: AnyObject { func didSaveInstance(url: URL) func didUnsaveInstance(url: URL) } -class InstanceTimelineViewController: TimelineTableViewController { +class InstanceTimelineViewController: TimelineViewController { weak var delegate: InstanceTimelineViewControllerDelegate? @@ -68,19 +69,15 @@ class InstanceTimelineViewController: TimelineTableViewController { toggleSaveButton.title = toggleSaveButtonTitle } - // MARK: - Table view data source - - override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - let cell = super.tableView(tableView, cellForRowAt: indexPath) as! TimelineStatusTableViewCell + override func configureStatusCell(_ cell: TimelineStatusCollectionViewCell, id: String, state: StatusState) { cell.delegate = browsingEnabled ? self : nil - return cell + cell.overrideMastodonController = mastodonController + cell.updateUI(statusID: id, state: state) } - // MARK: - Table view delegate - - override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { guard browsingEnabled else { return } - super.tableView(tableView, didSelectRowAt: indexPath) + super.collectionView(collectionView, didSelectItemAt: indexPath) } // MARK: - Interaction diff --git a/Tusker/Screens/Timeline/TimelineViewController.swift b/Tusker/Screens/Timeline/TimelineViewController.swift index 0272a779..403e37fd 100644 --- a/Tusker/Screens/Timeline/TimelineViewController.swift +++ b/Tusker/Screens/Timeline/TimelineViewController.swift @@ -34,6 +34,7 @@ class TimelineViewController: UIViewController, TimelineLikeCollectionViewContro self.controller = TimelineLikeController(delegate: self) + self.navigationItem.title = timeline.title addKeyCommand(MenuController.refreshCommand(discoverabilityTitle: "Refresh Timeline")) } @@ -84,10 +85,15 @@ class TimelineViewController: UIViewController, TimelineLikeCollectionViewContro super.viewDidLoad() } + // separate method because InstanceTimelineViewController needs to be able to customize it + func configureStatusCell(_ cell: TimelineStatusCollectionViewCell, id: String, state: StatusState) { + cell.delegate = self + cell.updateUI(statusID: id, state: state) + } + private func createDataSource() -> UICollectionViewDiffableDataSource { let statusCell = UICollectionView.CellRegistration { [unowned self] cell, indexPath, item in - cell.delegate = self - cell.updateUI(statusID: item.0, state: item.1) + self.configureStatusCell(cell, id: item.0, state: item.1) } let timelineDescriptionCell = UICollectionView.CellRegistration { [unowned self] cell, indexPath, item in guard case .public(let local) = timeline else { @@ -114,15 +120,16 @@ class TimelineViewController: UIViewController, TimelineLikeCollectionViewContro } } - private func applyInitialSnapshot() { + // non-private, because ListTimelineViewController needs to be able to reload it from scratch + func applyInitialSnapshot() { + var snapshot = NSDiffableDataSourceSnapshot() if case .public(let local) = timeline, (local && !Preferences.shared.hasShownLocalTimelineDescription) || (!local && !Preferences.shared.hasShownFederatedTimelineDescription) { - var snapshot = dataSource.snapshot() snapshot.appendSections([.header]) snapshot.appendItems([.publicTimelineDescription], toSection: .header) - dataSource.apply(snapshot, animatingDifferences: false) } + dataSource.apply(snapshot, animatingDifferences: false) } override func viewWillAppear(_ animated: Bool) { diff --git a/Tusker/TimelineLikeController.swift b/Tusker/TimelineLikeController.swift index 3e41bdb7..591e4c99 100644 --- a/Tusker/TimelineLikeController.swift +++ b/Tusker/TimelineLikeController.swift @@ -51,7 +51,7 @@ actor TimelineLikeController { } func loadInitial() async { - guard state == .notLoadedInitial else { + guard state == .notLoadedInitial || state == .idle else { return } let token = LoadAttemptToken() @@ -175,14 +175,14 @@ actor TimelineLikeController { switch self { case .notLoadedInitial: switch to { - case .loadingInitial(_, hasAddedLoadingIndicator: _): + case .loadingInitial(_, _): return true default: return false } case .idle: switch to { - case .loadingNewer(_), .loadingOlder(_, _): + case .loadingInitial(_, _), .loadingNewer(_), .loadingOlder(_, _): return true default: return false diff --git a/Tusker/Views/Status/StatusCollectionViewCell.swift b/Tusker/Views/Status/StatusCollectionViewCell.swift index f6a3b67f..2b8fc7f0 100644 --- a/Tusker/Views/Status/StatusCollectionViewCell.swift +++ b/Tusker/Views/Status/StatusCollectionViewCell.swift @@ -30,6 +30,7 @@ protocol StatusCollectionViewCell: UICollectionViewCell, AttachmentViewDelegate var moreButton: UIButton { get } var delegate: StatusCollectionViewCellDelegate? { get } + var mastodonController: MastodonController! { get } var showStatusAutomatically: Bool { get } var showReplyIndicator: Bool { get } @@ -75,8 +76,6 @@ extension StatusCollectionViewCell { } func doUpdateUI(status: StatusMO) { - precondition(delegate != nil, "StatusCollectionViewCell must have delegate") - statusID = status.id accountID = status.account.id diff --git a/Tusker/Views/Status/TimelineStatusCollectionViewCell.swift b/Tusker/Views/Status/TimelineStatusCollectionViewCell.swift index 74d4a581..b61455e7 100644 --- a/Tusker/Views/Status/TimelineStatusCollectionViewCell.swift +++ b/Tusker/Views/Status/TimelineStatusCollectionViewCell.swift @@ -227,6 +227,8 @@ class TimelineStatusCollectionViewCell: UICollectionViewListCell, StatusCollecti private var mainContainerBottomToActionsConstraint: NSLayoutConstraint! private var mainContainerBottomToSelfConstraint: NSLayoutConstraint! + weak var overrideMastodonController: MastodonController? + var mastodonController: MastodonController! { overrideMastodonController ?? delegate?.apiController } weak var delegate: StatusCollectionViewCellDelegate? var showStatusAutomatically: Bool { // TODO: needed once conversation controller refactored