From 5a3a10071bb256fc972d258aec138c5739123f73 Mon Sep 17 00:00:00 2001 From: Nathan Mattes Date: Tue, 21 Nov 2023 15:26:10 +0100 Subject: [PATCH] Show the correct familiar followers and their relationships (IOS-195) --- Mastodon.xcodeproj/project.pbxproj | 4 - .../DiscoveryForYouViewController.swift | 52 +++++++++---- ...ersViewController+DataSourceProvider.swift | 34 -------- .../FamiliarFollowersViewController.swift | 77 ++++++++++++++++++- 4 files changed, 112 insertions(+), 55 deletions(-) delete mode 100644 Mastodon/Scene/Profile/FamiliarFollowers/FamiliarFollowersViewController+DataSourceProvider.swift diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index 924225de8..2b9d89174 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -293,7 +293,6 @@ DB4FFC2C269EC39600D62E92 /* SearchTransitionController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB4FFC2A269EC39600D62E92 /* SearchTransitionController.swift */; }; DB5B549A2833A60400DEF8B2 /* FamiliarFollowersViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB5B54992833A60400DEF8B2 /* FamiliarFollowersViewController.swift */; }; DB5B549D2833A67400DEF8B2 /* FamiliarFollowersViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB5B549C2833A67400DEF8B2 /* FamiliarFollowersViewModel.swift */; }; - DB5B54A12833A89600DEF8B2 /* FamiliarFollowersViewController+DataSourceProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB5B54A02833A89600DEF8B2 /* FamiliarFollowersViewController+DataSourceProvider.swift */; }; DB5B54A32833BD1A00DEF8B2 /* UserListViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB5B54A22833BD1A00DEF8B2 /* UserListViewModel.swift */; }; DB5B54A62833BE0000DEF8B2 /* UserListViewModel+State.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB5B54A52833BE0000DEF8B2 /* UserListViewModel+State.swift */; }; DB5B54A82833BFA500DEF8B2 /* FavoritedByViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB5B54A72833BFA500DEF8B2 /* FavoritedByViewController.swift */; }; @@ -1004,7 +1003,6 @@ DB519B17281BCC2F00F0C99D /* tr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = tr; path = tr.lproj/Intents.stringsdict; sourceTree = ""; }; DB5B54992833A60400DEF8B2 /* FamiliarFollowersViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FamiliarFollowersViewController.swift; sourceTree = ""; }; DB5B549C2833A67400DEF8B2 /* FamiliarFollowersViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FamiliarFollowersViewModel.swift; sourceTree = ""; }; - DB5B54A02833A89600DEF8B2 /* FamiliarFollowersViewController+DataSourceProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FamiliarFollowersViewController+DataSourceProvider.swift"; sourceTree = ""; }; DB5B54A22833BD1A00DEF8B2 /* UserListViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserListViewModel.swift; sourceTree = ""; }; DB5B54A52833BE0000DEF8B2 /* UserListViewModel+State.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UserListViewModel+State.swift"; sourceTree = ""; }; DB5B54A72833BFA500DEF8B2 /* FavoritedByViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FavoritedByViewController.swift; sourceTree = ""; }; @@ -2284,7 +2282,6 @@ isa = PBXGroup; children = ( DB5B54992833A60400DEF8B2 /* FamiliarFollowersViewController.swift */, - DB5B54A02833A89600DEF8B2 /* FamiliarFollowersViewController+DataSourceProvider.swift */, DB5B549C2833A67400DEF8B2 /* FamiliarFollowersViewModel.swift */, ); path = FamiliarFollowers; @@ -3751,7 +3748,6 @@ D8E5C349296DB8A3007E76A7 /* StatusEditHistoryViewController.swift in Sources */, DBE0822425CD3F1E00FD6BBD /* MastodonRegisterViewModel.swift in Sources */, D8318A882A4468D300C0FB73 /* NotificationSettingsViewController.swift in Sources */, - DB5B54A12833A89600DEF8B2 /* FamiliarFollowersViewController+DataSourceProvider.swift in Sources */, 2D82B9FF25E7863200E36F0F /* OnboardingViewControllerAppearance.swift in Sources */, DB025B78278D606A002F581E /* StatusItem.swift in Sources */, D82BD7532ABC44C2009A374A /* Coordinator.swift in Sources */, diff --git a/Mastodon/Scene/Discovery/ForYou/DiscoveryForYouViewController.swift b/Mastodon/Scene/Discovery/ForYou/DiscoveryForYouViewController.swift index a6b6720af..e0b78d39b 100644 --- a/Mastodon/Scene/Discovery/ForYou/DiscoveryForYouViewController.swift +++ b/Mastodon/Scene/Discovery/ForYou/DiscoveryForYouViewController.swift @@ -9,6 +9,7 @@ import UIKit import Combine import MastodonUI import MastodonCore +import MastodonSDK final class DiscoveryForYouViewController: UIViewController, NeedsDependency, MediaPreviewableViewController { @@ -136,20 +137,38 @@ extension DiscoveryForYouViewController: ProfileCardTableViewCellDelegate { guard let indexPath = tableView.indexPath(for: cell) else { return } guard case let .account(account, _) = viewModel.diffableDataSource?.itemIdentifier(for: indexPath) else { return } - let userID = account.id - let _familiarFollowers = viewModel.familiarFollowers.first(where: { $0.id == userID }) - guard let familiarFollowers = _familiarFollowers else { - assertionFailure() - return - } - - let familiarFollowersViewModel = FamiliarFollowersViewModel(context: context, authContext: authContext, accounts: viewModel.accounts, relationships: viewModel.relationships) + coordinator.showLoading() - _ = coordinator.present( - scene: .familiarFollowers(viewModel: familiarFollowersViewModel), - from: self, - transition: .show - ) + Task { [weak self] in + + guard let self else { return } + do { + let userID = account.id + let familiarFollowers = viewModel.familiarFollowers.first(where: { $0.id == userID })?.accounts ?? [] + let relationships = try await context.apiService.relationship(forAccounts: familiarFollowers, authenticationBox: authContext.mastodonAuthenticationBox).value + + let familiarFollowersViewModel = FamiliarFollowersViewModel( + context: context, + authContext: authContext, + accounts: familiarFollowers, + relationships: relationships + ) + + coordinator.hideLoading() + + let viewController = coordinator.present( + scene: .familiarFollowers(viewModel: familiarFollowersViewModel), + from: self, + transition: .show + ) + + if let familiarFollowersViewController = viewController as? FamiliarFollowersViewController { + familiarFollowersViewController.delegate = self + } + } catch { + + } + } } } @@ -158,3 +177,10 @@ extension DiscoveryForYouViewController: ScrollViewContainer { var scrollView: UIScrollView { tableView } } +extension DiscoveryForYouViewController: FamiliarFollowersViewControllerDelegate { + func relationshipChanged(_ viewController: UIViewController, account: Mastodon.Entity.Account) { + Task { + try? await viewModel.fetch() + } + } +} diff --git a/Mastodon/Scene/Profile/FamiliarFollowers/FamiliarFollowersViewController+DataSourceProvider.swift b/Mastodon/Scene/Profile/FamiliarFollowers/FamiliarFollowersViewController+DataSourceProvider.swift deleted file mode 100644 index c014a7900..000000000 --- a/Mastodon/Scene/Profile/FamiliarFollowers/FamiliarFollowersViewController+DataSourceProvider.swift +++ /dev/null @@ -1,34 +0,0 @@ -// -// FamiliarFollowersViewController+DataSourceProvider.swift -// Mastodon -// -// Created by MainasuK on 2022-5-17. -// - -import UIKit - -extension FamiliarFollowersViewController: DataSourceProvider { - func item(from source: DataSourceItem.Source) async -> DataSourceItem? { - var _indexPath = source.indexPath - if _indexPath == nil, let cell = source.tableViewCell { - _indexPath = await self.indexPath(for: cell) - } - guard let indexPath = _indexPath else { return nil } - - guard let item = viewModel.diffableDataSource?.itemIdentifier(for: indexPath) else { - return nil - } - - switch item { - case .user(let record): - return .user(record: record) - default: - return nil - } - } - - @MainActor - private func indexPath(for cell: UITableViewCell) async -> IndexPath? { - return tableView.indexPath(for: cell) - } -} diff --git a/Mastodon/Scene/Profile/FamiliarFollowers/FamiliarFollowersViewController.swift b/Mastodon/Scene/Profile/FamiliarFollowers/FamiliarFollowersViewController.swift index cae1cc741..5ae64d00c 100644 --- a/Mastodon/Scene/Profile/FamiliarFollowers/FamiliarFollowersViewController.swift +++ b/Mastodon/Scene/Profile/FamiliarFollowers/FamiliarFollowersViewController.swift @@ -10,16 +10,20 @@ import Combine import MastodonCore import MastodonLocalization import MastodonUI +import MastodonSDK import CoreDataStack +protocol FamiliarFollowersViewControllerDelegate: AnyObject { + func relationshipChanged(_ viewController: UIViewController, account: Mastodon.Entity.Account) +} + final class FamiliarFollowersViewController: UIViewController, NeedsDependency { weak var context: AppContext! weak var coordinator: SceneCoordinator! + let viewModel: FamiliarFollowersViewModel + weak var delegate: FamiliarFollowersViewControllerDelegate? - var disposeBag = Set() - var viewModel: FamiliarFollowersViewModel - let tableView: UITableView init(viewModel: FamiliarFollowersViewModel, context: AppContext, coordinator: SceneCoordinator) { @@ -81,4 +85,69 @@ extension FamiliarFollowersViewController: UITableViewDelegate, AutoGenerateTabl } // MARK: - UserTableViewCellDelegate -extension FamiliarFollowersViewController: UserTableViewCellDelegate {} +extension FamiliarFollowersViewController: UserTableViewCellDelegate { + func userView(_ view: UserView, didTapButtonWith state: UserView.ButtonState, for user: MastodonUser) { } + func userView(_ view: UserView, didTapButtonWith state: UserView.ButtonState, for account: Mastodon.Entity.Account, me: MastodonUser?) { + + // Can we call the default implementation somehow? Maybe add a FollowAction-class with a completion-block? + Task { + await MainActor.run { view.setButtonState(.loading) } + + try await DataSourceFacade.responseToUserViewButtonAction( + dependency: self, + user: account, + buttonState: state + ) + + // this is a dirty hack to give the backend enough time to process the relationship-change + // Otherwise the relationship might still be `pending` + try await Task.sleep(for: .seconds(1)) + + let relationship = try await self.context.apiService.relationship(forAccounts: [account], authenticationBox: authContext.mastodonAuthenticationBox).value.first + + let isMe: Bool + if let me { + isMe = account.id == me.id + } else { + isMe = false + } + + await MainActor.run { + view.viewModel.relationship = relationship + view.updateButtonState(with: relationship, isMe: isMe) + + delegate?.relationshipChanged(self, account: account) + } + } + } + +} + +//MARK: - DataSourceProvider +extension FamiliarFollowersViewController: DataSourceProvider { + func item(from source: DataSourceItem.Source) async -> DataSourceItem? { + var _indexPath = source.indexPath + if _indexPath == nil, let cell = source.tableViewCell { + _indexPath = await self.indexPath(for: cell) + } + guard let indexPath = _indexPath else { return nil } + + guard let item = viewModel.diffableDataSource?.itemIdentifier(for: indexPath) else { + return nil + } + + switch item { + case .account(let account, relationship: let relationship): + return .account(account: account, relationship: relationship) + + default: + return nil + } + } + + @MainActor + private func indexPath(for cell: UITableViewCell) async -> IndexPath? { + return tableView.indexPath(for: cell) + } +} +