From 2b22180191a2217b5a53bae9bde42f5f4468a3e0 Mon Sep 17 00:00:00 2001 From: Shadowfacts Date: Thu, 25 Nov 2021 12:29:35 -0500 Subject: [PATCH] Remove TimelineLikeTableViewController Everything now uses DiffableTimelineLike --- Tusker.xcodeproj/project.pbxproj | 4 - .../TimelineLikeTableViewController.swift | 254 ------------------ 2 files changed, 258 deletions(-) delete mode 100644 Tusker/Screens/Utilities/TimelineLikeTableViewController.swift diff --git a/Tusker.xcodeproj/project.pbxproj b/Tusker.xcodeproj/project.pbxproj index c037ce60..0a7a7273 100644 --- a/Tusker.xcodeproj/project.pbxproj +++ b/Tusker.xcodeproj/project.pbxproj @@ -154,7 +154,6 @@ D64D0AB12128D9AE005A6F37 /* OnboardingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D64D0AB02128D9AE005A6F37 /* OnboardingViewController.swift */; }; D64D8CA92463B494006B0BAA /* MultiThreadDictionary.swift in Sources */ = {isa = PBXBuildFile; fileRef = D64D8CA82463B494006B0BAA /* MultiThreadDictionary.swift */; }; D64F80E2215875CC00BEF393 /* XCBActionType.swift in Sources */ = {isa = PBXBuildFile; fileRef = D64F80E1215875CC00BEF393 /* XCBActionType.swift */; }; - D65234C9256189D0001AF9CF /* TimelineLikeTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D65234C8256189D0001AF9CF /* TimelineLikeTableViewController.swift */; }; D65234D325618EFA001AF9CF /* TimelineTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D65234D225618EFA001AF9CF /* TimelineTableViewController.swift */; }; D65234E12561AA68001AF9CF /* NotificationsTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D65234E02561AA68001AF9CF /* NotificationsTableViewController.swift */; }; D6531DEE246B81C9000F9538 /* GifvAttachmentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6531DED246B81C9000F9538 /* GifvAttachmentView.swift */; }; @@ -559,7 +558,6 @@ D64D0AB02128D9AE005A6F37 /* OnboardingViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingViewController.swift; sourceTree = ""; }; D64D8CA82463B494006B0BAA /* MultiThreadDictionary.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MultiThreadDictionary.swift; sourceTree = ""; }; D64F80E1215875CC00BEF393 /* XCBActionType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XCBActionType.swift; sourceTree = ""; }; - D65234C8256189D0001AF9CF /* TimelineLikeTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineLikeTableViewController.swift; sourceTree = ""; }; D65234D225618EFA001AF9CF /* TimelineTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineTableViewController.swift; sourceTree = ""; }; D65234E02561AA68001AF9CF /* NotificationsTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationsTableViewController.swift; sourceTree = ""; }; D6531DED246B81C9000F9538 /* GifvAttachmentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GifvAttachmentView.swift; sourceTree = ""; }; @@ -1523,7 +1521,6 @@ D6412B0224AFF6A600F5412E /* TabBarScrollableViewController.swift */, D6B22A0E2560D52D004D82EF /* TabbedPageViewController.swift */, D6538944214D6D7500E3CEFC /* TableViewSwipeActionProvider.swift */, - D65234C8256189D0001AF9CF /* TimelineLikeTableViewController.swift */, D6DFC69D242C490400ACC392 /* TrackpadScrollGestureRecognizer.swift */, D6B8DB332182A59300424AF7 /* UIAlertController+Visibility.swift */, D6C693FD2162FEEA007D6A6D /* UIViewController+Children.swift */, @@ -2080,7 +2077,6 @@ D64BC18F23C18B9D000D0238 /* FollowRequestNotificationTableViewCell.swift in Sources */, D693DE5923FE24310061E07D /* InteractivePushTransition.swift in Sources */, D69693FA25859A8000F4E116 /* ComposeSceneDelegate.swift in Sources */, - D65234C9256189D0001AF9CF /* TimelineLikeTableViewController.swift in Sources */, D6A3BC8A2321F79B00FD64D5 /* AccountTableViewCell.swift in Sources */, D66A77BB233838DC0058F1EC /* UIFont+Traits.swift in Sources */, D68FEC4F232C5BC300C84F23 /* SegmentedPageViewController.swift in Sources */, diff --git a/Tusker/Screens/Utilities/TimelineLikeTableViewController.swift b/Tusker/Screens/Utilities/TimelineLikeTableViewController.swift deleted file mode 100644 index 177ca134..00000000 --- a/Tusker/Screens/Utilities/TimelineLikeTableViewController.swift +++ /dev/null @@ -1,254 +0,0 @@ -// -// TimelineLikeTableViewController.swift -// Tusker -// -// Created by Shadowfacts on 11/15/20. -// Copyright © 2020 Shadowfacts. All rights reserved. -// - -import UIKit - -/// A table view controller that manages common functionality between timeline-like UIs. -/// For example, this class handles loading new items when the user scrolls to the end, -/// refreshing, and pruning offscreen rows automatically. -class TimelineLikeTableViewController: EnhancedTableViewController, RefreshableViewController { - - private(set) var loaded = false - - var sections: [[Item]] = [] - - private let pageSize = 20 - - private var lastLastVisibleRow: IndexPath? - - init() { - super.init(style: .plain) - - addKeyCommand(MenuController.refreshCommand(discoverabilityTitle: Self.refreshCommandTitle())) - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - func item(for indexPath: IndexPath) -> Item { - return sections[indexPath.section][indexPath.row] - } - - override func viewDidLoad() { - super.viewDidLoad() - - tableView.rowHeight = UITableView.automaticDimension - tableView.estimatedRowHeight = 140 - - #if !targetEnvironment(macCatalyst) - self.refreshControl = UIRefreshControl() - self.refreshControl!.addTarget(self, action: #selector(refresh), for: .valueChanged) - #endif - - if let prefetchSource = self as? UITableViewDataSourcePrefetching { - tableView.prefetchDataSource = prefetchSource - } - } - - override func viewWillAppear(_ animated: Bool) { - super.viewWillAppear(animated) - - loadInitial() - } - - override func viewWillDisappear(_ animated: Bool) { - super.viewWillDisappear(animated) - - pruneOffscreenRows() - } - - func loadInitial() { - guard !loaded else { return } - // set loaded immediately so we don't trigger another request while the current one is running - loaded = true - - loadInitialItems() { (items) in - DispatchQueue.main.async { - guard items.count > 0 else { - // set loaded back to false so the next time the VC appears, we try to load again - // todo: this should probably retry automatically - self.loaded = false - return - } - - if self.sections.count < self.headerSectionsCount() { - self.sections.insert(contentsOf: Array(repeating: [], count: self.headerSectionsCount() - self.sections.count), at: 0) - } - - self.sections.append(items) - - self.tableView.reloadData() - } - } - } - - func reloadInitialItems() { - loaded = false - sections = [] - loadInitial() - } - - func cellHeightChanged() { - // causes the table view to recalculate the cell heights - tableView.beginUpdates() - tableView.endUpdates() - } - - class func refreshCommandTitle() -> String { - return "Refresh" - } - - // todo: these three should use Result<[Item], Client.Error> so we can differentiate between failed requests and there actually being no results - - func loadInitialItems(completion: @escaping ([Item]) -> Void) { - fatalError("loadInitialItems(completion:) must be implemented by subclasses") - } - - func loadOlder(completion: @escaping ([Item]) -> Void) { - fatalError("loadOlder(completion:) must be implemented by subclasses") - } - - func loadNewer(completion: @escaping ([Item]) -> Void) { - fatalError("loadNewer(completion:) must be implemented by subclasses") - } - - func willRemoveRows(at indexPaths: [IndexPath]) { - } - - func headerSectionsCount() -> Int { - return 0 - } - - private func pruneOffscreenRows() { - guard let lastVisibleRow = lastLastVisibleRow, - // never remove the last section - sections.count - headerSectionsCount() > 1 else { - return - } - let lastSectionIndex = sections.count - 1 - - if lastVisibleRow.section < lastSectionIndex { - // if there is a section below the last visible one - - let sectionsToRemove = (lastVisibleRow.section + 1)...lastSectionIndex - - let indexPathsToRemove = sectionsToRemove.flatMap { (section) in - sections[section].indices.map { (row) in - IndexPath(row: row, section: section) - } - } - willRemoveRows(at: indexPathsToRemove) - - UIView.performWithoutAnimation { - tableView.deleteSections(IndexSet(sectionsToRemove), with: .none) - } - - sections.removeSubrange(sectionsToRemove) - } else if lastVisibleRow.section == lastSectionIndex { - let lastSection = sections.last! - let lastRowIndex = lastSection.count - 1 - - if lastVisibleRow.row < lastRowIndex - pageSize { - // if there are more than pageSize rows in the current section below the last visible one - - let rowIndicesInLastSectionToRemove = (lastVisibleRow.row + pageSize).. Int { - return sections.count - } - - override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - return sections[section].count - } - - override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - fatalError("tableView(_:cellForRowAt:) must be implemented by subclasses") - } - - // MARK: - UITableViewDelegate - override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) { - // this assumes that indexPathsForVisibleRows is always in order - lastLastVisibleRow = tableView.indexPathsForVisibleRows?.last - - if indexPath.section == sections.count - 1, - indexPath.row == sections[indexPath.section].count - 1 { - loadOlder() { (newItems) in - guard newItems.count > 0 else { return } - - DispatchQueue.main.async { - let newRows = self.sections.last!.count..<(self.sections.last!.count + newItems.count) - let newIndexPaths = newRows.map { IndexPath(row: $0, section: self.sections.count - 1) } - - self.sections[self.sections.count - 1].append(contentsOf: newItems) - - UIView.performWithoutAnimation { - self.tableView.insertRows(at: newIndexPaths, with: .none) - } - } - } - } - } - - override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool { - return true - } - - override func tableView(_ tableView: UITableView, leadingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? { - return (tableView.cellForRow(at: indexPath) as? TableViewSwipeActionProvider)?.leadingSwipeActionsConfiguration() - } - - override func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? { - return (tableView.cellForRow(at: indexPath) as? TableViewSwipeActionProvider)?.trailingSwipeActionsConfiguration() - } - - // MARK: - RefreshableViewController - func refresh() { - loadNewer() { (newItems) in - DispatchQueue.main.async { - self.refreshControl?.endRefreshing() - - guard newItems.count > 0 else { return } - - let firstNonHeaderSection = self.headerSectionsCount() - - self.sections[firstNonHeaderSection].insert(contentsOf: newItems, at: 0) - - let newIndexPaths = (0..