mirror of
https://github.com/mastodon/mastodon-ios.git
synced 2025-02-02 18:36:44 +01:00
* Fix Profile Editing again (IOS-239, #1244) This needs a bit of explanation, I guess, so please don't squash if possible? I didn't take into consideration, that the `ProfileViewController.viewModel` changes. And when it changes, all the combine-connections just ... disappear. This PR changes that (but probably I oversaw something again). * Disable pull to refresh for editing mode (IOS-239) * In case of nothing change, cancel editing (IOS-239)
This commit is contained in:
parent
83fd4a89fa
commit
ab39c6ef87
@ -49,6 +49,15 @@ extension ProfileAboutViewController {
|
||||
view.addSubview(collectionView)
|
||||
collectionView.pinToParent()
|
||||
|
||||
let longPressReorderGesture = UILongPressGestureRecognizer(
|
||||
target: self,
|
||||
action: #selector(ProfileAboutViewController.longPressReorderGestureHandler(_:))
|
||||
)
|
||||
collectionView.addGestureRecognizer(longPressReorderGesture)
|
||||
}
|
||||
|
||||
override func viewWillAppear(_ animated: Bool) {
|
||||
super.viewWillAppear(animated)
|
||||
collectionView.delegate = self
|
||||
viewModel.setupDiffableDataSource(
|
||||
collectionView: collectionView,
|
||||
@ -56,11 +65,6 @@ extension ProfileAboutViewController {
|
||||
profileFieldEditCollectionViewCellDelegate: self
|
||||
)
|
||||
|
||||
let longPressReorderGesture = UILongPressGestureRecognizer(
|
||||
target: self,
|
||||
action: #selector(ProfileAboutViewController.longPressReorderGestureHandler(_:))
|
||||
)
|
||||
collectionView.addGestureRecognizer(longPressReorderGesture)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -51,7 +51,7 @@ extension ProfileAboutViewModel {
|
||||
diffableDataSource.apply(snapshot)
|
||||
|
||||
let fields = Publishers.CombineLatest3(
|
||||
$isEditing.removeDuplicates(),
|
||||
$isEditing,
|
||||
profileInfo.$fields.removeDuplicates(),
|
||||
profileInfoEditing.$fields.removeDuplicates()
|
||||
).map { isEditing, displayFields, editingFields in
|
||||
@ -60,7 +60,7 @@ extension ProfileAboutViewModel {
|
||||
|
||||
|
||||
Publishers.CombineLatest4(
|
||||
$isEditing.removeDuplicates(),
|
||||
$isEditing,
|
||||
$createdAt.removeDuplicates(),
|
||||
fields,
|
||||
$emojiMeta.removeDuplicates()
|
||||
@ -68,7 +68,7 @@ extension ProfileAboutViewModel {
|
||||
.throttle(for: 0.3, scheduler: DispatchQueue.main, latest: true)
|
||||
.receive(on: DispatchQueue.main)
|
||||
.sink { [weak self] isEditing, createdAt, fields, emojiMeta in
|
||||
guard let self = self else { return }
|
||||
guard let self else { return }
|
||||
guard let diffableDataSource = self.diffableDataSource else { return }
|
||||
|
||||
var snapshot = NSDiffableDataSourceSnapshot<ProfileFieldSection, ProfileFieldItem>()
|
||||
|
@ -32,7 +32,18 @@ final class ProfileViewController: UIViewController, NeedsDependency, MediaPrevi
|
||||
|
||||
var disposeBag = Set<AnyCancellable>()
|
||||
//TODO: Replace with something better than !
|
||||
var viewModel: ProfileViewModel!
|
||||
var viewModel: ProfileViewModel! {
|
||||
didSet {
|
||||
if isViewLoaded {
|
||||
bindViewModel()
|
||||
|
||||
viewModel.isEditing = false
|
||||
profileHeaderViewController.viewModel.isEditing = false
|
||||
profilePagingViewController.viewModel.profileAboutViewController.viewModel.isEditing = false
|
||||
viewModel.profileAboutViewModel.isEditing = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mediaPreviewTransitionController = MediaPreviewTransitionController()
|
||||
|
||||
@ -182,6 +193,98 @@ extension ProfileViewController {
|
||||
|
||||
navigationItem.titleView = titleView
|
||||
|
||||
addChild(tabBarPagerController)
|
||||
tabBarPagerController.view.translatesAutoresizingMaskIntoConstraints = false
|
||||
view.addSubview(tabBarPagerController.view)
|
||||
tabBarPagerController.didMove(toParent: self)
|
||||
tabBarPagerController.view.pinToParent()
|
||||
|
||||
tabBarPagerController.delegate = self
|
||||
tabBarPagerController.dataSource = self
|
||||
|
||||
tabBarPagerController.relayScrollView.refreshControl = refreshControl
|
||||
refreshControl.addTarget(self, action: #selector(ProfileViewController.refreshControlValueChanged(_:)), for: .valueChanged)
|
||||
|
||||
// setup delegate
|
||||
profileHeaderViewController.delegate = self
|
||||
profilePagingViewController.viewModel.profileAboutViewController.delegate = self
|
||||
}
|
||||
|
||||
override func viewWillAppear(_ animated: Bool) {
|
||||
super.viewWillAppear(animated)
|
||||
|
||||
navigationController?.navigationBar.prefersLargeTitles = false
|
||||
|
||||
bindViewModel()
|
||||
bindTitleView()
|
||||
bindMoreBarButtonItem()
|
||||
bindPager()
|
||||
}
|
||||
|
||||
override func viewDidAppear(_ animated: Bool) {
|
||||
super.viewDidAppear(animated)
|
||||
viewModel.viewDidAppear.send()
|
||||
|
||||
setNeedsStatusBarAppearanceUpdate()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension ProfileViewController {
|
||||
|
||||
private func bindViewModel() {
|
||||
// header
|
||||
let headerViewModel = profileHeaderViewController.viewModel
|
||||
viewModel.$account
|
||||
.assign(to: \.account, on: headerViewModel)
|
||||
.store(in: &disposeBag)
|
||||
viewModel.$isEditing
|
||||
.assign(to: \.isEditing, on: headerViewModel)
|
||||
.store(in: &disposeBag)
|
||||
viewModel.$isUpdating
|
||||
.assign(to: \.isUpdating, on: headerViewModel)
|
||||
.store(in: &disposeBag)
|
||||
viewModel.$relationship
|
||||
.assign(to: \.relationship, on: headerViewModel)
|
||||
.store(in: &disposeBag)
|
||||
viewModel.$accountForEdit
|
||||
.assign(to: \.accountForEdit, on: headerViewModel)
|
||||
.store(in: &disposeBag)
|
||||
|
||||
[
|
||||
viewModel.postsUserTimelineViewModel,
|
||||
viewModel.repliesUserTimelineViewModel,
|
||||
viewModel.mediaUserTimelineViewModel,
|
||||
].forEach { userTimelineViewModel in
|
||||
|
||||
viewModel.relationship.publisher
|
||||
.map { $0.blocking }
|
||||
.assign(to: \UserTimelineViewModel.isBlocking, on: userTimelineViewModel)
|
||||
.store(in: &disposeBag)
|
||||
|
||||
viewModel.relationship.publisher
|
||||
.compactMap { $0.blockedBy }
|
||||
.assign(to: \UserTimelineViewModel.isBlockedBy, on: userTimelineViewModel)
|
||||
.store(in: &disposeBag)
|
||||
|
||||
viewModel.$account
|
||||
.compactMap { $0.suspended }
|
||||
.assign(to: \UserTimelineViewModel.isSuspended, on: userTimelineViewModel)
|
||||
.store(in: &disposeBag)
|
||||
}
|
||||
|
||||
// about
|
||||
let aboutViewModel = viewModel.profileAboutViewModel
|
||||
viewModel.$account
|
||||
.assign(to: \.account, on: aboutViewModel)
|
||||
.store(in: &disposeBag)
|
||||
viewModel.$isEditing
|
||||
.assign(to: \.isEditing, on: aboutViewModel)
|
||||
.store(in: &disposeBag)
|
||||
viewModel.$accountForEdit
|
||||
.assign(to: \.accountForEdit, on: aboutViewModel)
|
||||
.store(in: &disposeBag)
|
||||
|
||||
let editingAndUpdatingPublisher = Publishers.CombineLatest(
|
||||
viewModel.$isEditing,
|
||||
viewModel.$isUpdating
|
||||
@ -259,103 +362,25 @@ extension ProfileViewController {
|
||||
}
|
||||
.store(in: &disposeBag)
|
||||
|
||||
viewModel.$isEditing
|
||||
.receive(on: DispatchQueue.main)
|
||||
.sink { [weak self] isEditing in
|
||||
guard let self else { return }
|
||||
|
||||
if isEditing {
|
||||
tabBarPagerController.relayScrollView.refreshControl = nil
|
||||
} else {
|
||||
tabBarPagerController.relayScrollView.refreshControl = refreshControl
|
||||
}
|
||||
}
|
||||
.store(in: &disposeBag)
|
||||
|
||||
context.publisherService.statusPublishResult.sink { [weak self] result in
|
||||
if case .success(.edit(let status)) = result {
|
||||
self?.updateViewModelsWithDataControllers(status: .fromEntity(status.value), intent: .edit)
|
||||
}
|
||||
}.store(in: &disposeBag)
|
||||
|
||||
addChild(tabBarPagerController)
|
||||
tabBarPagerController.view.translatesAutoresizingMaskIntoConstraints = false
|
||||
view.addSubview(tabBarPagerController.view)
|
||||
tabBarPagerController.didMove(toParent: self)
|
||||
tabBarPagerController.view.pinToParent()
|
||||
|
||||
tabBarPagerController.delegate = self
|
||||
tabBarPagerController.dataSource = self
|
||||
|
||||
tabBarPagerController.relayScrollView.refreshControl = refreshControl
|
||||
refreshControl.addTarget(self, action: #selector(ProfileViewController.refreshControlValueChanged(_:)), for: .valueChanged)
|
||||
|
||||
// setup delegate
|
||||
profileHeaderViewController.delegate = self
|
||||
profilePagingViewController.viewModel.profileAboutViewController.delegate = self
|
||||
|
||||
bindViewModel()
|
||||
bindTitleView()
|
||||
bindMoreBarButtonItem()
|
||||
bindPager()
|
||||
}
|
||||
|
||||
override func viewWillAppear(_ animated: Bool) {
|
||||
super.viewWillAppear(animated)
|
||||
|
||||
navigationController?.navigationBar.prefersLargeTitles = false
|
||||
}
|
||||
|
||||
override func viewDidAppear(_ animated: Bool) {
|
||||
super.viewDidAppear(animated)
|
||||
viewModel.viewDidAppear.send()
|
||||
|
||||
setNeedsStatusBarAppearanceUpdate()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension ProfileViewController {
|
||||
|
||||
private func bindViewModel() {
|
||||
// header
|
||||
let headerViewModel = profileHeaderViewController.viewModel
|
||||
viewModel.$account
|
||||
.assign(to: \.account, on: headerViewModel)
|
||||
.store(in: &disposeBag)
|
||||
viewModel.$isEditing
|
||||
.assign(to: \.isEditing, on: headerViewModel)
|
||||
.store(in: &disposeBag)
|
||||
viewModel.$isUpdating
|
||||
.assign(to: \.isUpdating, on: headerViewModel)
|
||||
.store(in: &disposeBag)
|
||||
viewModel.$relationship
|
||||
.assign(to: \.relationship, on: headerViewModel)
|
||||
.store(in: &disposeBag)
|
||||
viewModel.$accountForEdit
|
||||
.assign(to: \.accountForEdit, on: headerViewModel)
|
||||
.store(in: &disposeBag)
|
||||
|
||||
[
|
||||
viewModel.postsUserTimelineViewModel,
|
||||
viewModel.repliesUserTimelineViewModel,
|
||||
viewModel.mediaUserTimelineViewModel,
|
||||
].forEach { userTimelineViewModel in
|
||||
|
||||
viewModel.relationship.publisher
|
||||
.map { $0.blocking }
|
||||
.assign(to: \UserTimelineViewModel.isBlocking, on: userTimelineViewModel)
|
||||
.store(in: &disposeBag)
|
||||
|
||||
viewModel.relationship.publisher
|
||||
.compactMap { $0.blockedBy }
|
||||
.assign(to: \UserTimelineViewModel.isBlockedBy, on: userTimelineViewModel)
|
||||
.store(in: &disposeBag)
|
||||
|
||||
viewModel.$account
|
||||
.compactMap { $0.suspended }
|
||||
.assign(to: \UserTimelineViewModel.isSuspended, on: userTimelineViewModel)
|
||||
.store(in: &disposeBag)
|
||||
}
|
||||
|
||||
// about
|
||||
let aboutViewModel = viewModel.profileAboutViewModel
|
||||
viewModel.$account
|
||||
.assign(to: \.account, on: aboutViewModel)
|
||||
.store(in: &disposeBag)
|
||||
viewModel.$isEditing
|
||||
.assign(to: \.isEditing, on: aboutViewModel)
|
||||
.store(in: &disposeBag)
|
||||
viewModel.$accountForEdit
|
||||
.assign(to: \.accountForEdit, on: aboutViewModel)
|
||||
.store(in: &disposeBag)
|
||||
}
|
||||
|
||||
private func bindTitleView() {
|
||||
@ -443,7 +468,7 @@ extension ProfileViewController {
|
||||
viewModel.$isPagingEnabled
|
||||
.receive(on: DispatchQueue.main)
|
||||
.sink { [weak self] isPagingEnabled in
|
||||
guard let self = self else { return }
|
||||
guard let self else { return }
|
||||
self.profilePagingViewController.containerView.isScrollEnabled = isPagingEnabled
|
||||
self.profilePagingViewController.buttonBarView.isUserInteractionEnabled = isPagingEnabled
|
||||
}
|
||||
@ -458,10 +483,9 @@ extension ProfileViewController {
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
|
||||
self.profilePagingViewController.becomeFirstResponder()
|
||||
}
|
||||
}
|
||||
|
||||
// dismiss keyboard if needs
|
||||
if !isEditing { self.view.endEditing(true) }
|
||||
self.view.endEditing(true)
|
||||
}
|
||||
|
||||
if isEditing,
|
||||
let index = self.profilePagingViewController.viewControllers.firstIndex(where: { type(of: $0) is ProfileAboutViewController.Type }),
|
||||
@ -495,8 +519,7 @@ extension ProfileViewController {
|
||||
extension ProfileViewController {
|
||||
|
||||
@objc private func cancelEditingBarButtonItemPressed(_ sender: UIBarButtonItem) {
|
||||
viewModel.isEditing = false
|
||||
profileHeaderViewController.viewModel.isEditing = false
|
||||
cancelEditing()
|
||||
}
|
||||
|
||||
@objc private func settingBarButtonItemPressed(_ sender: UIBarButtonItem) {
|
||||
@ -714,6 +737,8 @@ extension ProfileViewController: ProfileHeaderViewControllerDelegate {
|
||||
aboutProfileInfo: profileAboutViewModel.profileInfoEditing
|
||||
).value
|
||||
self.viewModel.isEditing = false
|
||||
self.profileHeaderViewController.viewModel.isEditing = false
|
||||
profileAboutViewModel.isEditing = false
|
||||
self.viewModel.account = updatedAccount
|
||||
|
||||
} catch {
|
||||
@ -757,15 +782,25 @@ extension ProfileViewController: ProfileHeaderViewControllerDelegate {
|
||||
// enter editing mode
|
||||
self.viewModel.isEditing = true
|
||||
self.profileHeaderViewController.viewModel.isEditing = true
|
||||
profileAboutViewModel.isEditing = true
|
||||
}
|
||||
} receiveValue: { [weak self] response in
|
||||
guard let self = self else { return }
|
||||
self.viewModel.accountForEdit = response.value
|
||||
}
|
||||
.store(in: &disposeBag)
|
||||
} else if isEdited == false {
|
||||
cancelEditing()
|
||||
}
|
||||
}
|
||||
|
||||
private func cancelEditing() {
|
||||
viewModel.isEditing = false
|
||||
profileHeaderViewController.viewModel.isEditing = false
|
||||
profilePagingViewController.viewModel.profileAboutViewController.viewModel.isEditing = false
|
||||
viewModel.profileAboutViewModel.isEditing = false
|
||||
}
|
||||
|
||||
private func editRelationship() {
|
||||
guard let relationship = viewModel.relationship, viewModel.isUpdating == false else {
|
||||
return
|
||||
|
Loading…
x
Reference in New Issue
Block a user