2018-08-16 11:46:19 +00:00
|
|
|
//
|
2020-11-15 20:48:49 +00:00
|
|
|
// TimelineTableViewController.swift
|
2018-08-16 11:46:19 +00:00
|
|
|
// Tusker
|
|
|
|
//
|
|
|
|
// Created by Shadowfacts on 8/15/18.
|
|
|
|
// Copyright © 2018 Shadowfacts. All rights reserved.
|
|
|
|
//
|
|
|
|
|
|
|
|
import UIKit
|
2018-09-11 14:52:21 +00:00
|
|
|
import Pachyderm
|
2018-08-16 11:46:19 +00:00
|
|
|
|
2020-11-15 20:48:49 +00:00
|
|
|
typealias TimelineEntry = (id: String, state: StatusState)
|
|
|
|
|
|
|
|
class TimelineTableViewController: TimelineLikeTableViewController<TimelineEntry> {
|
2018-08-21 21:17:25 +00:00
|
|
|
|
2020-11-15 20:48:49 +00:00
|
|
|
let timeline: Timeline
|
2020-01-20 04:02:07 +00:00
|
|
|
weak var mastodonController: MastodonController!
|
2018-08-21 21:17:25 +00:00
|
|
|
|
2020-10-27 02:55:58 +00:00
|
|
|
private var newer: RequestRange?
|
|
|
|
private var older: RequestRange?
|
|
|
|
|
2020-01-05 20:25:07 +00:00
|
|
|
init(for timeline: Timeline, mastodonController: MastodonController) {
|
2018-10-20 16:03:18 +00:00
|
|
|
self.timeline = timeline
|
2020-01-05 20:25:07 +00:00
|
|
|
self.mastodonController = mastodonController
|
2018-10-21 02:07:04 +00:00
|
|
|
|
2020-11-15 20:48:49 +00:00
|
|
|
super.init()
|
2018-10-20 16:03:18 +00:00
|
|
|
|
2020-12-14 23:44:41 +00:00
|
|
|
dragEnabled = true
|
|
|
|
|
2019-06-11 17:21:22 +00:00
|
|
|
title = timeline.title
|
|
|
|
tabBarItem.image = timeline.tabBarImage
|
2020-11-14 16:10:20 +00:00
|
|
|
|
2020-12-14 03:37:37 +00:00
|
|
|
if let id = mastodonController.accountInfo?.id {
|
|
|
|
userActivity = UserActivityManager.showTimelineActivity(timeline: timeline, accountID: id)
|
|
|
|
}
|
2018-10-20 16:03:18 +00:00
|
|
|
}
|
|
|
|
|
2020-11-15 20:48:49 +00:00
|
|
|
required init?(coder: NSCoder) {
|
2018-10-20 16:03:18 +00:00
|
|
|
fatalError("init(coder:) has not been implemented")
|
|
|
|
}
|
|
|
|
|
2020-04-13 03:06:02 +00:00
|
|
|
deinit {
|
2020-05-13 22:58:11 +00:00
|
|
|
guard let persistentContainer = mastodonController?.persistentContainer else { return }
|
2020-04-13 03:06:02 +00:00
|
|
|
// decrement reference counts of any statuses we still have
|
|
|
|
// if the app is currently being quit, this will not affect the persisted data because
|
|
|
|
// the persistent container would already have been saved in SceneDelegate.sceneDidEnterBackground(_:)
|
2020-11-15 20:48:49 +00:00
|
|
|
for section in sections {
|
|
|
|
for (id, _) in section {
|
2020-05-13 22:58:11 +00:00
|
|
|
persistentContainer.status(for: id)?.decrementReferenceCount()
|
2020-04-13 03:06:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-27 20:32:59 +00:00
|
|
|
override func viewDidLoad() {
|
|
|
|
super.viewDidLoad()
|
|
|
|
|
2020-11-15 20:48:49 +00:00
|
|
|
tableView.register(UINib(nibName: "TimelineStatusTableViewCell", bundle: .main), forCellReuseIdentifier: "statusCell")
|
2020-06-15 23:39:44 +00:00
|
|
|
}
|
|
|
|
|
2020-11-15 20:48:49 +00:00
|
|
|
override class func refreshCommandTitle() -> String {
|
|
|
|
return NSLocalizedString("Refresh Statuses", comment: "refresh status command discoverability title")
|
2019-12-18 03:56:53 +00:00
|
|
|
}
|
|
|
|
|
2020-11-15 20:48:49 +00:00
|
|
|
override func willRemoveRows(at indexPaths: [IndexPath]) {
|
|
|
|
for indexPath in indexPaths {
|
|
|
|
let id = item(for: indexPath).id
|
|
|
|
mastodonController.persistentContainer.status(for: id)?.decrementReferenceCount()
|
|
|
|
}
|
2020-10-27 02:55:58 +00:00
|
|
|
}
|
|
|
|
|
2020-11-15 20:48:49 +00:00
|
|
|
override func loadInitialItems(completion: @escaping ([TimelineEntry]) -> Void) {
|
2020-01-05 19:00:39 +00:00
|
|
|
let request = Client.getStatuses(timeline: timeline)
|
2020-11-15 20:48:49 +00:00
|
|
|
|
|
|
|
mastodonController?.run(request) { (response) in
|
2021-04-04 18:43:51 +00:00
|
|
|
guard case let .success(statuses, pagination) = response else {
|
|
|
|
completion([])
|
|
|
|
return
|
|
|
|
}
|
2020-11-15 20:48:49 +00:00
|
|
|
|
2018-09-11 14:52:21 +00:00
|
|
|
self.newer = pagination?.newer
|
|
|
|
self.older = pagination?.older
|
2020-11-15 20:48:49 +00:00
|
|
|
|
|
|
|
self.mastodonController?.persistentContainer.addAll(statuses: statuses) {
|
|
|
|
completion(statuses.map { ($0.id, .unknown) })
|
2020-01-25 16:11:48 +00:00
|
|
|
}
|
2018-08-17 02:39:16 +00:00
|
|
|
}
|
|
|
|
}
|
2020-10-27 02:55:58 +00:00
|
|
|
|
2020-11-15 20:48:49 +00:00
|
|
|
override func loadOlder(completion: @escaping ([TimelineEntry]) -> Void) {
|
|
|
|
guard let older = older else {
|
|
|
|
completion([])
|
2020-10-27 02:55:58 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2020-11-15 20:48:49 +00:00
|
|
|
let request = Client.getStatuses(timeline: timeline, range: older)
|
|
|
|
|
|
|
|
mastodonController.run(request) { (response) in
|
2021-04-04 18:43:51 +00:00
|
|
|
guard case let .success(statuses, pagination) = response else {
|
|
|
|
completion([])
|
|
|
|
return
|
|
|
|
}
|
2020-10-27 02:55:58 +00:00
|
|
|
|
2020-11-15 20:48:49 +00:00
|
|
|
self.older = pagination?.older
|
2020-10-27 02:55:58 +00:00
|
|
|
|
2020-11-15 20:48:49 +00:00
|
|
|
self.mastodonController?.persistentContainer.addAll(statuses: statuses) {
|
|
|
|
completion(statuses.map { ($0.id, .unknown) })
|
2020-10-27 02:55:58 +00:00
|
|
|
}
|
2020-11-15 20:48:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
override func loadNewer(completion: @escaping ([TimelineEntry]) -> Void) {
|
|
|
|
guard let newer = newer else {
|
|
|
|
completion([])
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
let request = Client.getStatuses(timeline: timeline, range: newer)
|
|
|
|
|
|
|
|
mastodonController.run(request) { (response) in
|
2021-04-04 18:43:51 +00:00
|
|
|
guard case let .success(statuses, pagination) = response else {
|
|
|
|
completion([])
|
|
|
|
return
|
|
|
|
}
|
2020-10-27 02:55:58 +00:00
|
|
|
|
2021-01-13 03:32:14 +00:00
|
|
|
// if there are no new statuses, pagination is nil
|
|
|
|
// if we were to then overwrite self.newer, future refreshes would fail
|
|
|
|
if let newer = pagination?.newer {
|
|
|
|
self.newer = newer
|
|
|
|
}
|
2020-10-27 02:55:58 +00:00
|
|
|
|
2020-11-15 20:48:49 +00:00
|
|
|
self.mastodonController?.persistentContainer.addAll(statuses: statuses) {
|
|
|
|
completion(statuses.map { ($0.id, .unknown) })
|
2020-10-27 02:55:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-11-15 20:48:49 +00:00
|
|
|
|
|
|
|
// MARK: - UITableViewDataSource
|
2018-08-17 02:39:16 +00:00
|
|
|
|
2018-08-16 11:46:19 +00:00
|
|
|
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
2019-11-19 17:08:11 +00:00
|
|
|
guard let cell = tableView.dequeueReusableCell(withIdentifier: "statusCell", for: indexPath) as? TimelineStatusTableViewCell else { fatalError() }
|
2019-08-02 03:01:15 +00:00
|
|
|
|
2020-11-15 20:48:49 +00:00
|
|
|
let (id, state) = item(for: indexPath)
|
2018-08-27 19:23:59 +00:00
|
|
|
cell.delegate = self
|
2020-06-17 03:00:48 +00:00
|
|
|
|
2020-01-06 00:54:28 +00:00
|
|
|
cell.updateUI(statusID: id, state: state)
|
2018-08-16 11:46:19 +00:00
|
|
|
|
|
|
|
return cell
|
|
|
|
}
|
2018-08-18 21:46:28 +00:00
|
|
|
|
2020-11-15 20:48:49 +00:00
|
|
|
}
|
2020-04-13 03:06:02 +00:00
|
|
|
|
2020-11-15 20:48:49 +00:00
|
|
|
extension TimelineTableViewController: TuskerNavigationDelegate {
|
2020-01-05 20:25:07 +00:00
|
|
|
var apiController: MastodonController { mastodonController }
|
2020-11-15 20:48:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
extension TimelineTableViewController: StatusTableViewCellDelegate {
|
2019-11-28 23:36:58 +00:00
|
|
|
func statusCellCollapsedStateChanged(_ cell: BaseStatusTableViewCell) {
|
2020-11-15 20:48:49 +00:00
|
|
|
cellHeightChanged()
|
2019-09-09 22:40:23 +00:00
|
|
|
}
|
|
|
|
}
|
2019-02-08 18:37:38 +00:00
|
|
|
|
2021-01-18 19:29:32 +00:00
|
|
|
extension TimelineTableViewController: UITableViewDataSourcePrefetching, StatusTablePrefetching {
|
2019-02-08 18:37:38 +00:00
|
|
|
func tableView(_ tableView: UITableView, prefetchRowsAt indexPaths: [IndexPath]) {
|
2021-01-18 19:29:32 +00:00
|
|
|
let ids = indexPaths.map { item(for: $0).id }
|
|
|
|
prefetchStatuses(with: ids)
|
2019-02-08 18:37:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func tableView(_ tableView: UITableView, cancelPrefetchingForRowsAt indexPaths: [IndexPath]) {
|
2021-01-18 19:29:32 +00:00
|
|
|
let ids: [String] = indexPaths.compactMap {
|
|
|
|
guard $0.section < sections.count,
|
|
|
|
$0.row < sections[$0.section].count else {
|
|
|
|
return nil
|
2019-02-08 18:37:38 +00:00
|
|
|
}
|
2021-01-18 19:29:32 +00:00
|
|
|
return item(for: $0).id
|
2019-02-08 18:37:38 +00:00
|
|
|
}
|
2021-01-18 19:29:32 +00:00
|
|
|
cancelPrefetchingStatuses(with: ids)
|
2019-02-08 18:37:38 +00:00
|
|
|
}
|
|
|
|
}
|