Use entities on suggestion-screen (IOS-190)
This commit is contained in:
parent
92fcd2e665
commit
49f6cd6d29
|
@ -6,8 +6,8 @@
|
|||
//
|
||||
|
||||
import Foundation
|
||||
import CoreDataStack
|
||||
import MastodonSDK
|
||||
|
||||
enum RecommendAccountItem: Hashable {
|
||||
case account(ManagedObjectRecord<MastodonUser>)
|
||||
case account(Mastodon.Entity.Account, relationship: Mastodon.Entity.Relationship?)
|
||||
}
|
||||
|
|
|
@ -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):
|
||||
case .account(let account, let relationship):
|
||||
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)
|
||||
)
|
||||
}
|
||||
cell.configure(account: account, relationship: relationship)
|
||||
}
|
||||
return cell
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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<Void, Never>()
|
||||
|
||||
|
@ -38,51 +36,38 @@ final class SuggestionAccountViewModel: NSObject {
|
|||
) {
|
||||
self.context = context
|
||||
self.authContext = authContext
|
||||
self.userFetchedResultsController = UserFetchedResultsController(
|
||||
managedObjectContext: context.managedObjectContext,
|
||||
domain: nil,
|
||||
additionalPredicate: nil
|
||||
)
|
||||
super.init()
|
||||
|
||||
userFetchedResultsController.domain = authContext.mastodonAuthenticationBox.domain
|
||||
accounts = []
|
||||
relationships = []
|
||||
|
||||
super.init()
|
||||
|
||||
// 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 {
|
||||
|
||||
}
|
||||
|
||||
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
|
||||
)
|
||||
self.relationships = []
|
||||
self.accounts = []
|
||||
}
|
||||
}
|
||||
.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<RecommendAccountSection, RecommendAccountItem>()
|
||||
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
|
||||
)
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}()
|
||||
|
||||
|
|
Loading…
Reference in New Issue