From 9ec7177bfab100779d0b3b5e61fe492bd424bd6e Mon Sep 17 00:00:00 2001 From: Shadowfacts Date: Sat, 22 May 2021 11:22:01 -0400 Subject: [PATCH] Fix crash when searching fails --- .../Search/SearchResultsViewController.swift | 127 +++++++++++------- 1 file changed, 82 insertions(+), 45 deletions(-) diff --git a/Tusker/Screens/Search/SearchResultsViewController.swift b/Tusker/Screens/Search/SearchResultsViewController.swift index 75e7f2b0..604b25c8 100644 --- a/Tusker/Screens/Search/SearchResultsViewController.swift +++ b/Tusker/Screens/Search/SearchResultsViewController.swift @@ -36,6 +36,7 @@ class SearchResultsViewController: EnhancedTableViewController { var dataSource: UITableViewDiffableDataSource! private var activityIndicator: UIActivityIndicatorView! + private var errorLabel: UILabel! /// Types of results to search for. `nil` means all results will be included. var resultTypes: [SearchResultType]? = nil @@ -60,6 +61,22 @@ class SearchResultsViewController: EnhancedTableViewController { override func viewDidLoad() { super.viewDidLoad() + + errorLabel = UILabel() + errorLabel.translatesAutoresizingMaskIntoConstraints = false + errorLabel.font = .preferredFont(forTextStyle: .callout) + errorLabel.textColor = .secondaryLabel + errorLabel.numberOfLines = 0 + errorLabel.textAlignment = .center + errorLabel.setContentHuggingPriority(.defaultLow, for: .horizontal) + tableView.addSubview(errorLabel) + NSLayoutConstraint.activate([ + errorLabel.centerYAnchor.constraint(equalTo: view.safeAreaLayoutGuide.centerYAnchor), + errorLabel.centerXAnchor.constraint(equalTo: tableView.centerXAnchor), + errorLabel.leadingAnchor.constraint(equalToSystemSpacingAfter: tableView.leadingAnchor, multiplier: 1), + tableView.trailingAnchor.constraint(equalToSystemSpacingAfter: errorLabel.trailingAnchor, multiplier: 1), + ]) + tableView.register(UINib(nibName: "AccountTableViewCell", bundle: .main), forCellReuseIdentifier: accountCell) tableView.register(UINib(nibName: "TimelineStatusTableViewCell", bundle: .main), forCellReuseIdentifier: statusCell) @@ -131,59 +148,79 @@ class SearchResultsViewController: EnhancedTableViewController { activityIndicator.isHidden = false activityIndicator.startAnimating() + errorLabel.isHidden = true - let resultTypes = self.resultTypes let request = Client.search(query: query, types: resultTypes, resolve: true, limit: 10) mastodonController.run(request) { (response) in - guard case let .success(results, _) = response else { fatalError() } - - DispatchQueue.main.async { - self.activityIndicator.isHidden = true - self.activityIndicator.stopAnimating() - } - - guard self.currentQuery == query else { return } - - let oldSnapshot = self.dataSource.snapshot() - var snapshot = NSDiffableDataSourceSnapshot() - - self.mastodonController.persistentContainer.performBatchUpdates({ (context, addAccounts, addStatuses) in - if oldSnapshot.indexOfSection(.accounts) != nil { - oldSnapshot.itemIdentifiers(inSection: .accounts).forEach { (item) in - guard case let .account(id) = item else { return } - self.mastodonController.persistentContainer.account(for: id, in: context)?.decrementReferenceCount() - } - } - - if oldSnapshot.indexOfSection(.statuses) != nil { - oldSnapshot.itemIdentifiers(inSection: .statuses).forEach { (item) in - guard case let .status(id, _) = item else { return } - self.mastodonController.persistentContainer.status(for: id, in: context)?.decrementReferenceCount() - } - } - - if !results.accounts.isEmpty && (resultTypes == nil || resultTypes!.contains(.accounts)) { - snapshot.appendSections([.accounts]) - snapshot.appendItems(results.accounts.map { .account($0.id) }, toSection: .accounts) - addAccounts(results.accounts) - } - if !results.hashtags.isEmpty && (resultTypes == nil || resultTypes!.contains(.hashtags)) { - snapshot.appendSections([.hashtags]) - snapshot.appendItems(results.hashtags.map { .hashtag($0) }, toSection: .hashtags) - } - if !results.statuses.isEmpty && (resultTypes == nil || resultTypes!.contains(.statuses)) { - snapshot.appendSections([.statuses]) - snapshot.appendItems(results.statuses.map { .status($0.id, .unknown) }, toSection: .statuses) - addStatuses(results.statuses) - } - }, completion: { + switch response { + case let .success(results, _): + guard self.currentQuery == query else { return } DispatchQueue.main.async { - self.dataSource.apply(snapshot) + self.activityIndicator.isHidden = true + self.activityIndicator.stopAnimating() } - }) + self.showSearchResults(results) + case let .failure(error): + DispatchQueue.main.async { + self.activityIndicator.isHidden = true + self.activityIndicator.stopAnimating() + + self.showSearchError(error) + } + } } } + private func showSearchResults(_ results: SearchResults) { + let oldSnapshot = self.dataSource.snapshot() + var snapshot = NSDiffableDataSourceSnapshot() + + self.mastodonController.persistentContainer.performBatchUpdates({ (context, addAccounts, addStatuses) in + if oldSnapshot.indexOfSection(.accounts) != nil { + oldSnapshot.itemIdentifiers(inSection: .accounts).forEach { (item) in + guard case let .account(id) = item else { return } + self.mastodonController.persistentContainer.account(for: id, in: context)?.decrementReferenceCount() + } + } + + if oldSnapshot.indexOfSection(.statuses) != nil { + oldSnapshot.itemIdentifiers(inSection: .statuses).forEach { (item) in + guard case let .status(id, _) = item else { return } + self.mastodonController.persistentContainer.status(for: id, in: context)?.decrementReferenceCount() + } + } + + let resultTypes = self.resultTypes + if !results.accounts.isEmpty && (resultTypes == nil || resultTypes!.contains(.accounts)) { + snapshot.appendSections([.accounts]) + snapshot.appendItems(results.accounts.map { .account($0.id) }, toSection: .accounts) + addAccounts(results.accounts) + } + if !results.hashtags.isEmpty && (resultTypes == nil || resultTypes!.contains(.hashtags)) { + snapshot.appendSections([.hashtags]) + snapshot.appendItems(results.hashtags.map { .hashtag($0) }, toSection: .hashtags) + } + if !results.statuses.isEmpty && (resultTypes == nil || resultTypes!.contains(.statuses)) { + snapshot.appendSections([.statuses]) + snapshot.appendItems(results.statuses.map { .status($0.id, .unknown) }, toSection: .statuses) + addStatuses(results.statuses) + } + }, completion: { + DispatchQueue.main.async { + self.errorLabel.isHidden = true + self.dataSource.apply(snapshot) + } + }) + } + + private func showSearchError(_ error: Client.Error) { + let snapshot = NSDiffableDataSourceSnapshot() + dataSource.apply(snapshot) + + errorLabel.isHidden = false + errorLabel.text = error.localizedDescription + } + // MARK: - Table view delegate override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {