Configure Profile-button based on relationship and accounts (IOS-192)

Also `me` is not optional anymore as we need it
This commit is contained in:
Nathan Mattes 2023-12-26 16:05:48 +01:00
parent 393722a31d
commit 76304e59e5
11 changed files with 83 additions and 34 deletions

View File

@ -98,6 +98,7 @@ final public class SceneCoordinator {
// show notification related content
guard let type = Mastodon.Entity.Notification.NotificationType(rawValue: pushNotification.notificationType) else { return }
guard let authContext = self.authContext else { return }
guard let me = authContext.mastodonAuthenticationBox.authentication.account() else { return }
let notificationID = String(pushNotification.notificationID)
switch type {
@ -114,7 +115,8 @@ final public class SceneCoordinator {
context: appContext,
authContext: authContext,
account: account,
relationship: relationship
relationship: relationship,
me: me
)
_ = self.present(
scene: .profile(viewModel: profileViewModel),

View File

@ -104,13 +104,15 @@ extension DataSourceFacade {
Task { @MainActor in
guard let relationship = try? await provider.context.apiService.relationship(forAccounts: [account], authenticationBox: provider.authContext.mastodonAuthenticationBox).value.first else { return }
guard let me = provider.authContext.mastodonAuthenticationBox.authentication.account(),
let relationship = try? await provider.context.apiService.relationship(forAccounts: [account], authenticationBox: provider.authContext.mastodonAuthenticationBox).value.first else { return }
let profileViewModel = ProfileViewModel(
context: provider.context,
authContext: provider.authContext,
account: account,
relationship: relationship
relationship: relationship,
me: me
)
_ = provider.coordinator.present(

View File

@ -82,11 +82,11 @@ final class ProfileHeaderViewController: UIViewController, NeedsDependency, Medi
return documentPickerController
}()
init(context: AppContext, authContext: AuthContext, account: Mastodon.Entity.Account, coordinator: SceneCoordinator) {
init(context: AppContext, authContext: AuthContext, coordinator: SceneCoordinator, profileViewModel: ProfileViewModel) {
self.context = context
self.coordinator = coordinator
self.viewModel = ProfileHeaderViewModel(context: context, authContext: authContext, account: account)
self.profileHeaderView = ProfileHeaderView(account: account)
self.viewModel = ProfileHeaderViewModel(context: context, authContext: authContext, account: profileViewModel.account, me: profileViewModel.me, relationship: profileViewModel.relationship)
self.profileHeaderView = ProfileHeaderView(account: profileViewModel.account, me: profileViewModel.me, relationship: profileViewModel.relationship)
super.init(nibName: nil, bundle: nil)
}

View File

@ -26,6 +26,7 @@ final class ProfileHeaderViewModel {
let context: AppContext
let authContext: AuthContext
@Published var me: Mastodon.Entity.Account
@Published var account: Mastodon.Entity.Account
@Published var relationship: Mastodon.Entity.Relationship?
@ -44,10 +45,12 @@ final class ProfileHeaderViewModel {
@Published var isTitleViewDisplaying = false
@Published var isTitleViewContentOffsetSet = false
init(context: AppContext, authContext: AuthContext, account: Mastodon.Entity.Account) {
init(context: AppContext, authContext: AuthContext, account: Mastodon.Entity.Account, me: Mastodon.Entity.Account, relationship: Mastodon.Entity.Relationship?) {
self.context = context
self.authContext = authContext
self.account = account
self.me = me
self.relationship = relationship
$accountForEdit
.receive(on: DispatchQueue.main)

View File

@ -46,13 +46,16 @@ extension ProfileHeaderView {
@Published var fields: [MastodonField] = []
@Published var me: Mastodon.Entity.Account
@Published var account: Mastodon.Entity.Account
@Published var relationship: Mastodon.Entity.Relationship?
@Published var isRelationshipActionButtonHidden = false
@Published var isMyself = false
init(account: Mastodon.Entity.Account) {
init(account: Mastodon.Entity.Account, me: Mastodon.Entity.Account, relationship: Mastodon.Entity.Relationship?) {
self.account = account
self.me = me
self.relationship = relationship
#warning("TODO: Implement")
// $relationshipActionOptionSet
@ -103,7 +106,8 @@ extension ProfileHeaderView.ViewModel {
// follows you
Publishers.CombineLatest($relationship, $isMyself)
.map { relationship, isMyself in
(relationship?.following ?? false) && (isMyself == false) }
return (relationship?.following ?? false) && (isMyself == false)
}
.receive(on: DispatchQueue.main)
.sink { isFollowing in
view.followsYouBlurEffectView.isHidden = (isFollowing == false)
@ -196,7 +200,9 @@ extension ProfileHeaderView.ViewModel {
Publishers.CombineLatest($relationship, $account)
.compactMap { relationship, account in
guard let relationship else { return nil }
let isBlocking = relationship.blocking
let isBlockedBy = relationship.blockedBy ?? false
let isSuspended = account.suspended ?? false
@ -263,13 +269,17 @@ extension ProfileHeaderView.ViewModel {
.assign(to: \.isHidden, on: view.relationshipActionButtonShadowContainer)
.store(in: &disposeBag)
#warning("TODO: Implement")
// Publishers.CombineLatest2(
// $relationshipActionOptionSet,
// $isEditing,
// $isUpdating
// )
// .receive(on: DispatchQueue.main)
// .sink { relationshipActionOptionSet, isEditing, isUpdating in
Publishers.CombineLatest3(
Publishers.CombineLatest3($me, $account, $relationship).eraseToAnyPublisher(),
$isEditing,
$isUpdating
)
.receive(on: DispatchQueue.main)
.sink { tuple, isEditing, isUpdating in
let (me, account, relationship) = tuple
guard let relationship else { return }
view.relationshipActionButton.configure(relationship: relationship, between: account, and: me, isEditing: isEditing, isUpdating: isUpdating)
// if relationshipActionOptionSet.contains(.edit) {
// // check .edit state and set .editing when isEditing
// view.relationshipActionButton.configure(actionOptionSet: isUpdating ? .updating : (isEditing ? .editing : .edit))
@ -277,8 +287,8 @@ extension ProfileHeaderView.ViewModel {
// } else {
// view.relationshipActionButton.configure(actionOptionSet: relationshipActionOptionSet)
// }
// }
// .store(in: &disposeBag)
}
.store(in: &disposeBag)
}
}

View File

@ -235,9 +235,9 @@ final class ProfileHeaderView: UIView {
return metaText
}()
init(account: Mastodon.Entity.Account) {
init(account: Mastodon.Entity.Account, me: Mastodon.Entity.Account, relationship: Mastodon.Entity.Relationship?) {
viewModel = ViewModel(account: account)
viewModel = ViewModel(account: account, me: me, relationship: relationship)
super.init(frame: .zero)

View File

@ -119,7 +119,7 @@ final class ProfileViewController: UIViewController, NeedsDependency, MediaPrevi
private(set) lazy var tabBarPagerController = TabBarPagerController()
private(set) lazy var profileHeaderViewController: ProfileHeaderViewController = {
let viewController = ProfileHeaderViewController(context: context, authContext: authContext, account: viewModel.account, coordinator: coordinator)
let viewController = ProfileHeaderViewController(context: context, authContext: authContext, coordinator: coordinator, profileViewModel: viewModel)
return viewController
}()
@ -691,7 +691,7 @@ extension ProfileViewController: ProfileHeaderViewControllerDelegate {
#warning("TODO: Implement")
// handle edit logic for editable profile
// handle relationship logic for non-editable profile
if let me = viewModel.me, me == viewModel.account {
if viewModel.me == viewModel.account {
// // do nothing when updating
guard !viewModel.isUpdating else { return }
@ -706,12 +706,13 @@ extension ProfileViewController: ProfileHeaderViewControllerDelegate {
Task { @MainActor in
do {
// TODO: handle error
_ = try await viewModel.updateProfileInfo(
let updatedAccount = try await viewModel.updateProfileInfo(
headerProfileInfo: profileHeaderViewModel.profileInfoEditing,
aboutProfileInfo: profileAboutViewModel.profileInfoEditing
)
).value
self.viewModel.isEditing = false
self.viewModel.account = updatedAccount
} catch {
let alertController = UIAlertController(
for: error,

View File

@ -34,7 +34,7 @@ class ProfileViewModel: NSObject {
let context: AppContext
let authContext: AuthContext
@Published var me: Mastodon.Entity.Account?
@Published var me: Mastodon.Entity.Account
@Published var account: Mastodon.Entity.Account
@Published var relationship: Mastodon.Entity.Relationship?
@ -56,11 +56,12 @@ class ProfileViewModel: NSObject {
// let needsPagePinToTop = CurrentValueSubject<Bool, Never>(false)
@MainActor
init(context: AppContext, authContext: AuthContext, account: Mastodon.Entity.Account, relationship: Mastodon.Entity.Relationship?) {
init(context: AppContext, authContext: AuthContext, account: Mastodon.Entity.Account, relationship: Mastodon.Entity.Relationship?, me: Mastodon.Entity.Account) {
self.context = context
self.authContext = authContext
self.account = account
self.relationship = relationship
self.me = me
self.postsUserTimelineViewModel = UserTimelineViewModel(
context: context,
@ -82,9 +83,6 @@ class ProfileViewModel: NSObject {
)
self.profileAboutViewModel = ProfileAboutViewModel(context: context, account: account)
super.init()
// bind me
self.me = authContext.mastodonAuthenticationBox.authentication.account()
// bind user
$account
@ -176,7 +174,7 @@ class ProfileViewModel: NSObject {
// fetch profile info before edit
func fetchEditProfileInfo() -> AnyPublisher<Mastodon.Response.Content<Mastodon.Entity.Account>, Error> {
guard let me, let domain = me.domain else {
guard let domain = me.domain else {
return Fail(error: APIService.APIError.implicit(.authenticationMissing)).eraseToAnyPublisher()
}

View File

@ -119,7 +119,7 @@ class MainTabBarController: UITabBarController {
let _viewController = ProfileViewController()
_viewController.context = context
_viewController.coordinator = coordinator
_viewController.viewModel = ProfileViewModel(context: context, authContext: authContext, account: me, relationship: nil)
_viewController.viewModel = ProfileViewModel(context: context, authContext: authContext, account: me, relationship: nil, me: me)
viewController = _viewController
}
viewController.title = self.title

View File

@ -141,6 +141,8 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
let domain = authContext.mastodonAuthenticationBox.domain
let authenticationBox = authContext.mastodonAuthenticationBox
guard let me = authenticationBox.authentication.account() else { return }
guard let account = try await AppContext.shared.apiService.search(
query: .init(q: incomingURL.absoluteString, type: .accounts, resolve: true),
authenticationBox: authenticationBox
@ -155,7 +157,8 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
context: AppContext.shared,
authContext: authContext,
account: account,
relationship: relationship
relationship: relationship,
me: me
)
_ = self.coordinator?.present(
scene: .profile(viewModel: profileViewModel),
@ -285,6 +288,8 @@ extension SceneDelegate {
let domain = authContext.mastodonAuthenticationBox.domain
let authenticationBox = authContext.mastodonAuthenticationBox
guard let me = authContext.mastodonAuthenticationBox.authentication.account() else { return }
guard let account = try await AppContext.shared.apiService.search(
query: .init(q: components[1], type: .accounts, resolve: true),
authenticationBox: authenticationBox
@ -299,7 +304,8 @@ extension SceneDelegate {
context: AppContext.shared,
authContext: authContext,
account: account,
relationship: relationship
relationship: relationship,
me: me
)
self.coordinator?.present(

View File

@ -7,6 +7,7 @@
import UIKit
import MastodonAsset
import MastodonSDK
import MastodonLocalization
public final class ProfileRelationshipActionButton: RoundedEdgesButton {
@ -55,6 +56,32 @@ extension ProfileRelationshipActionButton {
}
extension ProfileRelationshipActionButton {
public func configure(relationship: Mastodon.Entity.Relationship, between user: Mastodon.Entity.Account, and me: Mastodon.Entity.Account, isEditing: Bool = false, isUpdating: Bool = false) {
let isMyself = (user == me)
let title: String
if isMyself {
if isEditing {
title = "SAVE"
} else {
title = "EDIT"
}
} else if relationship.following {
title = L10n.Common.Controls.Friendship.follow
} else {
title = "TITLE"
}
setTitle(title, for: .normal)
if relationship.blocking || user.suspended ?? false {
isEnabled = false
} else {
isEnabled = true
}
}
public func configure(actionOptionSet: RelationshipActionOptionSet) {
setTitle(actionOptionSet.title, for: .normal)