diff --git a/Mastodon/Diffable/User/UserItem.swift b/Mastodon/Diffable/User/UserItem.swift index ba44aa52a..51c9cb443 100644 --- a/Mastodon/Diffable/User/UserItem.swift +++ b/Mastodon/Diffable/User/UserItem.swift @@ -11,7 +11,6 @@ import CoreDataStack import MastodonSDK enum UserItem: Hashable { - case user(record: ManagedObjectRecord) case account(account: Mastodon.Entity.Account, relationship: Mastodon.Entity.Relationship?) case bottomLoader case bottomHeader(text: String) diff --git a/Mastodon/Diffable/User/UserSection.swift b/Mastodon/Diffable/User/UserSection.swift index 6997e5159..1483de2e4 100644 --- a/Mastodon/Diffable/User/UserSection.swift +++ b/Mastodon/Diffable/User/UserSection.swift @@ -37,7 +37,7 @@ extension UserSection { case .account(let account, let relationship): let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: UserTableViewCell.self), for: indexPath) as! UserTableViewCell - guard let me = authContext.mastodonAuthenticationBox.authentication.user(in: context.managedObjectContext) else { return cell } + guard let me = authContext.mastodonAuthenticationBox.authentication.account() else { return cell } cell.userView.setButtonState(.loading) cell.configure( @@ -48,27 +48,6 @@ extension UserSection { delegate: userTableViewCellDelegate ) - return cell - - case .user(let record): - let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: UserTableViewCell.self), for: indexPath) as! UserTableViewCell - context.managedObjectContext.performAndWait { - guard let user = record.object(in: context.managedObjectContext) else { return } - configure( - context: context, - authContext: authContext, - tableView: tableView, - cell: cell, - viewModel: UserTableViewCell.ViewModel( - user: user, - followedUsers: authContext.mastodonAuthenticationBox.inMemoryCache.$followingUserIds.eraseToAnyPublisher(), - blockedUsers: authContext.mastodonAuthenticationBox.inMemoryCache.$blockedUserIds.eraseToAnyPublisher(), - followRequestedUsers: authContext.mastodonAuthenticationBox.inMemoryCache.$followRequestedUserIDs.eraseToAnyPublisher() - ), - userTableViewCellDelegate: userTableViewCellDelegate - ) - } - return cell case .bottomLoader: let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: TimelineBottomLoaderTableViewCell.self), for: indexPath) as! TimelineBottomLoaderTableViewCell @@ -82,23 +61,3 @@ extension UserSection { } } } - -extension UserSection { - - static func configure( - context: AppContext, - authContext: AuthContext, - tableView: UITableView, - cell: UserTableViewCell, - viewModel: UserTableViewCell.ViewModel, - userTableViewCellDelegate: UserTableViewCellDelegate? - ) { - cell.configure( - me: authContext.mastodonAuthenticationBox.authentication.user(in: context.managedObjectContext), - tableView: tableView, - viewModel: viewModel, - delegate: userTableViewCellDelegate - ) - } - -} diff --git a/Mastodon/Protocol/Provider/DataSourceFacade+Block.swift b/Mastodon/Protocol/Provider/DataSourceFacade+Block.swift index c8f1f9405..c87217595 100644 --- a/Mastodon/Protocol/Provider/DataSourceFacade+Block.swift +++ b/Mastodon/Protocol/Provider/DataSourceFacade+Block.swift @@ -13,7 +13,7 @@ import MastodonSDK extension DataSourceFacade { static func responseToUserBlockAction( dependency: NeedsDependency & AuthContextProvider, - user: ManagedObjectRecord + account: Mastodon.Entity.Account ) async throws { let selectionFeedbackGenerator = await UISelectionFeedbackGenerator() await selectionFeedbackGenerator.selectionChanged() @@ -22,7 +22,7 @@ extension DataSourceFacade { let authBox = dependency.authContext.mastodonAuthenticationBox _ = try await apiService.toggleBlock( - user: user, + account: account, authenticationBox: authBox ) diff --git a/Mastodon/Protocol/Provider/DataSourceFacade+Follow.swift b/Mastodon/Protocol/Provider/DataSourceFacade+Follow.swift index 84deba2ca..134e00ccb 100644 --- a/Mastodon/Protocol/Provider/DataSourceFacade+Follow.swift +++ b/Mastodon/Protocol/Provider/DataSourceFacade+Follow.swift @@ -15,27 +15,13 @@ import MastodonLocalization extension DataSourceFacade { static func responseToUserFollowAction( dependency: NeedsDependency & AuthContextProvider, - user: ManagedObjectRecord - ) async throws { - let selectionFeedbackGenerator = await UISelectionFeedbackGenerator() - await selectionFeedbackGenerator.selectionChanged() - - _ = try await dependency.context.apiService.toggleFollow( - user: user, - authenticationBox: dependency.authContext.mastodonAuthenticationBox - ) - dependency.context.authenticationService.fetchFollowingAndBlockedAsync() - } - - static func responseToUserFollowAction( - dependency: NeedsDependency & AuthContextProvider, - user: Mastodon.Entity.Account + account: Mastodon.Entity.Account ) async throws -> Mastodon.Entity.Relationship { let selectionFeedbackGenerator = await UISelectionFeedbackGenerator() await selectionFeedbackGenerator.selectionChanged() let response = try await dependency.context.apiService.toggleFollow( - user: user, + account: account, authenticationBox: dependency.authContext.mastodonAuthenticationBox ).value @@ -118,22 +104,12 @@ extension DataSourceFacade { } extension DataSourceFacade { - static func responseToShowHideReblogAction( - dependency: NeedsDependency & AuthContextProvider, - account: Mastodon.Entity.Account - ) async throws { - #warning("TODO: Implement") -// _ = try await dependency.context.apiService.toggleShowReblogs( -// for: user, -// authenticationBox: dependency.authContext.mastodonAuthenticationBox) - } - static func responseToShowHideReblogAction( - dependency: NeedsDependency & AuthContextProvider, - user: Mastodon.Entity.Account + dependency: NeedsDependency & AuthContextProvider, + account: Mastodon.Entity.Account ) async throws { - _ = try await dependency.context.apiService.toggleShowReblogs( - for: user, - authenticationBox: dependency.authContext.mastodonAuthenticationBox) + _ = try await dependency.context.apiService.toggleShowReblogs( + for: account, + authenticationBox: dependency.authContext.mastodonAuthenticationBox) } } diff --git a/Mastodon/Protocol/Provider/DataSourceFacade+Profile.swift b/Mastodon/Protocol/Provider/DataSourceFacade+Profile.swift index 464ecd374..30f556a2c 100644 --- a/Mastodon/Protocol/Provider/DataSourceFacade+Profile.swift +++ b/Mastodon/Protocol/Provider/DataSourceFacade+Profile.swift @@ -144,20 +144,8 @@ extension DataSourceFacade { return } - -#warning("TODO: Implement") - await DataSourceFacade.coordinateToProfileScene(provider: provider, domain: "", accountID: mention.id) -// let profileViewModel = ProfileViewModel( -// context: provider.context, -// authContext: provider.authContext, -// account: status.entity.account -// ) -// -// _ = provider.coordinator.present( -// scene: .profile(viewModel: profileViewModel), -// from: provider, -// transition: .show -// ) + + await DataSourceFacade.coordinateToProfileScene(provider: provider, domain: domain, accountID: mention.id) } } diff --git a/Mastodon/Protocol/Provider/DataSourceFacade+Status.swift b/Mastodon/Protocol/Provider/DataSourceFacade+Status.swift index 375c48575..9147569a7 100644 --- a/Mastodon/Protocol/Provider/DataSourceFacade+Status.swift +++ b/Mastodon/Protocol/Provider/DataSourceFacade+Status.swift @@ -354,7 +354,7 @@ extension DataSourceFacade { break case .followUser(_): try await DataSourceFacade.responseToUserFollowAction(dependency: dependency, - user: menuContext.author) + account: menuContext.author) } } // end func } diff --git a/Mastodon/Protocol/Provider/DataSourceFacade+UserView.swift b/Mastodon/Protocol/Provider/DataSourceFacade+UserView.swift index a34c2ad4a..8cea808fa 100644 --- a/Mastodon/Protocol/Provider/DataSourceFacade+UserView.swift +++ b/Mastodon/Protocol/Provider/DataSourceFacade+UserView.swift @@ -9,105 +9,46 @@ import MastodonSDK extension DataSourceFacade { static func responseToUserViewButtonAction( dependency: NeedsDependency & AuthContextProvider, - user: ManagedObjectRecord, - buttonState: UserView.ButtonState - ) async throws { - switch buttonState { - case .follow: - try await DataSourceFacade.responseToUserFollowAction( - dependency: dependency, - user: user - ) - - if let userObject = user.object(in: dependency.context.managedObjectContext) { - dependency.authContext.mastodonAuthenticationBox.inMemoryCache.followingUserIds.append(userObject.id) - } - - case .request: - try await DataSourceFacade.responseToUserFollowAction( - dependency: dependency, - user: user - ) - - if let userObject = user.object(in: dependency.context.managedObjectContext) { - dependency.authContext.mastodonAuthenticationBox.inMemoryCache.followRequestedUserIDs.append(userObject.id) - } - - case .unfollow: - try await DataSourceFacade.responseToUserFollowAction( - dependency: dependency, - user: user - ) - if let userObject = user.object(in: dependency.context.managedObjectContext) { - dependency.authContext.mastodonAuthenticationBox.inMemoryCache.followingUserIds.removeAll(where: { $0 == userObject.id }) - } - case .blocked: - try await DataSourceFacade.responseToUserBlockAction( - dependency: dependency, - user: user - ) - - if let userObject = user.object(in: dependency.context.managedObjectContext) { - dependency.authContext.mastodonAuthenticationBox.inMemoryCache.blockedUserIds.append(userObject.id) - } - - case .pending: - try await DataSourceFacade.responseToUserFollowAction( - dependency: dependency, - user: user - ) - - if let userObject = user.object(in: dependency.context.managedObjectContext) { - dependency.authContext.mastodonAuthenticationBox.inMemoryCache.followRequestedUserIDs.removeAll(where: { $0 == userObject.id }) - } - case .none, .loading: - break //no-op - } - } - - static func responseToUserViewButtonAction( - dependency: NeedsDependency & AuthContextProvider, - user: Mastodon.Entity.Account, + account: Mastodon.Entity.Account, buttonState: UserView.ButtonState ) async throws { switch buttonState { case .follow: _ = try await DataSourceFacade.responseToUserFollowAction( dependency: dependency, - user: user + account: account ) - dependency.authContext.mastodonAuthenticationBox.inMemoryCache.followingUserIds.append(user.id) - + dependency.authContext.mastodonAuthenticationBox.inMemoryCache.followingUserIds.append(account.id) case .request: _ = try await DataSourceFacade.responseToUserFollowAction( dependency: dependency, - user: user + account: account ) - dependency.authContext.mastodonAuthenticationBox.inMemoryCache.followRequestedUserIDs.append(user.id) + dependency.authContext.mastodonAuthenticationBox.inMemoryCache.followRequestedUserIDs.append(account.id) case .unfollow: _ = try await DataSourceFacade.responseToUserFollowAction( dependency: dependency, - user: user + account: account ) - dependency.authContext.mastodonAuthenticationBox.inMemoryCache.followingUserIds.removeAll(where: { $0 == user.id }) + dependency.authContext.mastodonAuthenticationBox.inMemoryCache.followingUserIds.removeAll(where: { $0 == account.id }) case .blocked: try await DataSourceFacade.responseToUserBlockAction( dependency: dependency, - user: user + account: account ) - dependency.authContext.mastodonAuthenticationBox.inMemoryCache.blockedUserIds.append(user.id) + dependency.authContext.mastodonAuthenticationBox.inMemoryCache.blockedUserIds.append(account.id) case .pending: _ = try await DataSourceFacade.responseToUserFollowAction( dependency: dependency, - user: user + account: account ) - dependency.authContext.mastodonAuthenticationBox.inMemoryCache.followRequestedUserIDs.removeAll(where: { $0 == user.id }) + dependency.authContext.mastodonAuthenticationBox.inMemoryCache.followRequestedUserIDs.removeAll(where: { $0 == account.id }) case .none, .loading: break //no-op } diff --git a/Mastodon/Scene/Discovery/ForYou/DiscoveryForYouViewController.swift b/Mastodon/Scene/Discovery/ForYou/DiscoveryForYouViewController.swift index 90a136611..1de2dd704 100644 --- a/Mastodon/Scene/Discovery/ForYou/DiscoveryForYouViewController.swift +++ b/Mastodon/Scene/Discovery/ForYou/DiscoveryForYouViewController.swift @@ -99,9 +99,7 @@ extension DiscoveryForYouViewController: UITableViewDelegate { func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { guard case let .account(account, _) = viewModel.diffableDataSource?.itemIdentifier(for: indexPath) else { return } - Task { - await DataSourceFacade.coordinateToProfileScene(provider: self, account: account) - } + DataSourceFacade.coordinateToProfileScene(provider: self, account: account) } } @@ -119,7 +117,7 @@ extension DiscoveryForYouViewController: ProfileCardTableViewCellDelegate { cell.profileCardView.setButtonState(.loading) Task { - let newRelationship = try await DataSourceFacade.responseToUserFollowAction(dependency: self, user: account) + let newRelationship = try await DataSourceFacade.responseToUserFollowAction(dependency: self, account: account) let isMe = (account.id == authContext.mastodonAuthenticationBox.userID) diff --git a/Mastodon/Scene/Profile/UserLIst/FavoritedBy/FavoritedByViewController+DataSourceProvider.swift b/Mastodon/Scene/Profile/UserLIst/FavoritedBy/FavoritedByViewController+DataSourceProvider.swift index 57e0c1408..53ccc6638 100644 --- a/Mastodon/Scene/Profile/UserLIst/FavoritedBy/FavoritedByViewController+DataSourceProvider.swift +++ b/Mastodon/Scene/Profile/UserLIst/FavoritedBy/FavoritedByViewController+DataSourceProvider.swift @@ -21,7 +21,7 @@ extension FavoritedByViewController: DataSourceProvider { } switch item { - case .user(_), .bottomHeader(_), .bottomLoader: + case .bottomHeader(_), .bottomLoader: return nil case .account(let account, let relationship): return .account(account: account, relationship: relationship) diff --git a/Mastodon/Scene/Profile/UserLIst/RebloggedBy/RebloggedByViewController+DataSourceProvider.swift b/Mastodon/Scene/Profile/UserLIst/RebloggedBy/RebloggedByViewController+DataSourceProvider.swift index 8332aa87a..57833a1b1 100644 --- a/Mastodon/Scene/Profile/UserLIst/RebloggedBy/RebloggedByViewController+DataSourceProvider.swift +++ b/Mastodon/Scene/Profile/UserLIst/RebloggedBy/RebloggedByViewController+DataSourceProvider.swift @@ -22,7 +22,7 @@ extension RebloggedByViewController: DataSourceProvider { } switch item { - case .user(_), .bottomHeader(_), .bottomLoader: + case .bottomHeader(_), .bottomLoader: return nil case .account(let account, let relationship): return .account(account: account, relationship: relationship) diff --git a/Mastodon/Scene/Report/ReportResult/ReportResultViewController.swift b/Mastodon/Scene/Report/ReportResult/ReportResultViewController.swift index 0b9ab1fba..5a6ec366f 100644 --- a/Mastodon/Scene/Report/ReportResult/ReportResultViewController.swift +++ b/Mastodon/Scene/Report/ReportResult/ReportResultViewController.swift @@ -90,7 +90,7 @@ extension ReportResultViewController { do { try await DataSourceFacade.responseToUserFollowAction( dependency: self, - user: self.viewModel.account + account: self.viewModel.account ) } catch { // handle error diff --git a/Mastodon/Scene/Search/SearchDetail/SearchResult/SearchResultSection.swift b/Mastodon/Scene/Search/SearchDetail/SearchResult/SearchResultSection.swift index 42b1a1585..254d301ff 100644 --- a/Mastodon/Scene/Search/SearchDetail/SearchResult/SearchResultSection.swift +++ b/Mastodon/Scene/Search/SearchDetail/SearchResult/SearchResultSection.swift @@ -44,7 +44,7 @@ extension SearchResultSection { case .account(let account, let relationship): let cell = tableView.dequeueReusableCell(withIdentifier: UserTableViewCell.reuseIdentifier, for: indexPath) as! UserTableViewCell - guard let me = authContext.mastodonAuthenticationBox.authentication.user(in: context.managedObjectContext) else { return cell } + guard let me = authContext.mastodonAuthenticationBox.authentication.account() else { return cell } cell.userView.setButtonState(.loading) cell.configure( @@ -110,21 +110,4 @@ extension SearchResultSection { delegate: configuration.statusViewTableViewCellDelegate ) } - - static func configure( - context: AppContext, - authContext: AuthContext, - tableView: UITableView, - cell: UserTableViewCell, - viewModel: UserTableViewCell.ViewModel, - configuration: Configuration - ) { - cell.configure( - me: authContext.mastodonAuthenticationBox.authentication.user(in: context.managedObjectContext), - tableView: tableView, - viewModel: viewModel, - delegate: configuration.userTableViewCellDelegate - ) - } - } diff --git a/Mastodon/Scene/Share/View/Content/UserView+Configuration.swift b/Mastodon/Scene/Share/View/Content/UserView+Configuration.swift index e3f91f462..4a3595c73 100644 --- a/Mastodon/Scene/Share/View/Content/UserView+Configuration.swift +++ b/Mastodon/Scene/Share/View/Content/UserView+Configuration.swift @@ -17,61 +17,9 @@ import MastodonSDK import MastodonAsset extension UserView { - public func configure(user: MastodonUser, delegate: UserViewDelegate?) { - self.delegate = delegate - viewModel.user = user - viewModel.account = nil - viewModel.relationship = nil - - Publishers.CombineLatest( - user.publisher(for: \.avatar), - UserDefaults.shared.publisher(for: \.preferredStaticAvatar) - ) - .map { _ in user.avatarImageURL() } - .assign(to: \.authorAvatarImageURL, on: viewModel) - .store(in: &disposeBag) - - // author name - Publishers.CombineLatest( - user.publisher(for: \.displayName), - user.publisher(for: \.emojis) - ) - .map { _, emojis in - do { - let content = MastodonContent(content: user.displayNameWithFallback, emojis: emojis.asDictionary) - let metaContent = try MastodonMetaContent.convert(document: content) - return metaContent - } catch { - assertionFailure(error.localizedDescription) - return PlaintextMetaContent(string: user.displayNameWithFallback) - } - } - .assign(to: \.authorName, on: viewModel) - .store(in: &disposeBag) - // author username - user.publisher(for: \.acct) - .map { $0 as String? } - .assign(to: \.authorUsername, on: viewModel) - .store(in: &disposeBag) - - user.publisher(for: \.followersCount) - .map { Int($0) } - .assign(to: \.authorFollowers, on: viewModel) - .store(in: &disposeBag) - - user.publisher(for: \.fields) - .map { fields in - let firstVerified = fields.first(where: { $0.verifiedAt != nil }) - return firstVerified?.value - } - .assign(to: \.authorVerifiedLink, on: viewModel) - .store(in: &disposeBag) - } - func configure(with account: Mastodon.Entity.Account, relationship: Mastodon.Entity.Relationship?, delegate: UserViewDelegate?) { viewModel.account = account viewModel.relationship = relationship - viewModel.user = nil self.delegate = delegate let authorUsername = PlaintextMetaContent(string: "@\(account.username)") diff --git a/Mastodon/Scene/Share/View/TableviewCell/UserTableViewCell+ViewModel.swift b/Mastodon/Scene/Share/View/TableviewCell/UserTableViewCell+ViewModel.swift index 6b8613292..ffb927166 100644 --- a/Mastodon/Scene/Share/View/TableviewCell/UserTableViewCell+ViewModel.swift +++ b/Mastodon/Scene/Share/View/TableviewCell/UserTableViewCell+ViewModel.swift @@ -14,14 +14,14 @@ import MastodonSDK extension UserTableViewCell { final class ViewModel { - let user: MastodonUser - + let account: Mastodon.Entity.Account + let followedUsers: AnyPublisher<[String], Never> let blockedUsers: AnyPublisher<[String], Never> let followRequestedUsers: AnyPublisher<[String], Never> - init(user: MastodonUser, followedUsers: AnyPublisher<[String], Never>, blockedUsers: AnyPublisher<[String], Never>, followRequestedUsers: AnyPublisher<[String], Never>) { - self.user = user + init(account: Mastodon.Entity.Account, followedUsers: AnyPublisher<[String], Never>, blockedUsers: AnyPublisher<[String], Never>, followRequestedUsers: AnyPublisher<[String], Never>) { + self.account = account self.followedUsers = followedUsers self.followRequestedUsers = followRequestedUsers self.blockedUsers = blockedUsers @@ -32,7 +32,7 @@ extension UserTableViewCell { extension UserTableViewCell { func configure( - me: MastodonUser, + me: Mastodon.Entity.Account, tableView: UITableView, account: Mastodon.Entity.Account, relationship: Mastodon.Entity.Relationship?, @@ -45,69 +45,16 @@ extension UserTableViewCell { self.delegate = delegate } - - func configure( - me: MastodonUser? = nil, - tableView: UITableView, - viewModel: ViewModel, - delegate: UserTableViewCellDelegate? - ) { - userView.configure(user: viewModel.user, delegate: delegate) - - guard let me = me else { - return userView.setButtonState(.none) - } - - if viewModel.user == me { - userView.setButtonState(.none) - } else { - userView.setButtonState(.loading) - } - - Publishers.CombineLatest3( - viewModel.followedUsers, - viewModel.followRequestedUsers, - viewModel.blockedUsers - ) - .receive(on: DispatchQueue.main) - .sink { [weak self] followed, requested, blocked in - if viewModel.user == me { - self?.userView.setButtonState(.none) - } else if blocked.contains(viewModel.user.id) { - self?.userView.setButtonState(.blocked) - } else if followed.contains(viewModel.user.id) { - self?.userView.setButtonState(.unfollow) - } else if requested.contains(viewModel.user.id) { - self?.userView.setButtonState(.pending) - } else if viewModel.user.locked { - self?.userView.setButtonState(.request) - } else if viewModel.user != me { - self?.userView.setButtonState(.follow) - } - } - .store(in: &disposeBag) - - self.delegate = delegate - } } extension UserTableViewCellDelegate where Self: NeedsDependency & AuthContextProvider { - func userView(_ view: UserView, didTapButtonWith state: UserView.ButtonState, for user: MastodonUser) { - Task { - try await DataSourceFacade.responseToUserViewButtonAction( - dependency: self, - user: user.asRecord, - buttonState: state - ) - } - } - func userView(_ view: UserView, didTapButtonWith state: UserView.ButtonState, for account: Mastodon.Entity.Account, me: MastodonUser?) { + func userView(_ view: UserView, didTapButtonWith state: UserView.ButtonState, for account: Mastodon.Entity.Account, me: Mastodon.Entity.Account?) { Task { await MainActor.run { view.setButtonState(.loading) } try await DataSourceFacade.responseToUserViewButtonAction( dependency: self, - user: account, + account: account, buttonState: state ) diff --git a/Mastodon/Scene/SuggestionAccount/SuggestionAccountViewModel.swift b/Mastodon/Scene/SuggestionAccount/SuggestionAccountViewModel.swift index 84cc4c46d..389da8427 100644 --- a/Mastodon/Scene/SuggestionAccount/SuggestionAccountViewModel.swift +++ b/Mastodon/Scene/SuggestionAccount/SuggestionAccountViewModel.swift @@ -121,7 +121,7 @@ final class SuggestionAccountViewModel: NSObject { taskGroup.addTask { try? await DataSourceFacade.responseToUserViewButtonAction( dependency: dependency, - user: account, + account: account, buttonState: .follow ) } diff --git a/MastodonSDK/Sources/MastodonCore/Service/API/APIService+Block.swift b/MastodonSDK/Sources/MastodonCore/Service/API/APIService+Block.swift index 428ef6eec..8d70ead23 100644 --- a/MastodonSDK/Sources/MastodonCore/Service/API/APIService+Block.swift +++ b/MastodonSDK/Sources/MastodonCore/Service/API/APIService+Block.swift @@ -61,40 +61,22 @@ extension APIService { } public func toggleBlock( - user: ManagedObjectRecord, + account: Mastodon.Entity.Account, authenticationBox: MastodonAuthenticationBox ) async throws -> Mastodon.Response.Content { - - let managedObjectContext = backgroundManagedObjectContext - let blockContext: MastodonBlockContext = try await managedObjectContext.performChanges { - let authentication = authenticationBox.authentication - - guard - let user = user.object(in: managedObjectContext), - let me = authentication.user(in: managedObjectContext) - else { - throw APIError.implicit(.badRequest) - } - let isBlocking = user.blockingBy.contains(me) - let isFollowing = user.followingBy.contains(me) - // toggle block state - user.update(isBlocking: !isBlocking, by: me) - // update follow state implicitly - if !isBlocking { - // will do block action. set to unfollow - user.update(isFollowing: false, by: me) - } + guard let me = authenticationBox.authentication.account(), + let relationship = try await relationship(forAccounts: [account], authenticationBox: authenticationBox).value.first + else { throw APIError.implicit(.badRequest) } + + let blockContext = MastodonBlockContext( + sourceUserID: me.id, + targetUserID: account.id, + targetUsername: account.username, + isBlocking: relationship.blocking, + isFollowing: relationship.following + ) - return MastodonBlockContext( - sourceUserID: me.id, - targetUserID: user.id, - targetUsername: user.username, - isBlocking: isBlocking, - isFollowing: isFollowing - ) - } - let result: Result, Error> do { if blockContext.isBlocking { @@ -117,34 +99,7 @@ extension APIService { } catch { result = .failure(error) } - - try await managedObjectContext.performChanges { - let authentication = authenticationBox.authentication - - guard - let user = user.object(in: managedObjectContext), - let me = authentication.user(in: managedObjectContext) - else { return } - - - switch result { - case .success(let response): - let relationship = response.value - Persistence.MastodonUser.update( - mastodonUser: user, - context: Persistence.MastodonUser.RelationshipContext( - entity: relationship, - me: me, - networkDate: response.networkDate - ) - ) - case .failure: - // rollback - user.update(isBlocking: blockContext.isBlocking, by: me) - user.update(isFollowing: blockContext.isFollowing, by: me) - } - } - + let response = try result.get() return response } diff --git a/MastodonSDK/Sources/MastodonCore/Service/API/APIService+Follow.swift b/MastodonSDK/Sources/MastodonCore/Service/API/APIService+Follow.swift index 398eaf2ee..c27e94bc4 100644 --- a/MastodonSDK/Sources/MastodonCore/Service/API/APIService+Follow.swift +++ b/MastodonSDK/Sources/MastodonCore/Service/API/APIService+Follow.swift @@ -30,95 +30,11 @@ extension APIService { /// - activeMastodonAuthenticationBox: `AuthenticationService.MastodonAuthenticationBox` /// - Returns: publisher for `Relationship` public func toggleFollow( - user: ManagedObjectRecord, + account: Mastodon.Entity.Account, authenticationBox: MastodonAuthenticationBox ) async throws -> Mastodon.Response.Content { - let managedObjectContext = backgroundManagedObjectContext - let _followContext: MastodonFollowContext? = try await managedObjectContext.performChanges { - guard let me = authenticationBox.authentication.user(in: managedObjectContext) else { return nil } - guard let user = user.object(in: managedObjectContext) else { return nil } - - let isFollowing = user.followingBy.contains(me) - let isPending = user.followRequestedBy.contains(me) - let needsUnfollow = isFollowing || isPending - - if needsUnfollow { - // unfollow - user.update(isFollowing: false, by: me) - user.update(isFollowRequested: false, by: me) - } else { - // follow - if user.locked { - user.update(isFollowing: false, by: me) - user.update(isFollowRequested: true, by: me) - } else { - user.update(isFollowing: true, by: me) - user.update(isFollowRequested: false, by: me) - } - } - let context = MastodonFollowContext( - sourceUserID: me.id, - targetUserID: user.id, - isFollowing: isFollowing, - isPending: isPending, - needsUnfollow: needsUnfollow - ) - return context - } - - guard let followContext = _followContext else { - throw APIError.implicit(.badRequest) - } - - // request follow or unfollow - let result: Result, Error> - do { - let response = try await Mastodon.API.Account.follow( - session: session, - domain: authenticationBox.domain, - accountID: followContext.targetUserID, - followQueryType: followContext.needsUnfollow ? .unfollow : .follow(query: .init()), - authorization: authenticationBox.userAuthorization - ).singleOutput() - result = .success(response) - } catch { - result = .failure(error) - } - - // update friendship state - try await managedObjectContext.performChanges { - guard let me = authenticationBox.authentication.user(in: managedObjectContext), - let user = user.object(in: managedObjectContext) - else { return } - - switch result { - case .success(let response): - Persistence.MastodonUser.update( - mastodonUser: user, - context: Persistence.MastodonUser.RelationshipContext( - entity: response.value, - me: me, - networkDate: response.networkDate - ) - ) - case .failure: - // rollback - user.update(isFollowing: followContext.isFollowing, by: me) - user.update(isFollowRequested: followContext.isPending, by: me) - } - } - - let response = try result.get() - return response - } - - public func toggleFollow( - user: Mastodon.Entity.Account, - authenticationBox: MastodonAuthenticationBox - ) async throws -> Mastodon.Response.Content { - - guard let relationship = try await relationship(forAccounts: [user], authenticationBox: authenticationBox).value.first else { + guard let relationship = try await relationship(forAccounts: [account], authenticationBox: authenticationBox).value.first else { throw APIError.implicit(.badRequest) } @@ -129,14 +45,14 @@ extension APIService { response = try await Mastodon.API.Account.unfollow( session: session, domain: authenticationBox.domain, - accountID: user.id, + accountID: account.id, authorization: authenticationBox.userAuthorization ).singleOutput() } else { response = try await Mastodon.API.Account.follow( session: session, domain: authenticationBox.domain, - accountID: user.id, + accountID: account.id, followQueryType: .follow(query: .init()), authorization: authenticationBox.userAuthorization ).singleOutput() diff --git a/MastodonSDK/Sources/MastodonCore/Service/API/APIService+Follower.swift b/MastodonSDK/Sources/MastodonCore/Service/API/APIService+Follower.swift index f463501f6..b55287cd3 100644 --- a/MastodonSDK/Sources/MastodonCore/Service/API/APIService+Follower.swift +++ b/MastodonSDK/Sources/MastodonCore/Service/API/APIService+Follower.swift @@ -32,28 +32,7 @@ extension APIService { query: query, authorization: authorization ).singleOutput() - - let managedObjectContext = self.backgroundManagedObjectContext - try await managedObjectContext.performChanges { - let me = authenticationBox.authentication.user(in: managedObjectContext) - - for entity in response.value { - let result = Persistence.MastodonUser.createOrMerge( - in: managedObjectContext, - context: Persistence.MastodonUser.PersistContext( - domain: domain, - entity: entity, - cache: nil, - networkDate: response.networkDate - ) - ) - - let user = result.user - me?.update(isFollowing: true, by: user) - } - } - + return response } - } diff --git a/MastodonSDK/Sources/MastodonUI/View/Content/UserView+ViewModel.swift b/MastodonSDK/Sources/MastodonUI/View/Content/UserView+ViewModel.swift index f35afb97b..c29bdd88d 100644 --- a/MastodonSDK/Sources/MastodonUI/View/Content/UserView+ViewModel.swift +++ b/MastodonSDK/Sources/MastodonUI/View/Content/UserView+ViewModel.swift @@ -26,7 +26,6 @@ extension UserView { @Published public var authorUsername: String? @Published public var authorFollowers: Int? @Published public var authorVerifiedLink: String? - @Published public var user: MastodonUser? @Published public var account: Mastodon.Entity.Account? @Published public var relationship: Mastodon.Entity.Relationship? } diff --git a/MastodonSDK/Sources/MastodonUI/View/Content/UserView.swift b/MastodonSDK/Sources/MastodonUI/View/Content/UserView.swift index 6ad31bc75..b58819df5 100644 --- a/MastodonSDK/Sources/MastodonUI/View/Content/UserView.swift +++ b/MastodonSDK/Sources/MastodonUI/View/Content/UserView.swift @@ -15,8 +15,7 @@ import CoreDataStack import MastodonSDK public protocol UserViewDelegate: AnyObject { - func userView(_ view: UserView, didTapButtonWith state: UserView.ButtonState, for user: MastodonUser) - func userView(_ view: UserView, didTapButtonWith state: UserView.ButtonState, for user: Mastodon.Entity.Account, me: MastodonUser?) + func userView(_ view: UserView, didTapButtonWith state: UserView.ButtonState, for user: Mastodon.Entity.Account, me: Mastodon.Entity.Account?) } public final class UserView: UIView { @@ -255,9 +254,7 @@ public extension UserView { } @objc private func didTapFollowButton() { - if let user = viewModel.user { - delegate?.userView(self, didTapButtonWith: currentButtonState, for: user) - } else if let account = viewModel.account { + if let account = viewModel.account { delegate?.userView(self, didTapButtonWith: currentButtonState, for: account, me: nil) } }