From 49f6cd6d298560ef6a8397d8e3fb41d2d6317a8b Mon Sep 17 00:00:00 2001 From: Nathan Mattes Date: Mon, 13 Nov 2023 14:44:26 +0100 Subject: [PATCH] Use entities on suggestion-screen (IOS-190) --- .../RecommendAccountItem.swift | 4 +- .../RecommendAccountSection.swift | 16 +--- .../SuggestionAccountViewController.swift | 21 +++-- .../SuggestionAccountViewModel.swift | 82 ++++++++----------- .../SuggestionAccountTableViewCell.swift | 21 ++--- 5 files changed, 58 insertions(+), 86 deletions(-) diff --git a/Mastodon/Scene/SuggestionAccount/RecommendAccountItem.swift b/Mastodon/Scene/SuggestionAccount/RecommendAccountItem.swift index 998f2f3e9..76ce3f434 100644 --- a/Mastodon/Scene/SuggestionAccount/RecommendAccountItem.swift +++ b/Mastodon/Scene/SuggestionAccount/RecommendAccountItem.swift @@ -6,8 +6,8 @@ // import Foundation -import CoreDataStack +import MastodonSDK enum RecommendAccountItem: Hashable { - case account(ManagedObjectRecord) + case account(Mastodon.Entity.Account, relationship: Mastodon.Entity.Relationship?) } diff --git a/Mastodon/Scene/SuggestionAccount/RecommendAccountSection.swift b/Mastodon/Scene/SuggestionAccount/RecommendAccountSection.swift index c3f477a96..7b69dd200 100644 --- a/Mastodon/Scene/SuggestionAccount/RecommendAccountSection.swift +++ b/Mastodon/Scene/SuggestionAccount/RecommendAccountSection.swift @@ -34,21 +34,11 @@ extension RecommendAccountSection { UITableViewDiffableDataSource(tableView: tableView) { tableView, indexPath, item -> UITableViewCell? in let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: SuggestionAccountTableViewCell.self)) as! SuggestionAccountTableViewCell switch item { - case .account(let record): - cell.delegate = configuration.suggestionAccountTableViewCellDelegate - context.managedObjectContext.performAndWait { - guard let user = record.object(in: context.managedObjectContext) else { return } - cell.configure(viewModel: - SuggestionAccountTableViewCell.ViewModel( - user: user, - followedUsers: configuration.authContext.mastodonAuthenticationBox.inMemoryCache.followingUserIds, - blockedUsers: configuration.authContext.mastodonAuthenticationBox.inMemoryCache.blockedUserIds, - followRequestedUsers: configuration.authContext.mastodonAuthenticationBox.inMemoryCache.followRequestedUserIDs) - ) - } + case .account(let account, let relationship): + cell.delegate = configuration.suggestionAccountTableViewCellDelegate + cell.configure(account: account, relationship: relationship) } return cell } } - } diff --git a/Mastodon/Scene/SuggestionAccount/SuggestionAccountViewController.swift b/Mastodon/Scene/SuggestionAccount/SuggestionAccountViewController.swift index 35e1f929d..45d925170 100644 --- a/Mastodon/Scene/SuggestionAccount/SuggestionAccountViewController.swift +++ b/Mastodon/Scene/SuggestionAccount/SuggestionAccountViewController.swift @@ -85,18 +85,21 @@ class SuggestionAccountViewController: UIViewController, NeedsDependency { // MARK: - UITableViewDelegate extension SuggestionAccountViewController: UITableViewDelegate { func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + guard let tableViewDiffableDataSource = viewModel.tableViewDiffableDataSource else { return } guard let item = tableViewDiffableDataSource.itemIdentifier(for: indexPath) else { return } switch item { - case .account(let record): - guard let account = record.object(in: context.managedObjectContext) else { return } - let cachedProfileViewModel = CachedProfileViewModel(context: context, authContext: viewModel.authContext, mastodonUser: account) - _ = coordinator.present( - scene: .profile(viewModel: cachedProfileViewModel), - from: self, - transition: .show - ) + case .account(let account, _): + print("Show \(account.acct)") +// let cachedProfileViewModel = CachedProfileViewModel(context: context, authContext: viewModel.authContext, mastodonUser: account) +// _ = coordinator.present( +// scene: .profile(viewModel: cachedProfileViewModel), +// from: self, +// transition: .show +// ) } + + tableView.deselectRow(at: indexPath, animated: true) } func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? { @@ -104,7 +107,7 @@ extension SuggestionAccountViewController: UITableViewDelegate { return nil } - footerView.followAllButton.isEnabled = viewModel.userFetchedResultsController.records.isNotEmpty + footerView.followAllButton.isEnabled = viewModel.accounts.isNotEmpty footerView.delegate = self return footerView diff --git a/Mastodon/Scene/SuggestionAccount/SuggestionAccountViewModel.swift b/Mastodon/Scene/SuggestionAccount/SuggestionAccountViewModel.swift index 81238105b..cb83ae511 100644 --- a/Mastodon/Scene/SuggestionAccount/SuggestionAccountViewModel.swift +++ b/Mastodon/Scene/SuggestionAccount/SuggestionAccountViewModel.swift @@ -6,9 +6,6 @@ // import Combine -import CoreData -import CoreDataStack -import GameplayKit import MastodonSDK import MastodonCore import UIKit @@ -25,7 +22,8 @@ final class SuggestionAccountViewModel: NSObject { // input let context: AppContext let authContext: AuthContext - let userFetchedResultsController: UserFetchedResultsController + @Published var accounts: [Mastodon.Entity.V2.SuggestionAccount] + var relationships: [Mastodon.Entity.Relationship] var viewWillAppear = PassthroughSubject() @@ -38,51 +36,38 @@ final class SuggestionAccountViewModel: NSObject { ) { self.context = context self.authContext = authContext - self.userFetchedResultsController = UserFetchedResultsController( - managedObjectContext: context.managedObjectContext, - domain: nil, - additionalPredicate: nil - ) + + accounts = [] + relationships = [] + super.init() - - userFetchedResultsController.domain = authContext.mastodonAuthenticationBox.domain // fetch recommended users Task { - var userIDs: [MastodonUser.ID] = [] + var suggestedAccounts: [Mastodon.Entity.V2.SuggestionAccount] = [] do { let response = try await context.apiService.suggestionAccountV2( query: .init(limit: 5), authenticationBox: authContext.mastodonAuthenticationBox ) - userIDs = response.value.map { $0.account.id } - } catch let error as Mastodon.API.Error where error.httpResponseStatus == .notFound { - let response = try await context.apiService.suggestionAccount( - query: nil, + suggestedAccounts = response.value + + guard suggestedAccounts.isNotEmpty else { return } + + let accounts = suggestedAccounts.compactMap { $0.account } + + let relationships = try await context.apiService.relationship( + forAccounts: accounts, authenticationBox: authContext.mastodonAuthenticationBox - ) - userIDs = response.value.map { $0.id } + ).value + + self.relationships = relationships + self.accounts = suggestedAccounts } catch { - + self.relationships = [] + self.accounts = [] } - - guard userIDs.isNotEmpty else { return } - userFetchedResultsController.userIDs = userIDs } - - // fetch relationship - userFetchedResultsController.$records - .removeDuplicates() - .sink { [weak self] records in - guard let _ = self else { return } - Task { - _ = try await context.apiService.relationship( - records: records, - authenticationBox: authContext.mastodonAuthenticationBox - ) - } - } - .store(in: &disposeBag) } func setupDiffableDataSource( @@ -98,15 +83,22 @@ final class SuggestionAccountViewModel: NSObject { ) ) - userFetchedResultsController.$records + $accounts .receive(on: DispatchQueue.main) - .sink { [weak self] records in - guard let self = self else { return } - guard let tableViewDiffableDataSource = self.tableViewDiffableDataSource else { return } + .sink { [weak self] suggestedAccounts in + guard let self, let tableViewDiffableDataSource = self.tableViewDiffableDataSource else { return } + + let accounts = suggestedAccounts.compactMap { $0.account } + + let accountsWithRelationship: [(account: Mastodon.Entity.Account, relationship: Mastodon.Entity.Relationship?)] = accounts.compactMap { account in + guard let relationship = self.relationships.first(where: {$0.id == account.id }) else { return (account: account, relationship: nil)} + + return (account: account, relationship: relationship) + } var snapshot = NSDiffableDataSourceSnapshot() snapshot.appendSections([.main]) - let items: [RecommendAccountItem] = records.map { RecommendAccountItem.account($0) } + let items: [RecommendAccountItem] = accountsWithRelationship.map { RecommendAccountItem.account($0.account, relationship: $0.relationship) } snapshot.appendItems(items, toSection: .main) tableViewDiffableDataSource.applySnapshotUsingReloadData(snapshot) @@ -116,17 +108,15 @@ final class SuggestionAccountViewModel: NSObject { func followAllSuggestedAccounts(_ dependency: NeedsDependency & AuthContextProvider, completion: (() -> Void)? = nil) { - let userRecords = userFetchedResultsController.records.compactMap { - $0.object(in: dependency.context.managedObjectContext)?.asRecord - } + let tmpAccounts = accounts.compactMap { $0.account } Task { await withTaskGroup(of: Void.self, body: { taskGroup in - for user in userRecords { + for account in tmpAccounts { taskGroup.addTask { try? await DataSourceFacade.responseToUserViewButtonAction( dependency: dependency, - user: user, + user: account, buttonState: .follow ) } diff --git a/Mastodon/Scene/SuggestionAccount/TableView-Components/SuggestionAccountTableViewCell.swift b/Mastodon/Scene/SuggestionAccount/TableView-Components/SuggestionAccountTableViewCell.swift index 1448be17f..17a8e5b55 100644 --- a/Mastodon/Scene/SuggestionAccount/TableView-Components/SuggestionAccountTableViewCell.swift +++ b/Mastodon/Scene/SuggestionAccount/TableView-Components/SuggestionAccountTableViewCell.swift @@ -85,28 +85,17 @@ final class SuggestionAccountTableViewCell: UITableViewCell { disposeBag.removeAll() } - func configure(viewModel: SuggestionAccountTableViewCell.ViewModel) { - userView.configure(user: viewModel.user, delegate: delegate) - - if viewModel.blockedUsers.contains(viewModel.user.id) { - self.userView.setButtonState(.blocked) - } else if viewModel.followedUsers.contains(viewModel.user.id) { - self.userView.setButtonState(.unfollow) - } else if viewModel.followRequestedUsers.contains(viewModel.user.id) { - self.userView.setButtonState(.pending) - } else if viewModel.user.locked { - self.userView.setButtonState(.request) - } else { - self.userView.setButtonState(.follow) - } + func configure(account: Mastodon.Entity.Account, relationship: Mastodon.Entity.Relationship?) { + userView.configure(with: account, relationship: relationship, delegate: delegate) + userView.updateButtonState(with: relationship, isMe: false) let metaContent: MetaContent = { do { - let mastodonContent = MastodonContent(content: viewModel.user.note ?? "", emojis: viewModel.user.emojis.asDictionary) + let mastodonContent = MastodonContent(content: account.note, emojis: account.emojis?.asDictionary ?? [:]) return try MastodonMetaContent.convert(document: mastodonContent) } catch { assertionFailure() - return PlaintextMetaContent(string: viewModel.user.note ?? "") + return PlaintextMetaContent(string: account.note) } }()