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:
parent
393722a31d
commit
76304e59e5
|
@ -98,6 +98,7 @@ final public class SceneCoordinator {
|
||||||
// show notification related content
|
// show notification related content
|
||||||
guard let type = Mastodon.Entity.Notification.NotificationType(rawValue: pushNotification.notificationType) else { return }
|
guard let type = Mastodon.Entity.Notification.NotificationType(rawValue: pushNotification.notificationType) else { return }
|
||||||
guard let authContext = self.authContext else { return }
|
guard let authContext = self.authContext else { return }
|
||||||
|
guard let me = authContext.mastodonAuthenticationBox.authentication.account() else { return }
|
||||||
let notificationID = String(pushNotification.notificationID)
|
let notificationID = String(pushNotification.notificationID)
|
||||||
|
|
||||||
switch type {
|
switch type {
|
||||||
|
@ -114,7 +115,8 @@ final public class SceneCoordinator {
|
||||||
context: appContext,
|
context: appContext,
|
||||||
authContext: authContext,
|
authContext: authContext,
|
||||||
account: account,
|
account: account,
|
||||||
relationship: relationship
|
relationship: relationship,
|
||||||
|
me: me
|
||||||
)
|
)
|
||||||
_ = self.present(
|
_ = self.present(
|
||||||
scene: .profile(viewModel: profileViewModel),
|
scene: .profile(viewModel: profileViewModel),
|
||||||
|
|
|
@ -104,13 +104,15 @@ extension DataSourceFacade {
|
||||||
|
|
||||||
Task { @MainActor in
|
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(
|
let profileViewModel = ProfileViewModel(
|
||||||
context: provider.context,
|
context: provider.context,
|
||||||
authContext: provider.authContext,
|
authContext: provider.authContext,
|
||||||
account: account,
|
account: account,
|
||||||
relationship: relationship
|
relationship: relationship,
|
||||||
|
me: me
|
||||||
)
|
)
|
||||||
|
|
||||||
_ = provider.coordinator.present(
|
_ = provider.coordinator.present(
|
||||||
|
|
|
@ -82,11 +82,11 @@ final class ProfileHeaderViewController: UIViewController, NeedsDependency, Medi
|
||||||
return documentPickerController
|
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.context = context
|
||||||
self.coordinator = coordinator
|
self.coordinator = coordinator
|
||||||
self.viewModel = ProfileHeaderViewModel(context: context, authContext: authContext, account: account)
|
self.viewModel = ProfileHeaderViewModel(context: context, authContext: authContext, account: profileViewModel.account, me: profileViewModel.me, relationship: profileViewModel.relationship)
|
||||||
self.profileHeaderView = ProfileHeaderView(account: account)
|
self.profileHeaderView = ProfileHeaderView(account: profileViewModel.account, me: profileViewModel.me, relationship: profileViewModel.relationship)
|
||||||
|
|
||||||
super.init(nibName: nil, bundle: nil)
|
super.init(nibName: nil, bundle: nil)
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,7 @@ final class ProfileHeaderViewModel {
|
||||||
let context: AppContext
|
let context: AppContext
|
||||||
let authContext: AuthContext
|
let authContext: AuthContext
|
||||||
|
|
||||||
|
@Published var me: Mastodon.Entity.Account
|
||||||
@Published var account: Mastodon.Entity.Account
|
@Published var account: Mastodon.Entity.Account
|
||||||
@Published var relationship: Mastodon.Entity.Relationship?
|
@Published var relationship: Mastodon.Entity.Relationship?
|
||||||
|
|
||||||
|
@ -44,10 +45,12 @@ final class ProfileHeaderViewModel {
|
||||||
@Published var isTitleViewDisplaying = false
|
@Published var isTitleViewDisplaying = false
|
||||||
@Published var isTitleViewContentOffsetSet = 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.context = context
|
||||||
self.authContext = authContext
|
self.authContext = authContext
|
||||||
self.account = account
|
self.account = account
|
||||||
|
self.me = me
|
||||||
|
self.relationship = relationship
|
||||||
|
|
||||||
$accountForEdit
|
$accountForEdit
|
||||||
.receive(on: DispatchQueue.main)
|
.receive(on: DispatchQueue.main)
|
||||||
|
|
|
@ -46,13 +46,16 @@ extension ProfileHeaderView {
|
||||||
|
|
||||||
@Published var fields: [MastodonField] = []
|
@Published var fields: [MastodonField] = []
|
||||||
|
|
||||||
|
@Published var me: Mastodon.Entity.Account
|
||||||
@Published var account: Mastodon.Entity.Account
|
@Published var account: Mastodon.Entity.Account
|
||||||
@Published var relationship: Mastodon.Entity.Relationship?
|
@Published var relationship: Mastodon.Entity.Relationship?
|
||||||
@Published var isRelationshipActionButtonHidden = false
|
@Published var isRelationshipActionButtonHidden = false
|
||||||
@Published var isMyself = 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.account = account
|
||||||
|
self.me = me
|
||||||
|
self.relationship = relationship
|
||||||
|
|
||||||
#warning("TODO: Implement")
|
#warning("TODO: Implement")
|
||||||
// $relationshipActionOptionSet
|
// $relationshipActionOptionSet
|
||||||
|
@ -103,7 +106,8 @@ extension ProfileHeaderView.ViewModel {
|
||||||
// follows you
|
// follows you
|
||||||
Publishers.CombineLatest($relationship, $isMyself)
|
Publishers.CombineLatest($relationship, $isMyself)
|
||||||
.map { relationship, isMyself in
|
.map { relationship, isMyself in
|
||||||
(relationship?.following ?? false) && (isMyself == false) }
|
return (relationship?.following ?? false) && (isMyself == false)
|
||||||
|
}
|
||||||
.receive(on: DispatchQueue.main)
|
.receive(on: DispatchQueue.main)
|
||||||
.sink { isFollowing in
|
.sink { isFollowing in
|
||||||
view.followsYouBlurEffectView.isHidden = (isFollowing == false)
|
view.followsYouBlurEffectView.isHidden = (isFollowing == false)
|
||||||
|
@ -196,7 +200,9 @@ extension ProfileHeaderView.ViewModel {
|
||||||
|
|
||||||
Publishers.CombineLatest($relationship, $account)
|
Publishers.CombineLatest($relationship, $account)
|
||||||
.compactMap { relationship, account in
|
.compactMap { relationship, account in
|
||||||
|
|
||||||
guard let relationship else { return nil }
|
guard let relationship else { return nil }
|
||||||
|
|
||||||
let isBlocking = relationship.blocking
|
let isBlocking = relationship.blocking
|
||||||
let isBlockedBy = relationship.blockedBy ?? false
|
let isBlockedBy = relationship.blockedBy ?? false
|
||||||
let isSuspended = account.suspended ?? false
|
let isSuspended = account.suspended ?? false
|
||||||
|
@ -263,13 +269,17 @@ extension ProfileHeaderView.ViewModel {
|
||||||
.assign(to: \.isHidden, on: view.relationshipActionButtonShadowContainer)
|
.assign(to: \.isHidden, on: view.relationshipActionButtonShadowContainer)
|
||||||
.store(in: &disposeBag)
|
.store(in: &disposeBag)
|
||||||
#warning("TODO: Implement")
|
#warning("TODO: Implement")
|
||||||
// Publishers.CombineLatest2(
|
Publishers.CombineLatest3(
|
||||||
// $relationshipActionOptionSet,
|
Publishers.CombineLatest3($me, $account, $relationship).eraseToAnyPublisher(),
|
||||||
// $isEditing,
|
$isEditing,
|
||||||
// $isUpdating
|
$isUpdating
|
||||||
// )
|
)
|
||||||
// .receive(on: DispatchQueue.main)
|
.receive(on: DispatchQueue.main)
|
||||||
// .sink { relationshipActionOptionSet, isEditing, isUpdating in
|
.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) {
|
// if relationshipActionOptionSet.contains(.edit) {
|
||||||
// // check .edit state and set .editing when isEditing
|
// // check .edit state and set .editing when isEditing
|
||||||
// view.relationshipActionButton.configure(actionOptionSet: isUpdating ? .updating : (isEditing ? .editing : .edit))
|
// view.relationshipActionButton.configure(actionOptionSet: isUpdating ? .updating : (isEditing ? .editing : .edit))
|
||||||
|
@ -277,8 +287,8 @@ extension ProfileHeaderView.ViewModel {
|
||||||
// } else {
|
// } else {
|
||||||
// view.relationshipActionButton.configure(actionOptionSet: relationshipActionOptionSet)
|
// view.relationshipActionButton.configure(actionOptionSet: relationshipActionOptionSet)
|
||||||
// }
|
// }
|
||||||
// }
|
}
|
||||||
// .store(in: &disposeBag)
|
.store(in: &disposeBag)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -235,9 +235,9 @@ final class ProfileHeaderView: UIView {
|
||||||
return metaText
|
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)
|
super.init(frame: .zero)
|
||||||
|
|
||||||
|
|
|
@ -119,7 +119,7 @@ final class ProfileViewController: UIViewController, NeedsDependency, MediaPrevi
|
||||||
private(set) lazy var tabBarPagerController = TabBarPagerController()
|
private(set) lazy var tabBarPagerController = TabBarPagerController()
|
||||||
|
|
||||||
private(set) lazy var profileHeaderViewController: ProfileHeaderViewController = {
|
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
|
return viewController
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
@ -691,7 +691,7 @@ extension ProfileViewController: ProfileHeaderViewControllerDelegate {
|
||||||
#warning("TODO: Implement")
|
#warning("TODO: Implement")
|
||||||
// handle edit logic for editable profile
|
// handle edit logic for editable profile
|
||||||
// handle relationship logic for non-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
|
// // do nothing when updating
|
||||||
guard !viewModel.isUpdating else { return }
|
guard !viewModel.isUpdating else { return }
|
||||||
|
|
||||||
|
@ -706,11 +706,12 @@ extension ProfileViewController: ProfileHeaderViewControllerDelegate {
|
||||||
Task { @MainActor in
|
Task { @MainActor in
|
||||||
do {
|
do {
|
||||||
// TODO: handle error
|
// TODO: handle error
|
||||||
_ = try await viewModel.updateProfileInfo(
|
let updatedAccount = try await viewModel.updateProfileInfo(
|
||||||
headerProfileInfo: profileHeaderViewModel.profileInfoEditing,
|
headerProfileInfo: profileHeaderViewModel.profileInfoEditing,
|
||||||
aboutProfileInfo: profileAboutViewModel.profileInfoEditing
|
aboutProfileInfo: profileAboutViewModel.profileInfoEditing
|
||||||
)
|
).value
|
||||||
self.viewModel.isEditing = false
|
self.viewModel.isEditing = false
|
||||||
|
self.viewModel.account = updatedAccount
|
||||||
|
|
||||||
} catch {
|
} catch {
|
||||||
let alertController = UIAlertController(
|
let alertController = UIAlertController(
|
||||||
|
|
|
@ -34,7 +34,7 @@ class ProfileViewModel: NSObject {
|
||||||
let context: AppContext
|
let context: AppContext
|
||||||
let authContext: AuthContext
|
let authContext: AuthContext
|
||||||
|
|
||||||
@Published var me: Mastodon.Entity.Account?
|
@Published var me: Mastodon.Entity.Account
|
||||||
@Published var account: Mastodon.Entity.Account
|
@Published var account: Mastodon.Entity.Account
|
||||||
@Published var relationship: Mastodon.Entity.Relationship?
|
@Published var relationship: Mastodon.Entity.Relationship?
|
||||||
|
|
||||||
|
@ -56,11 +56,12 @@ class ProfileViewModel: NSObject {
|
||||||
// let needsPagePinToTop = CurrentValueSubject<Bool, Never>(false)
|
// let needsPagePinToTop = CurrentValueSubject<Bool, Never>(false)
|
||||||
|
|
||||||
@MainActor
|
@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.context = context
|
||||||
self.authContext = authContext
|
self.authContext = authContext
|
||||||
self.account = account
|
self.account = account
|
||||||
self.relationship = relationship
|
self.relationship = relationship
|
||||||
|
self.me = me
|
||||||
|
|
||||||
self.postsUserTimelineViewModel = UserTimelineViewModel(
|
self.postsUserTimelineViewModel = UserTimelineViewModel(
|
||||||
context: context,
|
context: context,
|
||||||
|
@ -83,9 +84,6 @@ class ProfileViewModel: NSObject {
|
||||||
self.profileAboutViewModel = ProfileAboutViewModel(context: context, account: account)
|
self.profileAboutViewModel = ProfileAboutViewModel(context: context, account: account)
|
||||||
super.init()
|
super.init()
|
||||||
|
|
||||||
// bind me
|
|
||||||
self.me = authContext.mastodonAuthenticationBox.authentication.account()
|
|
||||||
|
|
||||||
// bind user
|
// bind user
|
||||||
$account
|
$account
|
||||||
.map { user -> UserIdentifier? in
|
.map { user -> UserIdentifier? in
|
||||||
|
@ -176,7 +174,7 @@ class ProfileViewModel: NSObject {
|
||||||
|
|
||||||
// fetch profile info before edit
|
// fetch profile info before edit
|
||||||
func fetchEditProfileInfo() -> AnyPublisher<Mastodon.Response.Content<Mastodon.Entity.Account>, Error> {
|
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()
|
return Fail(error: APIService.APIError.implicit(.authenticationMissing)).eraseToAnyPublisher()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -119,7 +119,7 @@ class MainTabBarController: UITabBarController {
|
||||||
let _viewController = ProfileViewController()
|
let _viewController = ProfileViewController()
|
||||||
_viewController.context = context
|
_viewController.context = context
|
||||||
_viewController.coordinator = coordinator
|
_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 = _viewController
|
||||||
}
|
}
|
||||||
viewController.title = self.title
|
viewController.title = self.title
|
||||||
|
|
|
@ -141,6 +141,8 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
|
||||||
let domain = authContext.mastodonAuthenticationBox.domain
|
let domain = authContext.mastodonAuthenticationBox.domain
|
||||||
let authenticationBox = authContext.mastodonAuthenticationBox
|
let authenticationBox = authContext.mastodonAuthenticationBox
|
||||||
|
|
||||||
|
guard let me = authenticationBox.authentication.account() else { return }
|
||||||
|
|
||||||
guard let account = try await AppContext.shared.apiService.search(
|
guard let account = try await AppContext.shared.apiService.search(
|
||||||
query: .init(q: incomingURL.absoluteString, type: .accounts, resolve: true),
|
query: .init(q: incomingURL.absoluteString, type: .accounts, resolve: true),
|
||||||
authenticationBox: authenticationBox
|
authenticationBox: authenticationBox
|
||||||
|
@ -155,7 +157,8 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
|
||||||
context: AppContext.shared,
|
context: AppContext.shared,
|
||||||
authContext: authContext,
|
authContext: authContext,
|
||||||
account: account,
|
account: account,
|
||||||
relationship: relationship
|
relationship: relationship,
|
||||||
|
me: me
|
||||||
)
|
)
|
||||||
_ = self.coordinator?.present(
|
_ = self.coordinator?.present(
|
||||||
scene: .profile(viewModel: profileViewModel),
|
scene: .profile(viewModel: profileViewModel),
|
||||||
|
@ -285,6 +288,8 @@ extension SceneDelegate {
|
||||||
let domain = authContext.mastodonAuthenticationBox.domain
|
let domain = authContext.mastodonAuthenticationBox.domain
|
||||||
let authenticationBox = authContext.mastodonAuthenticationBox
|
let authenticationBox = authContext.mastodonAuthenticationBox
|
||||||
|
|
||||||
|
guard let me = authContext.mastodonAuthenticationBox.authentication.account() else { return }
|
||||||
|
|
||||||
guard let account = try await AppContext.shared.apiService.search(
|
guard let account = try await AppContext.shared.apiService.search(
|
||||||
query: .init(q: components[1], type: .accounts, resolve: true),
|
query: .init(q: components[1], type: .accounts, resolve: true),
|
||||||
authenticationBox: authenticationBox
|
authenticationBox: authenticationBox
|
||||||
|
@ -299,7 +304,8 @@ extension SceneDelegate {
|
||||||
context: AppContext.shared,
|
context: AppContext.shared,
|
||||||
authContext: authContext,
|
authContext: authContext,
|
||||||
account: account,
|
account: account,
|
||||||
relationship: relationship
|
relationship: relationship,
|
||||||
|
me: me
|
||||||
)
|
)
|
||||||
|
|
||||||
self.coordinator?.present(
|
self.coordinator?.present(
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
import MastodonAsset
|
import MastodonAsset
|
||||||
|
import MastodonSDK
|
||||||
import MastodonLocalization
|
import MastodonLocalization
|
||||||
|
|
||||||
public final class ProfileRelationshipActionButton: RoundedEdgesButton {
|
public final class ProfileRelationshipActionButton: RoundedEdgesButton {
|
||||||
|
@ -55,6 +56,32 @@ extension ProfileRelationshipActionButton {
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
public func configure(actionOptionSet: RelationshipActionOptionSet) {
|
||||||
setTitle(actionOptionSet.title, for: .normal)
|
setTitle(actionOptionSet.title, for: .normal)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue