diff --git a/Mastodon/Scene/Profile/Follower/FollowerListViewModel.swift b/Mastodon/Scene/Profile/Follower/FollowerListViewModel.swift index b0d31417a..0f4b2fba1 100644 --- a/Mastodon/Scene/Profile/Follower/FollowerListViewModel.swift +++ b/Mastodon/Scene/Profile/Follower/FollowerListViewModel.swift @@ -7,8 +7,6 @@ import Foundation import Combine -import CoreData -import CoreDataStack import GameplayKit import MastodonSDK import MastodonCore diff --git a/Mastodon/Scene/Profile/UserLIst/FavoritedBy/FavoritedByViewController+DataSourceProvider.swift b/Mastodon/Scene/Profile/UserLIst/FavoritedBy/FavoritedByViewController+DataSourceProvider.swift index 4f9580fbd..57e0c1408 100644 --- a/Mastodon/Scene/Profile/UserLIst/FavoritedBy/FavoritedByViewController+DataSourceProvider.swift +++ b/Mastodon/Scene/Profile/UserLIst/FavoritedBy/FavoritedByViewController+DataSourceProvider.swift @@ -21,10 +21,10 @@ extension FavoritedByViewController: DataSourceProvider { } switch item { - case .user(let record): - return .user(record: record) - default: - return nil + case .user(_), .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 61387c044..8332aa87a 100644 --- a/Mastodon/Scene/Profile/UserLIst/RebloggedBy/RebloggedByViewController+DataSourceProvider.swift +++ b/Mastodon/Scene/Profile/UserLIst/RebloggedBy/RebloggedByViewController+DataSourceProvider.swift @@ -20,12 +20,12 @@ extension RebloggedByViewController: DataSourceProvider { guard let item = viewModel.diffableDataSource?.itemIdentifier(for: indexPath) else { return nil } - + switch item { - case .user(let record): - return .user(record: record) - default: - return nil + case .user(_), .bottomHeader(_), .bottomLoader: + return nil + case .account(let account, let relationship): + return .account(account: account, relationship: relationship) } } diff --git a/Mastodon/Scene/Profile/UserLIst/UserListViewModel+Diffable.swift b/Mastodon/Scene/Profile/UserLIst/UserListViewModel+Diffable.swift index d4830affc..b66f77785 100644 --- a/Mastodon/Scene/Profile/UserLIst/UserListViewModel+Diffable.swift +++ b/Mastodon/Scene/Profile/UserLIst/UserListViewModel+Diffable.swift @@ -9,6 +9,7 @@ import UIKit import MastodonAsset import MastodonLocalization import Combine +import MastodonSDK extension UserListViewModel { @MainActor @@ -33,15 +34,23 @@ extension UserListViewModel { // trigger initial loading stateMachine.enter(UserListViewModel.State.Reloading.self) - userFetchedResultsController.$records + $accounts .receive(on: DispatchQueue.main) - .sink { [weak self] records in + .sink { [weak self] accounts in guard let self = self else { return } guard let diffableDataSource = self.diffableDataSource else { return } var snapshot = NSDiffableDataSourceSnapshot() + snapshot.appendSections([.main]) - let items = records.map { UserItem.user(record: $0) } + + 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) + } + + let items = accountsWithRelationship.map { UserItem.account(account: $0.account, relationship: $0.relationship) } snapshot.appendItems(items, toSection: .main) if let currentState = self.stateMachine.currentState { diff --git a/Mastodon/Scene/Profile/UserLIst/UserListViewModel+State.swift b/Mastodon/Scene/Profile/UserLIst/UserListViewModel+State.swift index cb6e9d3fa..912dcd7e3 100644 --- a/Mastodon/Scene/Profile/UserLIst/UserListViewModel+State.swift +++ b/Mastodon/Scene/Profile/UserLIst/UserListViewModel+State.swift @@ -30,7 +30,7 @@ extension UserListViewModel { extension UserListViewModel.State { class Initial: UserListViewModel.State { override func isValidNextState(_ stateClass: AnyClass) -> Bool { - guard let _ = viewModel else { return false } + guard viewModel != nil else { return false } switch stateClass { case is Reloading.Type: return true @@ -52,10 +52,10 @@ extension UserListViewModel.State { override func didEnter(from previousState: GKState?) { super.didEnter(from: previousState) - guard let viewModel = viewModel, let stateMachine = stateMachine else { return } + guard let viewModel, let stateMachine else { return } // reset - viewModel.userFetchedResultsController.userIDs = [] + viewModel.accounts = [] stateMachine.enter(Loading.self) } @@ -74,8 +74,8 @@ extension UserListViewModel.State { override func didEnter(from previousState: GKState?) { super.didEnter(from: previousState) - guard let _ = viewModel, let stateMachine = stateMachine else { return } - + guard viewModel != nil, let stateMachine else { return } + DispatchQueue.main.asyncAfter(deadline: .now() + 3) { stateMachine.enter(Loading.self) } @@ -117,10 +117,11 @@ extension UserListViewModel.State { maxID = nil } - guard let viewModel = viewModel else { return } + guard let viewModel else { return } let maxID = self.maxID - + let authenticationBox = viewModel.authContext.mastodonAuthenticationBox + Task { do { let response: Mastodon.Response.Content<[Mastodon.Entity.Account]> @@ -129,24 +130,45 @@ extension UserListViewModel.State { response = try await viewModel.context.apiService.favoritedBy( status: status, query: .init(maxID: maxID, limit: nil), - authenticationBox: viewModel.authContext.mastodonAuthenticationBox + authenticationBox: authenticationBox ) case .rebloggedBy(let status): response = try await viewModel.context.apiService.rebloggedBy( status: status, query: .init(maxID: maxID, limit: nil), - authenticationBox: viewModel.authContext.mastodonAuthenticationBox + authenticationBox: authenticationBox ) } + if response.value.isEmpty { + await enter(state: NoMore.self) + + viewModel.accounts = [] + viewModel.relationships = [] + return + } + + let newRelationships = try await viewModel.context.apiService.relationship( + forAccounts: response.value, + authenticationBox: authenticationBox + ) + var hasNewAppend = false - var userIDs = viewModel.userFetchedResultsController.userIDs - for user in response.value { - guard !userIDs.contains(user.id) else { continue } - userIDs.append(user.id) + var accounts = viewModel.accounts + for account in response.value { + guard !accounts.contains(account) else { continue } + + accounts.append(account) hasNewAppend = true } - + + var relationships = viewModel.relationships + + for relationship in newRelationships.value { + guard relationships.contains(relationship) == false else { continue } + relationships.append(relationship) + } + let maxID = response.link?.maxID if hasNewAppend, maxID != nil { @@ -155,8 +177,9 @@ extension UserListViewModel.State { await enter(state: NoMore.self) } self.maxID = maxID - viewModel.userFetchedResultsController.userIDs = userIDs - + viewModel.relationships = relationships + viewModel.accounts = accounts + } catch { await enter(state: Fail.self) } @@ -177,9 +200,9 @@ extension UserListViewModel.State { override func didEnter(from previousState: GKState?) { super.didEnter(from: previousState) - guard let viewModel = viewModel else { return } + guard let viewModel else { return } // trigger reload - viewModel.userFetchedResultsController.userIDs = viewModel.userFetchedResultsController.userIDs + viewModel.accounts = viewModel.accounts } } } diff --git a/Mastodon/Scene/Profile/UserLIst/UserListViewModel.swift b/Mastodon/Scene/Profile/UserLIst/UserListViewModel.swift index 9e26b81e6..14665334a 100644 --- a/Mastodon/Scene/Profile/UserLIst/UserListViewModel.swift +++ b/Mastodon/Scene/Profile/UserLIst/UserListViewModel.swift @@ -19,7 +19,8 @@ final class UserListViewModel { let context: AppContext let authContext: AuthContext let kind: Kind - let userFetchedResultsController: UserFetchedResultsController + @Published var accounts: [Mastodon.Entity.Account] + @Published var relationships: [Mastodon.Entity.Relationship] let listBatchFetchViewModel = ListBatchFetchViewModel() // output @@ -44,12 +45,8 @@ final class UserListViewModel { self.context = context self.authContext = authContext self.kind = kind - self.userFetchedResultsController = UserFetchedResultsController( - managedObjectContext: context.managedObjectContext, - domain: authContext.mastodonAuthenticationBox.domain, - additionalPredicate: nil - ) - // end init + self.accounts = [] + self.relationships = [] } }