// // StatusesTableViewController.swift // Tusker // // Created by Shadowfacts on 8/15/18. // Copyright © 2018 Shadowfacts. All rights reserved. // import UIKit import Pachyderm class TimelineTableViewController: EnhancedTableViewController { var timeline: Timeline! weak var mastodonController: MastodonController! var timelineSegments: [[(id: String, state: StatusState)]] = [] var newer: RequestRange? var older: RequestRange? init(for timeline: Timeline, mastodonController: MastodonController) { self.timeline = timeline self.mastodonController = mastodonController super.init(style: .plain) title = timeline.title tabBarItem.image = timeline.tabBarImage self.refreshControl = UIRefreshControl() refreshControl!.addTarget(self, action: #selector(refreshStatuses(_:)), for: .valueChanged) userActivity = UserActivityManager.showTimelineActivity(timeline: timeline) } required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } func statusID(for indexPath: IndexPath) -> String { return timelineSegments[indexPath.section][indexPath.row].id } override func viewDidLoad() { super.viewDidLoad() tableView.rowHeight = UITableView.automaticDimension tableView.estimatedRowHeight = 140 tableView.register(UINib(nibName: "TimelineStatusTableViewCell", bundle: nil), forCellReuseIdentifier: "statusCell") tableView.prefetchDataSource = self loadInitialStatuses() } func loadInitialStatuses() { let request = Client.getStatuses(timeline: timeline) mastodonController.run(request) { response in guard case let .success(statuses, pagination) = response else { fatalError() } // self.mastodonController.cache.addAll(statuses: statuses) // todo: possible race condition here? we update the underlying data before waiting to reload the table view self.timelineSegments.insert(statuses.map { ($0.id, .unknown) }, at: 0) self.newer = pagination?.newer self.older = pagination?.older self.mastodonController.persistentContainer.addAll(statuses: statuses) { DispatchQueue.main.async { self.tableView.reloadData() } } } } // MARK: - Table view data source override func numberOfSections(in tableView: UITableView) -> Int { return timelineSegments.count } override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return timelineSegments[section].count } override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { guard let cell = tableView.dequeueReusableCell(withIdentifier: "statusCell", for: indexPath) as? TimelineStatusTableViewCell else { fatalError() } let (id, state) = timelineSegments[indexPath.section][indexPath.row] cell.delegate = self cell.updateUI(statusID: id, state: state) return cell } // MARK: - Table view delegate override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) { if indexPath.section == timelineSegments.count - 1, indexPath.row == timelineSegments[indexPath.section].count - 1 { guard let older = older else { return } let request = Client.getStatuses(timeline: timeline, range: older) mastodonController.run(request) { response in guard case let .success(newStatuses, pagination) = response else { fatalError() } self.older = pagination?.older // self.mastodonController.cache.addAll(statuses: newStatuses) let newRows = self.timelineSegments.last!.count..<(self.timelineSegments.last!.count + newStatuses.count) let newIndexPaths = newRows.map { IndexPath(row: $0, section: self.timelineSegments.count - 1) } self.timelineSegments[self.timelineSegments.count - 1].append(contentsOf: newStatuses.map { ($0.id, .unknown) }) self.mastodonController.persistentContainer.addAll(statuses: newStatuses) { DispatchQueue.main.async { 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() } @objc func refreshStatuses(_ sender: Any) { guard let newer = newer else { return } let request = Client.getStatuses(timeline: timeline, range: newer) mastodonController.run(request) { response in guard case let .success(newStatuses, pagination) = response else { fatalError() } self.newer = pagination?.newer // self.mastodonController.cache.addAll(statuses: newStatuses) self.timelineSegments[0].insert(contentsOf: newStatuses.map { ($0.id, .unknown) }, at: 0) if let newer = pagination?.newer { self.newer = newer } self.mastodonController.persistentContainer.addAll(statuses: newStatuses) { DispatchQueue.main.async { let newIndexPaths = (0..