Show profile-page for suggested accounts in search (IOS-141)

This commit is contained in:
Nathan Mattes 2023-09-17 12:48:58 +02:00
parent 1afecc85ea
commit a304fb2108
5 changed files with 130 additions and 98 deletions

View File

@ -39,30 +39,31 @@ extension UserSection {
return UITableViewDiffableDataSource(tableView: tableView) { tableView, indexPath, item -> UITableViewCell? in
switch item {
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(value: .user(user),
followedUsers: authContext.mastodonAuthenticationBox.inMemoryCache.$followingUserIds.eraseToAnyPublisher(),
blockedUsers: authContext.mastodonAuthenticationBox.inMemoryCache.$blockedUserIds.eraseToAnyPublisher(),
followRequestedUsers: authContext.mastodonAuthenticationBox.inMemoryCache.$followRequestedUserIDs.eraseToAnyPublisher()
),
configuration: configuration
)
}
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()
),
configuration: configuration
)
}
return cell
case .bottomLoader:
let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: TimelineBottomLoaderTableViewCell.self), for: indexPath) as! TimelineBottomLoaderTableViewCell
cell.startAnimating()
return cell
case .bottomHeader(let text):
return cell
case .bottomLoader:
let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: TimelineBottomLoaderTableViewCell.self), for: indexPath) as! TimelineBottomLoaderTableViewCell
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

View File

@ -33,7 +33,7 @@ extension DataSourceFacade {
@MainActor
static func coordinateToProfileScene(
provider: DataSourceProvider & AuthContextProvider,
provider: NeedsDependency & UIViewController & AuthContextProvider,
user: ManagedObjectRecord<MastodonUser>
) async {
guard let user = user.object(in: provider.context.managedObjectContext) else {

View File

@ -51,36 +51,52 @@ class SearchResultsOverviewTableViewController: UIViewController, NeedsDependenc
case .suggestion(let suggestion):
guard let cell = tableView.dequeueReusableCell(withIdentifier: SearchResultDefaultSectionTableViewCell.reuseIdentifier, for: indexPath) as? SearchResultDefaultSectionTableViewCell else { fatalError() }
switch suggestion {
cell.configure(item: suggestion)
return cell
case .hashtag(let hashtag):
// switch suggestion {
//
// case .hashtag(let hashtag):
//
// case .profile(let profile):
// //TODO: Use `UserFetchedResultsController` or `Persistence.MastodonUser.fetch` ???
//
// guard let cell = tableView.dequeueReusableCell(withIdentifier: UserTableViewCell.reuseIdentifier, for: indexPath) as? UserTableViewCell else { fatalError() }
guard let cell = tableView.dequeueReusableCell(withIdentifier: SearchResultDefaultSectionTableViewCell.reuseIdentifier, for: indexPath) as? SearchResultDefaultSectionTableViewCell else { fatalError() }
cell.configure(item: .hashtag(tag: hashtag))
return cell
//
case .profile(let profile):
guard let cell = tableView.dequeueReusableCell(withIdentifier: UserTableViewCell.reuseIdentifier, for: indexPath) as? UserTableViewCell else { fatalError() }
// how the fuck do I get a MastodonUser???
// try await managedObjectContext.perform {
// Persistence.MastodonUser.fetch(in: managedObjectContext,
// context: Persistence.MastodonUser.PersistContext(
// domain: domain,
// entity: profile.value,
// cache: nil,
// networkDate: profile.netwo
// ))
// }
//
let managedObjectContext = appContext.managedObjectContext
Task {
do {
// cell.configure(me: <#T##MastodonUser?#>, tableView: <#T##UITableView#>, viewModel: <#T##UserTableViewCell.ViewModel#>, delegate: <#T##UserTableViewCellDelegate?#>)
try await managedObjectContext.perform {
guard let user = Persistence.MastodonUser.fetch(in: managedObjectContext,
context: Persistence.MastodonUser.PersistContext(
domain: authContext.mastodonAuthenticationBox.domain,
entity: profile,
cache: nil,
networkDate: Date()
)) else { return }
// return cell
// }
cell.configure(
me: authContext.mastodonAuthenticationBox.authenticationRecord.object(in: managedObjectContext)?.user,
tableView: tableView,
viewModel: UserTableViewCell.ViewModel(
user: user,
followedUsers: authContext.mastodonAuthenticationBox.inMemoryCache.$followingUserIds.eraseToAnyPublisher(),
blockedUsers: authContext.mastodonAuthenticationBox.inMemoryCache.$blockedUserIds.eraseToAnyPublisher(),
followRequestedUsers: authContext.mastodonAuthenticationBox.inMemoryCache.$followRequestedUserIDs.eraseToAnyPublisher()),
delegate: nil)
}
}
catch {
// do nothing
}
}
return cell
}
}
}
@ -183,6 +199,28 @@ class SearchResultsOverviewTableViewController: UIViewController, NeedsDependenc
)
}
}
func showProfile(for account: Mastodon.Entity.Account) {
let managedObjectContext = context.managedObjectContext
let domain = authContext.mastodonAuthenticationBox.domain
Task {
let user = try await managedObjectContext.perform {
return Persistence.MastodonUser.fetch(in: managedObjectContext,
context: Persistence.MastodonUser.PersistContext(
domain: domain,
entity: account,
cache: nil,
networkDate: Date()
))
}
if let user {
await DataSourceFacade.coordinateToProfileScene(provider:self,
user: user.asRecord)
}
}
}
}
//MARK: UITableViewDelegate
@ -198,8 +236,10 @@ extension SearchResultsOverviewTableViewController: UITableViewDelegate {
case .default(let defaultSectionEntry):
switch defaultSectionEntry {
case .posts(let hashtag):
//FIXME: Show statuses instead of tag-content. Reuse SearchResultsViewController with statuses here?
showPosts(tag: Mastodon.Entity.Tag(name: hashtag, url: authContext.mastodonAuthenticationBox.domain))
case .people(let string):
//FIXME: Invoke SearchResultsViewController with people-scope here
delegate?.showPeople(self)
case .profile(let profile, let instanceName):
delegate?.showProfile(self)
@ -211,8 +251,8 @@ extension SearchResultsOverviewTableViewController: UITableViewDelegate {
case .hashtag(let tag):
showPosts(tag: tag)
case .profile(_):
delegate?.showProfile(self)
case .profile(let account):
showProfile(for: account)
}
}

View File

@ -53,7 +53,7 @@ extension SearchResultSection {
authContext: authContext,
tableView: tableView,
cell: cell,
viewModel: UserTableViewCell.ViewModel(value: .user(user),
viewModel: UserTableViewCell.ViewModel(user: user,
followedUsers: authContext.mastodonAuthenticationBox.inMemoryCache.$followingUserIds.eraseToAnyPublisher(),
blockedUsers: authContext.mastodonAuthenticationBox.inMemoryCache.$blockedUserIds.eraseToAnyPublisher(),
followRequestedUsers: authContext.mastodonAuthenticationBox.inMemoryCache.$followRequestedUserIDs.eraseToAnyPublisher()),

View File

@ -12,72 +12,63 @@ import Combine
extension UserTableViewCell {
final class ViewModel {
let value: Value
let user: MastodonUser
let followedUsers: AnyPublisher<[String], Never>
let blockedUsers: AnyPublisher<[String], Never>
let followRequestedUsers: AnyPublisher<[String], Never>
init(value: Value, followedUsers: AnyPublisher<[String], Never>, blockedUsers: AnyPublisher<[String], Never>, followRequestedUsers: AnyPublisher<[String], Never>) {
self.value = value
init(user: MastodonUser, followedUsers: AnyPublisher<[String], Never>, blockedUsers: AnyPublisher<[String], Never>, followRequestedUsers: AnyPublisher<[String], Never>) {
self.user = user
self.followedUsers = followedUsers
self.followRequestedUsers = followRequestedUsers
self.blockedUsers = blockedUsers
}
enum Value {
case user(MastodonUser)
// case status(Status)
}
}
}
extension UserTableViewCell {
func configure(
me: MastodonUser?,
me: MastodonUser? = nil,
tableView: UITableView,
viewModel: ViewModel,
delegate: UserTableViewCellDelegate?
) {
switch viewModel.value {
case .user(let user):
userView.configure(user: user, delegate: delegate)
guard let me = me else {
return userView.setButtonState(.none)
}
if 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 blocked.contains(user.id) {
self?.userView.setButtonState(.blocked)
} else if followed.contains(user.id) {
self?.userView.setButtonState(.unfollow)
} else if requested.contains(user.id) {
self?.userView.setButtonState(.pending)
} else if user.locked {
self?.userView.setButtonState(.request)
} else if user != me {
self?.userView.setButtonState(.follow)
}
}
.store(in: &disposeBag)
userView.configure(user: viewModel.user, delegate: delegate)
guard let me = me else {
return userView.setButtonState(.none)
}
self.delegate = delegate
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 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
}
}