From 1ad591fd8246000f8d6d6c12e6ea82e099b6241f Mon Sep 17 00:00:00 2001 From: Nathan Mattes Date: Sun, 17 Sep 2023 13:01:46 +0200 Subject: [PATCH] Search for people (IOS-141) --- Mastodon/Coordinator/SceneCoordinator.swift | 313 +++++++++--------- .../SearchResultOverviewSection.swift | 36 +- ...chResultsOverviewTableViewController.swift | 30 +- 3 files changed, 189 insertions(+), 190 deletions(-) diff --git a/Mastodon/Coordinator/SceneCoordinator.swift b/Mastodon/Coordinator/SceneCoordinator.swift index 4908a533a..73eda67eb 100644 --- a/Mastodon/Coordinator/SceneCoordinator.swift +++ b/Mastodon/Coordinator/SceneCoordinator.swift @@ -153,6 +153,7 @@ extension SceneCoordinator { // search case searchDetail(viewModel: SearchDetailViewModel) + case searchResult(viewModel: SearchResultViewModel) // compose case compose(viewModel: ComposeViewModel) @@ -376,159 +377,169 @@ private extension SceneCoordinator { let viewController: UIViewController? switch scene { - case .welcome: - let _viewController = WelcomeViewController() - viewController = _viewController - case .mastodonPickServer(let viewModel): - let _viewController = MastodonPickServerViewController() - _viewController.viewModel = viewModel - viewController = _viewController - case .mastodonRegister(let viewModel): - let _viewController = MastodonRegisterViewController() - _viewController.viewModel = viewModel - viewController = _viewController - case .mastodonServerRules(let viewModel): - let _viewController = MastodonServerRulesViewController() - _viewController.viewModel = viewModel - viewController = _viewController - case .mastodonConfirmEmail(let viewModel): - let _viewController = MastodonConfirmEmailViewController() - _viewController.viewModel = viewModel - viewController = _viewController - case .mastodonLogin: - let loginViewController = MastodonLoginViewController(appContext: appContext, - authenticationViewModel: AuthenticationViewModel(context: appContext, coordinator: self, isAuthenticationExist: false), - sceneCoordinator: self) - loginViewController.delegate = self + case .welcome: + let _viewController = WelcomeViewController() + viewController = _viewController + case .mastodonPickServer(let viewModel): + let _viewController = MastodonPickServerViewController() + _viewController.viewModel = viewModel + viewController = _viewController + case .mastodonRegister(let viewModel): + let _viewController = MastodonRegisterViewController() + _viewController.viewModel = viewModel + viewController = _viewController + case .mastodonServerRules(let viewModel): + let _viewController = MastodonServerRulesViewController() + _viewController.viewModel = viewModel + viewController = _viewController + case .mastodonConfirmEmail(let viewModel): + let _viewController = MastodonConfirmEmailViewController() + _viewController.viewModel = viewModel + viewController = _viewController + case .mastodonLogin: + let loginViewController = MastodonLoginViewController(appContext: appContext, + authenticationViewModel: AuthenticationViewModel(context: appContext, coordinator: self, isAuthenticationExist: false), + sceneCoordinator: self) + loginViewController.delegate = self - viewController = loginViewController - case .mastodonPrivacyPolicies(let viewModel): - let privacyViewController = PrivacyTableViewController(context: appContext, coordinator: self, viewModel: viewModel) - viewController = privacyViewController - case .mastodonResendEmail(let viewModel): - let _viewController = MastodonResendEmailViewController() - _viewController.viewModel = viewModel - viewController = _viewController - case .mastodonWebView(let viewModel): - let _viewController = WebViewController() - _viewController.viewModel = viewModel - viewController = _viewController - case .searchDetail(let viewModel): - let _viewController = SearchDetailViewController() - _viewController.viewModel = viewModel - viewController = _viewController - case .compose(let viewModel): - let _viewController = ComposeViewController(viewModel: viewModel) - viewController = _viewController - case .thread(let viewModel): - let _viewController = ThreadViewController() - _viewController.viewModel = viewModel - viewController = _viewController - case .editHistory(let viewModel): - let editHistoryViewController = StatusEditHistoryViewController(viewModel: viewModel) - viewController = editHistoryViewController - case .hashtagTimeline(let viewModel): - let _viewController = HashtagTimelineViewController() - _viewController.viewModel = viewModel - viewController = _viewController - case .accountList(let viewModel): - let _viewController = AccountListViewController() - _viewController.viewModel = viewModel - viewController = _viewController - case .profile(let viewModel): - let _viewController = ProfileViewController() - _viewController.viewModel = viewModel - viewController = _viewController - case .bookmark(let viewModel): - let _viewController = BookmarkViewController() - _viewController.viewModel = viewModel - viewController = _viewController - case .followedTags(let viewModel): - let _viewController = FollowedTagsViewController() - _viewController.viewModel = viewModel - viewController = _viewController - case .favorite(let viewModel): - let _viewController = FavoriteViewController() - _viewController.viewModel = viewModel - viewController = _viewController - case .follower(let viewModel): - let _viewController = FollowerListViewController() - _viewController.viewModel = viewModel - viewController = _viewController - case .following(let viewModel): - let _viewController = FollowingListViewController() - _viewController.viewModel = viewModel - viewController = _viewController - case .familiarFollowers(let viewModel): - let _viewController = FamiliarFollowersViewController() - _viewController.viewModel = viewModel - viewController = _viewController - case .rebloggedBy(let viewModel): - let _viewController = RebloggedByViewController() - _viewController.viewModel = viewModel - viewController = _viewController - case .favoritedBy(let viewModel): - let _viewController = FavoritedByViewController() - _viewController.viewModel = viewModel - viewController = _viewController - case .report(let viewModel): - let _viewController = ReportViewController() - _viewController.viewModel = viewModel - viewController = _viewController - case .reportServerRules(let viewModel): - let _viewController = ReportServerRulesViewController() - _viewController.viewModel = viewModel - viewController = _viewController - case .reportStatus(let viewModel): - let _viewController = ReportStatusViewController() - _viewController.viewModel = viewModel - viewController = _viewController - case .reportSupplementary(let viewModel): - let _viewController = ReportSupplementaryViewController() - _viewController.viewModel = viewModel - viewController = _viewController - case .reportResult(let viewModel): - let _viewController = ReportResultViewController() - _viewController.viewModel = viewModel - viewController = _viewController - case .suggestionAccount(let viewModel): - let _viewController = SuggestionAccountViewController() - _viewController.viewModel = viewModel - viewController = _viewController - case .mediaPreview(let viewModel): - let _viewController = MediaPreviewViewController() - _viewController.viewModel = viewModel - viewController = _viewController - case .safari(let url): - guard let scheme = url.scheme?.lowercased(), - scheme == "http" || scheme == "https" else { - return nil - } - let _viewController = SFSafariViewController(url: url) - _viewController.preferredBarTintColor = ThemeService.shared.currentTheme.value.navigationBarBackgroundColor - _viewController.preferredControlTintColor = Asset.Colors.Brand.blurple.color - viewController = _viewController + viewController = loginViewController + case .mastodonPrivacyPolicies(let viewModel): + let privacyViewController = PrivacyTableViewController(context: appContext, coordinator: self, viewModel: viewModel) + viewController = privacyViewController + case .mastodonResendEmail(let viewModel): + let _viewController = MastodonResendEmailViewController() + _viewController.viewModel = viewModel + viewController = _viewController + case .mastodonWebView(let viewModel): + let _viewController = WebViewController() + _viewController.viewModel = viewModel + viewController = _viewController - case .alertController(let alertController): - if let popoverPresentationController = alertController.popoverPresentationController { - assert( - popoverPresentationController.sourceView != nil || - popoverPresentationController.sourceRect != .zero || - popoverPresentationController.barButtonItem != nil - ) - } - viewController = alertController - case .activityViewController(let activityViewController, let sourceView, let barButtonItem): - activityViewController.popoverPresentationController?.sourceView = sourceView - activityViewController.popoverPresentationController?.barButtonItem = barButtonItem - viewController = activityViewController - case .settings(let viewModel): - let _viewController = SettingsViewController() - _viewController.viewModel = viewModel - viewController = _viewController - case .editStatus(let viewModel): - let composeViewController = ComposeViewController(viewModel: viewModel) - viewController = composeViewController + + case .searchDetail(let viewModel): + let _viewController = SearchDetailViewController() + _viewController.viewModel = viewModel + viewController = _viewController + case .searchResult(let viewModel): + let searchResultViewController = SearchResultViewController() + searchResultViewController.context = appContext + searchResultViewController.coordinator = self + searchResultViewController.viewModel = viewModel + viewController = searchResultViewController + + + case .compose(let viewModel): + let _viewController = ComposeViewController(viewModel: viewModel) + viewController = _viewController + case .thread(let viewModel): + let _viewController = ThreadViewController() + _viewController.viewModel = viewModel + viewController = _viewController + case .editHistory(let viewModel): + let editHistoryViewController = StatusEditHistoryViewController(viewModel: viewModel) + viewController = editHistoryViewController + case .hashtagTimeline(let viewModel): + let _viewController = HashtagTimelineViewController() + _viewController.viewModel = viewModel + viewController = _viewController + case .accountList(let viewModel): + let _viewController = AccountListViewController() + _viewController.viewModel = viewModel + viewController = _viewController + case .profile(let viewModel): + let _viewController = ProfileViewController() + _viewController.viewModel = viewModel + viewController = _viewController + case .bookmark(let viewModel): + let _viewController = BookmarkViewController() + _viewController.viewModel = viewModel + viewController = _viewController + case .followedTags(let viewModel): + let _viewController = FollowedTagsViewController() + _viewController.viewModel = viewModel + viewController = _viewController + case .favorite(let viewModel): + let _viewController = FavoriteViewController() + _viewController.viewModel = viewModel + viewController = _viewController + case .follower(let viewModel): + let _viewController = FollowerListViewController() + _viewController.viewModel = viewModel + viewController = _viewController + case .following(let viewModel): + let _viewController = FollowingListViewController() + _viewController.viewModel = viewModel + viewController = _viewController + case .familiarFollowers(let viewModel): + let _viewController = FamiliarFollowersViewController() + _viewController.viewModel = viewModel + viewController = _viewController + case .rebloggedBy(let viewModel): + let _viewController = RebloggedByViewController() + _viewController.viewModel = viewModel + viewController = _viewController + case .favoritedBy(let viewModel): + let _viewController = FavoritedByViewController() + _viewController.viewModel = viewModel + viewController = _viewController + case .report(let viewModel): + let _viewController = ReportViewController() + _viewController.viewModel = viewModel + viewController = _viewController + case .reportServerRules(let viewModel): + let _viewController = ReportServerRulesViewController() + _viewController.viewModel = viewModel + viewController = _viewController + case .reportStatus(let viewModel): + let _viewController = ReportStatusViewController() + _viewController.viewModel = viewModel + viewController = _viewController + case .reportSupplementary(let viewModel): + let _viewController = ReportSupplementaryViewController() + _viewController.viewModel = viewModel + viewController = _viewController + case .reportResult(let viewModel): + let _viewController = ReportResultViewController() + _viewController.viewModel = viewModel + viewController = _viewController + case .suggestionAccount(let viewModel): + let _viewController = SuggestionAccountViewController() + _viewController.viewModel = viewModel + viewController = _viewController + case .mediaPreview(let viewModel): + let _viewController = MediaPreviewViewController() + _viewController.viewModel = viewModel + viewController = _viewController + case .safari(let url): + guard let scheme = url.scheme?.lowercased(), + scheme == "http" || scheme == "https" else { + return nil + } + let _viewController = SFSafariViewController(url: url) + _viewController.preferredBarTintColor = ThemeService.shared.currentTheme.value.navigationBarBackgroundColor + _viewController.preferredControlTintColor = Asset.Colors.Brand.blurple.color + viewController = _viewController + + case .alertController(let alertController): + if let popoverPresentationController = alertController.popoverPresentationController { + assert( + popoverPresentationController.sourceView != nil || + popoverPresentationController.sourceRect != .zero || + popoverPresentationController.barButtonItem != nil + ) + } + viewController = alertController + case .activityViewController(let activityViewController, let sourceView, let barButtonItem): + activityViewController.popoverPresentationController?.sourceView = sourceView + activityViewController.popoverPresentationController?.barButtonItem = barButtonItem + viewController = activityViewController + case .settings(let viewModel): + let _viewController = SettingsViewController() + _viewController.viewModel = viewModel + viewController = _viewController + case .editStatus(let viewModel): + let composeViewController = ComposeViewController(viewModel: viewModel) + viewController = composeViewController } setupDependency(for: viewController as? NeedsDependency) diff --git a/Mastodon/Scene/Search/SearchDetail/Search Results Overview/SearchResultOverviewSection.swift b/Mastodon/Scene/Search/SearchDetail/Search Results Overview/SearchResultOverviewSection.swift index 37d352b07..0909f5eab 100644 --- a/Mastodon/Scene/Search/SearchDetail/Search Results Overview/SearchResultOverviewSection.swift +++ b/Mastodon/Scene/Search/SearchDetail/Search Results Overview/SearchResultOverviewSection.swift @@ -46,39 +46,25 @@ enum SearchResultOverviewItem: Hashable { } } } - + enum SuggestionSectionEntry: Hashable { case hashtag(tag: Mastodon.Entity.Tag) case profile(user: Mastodon.Entity.Account) - + var title: String? { - switch self { - - case .hashtag(tag: let tag): - return tag.name - case .profile(user: let user): - return "\(user.displayName) — \(user.acct)" + if case let .hashtag(tag) = self { + return tag.name + } else { + return nil } -// if case let .hashtag(tag) = self { -// return tag.name -// } else { -// return nil -// } } - + var icon: UIImage? { - switch self { - - case .hashtag(tag: _): - return UIImage(systemName: "number") - - case .profile(user: _): - return UIImage(systemName: "person.circle") - + if case .hashtag(_) = self { + return UIImage(systemName: "number") + } else { + return nil } -// if case let .hashtag(tag) = self { -// } else { -// } } } } diff --git a/Mastodon/Scene/Search/SearchDetail/Search Results Overview/SearchResultsOverviewTableViewController.swift b/Mastodon/Scene/Search/SearchDetail/Search Results Overview/SearchResultsOverviewTableViewController.swift index b3026e279..5097dd605 100644 --- a/Mastodon/Scene/Search/SearchDetail/Search Results Overview/SearchResultsOverviewTableViewController.swift +++ b/Mastodon/Scene/Search/SearchDetail/Search Results Overview/SearchResultsOverviewTableViewController.swift @@ -61,23 +61,21 @@ class SearchResultsOverviewTableViewController: UIViewController, NeedsDependenc cell.configure(item: .hashtag(tag: hashtag)) return cell - // case .profile(let profile): guard let cell = tableView.dequeueReusableCell(withIdentifier: UserTableViewCell.reuseIdentifier, for: indexPath) as? UserTableViewCell else { fatalError() } - // how the fuck do I get a MastodonUser??? let managedObjectContext = appContext.managedObjectContext Task { do { try await managedObjectContext.perform { guard let user = Persistence.MastodonUser.fetch(in: managedObjectContext, - context: Persistence.MastodonUser.PersistContext( - domain: authContext.mastodonAuthenticationBox.domain, - entity: profile, - cache: nil, - networkDate: Date() - )) else { return } + context: Persistence.MastodonUser.PersistContext( + domain: authContext.mastodonAuthenticationBox.domain, + entity: profile, + cache: nil, + networkDate: Date() + )) else { return } cell.configure( me: authContext.mastodonAuthenticationBox.authenticationRecord.object(in: managedObjectContext)?.user, @@ -89,8 +87,7 @@ class SearchResultsOverviewTableViewController: UIViewController, NeedsDependenc followRequestedUsers: authContext.mastodonAuthenticationBox.inMemoryCache.$followRequestedUserIDs.eraseToAnyPublisher()), delegate: nil) } - } - catch { + } catch { // do nothing } } @@ -105,7 +102,6 @@ class SearchResultsOverviewTableViewController: UIViewController, NeedsDependenc tableView.delegate = self self.dataSource = dataSource - view.addSubview(tableView) tableView.pinToParent() } @@ -221,6 +217,13 @@ class SearchResultsOverviewTableViewController: UIViewController, NeedsDependenc } } } + + func searchForPeople(withName searchText: String) { + let searchResultViewModel = SearchResultViewModel(context: context, authContext: authContext, searchScope: .people) + searchResultViewModel.searchText.value = searchText + + coordinator.present(scene: .searchResult(viewModel: searchResultViewModel), transition: .show) + } } //MARK: UITableViewDelegate @@ -238,9 +241,8 @@ extension SearchResultsOverviewTableViewController: UITableViewDelegate { case .posts(let hashtag): //FIXME: Show statuses instead of tag-content. Reuse SearchResultsViewController with statuses here? showPosts(tag: Mastodon.Entity.Tag(name: hashtag, url: authContext.mastodonAuthenticationBox.domain)) - case .people(let string): - //FIXME: Invoke SearchResultsViewController with people-scope here - delegate?.showPeople(self) + case .people(let searchText): + searchForPeople(withName: searchText) case .profile(let profile, let instanceName): delegate?.showProfile(self) case .openLink(let string):