From 0738683ee38f74c72fdcc09c6d3ab865fb4ef528 Mon Sep 17 00:00:00 2001 From: Shadowfacts Date: Sun, 22 Jan 2023 11:41:38 -0500 Subject: [PATCH] Add search scopes Closes #328 --- .../Explore/ExploreViewController.swift | 4 ++ .../HashtagSearchResultsViewController.swift | 2 +- .../EditListAccountsViewController.swift | 2 +- .../Search/SearchResultsViewController.swift | 58 ++++++++++++++++--- .../Screens/Search/SearchViewController.swift | 4 ++ 5 files changed, 59 insertions(+), 11 deletions(-) diff --git a/Tusker/Screens/Explore/ExploreViewController.swift b/Tusker/Screens/Explore/ExploreViewController.swift index 5e634b61f8..e8e92f238c 100644 --- a/Tusker/Screens/Explore/ExploreViewController.swift +++ b/Tusker/Screens/Explore/ExploreViewController.swift @@ -64,8 +64,12 @@ class ExploreViewController: UIViewController, UICollectionViewDelegate, Collect resultsController.exploreNavigationController = self.navigationController! searchController = UISearchController(searchResultsController: resultsController) searchController.searchResultsUpdater = resultsController + if #available(iOS 16.0, *) { + searchController.scopeBarActivation = .onSearchActivation + } searchController.searchBar.autocapitalizationType = .none searchController.searchBar.delegate = resultsController + searchController.searchBar.scopeButtonTitles = SearchResultsViewController.Scope.allCases.map(\.title) definesPresentationContext = true navigationItem.searchController = searchController diff --git a/Tusker/Screens/Explore/HashtagSearchResultsViewController.swift b/Tusker/Screens/Explore/HashtagSearchResultsViewController.swift index 7ed96e5b07..d75d94026f 100644 --- a/Tusker/Screens/Explore/HashtagSearchResultsViewController.swift +++ b/Tusker/Screens/Explore/HashtagSearchResultsViewController.swift @@ -11,7 +11,7 @@ import UIKit class HashtagSearchResultsViewController: SearchResultsViewController { init(mastodonController: MastodonController) { - super.init(mastodonController: mastodonController, resultTypes: [.hashtags]) + super.init(mastodonController: mastodonController, scope: .hashtags) } required init?(coder: NSCoder) { diff --git a/Tusker/Screens/Lists/EditListAccountsViewController.swift b/Tusker/Screens/Lists/EditListAccountsViewController.swift index f0eb2e1679..4891959c85 100644 --- a/Tusker/Screens/Lists/EditListAccountsViewController.swift +++ b/Tusker/Screens/Lists/EditListAccountsViewController.swift @@ -65,7 +65,7 @@ class EditListAccountsViewController: EnhancedTableViewController { }) dataSource.editListAccountsController = self - searchResultsController = SearchResultsViewController(mastodonController: mastodonController, resultTypes: [.accounts]) + searchResultsController = SearchResultsViewController(mastodonController: mastodonController, scope: .people) searchResultsController.following = true searchResultsController.delegate = self searchController = UISearchController(searchResultsController: searchResultsController) diff --git a/Tusker/Screens/Search/SearchResultsViewController.swift b/Tusker/Screens/Search/SearchResultsViewController.swift index 0bfb26534a..d14bd605c9 100644 --- a/Tusker/Screens/Search/SearchResultsViewController.swift +++ b/Tusker/Screens/Search/SearchResultsViewController.swift @@ -38,17 +38,17 @@ class SearchResultsViewController: EnhancedTableViewController { 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 + /// Types of results to search for. + var scope: Scope /// Whether to limit results to accounts the users is following. var following: Bool? = nil let searchSubject = PassthroughSubject() var currentQuery: String? - init(mastodonController: MastodonController, resultTypes: [SearchResultType]? = nil) { + init(mastodonController: MastodonController, scope: Scope = .all) { self.mastodonController = mastodonController - self.resultTypes = resultTypes + self.scope = scope super.init(style: .grouped) @@ -153,7 +153,7 @@ class SearchResultsViewController: EnhancedTableViewController { activityIndicator.startAnimating() errorLabel.isHidden = true - let request = Client.search(query: query, types: resultTypes, resolve: true, limit: 10, following: following) + let request = Client.search(query: query, types: scope.resultTypes, resolve: true, limit: 10, following: following) mastodonController.run(request) { (response) in switch response { case let .success(results, _): @@ -178,17 +178,17 @@ class SearchResultsViewController: EnhancedTableViewController { var snapshot = NSDiffableDataSourceSnapshot() self.mastodonController.persistentContainer.performBatchUpdates({ (context, addAccounts, addStatuses) in - let resultTypes = self.resultTypes - if !results.accounts.isEmpty && (resultTypes == nil || resultTypes!.contains(.accounts)) { + let resultTypes = self.scope.resultTypes + if !results.accounts.isEmpty && 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)) { + if !results.hashtags.isEmpty && resultTypes.contains(.hashtags) { snapshot.appendSections([.hashtags]) snapshot.appendItems(results.hashtags.map { .hashtag($0) }, toSection: .hashtags) } - if !results.statuses.isEmpty && (resultTypes == nil || resultTypes!.contains(.statuses)) { + if !results.statuses.isEmpty && resultTypes.contains(.statuses) { snapshot.appendSections([.statuses]) snapshot.appendItems(results.statuses.map { .status($0.id, .unknown) }, toSection: .statuses) addStatuses(results.statuses) @@ -252,6 +252,41 @@ class SearchResultsViewController: EnhancedTableViewController { } +extension SearchResultsViewController { + enum Scope: CaseIterable { + case all + case people + case hashtags + case posts + + var title: String { + switch self { + case .all: + return "All" + case .people: + return "People" + case .hashtags: + return "Hashtags" + case .posts: + return "Posts" + } + } + + var resultTypes: [SearchResultType] { + switch self { + case .all: + return [.accounts, .statuses, .hashtags] + case .people: + return [.accounts] + case .hashtags: + return [.hashtags] + case .posts: + return [.statuses] + } + } + } +} + extension SearchResultsViewController { enum Section: CaseIterable { case accounts @@ -311,6 +346,11 @@ extension SearchResultsViewController: UISearchBarDelegate { // perform a search immedaitely when the search button is pressed performSearch(query: searchBar.text?.trimmingCharacters(in: .whitespacesAndNewlines)) } + + func searchBar(_ searchBar: UISearchBar, selectedScopeButtonIndexDidChange selectedScope: Int) { + self.scope = Scope.allCases[selectedScope] + performSearch(query: searchBar.text?.trimmingCharacters(in: .whitespacesAndNewlines)) + } } extension SearchResultsViewController: TuskerNavigationDelegate { diff --git a/Tusker/Screens/Search/SearchViewController.swift b/Tusker/Screens/Search/SearchViewController.swift index 5a02feb3db..e8239cb53c 100644 --- a/Tusker/Screens/Search/SearchViewController.swift +++ b/Tusker/Screens/Search/SearchViewController.swift @@ -79,8 +79,12 @@ class SearchViewController: UIViewController { resultsController.exploreNavigationController = self.navigationController searchController = UISearchController(searchResultsController: resultsController) searchController.obscuresBackgroundDuringPresentation = true + if #available(iOS 16.0, *) { + searchController.scopeBarActivation = .onSearchActivation + } searchController.searchBar.autocapitalizationType = .none searchController.searchBar.delegate = resultsController + searchController.searchBar.scopeButtonTitles = SearchResultsViewController.Scope.allCases.map(\.title) searchController.hidesNavigationBarDuringPresentation = false definesPresentationContext = true