diff --git a/elpha-ios/AbstractStatusTableViewController.swift b/elpha-ios/AbstractStatusTableViewController.swift index 597c1a2..dcb64e2 100644 --- a/elpha-ios/AbstractStatusTableViewController.swift +++ b/elpha-ios/AbstractStatusTableViewController.swift @@ -6,13 +6,18 @@ // Copyright © 2018 Elpha. All rights reserved. // +import CoreData import UIKit import SafariServices +protocol AbstractStatusTableViewCell { + var statusView: StatusView! { get set } +} + class AbstractStatusTableViewController: UITableViewController, StatusViewDelegate { let fetchLimit = 20 var currentPaginationContext: String = "" - var cellHeightsDictionary: NSMutableDictionary = [:] + var fetchedResultsController: NSFetchedResultsController? = nil var loading: Bool = false { didSet { @@ -77,6 +82,53 @@ class AbstractStatusTableViewController: UITableViewController, StatusViewDelega func hideTapped() {} func boostTapped() {} func favoriteTapped() {} + + func updateCell(_ cell: AbstractStatusTableViewCell, withStatusAt indexPath: IndexPath) { + guard let status = fetchedResultsController?.object(at: indexPath) else { + fatalError("CoreData error") + } + + cell.statusView.update(withStatus: status) + cell.statusView.topDividerView.isHidden = indexPath.row == 0 + cell.statusView.topLoadMoreView.isHidden = true + cell.statusView.bottomLoadMoreView.isHidden = true + + let statusCount = fetchedResultsController?.fetchedObjects?.count ?? 0 + + if let markers = status.markers { + markers.forEach { marker in + if marker.context == self.currentPaginationContext { + switch marker.item.direction { + case .prev: + if indexPath.row > 0, let previousStatus = fetchedResultsController?.object(at: IndexPath(row: indexPath.row - 1, section: indexPath.section)) { + let previousMarkers = previousStatus.markers ?? [] + let previousMarker = previousMarkers.first { $0.context == self.currentPaginationContext && $0.item.direction == .next } + + if previousStatus.id! != marker.item.statusID && previousMarker != nil { + cell.statusView.topLoadMoreView.isHidden = false + cell.statusView.topDividerView.isHidden = true + } + } + case .next: + if indexPath.row < statusCount - 1, let nextStatus = fetchedResultsController?.object(at: IndexPath(row: indexPath.row + 1, section: indexPath.section)) { + let nextMarkers = nextStatus.markers ?? [] + let nextMarker = nextMarkers.first { $0.context == self.currentPaginationContext && $0.item.direction == .prev } + + if nextStatus.id! != marker.item.statusID && nextMarker != nil { + cell.statusView.bottomLoadMoreView.isHidden = false + cell.statusView.bottomDividerView.isHidden = true + } + } + } + } + } + } + + if indexPath.row == statusCount - 1 { + cell.statusView.bottomLoadMoreView.isHidden = false + cell.statusView.bottomDividerView.isHidden = true + } + } } extension AbstractStatusTableViewController: SFSafariViewControllerDelegate { diff --git a/elpha-ios/AccountTableViewCell.swift b/elpha-ios/AccountTableViewCell.swift index 632aa34..6dbe70b 100644 --- a/elpha-ios/AccountTableViewCell.swift +++ b/elpha-ios/AccountTableViewCell.swift @@ -8,6 +8,6 @@ import UIKit -class AccountTableViewCell: UITableViewCell { +class AccountTableViewCell: UITableViewCell, AbstractStatusTableViewCell { @IBOutlet var statusView: StatusView! } diff --git a/elpha-ios/AccountTableViewController.swift b/elpha-ios/AccountTableViewController.swift index d3b7104..c8a6c8a 100644 --- a/elpha-ios/AccountTableViewController.swift +++ b/elpha-ios/AccountTableViewController.swift @@ -74,8 +74,7 @@ class AccountTableViewController: AbstractStatusTableViewController { @IBOutlet var statusTypeSegmentedControl: UISegmentedControl! @IBOutlet var contentTextView: UITextViewFixed! @IBOutlet var fieldTableView: UITableView! - - var fetchedResultsController: NSFetchedResultsController? = nil + var account: AccountMO? = nil var fieldTableViewController: FieldTableViewController? = nil @@ -320,8 +319,28 @@ extension AccountTableViewController: NSFetchedResultsControllerDelegate { } } + func controllerWillChangeContent(_ controller: NSFetchedResultsController) { + tableView.beginUpdates() + } + + func controller(_ controller: NSFetchedResultsController, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) { + switch type { + case NSFetchedResultsChangeType.insert: + tableView.insertRows(at: [newIndexPath!], with: UITableView.RowAnimation.none) + case NSFetchedResultsChangeType.delete: + tableView.deleteRows(at: [indexPath!], with: UITableView.RowAnimation.none) + case NSFetchedResultsChangeType.update: + if let cell = tableView.cellForRow(at: indexPath!) as? AccountTableViewCell { + updateCell(cell, withStatusAt: indexPath!) + } + case NSFetchedResultsChangeType.move: + tableView.deleteRows(at: [indexPath!], with: UITableView.RowAnimation.fade) + tableView.insertRows(at: [newIndexPath!], with: UITableView.RowAnimation.fade) + } + } + func controllerDidChangeContent(_ controller: NSFetchedResultsController) { - self.tableView.reloadData() + tableView.endUpdates() } override func numberOfSections(in tableView: UITableView) -> Int { @@ -351,50 +370,8 @@ extension AccountTableViewController: NSFetchedResultsControllerDelegate { fatalError("Unable to find reusable cell") } - guard let status = fetchedResultsController?.object(at: indexPath) else { - fatalError("CoreData error") - } - + updateCell(cell, withStatusAt: indexPath) cell.statusView.delegate = self - cell.statusView.update(withStatus: status) - cell.statusView.topLoadMoreView.isHidden = true - cell.statusView.bottomLoadMoreView.isHidden = true - - let statusCount = fetchedResultsController?.fetchedObjects?.count ?? 0 - - if let markers = status.markers { - markers.forEach { marker in - if marker.context == self.currentPaginationContext { - switch marker.item.direction { - case .prev: - if indexPath.row > 0, let previousStatus = fetchedResultsController?.object(at: IndexPath(row: indexPath.row - 1, section: indexPath.section)) { - let previousMarkers = previousStatus.markers ?? [] - let previousMarker = previousMarkers.first { $0.context == self.currentPaginationContext && $0.item.direction == .next } - - if previousStatus.id! != marker.item.statusID && previousMarker != nil { - cell.statusView.topLoadMoreView.isHidden = false - cell.statusView.topDividerView.isHidden = true - } - } - case .next: - if indexPath.row < statusCount - 1, let nextStatus = fetchedResultsController?.object(at: IndexPath(row: indexPath.row + 1, section: indexPath.section)) { - let nextMarkers = nextStatus.markers ?? [] - let nextMarker = nextMarkers.first { $0.context == self.currentPaginationContext && $0.item.direction == .prev } - - if nextStatus.id! != marker.item.statusID && nextMarker != nil { - cell.statusView.bottomLoadMoreView.isHidden = false - cell.statusView.bottomDividerView.isHidden = true - } - } - } - } - } - } - - if indexPath.row == statusCount - 1 { - cell.statusView.bottomLoadMoreView.isHidden = false - cell.statusView.bottomDividerView.isHidden = true - } return cell } diff --git a/elpha-ios/Base.lproj/Main.storyboard b/elpha-ios/Base.lproj/Main.storyboard index 700ee61..bd3b80f 100644 --- a/elpha-ios/Base.lproj/Main.storyboard +++ b/elpha-ios/Base.lproj/Main.storyboard @@ -848,7 +848,7 @@ - + @@ -883,7 +883,7 @@ - + @@ -898,9 +898,39 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -919,14 +949,14 @@ - - + + - + - - - - + + + @@ -953,6 +983,7 @@ + @@ -1316,15 +1347,15 @@ - + - + - + - + @@ -1351,7 +1382,7 @@ - + @@ -1391,7 +1422,7 @@ - + @@ -1422,7 +1453,7 @@ - + @@ -1449,7 +1480,7 @@ - + @@ -1480,7 +1511,7 @@ - + @@ -1503,7 +1534,7 @@ - + @@ -1511,7 +1542,7 @@ - + @@ -1529,6 +1560,7 @@ + @@ -1566,7 +1598,7 @@ - + @@ -1822,6 +1854,9 @@ + + + diff --git a/elpha-ios/SettingsManager.swift b/elpha-ios/SettingsManager.swift index 48d898a..949df14 100644 --- a/elpha-ios/SettingsManager.swift +++ b/elpha-ios/SettingsManager.swift @@ -9,13 +9,26 @@ import Foundation class SettingsManager { + private static let gifKey = "settings:gif" + private static let refreshTimelinesKey = "settings:refreshTimelines" + public static var automaticallyPlayGIFs: Bool { get { - return UserDefaults.standard.bool(forKey: "settings:gif") + return UserDefaults.standard.bool(forKey: gifKey) } set { - UserDefaults.standard.set(newValue, forKey: "settings:gif") + UserDefaults.standard.set(newValue, forKey: gifKey) + } + } + + public static var automaticallyRefreshTimelines: Bool { + get { + return UserDefaults.standard.bool(forKey: refreshTimelinesKey) + } + + set { + UserDefaults.standard.set(newValue, forKey: refreshTimelinesKey) } } } diff --git a/elpha-ios/SettingsTableViewController.swift b/elpha-ios/SettingsTableViewController.swift index 0c89b47..d8ee544 100644 --- a/elpha-ios/SettingsTableViewController.swift +++ b/elpha-ios/SettingsTableViewController.swift @@ -15,6 +15,7 @@ class SettingsTableViewController: UITableViewController { @IBOutlet var displayNameLabel: UILabel! @IBOutlet var usernameLabel: UILabel! @IBOutlet var gifSwitch: UISwitch! + @IBOutlet var refreshTimelinesSwitch: UISwitch! override func viewDidLoad() { super.viewDidLoad() @@ -34,6 +35,7 @@ class SettingsTableViewController: UITableViewController { } gifSwitch.isOn = SettingsManager.automaticallyPlayGIFs + refreshTimelinesSwitch.isOn = SettingsManager.automaticallyRefreshTimelines } override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { @@ -52,4 +54,8 @@ class SettingsTableViewController: UITableViewController { @IBAction func gifChanged(_ sender: Any) { SettingsManager.automaticallyPlayGIFs = gifSwitch.isOn } + + @IBAction func refreshTimelinesChanged(_ sender: Any) { + SettingsManager.automaticallyRefreshTimelines = refreshTimelinesSwitch.isOn + } } diff --git a/elpha-ios/StatusTableViewCell.swift b/elpha-ios/StatusTableViewCell.swift index 7cbe1e2..ef81210 100644 --- a/elpha-ios/StatusTableViewCell.swift +++ b/elpha-ios/StatusTableViewCell.swift @@ -8,6 +8,6 @@ import UIKit -class StatusTableViewCell: UITableViewCell { +class StatusTableViewCell: UITableViewCell, AbstractStatusTableViewCell { @IBOutlet var statusView: StatusView! } diff --git a/elpha-ios/StatusTableViewController.swift b/elpha-ios/StatusTableViewController.swift index 8e485cc..6771f57 100644 --- a/elpha-ios/StatusTableViewController.swift +++ b/elpha-ios/StatusTableViewController.swift @@ -11,15 +11,8 @@ import Kingfisher import UIKit import SafariServices -enum StatusType { - case ancestor, status, descendant -} - class StatusTableViewController: AbstractStatusTableViewController, UIGestureRecognizerDelegate { public var status: StatusMO? = nil - - var ancestors: [StatusMO] = [] - var descendants: [StatusMO] = [] var feedbackGenerator: UINotificationFeedbackGenerator? = nil override func viewDidLoad() { @@ -27,11 +20,12 @@ class StatusTableViewController: AbstractStatusTableViewController, UIGestureRec feedbackGenerator = UINotificationFeedbackGenerator() navigationItem.title = "Toot" + + initializeFetchedResultsController() } override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) - loadStatuses() fetchStatuses { error in if error != nil { @@ -162,8 +156,6 @@ class StatusTableViewController: AbstractStatusTableViewController, UIGestureRec CoreDataManager.shared.saveContext() self.loading = false - self.loadStatuses() - completion(nil) } } @@ -171,7 +163,85 @@ class StatusTableViewController: AbstractStatusTableViewController, UIGestureRec } } - func loadStatuses() { + override func updateCell(_ cell: AbstractStatusTableViewCell, withStatusAt indexPath: IndexPath) { + guard let status = fetchedResultsController?.object(at: indexPath) else { + fatalError("CoreData error") + } + + cell.statusView.delegate = self + cell.statusView.update(withStatus: status) + cell.statusView.topDividerView.isHidden = indexPath.row == 0 + cell.statusView.bottomDividerView.isHidden = false + cell.statusView.topLoadMoreView.isHidden = true + cell.statusView.bottomLoadMoreView.isHidden = true + cell.statusView.replyView.isHidden = true + } + + func updateMainCell(_ cell: MainStatusTableViewCell, withStatus status: StatusMO) { + cell.avatarImageView.setRoundedCorners() + + func updateAccountView(status: StatusMO) { + if let account = status.account { + let options: KingfisherOptionsInfo = SettingsManager.automaticallyPlayGIFs ? [] : [.onlyLoadFirstFrame] + cell.avatarImageView.kf.setImage(with: account.avatarURL!, options: options) + cell.displayNameLabel.text = account.displayName + cell.usernameLabel.text = "@\(account.acct!)" + } + } + + if let reblog = status.reblog { + updateAccountView(status: reblog) + } else { + updateAccountView(status: status) + } + + if let content = status.content { + cell.contentTextView.attributedText = content.htmlAttributed(size: 16) + } + + cell.attachmentsView.backgroundColor = UIColor.white + cell.attachmentsView.isHidden = true + + if let attachments = status.attachments, attachments.count > 0 { + cell.attachmentsView.isHidden = false + cell.attachmentsView.isUserInteractionEnabled = true + + let attachmentManager = AttachmentManager() + attachmentManager.delegate = self + attachmentManager.setupAttachmentView(cell.attachmentsView, withAttachments: attachments) + } + + let dateFormatter = DateFormatter() + dateFormatter.dateStyle = .medium + dateFormatter.timeStyle = .none + + cell.timestampDateLabel.text = dateFormatter.string(from: status.createdAt!) + + dateFormatter.dateStyle = .none + dateFormatter.timeStyle = .short + + cell.timestampTimeLabel.text = dateFormatter.string(from: status.createdAt!) + + cell.repliesLabel.text = NumberFormatter.localizedString(from: NSNumber(value: status.repliesCount), number: .decimal) + cell.boostsLabel.text = NumberFormatter.localizedString(from: NSNumber(value: status.reblogsCount), number: .decimal) + cell.favoritesLabel.text = NumberFormatter.localizedString(from: NSNumber(value: status.favoritesCount), number: .decimal) + + if status.reblogged { + cell.boostsImageView.image = UIImage(named: "Boost Bold") + } else { + cell.boostsImageView.image = UIImage(named: "Boost Regular") + } + + if status.favorited { + cell.favoritesImageView.image = UIImage(named: "Star Filled") + } else { + cell.favoritesImageView.image = UIImage(named: "Star Regular") + } + } +} + +extension StatusTableViewController: NSFetchedResultsControllerDelegate { + func initializeFetchedResultsController() { guard let status = status else { return } @@ -179,54 +249,57 @@ class StatusTableViewController: AbstractStatusTableViewController, UIGestureRec let request = NSFetchRequest(entityName: "Status") request.predicate = NSPredicate(format: "id == %@ OR ANY ancestors == %@ OR ANY descendants == %@", status.id!, status, status) request.sortDescriptors = [ - NSSortDescriptor(key: "createdAt", ascending: false), + NSSortDescriptor(key: "createdAt", ascending: true), ] - ancestors = [] - descendants = [] + fetchedResultsController = NSFetchedResultsController( + fetchRequest: request, + managedObjectContext: CoreDataManager.shared.context, + sectionNameKeyPath: nil, + cacheName: nil + ) + + fetchedResultsController!.delegate = self do { - let statuses = try CoreDataManager.shared.context.fetch(request) - statuses.forEach { s in - switch s.createdAt!.compare(status.createdAt!) { - case .orderedAscending: - ancestors.append(s) - case .orderedSame: - return - case .orderedDescending: - descendants.append(s) - } - } - - ancestors.reverse() - descendants.reverse() - - self.tableView.reloadData() + try fetchedResultsController!.performFetch() } catch { print("\(error)") } } - override func boostTapped() { - loadStatuses() - } - - override func favoriteTapped() { - loadStatuses() + func controllerWillChangeContent(_ controller: NSFetchedResultsController) { + tableView.beginUpdates() } - override func revealTapped() { - loadStatuses() + func controller(_ controller: NSFetchedResultsController, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) { + switch type { + case NSFetchedResultsChangeType.insert: + tableView.insertRows(at: [newIndexPath!], with: UITableView.RowAnimation.none) + case NSFetchedResultsChangeType.delete: + tableView.deleteRows(at: [indexPath!], with: UITableView.RowAnimation.none) + case NSFetchedResultsChangeType.update: + if let cell = tableView.cellForRow(at: indexPath!) as? StatusTableViewCell { + updateCell(cell, withStatusAt: indexPath!) + } + + if let cell = tableView.cellForRow(at: indexPath!) as? MainStatusTableViewCell { + updateMainCell(cell, withStatus: anObject as! StatusMO) + } + case NSFetchedResultsChangeType.move: + tableView.deleteRows(at: [indexPath!], with: UITableView.RowAnimation.fade) + tableView.insertRows(at: [newIndexPath!], with: UITableView.RowAnimation.fade) + } } - override func hideTapped() { - loadStatuses() + func controllerDidChangeContent(_ controller: NSFetchedResultsController) { + tableView.endUpdates() } } extension StatusTableViewController { override func numberOfSections(in tableView: UITableView) -> Int { - return 3 + return 1 } override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) { @@ -236,45 +309,28 @@ extension StatusTableViewController { } override func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat { - switch indexPath.section { - case 0: return CellHeightManager.get(status: self.ancestors[indexPath.row]) - case 2: return CellHeightManager.get(status: self.descendants[indexPath.row]) - default: return UITableView.automaticDimension + guard let status = fetchedResultsController?.object(at: indexPath) else { + return UITableView.automaticDimension } - } - - override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { - let height = CGFloat(25) - switch section { - case 0: return ancestors.count > 0 ? height : 0 - case 2: return descendants.count > 0 ? height : 0 - default: return height - } - } - - override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { - switch section { - case 0: return ancestors.count > 0 ? "In Reply To" : nil - case 2: return descendants.count > 0 ? "Replies" : nil - default: return "Toot" + if status == self.status { + return UITableView.automaticDimension } + + return CellHeightManager.get(status: status) } override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - switch section { - case 0: return ancestors.count - case 2: return descendants.count - default: return 1 + guard let count = fetchedResultsController?.fetchedObjects?.count else { + return 0 } + + return count } override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - var status: StatusMO - switch indexPath.section { - case 0: status = self.ancestors[indexPath.row] - case 2: status = self.descendants[indexPath.row] - default: status = self.status! + guard let status = fetchedResultsController?.object(at: indexPath) else { + fatalError("CoreData error") } if status == self.status { @@ -282,66 +338,9 @@ extension StatusTableViewController { fatalError("Unable to find reusable cell") } + updateMainCell(cell, withStatus: status) cell.contentTextView.delegate = self - cell.avatarImageView.setRoundedCorners() - func updateAccountView(status: StatusMO) { - if let account = status.account { - let options: KingfisherOptionsInfo = SettingsManager.automaticallyPlayGIFs ? [] : [.onlyLoadFirstFrame] - cell.avatarImageView.kf.setImage(with: account.avatarURL!, options: options) - cell.displayNameLabel.text = account.displayName - cell.usernameLabel.text = "@\(account.acct!)" - } - } - - if let reblog = status.reblog { - updateAccountView(status: reblog) - } else { - updateAccountView(status: status) - } - - if let content = status.content { - cell.contentTextView.attributedText = content.htmlAttributed(size: 16) - } - - cell.attachmentsView.backgroundColor = UIColor.white - cell.attachmentsView.isHidden = true - - if let attachments = status.attachments, attachments.count > 0 { - cell.attachmentsView.isHidden = false - cell.attachmentsView.isUserInteractionEnabled = true - - let attachmentManager = AttachmentManager() - attachmentManager.delegate = self - attachmentManager.setupAttachmentView(cell.attachmentsView, withAttachments: attachments) - } - - let dateFormatter = DateFormatter() - dateFormatter.dateStyle = .medium - dateFormatter.timeStyle = .none - - cell.timestampDateLabel.text = dateFormatter.string(from: status.createdAt!) - - dateFormatter.dateStyle = .none - dateFormatter.timeStyle = .short - - cell.timestampTimeLabel.text = dateFormatter.string(from: status.createdAt!) - - cell.repliesLabel.text = NumberFormatter.localizedString(from: NSNumber(value: status.repliesCount), number: .decimal) - cell.boostsLabel.text = NumberFormatter.localizedString(from: NSNumber(value: status.reblogsCount), number: .decimal) - cell.favoritesLabel.text = NumberFormatter.localizedString(from: NSNumber(value: status.favoritesCount), number: .decimal) - - if status.reblogged { - cell.boostsImageView.image = UIImage(named: "Boost Bold") - } else { - cell.boostsImageView.image = UIImage(named: "Boost Regular") - } - - if status.favorited { - cell.favoritesImageView.image = UIImage(named: "Star Filled") - } else { - cell.favoritesImageView.image = UIImage(named: "Star Regular") - } return cell } else { @@ -349,13 +348,8 @@ extension StatusTableViewController { fatalError("Unable to find reusable cell") } + updateCell(cell, withStatusAt: indexPath) cell.statusView.delegate = self - cell.statusView.update(withStatus: status) - cell.statusView.topDividerView.isHidden = indexPath.row == 0 - cell.statusView.bottomDividerView.isHidden = false - cell.statusView.topLoadMoreView.isHidden = true - cell.statusView.bottomLoadMoreView.isHidden = true - cell.statusView.replyView.isHidden = true return cell } diff --git a/elpha-ios/TimelineTableViewCell.swift b/elpha-ios/TimelineTableViewCell.swift index 417e8f4..8dd2543 100644 --- a/elpha-ios/TimelineTableViewCell.swift +++ b/elpha-ios/TimelineTableViewCell.swift @@ -8,6 +8,6 @@ import UIKit -class TimelineTableViewCell: UITableViewCell { +class TimelineTableViewCell: UITableViewCell, AbstractStatusTableViewCell { @IBOutlet var statusView: StatusView! } diff --git a/elpha-ios/TimelineTableViewController.swift b/elpha-ios/TimelineTableViewController.swift index 0c71dcf..3e6ff96 100644 --- a/elpha-ios/TimelineTableViewController.swift +++ b/elpha-ios/TimelineTableViewController.swift @@ -13,7 +13,6 @@ import SafariServices class TimelineTableViewController: AbstractStatusTableViewController { var feedbackGenerator: UINotificationFeedbackGenerator? = nil - var fetchedResultsController: NSFetchedResultsController? = nil override var currentPaginationContext: String { get { @@ -77,6 +76,10 @@ class TimelineTableViewController: AbstractStatusTableViewController { if fetchedResultsController?.fetchedObjects?.count ?? 0 == 0 { initializeFetchedResultsController() } + + if SettingsManager.automaticallyRefreshTimelines { + self.fetch() + } } override func loadMoreTapped(status: StatusMO, direction: PaginationDirection) { @@ -324,7 +327,7 @@ extension TimelineTableViewController: NSFetchedResultsControllerDelegate { tableView.deleteRows(at: [indexPath!], with: UITableView.RowAnimation.none) case NSFetchedResultsChangeType.update: if let cell = tableView.cellForRow(at: indexPath!) as? TimelineTableViewCell { - cell.statusView.update(withStatus: anObject as! StatusMO) + updateCell(cell, withStatusAt: indexPath!) } case NSFetchedResultsChangeType.move: tableView.deleteRows(at: [indexPath!], with: UITableView.RowAnimation.fade) @@ -365,52 +368,8 @@ extension TimelineTableViewController { fatalError("Unable to find reusable cell") } - guard let status = fetchedResultsController?.object(at: indexPath) else { - fatalError("CoreData error") - } - + updateCell(cell, withStatusAt: indexPath) cell.statusView.delegate = self - cell.statusView.update(withStatus: status) - cell.statusView.topDividerView.isHidden = indexPath.row == 0 - cell.statusView.bottomDividerView.isHidden = false - cell.statusView.topLoadMoreView.isHidden = true - cell.statusView.bottomLoadMoreView.isHidden = true - - let statusCount = fetchedResultsController?.fetchedObjects?.count ?? 0 - - if let markers = status.markers { - markers.forEach { marker in - if marker.context == self.currentPaginationContext { - switch marker.item.direction { - case .prev: - if indexPath.row > 0, let previousStatus = fetchedResultsController?.object(at: IndexPath(row: indexPath.row - 1, section: indexPath.section)) { - let previousMarkers = previousStatus.markers ?? [] - let previousMarker = previousMarkers.first { $0.context == self.currentPaginationContext && $0.item.direction == .next } - - if previousStatus.id! != marker.item.statusID && previousMarker != nil { - cell.statusView.topLoadMoreView.isHidden = false - cell.statusView.topDividerView.isHidden = true - } - } - case .next: - if indexPath.row < statusCount - 1, let nextStatus = fetchedResultsController?.object(at: IndexPath(row: indexPath.row + 1, section: indexPath.section)) { - let nextMarkers = nextStatus.markers ?? [] - let nextMarker = nextMarkers.first { $0.context == self.currentPaginationContext && $0.item.direction == .prev } - - if nextStatus.id! != marker.item.statusID && nextMarker != nil { - cell.statusView.bottomLoadMoreView.isHidden = false - cell.statusView.bottomDividerView.isHidden = true - } - } - } - } - } - } - - if indexPath.row == statusCount - 1 { - cell.statusView.bottomLoadMoreView.isHidden = false - cell.statusView.bottomDividerView.isHidden = true - } return cell }