diff --git a/Mastodon/Diffable/User/UserItem.swift b/Mastodon/Diffable/User/UserItem.swift index ff533d897..2bc5f33a6 100644 --- a/Mastodon/Diffable/User/UserItem.swift +++ b/Mastodon/Diffable/User/UserItem.swift @@ -8,9 +8,11 @@ import Foundation import CoreData import CoreDataStack +import MastodonSDK enum UserItem: Hashable { case user(record: ManagedObjectRecord) + case account(account: Mastodon.Entity.Account) case bottomLoader case bottomHeader(text: String) } diff --git a/Mastodon/Diffable/User/UserSection.swift b/Mastodon/Diffable/User/UserSection.swift index e6632c337..5667b3450 100644 --- a/Mastodon/Diffable/User/UserSection.swift +++ b/Mastodon/Diffable/User/UserSection.swift @@ -19,15 +19,11 @@ enum UserSection: Hashable { } extension UserSection { - struct Configuration { - weak var userTableViewCellDelegate: UserTableViewCellDelegate? - } - static func diffableDataSource( tableView: UITableView, context: AppContext, authContext: AuthContext, - configuration: Configuration + userTableViewCellDelegate: UserTableViewCellDelegate? ) -> UITableViewDiffableDataSource { tableView.register(UserTableViewCell.self, forCellReuseIdentifier: String(describing: UserTableViewCell.self)) tableView.register(TimelineBottomLoaderTableViewCell.self, forCellReuseIdentifier: String(describing: TimelineBottomLoaderTableViewCell.self)) @@ -35,6 +31,12 @@ extension UserSection { return UITableViewDiffableDataSource(tableView: tableView) { tableView, indexPath, item -> UITableViewCell? in switch item { + case .account(let account): + let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: UserTableViewCell.self), for: indexPath) as! UserTableViewCell + cell.configure(tableView: tableView, account: account, delegate: userTableViewCellDelegate) + + return cell + case .user(let record): let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: UserTableViewCell.self), for: indexPath) as! UserTableViewCell context.managedObjectContext.performAndWait { @@ -50,7 +52,7 @@ extension UserSection { blockedUsers: authContext.mastodonAuthenticationBox.inMemoryCache.$blockedUserIds.eraseToAnyPublisher(), followRequestedUsers: authContext.mastodonAuthenticationBox.inMemoryCache.$followRequestedUserIDs.eraseToAnyPublisher() ), - configuration: configuration + userTableViewCellDelegate: userTableViewCellDelegate ) } @@ -60,13 +62,12 @@ extension UserSection { cell.startAnimating() return cell case .bottomHeader(let text): - let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: TimelineFooterTableViewCell.self), for: indexPath) as! TimelineFooterTableViewCell - cell.messageLabel.text = text - return cell - } // end switch - } // end UITableViewDiffableDataSource - } // end static func tableViewDiffableDataSource { … } - + let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: TimelineFooterTableViewCell.self), for: indexPath) as! TimelineFooterTableViewCell + cell.messageLabel.text = text + return cell + } + } + } } extension UserSection { @@ -77,13 +78,13 @@ extension UserSection { tableView: UITableView, cell: UserTableViewCell, viewModel: UserTableViewCell.ViewModel, - configuration: Configuration + userTableViewCellDelegate: UserTableViewCellDelegate? ) { cell.configure( me: authContext.mastodonAuthenticationBox.authentication.user(in: context.managedObjectContext), tableView: tableView, viewModel: viewModel, - delegate: configuration.userTableViewCellDelegate + delegate: userTableViewCellDelegate ) } diff --git a/Mastodon/Scene/Profile/FamiliarFollowers/FamiliarFollowersViewModel+Diffable.swift b/Mastodon/Scene/Profile/FamiliarFollowers/FamiliarFollowersViewModel+Diffable.swift index 0b0428c67..291a6b3ff 100644 --- a/Mastodon/Scene/Profile/FamiliarFollowers/FamiliarFollowersViewModel+Diffable.swift +++ b/Mastodon/Scene/Profile/FamiliarFollowers/FamiliarFollowersViewModel+Diffable.swift @@ -17,9 +17,7 @@ extension FamiliarFollowersViewModel { tableView: tableView, context: context, authContext: authContext, - configuration: UserSection.Configuration( - userTableViewCellDelegate: userTableViewCellDelegate - ) + userTableViewCellDelegate: userTableViewCellDelegate ) userFetchedResultsController.$records diff --git a/Mastodon/Scene/Profile/Follower/FollowerListViewModel+Diffable.swift b/Mastodon/Scene/Profile/Follower/FollowerListViewModel+Diffable.swift index 11276c04f..d0676dc59 100644 --- a/Mastodon/Scene/Profile/Follower/FollowerListViewModel+Diffable.swift +++ b/Mastodon/Scene/Profile/Follower/FollowerListViewModel+Diffable.swift @@ -18,9 +18,7 @@ extension FollowerListViewModel { tableView: tableView, context: context, authContext: authContext, - configuration: UserSection.Configuration( - userTableViewCellDelegate: userTableViewCellDelegate - ) + userTableViewCellDelegate: userTableViewCellDelegate ) // workaround to append loader wrong animation issue diff --git a/Mastodon/Scene/Profile/Following/FollowingListViewModel+Diffable.swift b/Mastodon/Scene/Profile/Following/FollowingListViewModel+Diffable.swift index 785937335..d40c37ae8 100644 --- a/Mastodon/Scene/Profile/Following/FollowingListViewModel+Diffable.swift +++ b/Mastodon/Scene/Profile/Following/FollowingListViewModel+Diffable.swift @@ -19,9 +19,7 @@ extension FollowingListViewModel { tableView: tableView, context: context, authContext: authContext, - configuration: UserSection.Configuration( - userTableViewCellDelegate: userTableViewCellDelegate - ) + userTableViewCellDelegate: userTableViewCellDelegate ) // workaround to append loader wrong animation issue @@ -31,30 +29,32 @@ extension FollowingListViewModel { snapshot.appendItems([.bottomLoader], toSection: .main) diffableDataSource?.applySnapshotUsingReloadData(snapshot) - userFetchedResultsController.$records + $accounts .receive(on: DispatchQueue.main) - .sink { [weak self] records in - guard let self = self else { return } + .sink { [weak self] accounts in + guard let 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 items = accounts.map { UserItem.account(account: $0) } snapshot.appendItems(items, toSection: .main) if let currentState = self.stateMachine.currentState { switch currentState { - case is State.Idle, is State.Loading, is State.Fail: - snapshot.appendItems([.bottomLoader], toSection: .main) - case is State.NoMore: - guard let userID = self.userID, - userID != self.authContext.mastodonAuthenticationBox.userID - else { break } - // display footer exclude self - let text = L10n.Scene.Following.footer - snapshot.appendItems([.bottomHeader(text: text)], toSection: .main) - default: - break + case is State.Loading: + snapshot.appendItems([.bottomLoader], toSection: .main) + case is State.NoMore: + guard let userID = self.userID, + userID != self.authContext.mastodonAuthenticationBox.userID + else { break } + // display footer exclude self + let text = L10n.Scene.Following.footer + snapshot.appendItems([.bottomHeader(text: text)], toSection: .main) + case is State.Idle, is State.Fail: + break + default: + break } } diff --git a/Mastodon/Scene/Profile/Following/FollowingListViewModel+State.swift b/Mastodon/Scene/Profile/Following/FollowingListViewModel+State.swift index df71c0d7c..32856c643 100644 --- a/Mastodon/Scene/Profile/Following/FollowingListViewModel+State.swift +++ b/Mastodon/Scene/Profile/Following/FollowingListViewModel+State.swift @@ -11,7 +11,7 @@ import MastodonSDK extension FollowingListViewModel { class State: GKState { - + let id = UUID() weak var viewModel: FollowingListViewModel? @@ -32,10 +32,10 @@ extension FollowingListViewModel.State { override func isValidNextState(_ stateClass: AnyClass) -> Bool { guard let viewModel = viewModel else { return false } switch stateClass { - case is Reloading.Type: - return viewModel.userID != nil - default: - return false + case is Reloading.Type: + return viewModel.userID != nil + default: + return false } } } @@ -43,19 +43,19 @@ extension FollowingListViewModel.State { class Reloading: FollowingListViewModel.State { override func isValidNextState(_ stateClass: AnyClass) -> Bool { switch stateClass { - case is Loading.Type: - return true - default: - return false + case is Loading.Type: + return true + default: + return false } } 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) } @@ -65,10 +65,10 @@ extension FollowingListViewModel.State { override func isValidNextState(_ stateClass: AnyClass) -> Bool { switch stateClass { - case is Loading.Type: - return true - default: - return false + case is Loading.Type: + return true + default: + return false } } @@ -85,10 +85,10 @@ extension FollowingListViewModel.State { class Idle: FollowingListViewModel.State { override func isValidNextState(_ stateClass: AnyClass) -> Bool { switch stateClass { - case is Reloading.Type, is Loading.Type: - return true - default: - return false + case is Reloading.Type, is Loading.Type: + return true + default: + return false } } } @@ -99,14 +99,14 @@ extension FollowingListViewModel.State { override func isValidNextState(_ stateClass: AnyClass) -> Bool { switch stateClass { - case is Fail.Type: - return true - case is Idle.Type: - return true - case is NoMore.Type: - return true - default: - return false + case is Fail.Type: + return true + case is Idle.Type: + return true + case is NoMore.Type: + return true + default: + return false } } @@ -117,9 +117,9 @@ extension FollowingListViewModel.State { maxID = nil } - guard let viewModel = viewModel, let stateMachine = stateMachine else { return } + guard let viewModel, let stateMachine else { return } - guard let userID = viewModel.userID, !userID.isEmpty else { + guard let userID = viewModel.userID, userID.isEmpty == false else { stateMachine.enter(Fail.self) return } @@ -131,15 +131,17 @@ extension FollowingListViewModel.State { maxID: maxID, authenticationBox: viewModel.authContext.mastodonAuthenticationBox ) - + var hasNewAppend = false - var userIDs = viewModel.userFetchedResultsController.userIDs + var accounts = viewModel.accounts + for user in response.value { - guard !userIDs.contains(user.id) else { continue } - userIDs.append(user.id) + guard accounts.contains(user) == false else { continue } + accounts.append(user) hasNewAppend = true } - + + let maxID = response.link?.maxID if hasNewAppend, maxID != nil { @@ -147,28 +149,24 @@ extension FollowingListViewModel.State { } else { await enter(state: NoMore.self) } - self.maxID = maxID - viewModel.userFetchedResultsController.userIDs = userIDs + viewModel.accounts = accounts + self.maxID = maxID } catch { await enter(state: Fail.self) } - } // end Task - } // end func didEnter + } + } } class NoMore: FollowingListViewModel.State { override func isValidNextState(_ stateClass: AnyClass) -> Bool { switch stateClass { - case is Reloading.Type: - return true - default: - return false + case is Reloading.Type: + return true + default: + return false } } - - override func didEnter(from previousState: GKState?) { - super.didEnter(from: previousState) - } } } diff --git a/Mastodon/Scene/Profile/Following/FollowingListViewModel.swift b/Mastodon/Scene/Profile/Following/FollowingListViewModel.swift index e8758e645..9b634c9a6 100644 --- a/Mastodon/Scene/Profile/Following/FollowingListViewModel.swift +++ b/Mastodon/Scene/Profile/Following/FollowingListViewModel.swift @@ -20,9 +20,9 @@ final class FollowingListViewModel { // input let context: AppContext let authContext: AuthContext - let userFetchedResultsController: UserFetchedResultsController - let listBatchFetchViewModel = ListBatchFetchViewModel() - + @Published var accounts: [Mastodon.Entity.Account] + let listBatchFetchViewModel: ListBatchFetchViewModel + @Published var domain: String? @Published var userID: String? @@ -49,14 +49,9 @@ final class FollowingListViewModel { ) { self.context = context self.authContext = authContext - self.userFetchedResultsController = UserFetchedResultsController( - managedObjectContext: context.managedObjectContext, - domain: domain, - additionalPredicate: nil - ) self.domain = domain self.userID = userID - // super.init() - + self.accounts = [] + self.listBatchFetchViewModel = ListBatchFetchViewModel() } } diff --git a/Mastodon/Scene/Profile/UserLIst/UserListViewModel+Diffable.swift b/Mastodon/Scene/Profile/UserLIst/UserListViewModel+Diffable.swift index bbc46063a..d4830affc 100644 --- a/Mastodon/Scene/Profile/UserLIst/UserListViewModel+Diffable.swift +++ b/Mastodon/Scene/Profile/UserLIst/UserListViewModel+Diffable.swift @@ -20,9 +20,7 @@ extension UserListViewModel { tableView: tableView, context: context, authContext: authContext, - configuration: UserSection.Configuration( - userTableViewCellDelegate: userTableViewCellDelegate - ) + userTableViewCellDelegate: userTableViewCellDelegate ) // workaround to append loader wrong animation issue diff --git a/Mastodon/Scene/Share/View/Content/UserView+Configuration.swift b/Mastodon/Scene/Share/View/Content/UserView+Configuration.swift index c83838492..90633bae0 100644 --- a/Mastodon/Scene/Share/View/Content/UserView+Configuration.swift +++ b/Mastodon/Scene/Share/View/Content/UserView+Configuration.swift @@ -19,6 +19,7 @@ extension UserView { public func configure(user: MastodonUser, delegate: UserViewDelegate?) { self.delegate = delegate viewModel.user = user + viewModel.account = nil Publishers.CombineLatest( user.publisher(for: \.avatar), @@ -67,5 +68,11 @@ extension UserView { func configure(with account: Mastodon.Entity.Account) { //TODO: Implement + viewModel.account = account + viewModel.user = nil + + // username + let metaContent = PlaintextMetaContent(string: "@\(account.username)") + authorUsernameLabel.configure(content: metaContent) } } diff --git a/Mastodon/Scene/Share/View/TableviewCell/UserTableViewCell+ViewModel.swift b/Mastodon/Scene/Share/View/TableviewCell/UserTableViewCell+ViewModel.swift index d2f62e2fc..5d3e9c2c8 100644 --- a/Mastodon/Scene/Share/View/TableviewCell/UserTableViewCell+ViewModel.swift +++ b/Mastodon/Scene/Share/View/TableviewCell/UserTableViewCell+ViewModel.swift @@ -31,6 +31,18 @@ extension UserTableViewCell { extension UserTableViewCell { + func configure( + me: MastodonUser? = nil, + tableView: UITableView, + account: Mastodon.Entity.Account, + delegate: UserTableViewCellDelegate? + ) { + //TODO: Implement + userView.configure(with: account) + } + + + //TODO: Duplicate func configure( me: MastodonUser? = nil, tableView: UITableView,