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
@ -48,21 +48,25 @@ extension ProfileAboutViewController {
|
||||
collectionView.translatesAutoresizingMaskIntoConstraints = false
|
||||
view.addSubview(collectionView)
|
||||
collectionView.pinToParent()
|
||||
|
||||
collectionView.delegate = self
|
||||
viewModel.setupDiffableDataSource(
|
||||
collectionView: collectionView,
|
||||
profileFieldCollectionViewCellDelegate: self,
|
||||
profileFieldEditCollectionViewCellDelegate: self
|
||||
)
|
||||
|
||||
|
||||
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,
|
||||
profileFieldCollectionViewCellDelegate: self,
|
||||
profileFieldEditCollectionViewCellDelegate: self
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension ProfileAboutViewController {
|
||||
|
@ -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,8 +32,19 @@ 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()
|
||||
|
||||
private(set) lazy var cancelEditingBarButtonItem: UIBarButtonItem = {
|
||||
@ -182,89 +193,6 @@ extension ProfileViewController {
|
||||
|
||||
navigationItem.titleView = titleView
|
||||
|
||||
let editingAndUpdatingPublisher = Publishers.CombineLatest(
|
||||
viewModel.$isEditing,
|
||||
viewModel.$isUpdating
|
||||
)
|
||||
// note: not add .share() here
|
||||
|
||||
let barButtonItemHiddenPublisher = Publishers.CombineLatest3(
|
||||
viewModel.$isMeBarButtonItemsHidden,
|
||||
viewModel.$isReplyBarButtonItemHidden,
|
||||
viewModel.$isMoreMenuBarButtonItemHidden
|
||||
)
|
||||
|
||||
editingAndUpdatingPublisher
|
||||
.receive(on: DispatchQueue.main)
|
||||
.sink { [weak self] isEditing, isUpdating in
|
||||
guard let self = self else { return }
|
||||
self.cancelEditingBarButtonItem.isEnabled = !isUpdating
|
||||
}
|
||||
.store(in: &disposeBag)
|
||||
|
||||
// build items
|
||||
Publishers.CombineLatest4(
|
||||
viewModel.$relationship,
|
||||
profileHeaderViewController.viewModel.$isTitleViewDisplaying,
|
||||
editingAndUpdatingPublisher,
|
||||
barButtonItemHiddenPublisher
|
||||
)
|
||||
.receive(on: DispatchQueue.main)
|
||||
.sink { [weak self] account, isTitleViewDisplaying, tuple1, tuple2 in
|
||||
guard let self else { return }
|
||||
let (isEditing, _) = tuple1
|
||||
let (isMeBarButtonItemsHidden, isReplyBarButtonItemHidden, isMoreMenuBarButtonItemHidden) = tuple2
|
||||
|
||||
var items: [UIBarButtonItem] = []
|
||||
defer {
|
||||
if items.isNotEmpty {
|
||||
self.navigationItem.rightBarButtonItems = items
|
||||
} else {
|
||||
self.navigationItem.rightBarButtonItems = nil
|
||||
}
|
||||
}
|
||||
|
||||
if let suspended = self.viewModel.account.suspended, suspended == true {
|
||||
return
|
||||
}
|
||||
|
||||
guard isEditing == false else {
|
||||
items.append(self.cancelEditingBarButtonItem)
|
||||
return
|
||||
}
|
||||
|
||||
guard isTitleViewDisplaying == false else {
|
||||
return
|
||||
}
|
||||
|
||||
guard isMeBarButtonItemsHidden else {
|
||||
items.append(self.settingBarButtonItem)
|
||||
items.append(self.shareBarButtonItem)
|
||||
items.append(self.favoriteBarButtonItem)
|
||||
items.append(self.bookmarkBarButtonItem)
|
||||
|
||||
if self.currentInstance?.canFollowTags == true {
|
||||
items.append(self.followedTagsBarButtonItem)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if !isMoreMenuBarButtonItemHidden {
|
||||
items.append(self.moreMenuBarButtonItem)
|
||||
}
|
||||
if !isReplyBarButtonItemHidden {
|
||||
items.append(self.replyBarButtonItem)
|
||||
}
|
||||
}
|
||||
.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)
|
||||
@ -280,17 +208,17 @@ extension ProfileViewController {
|
||||
// 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
|
||||
|
||||
bindViewModel()
|
||||
bindTitleView()
|
||||
bindMoreBarButtonItem()
|
||||
bindPager()
|
||||
}
|
||||
|
||||
override func viewDidAppear(_ animated: Bool) {
|
||||
@ -356,6 +284,103 @@ extension ProfileViewController {
|
||||
viewModel.$accountForEdit
|
||||
.assign(to: \.accountForEdit, on: aboutViewModel)
|
||||
.store(in: &disposeBag)
|
||||
|
||||
let editingAndUpdatingPublisher = Publishers.CombineLatest(
|
||||
viewModel.$isEditing,
|
||||
viewModel.$isUpdating
|
||||
)
|
||||
// note: not add .share() here
|
||||
|
||||
let barButtonItemHiddenPublisher = Publishers.CombineLatest3(
|
||||
viewModel.$isMeBarButtonItemsHidden,
|
||||
viewModel.$isReplyBarButtonItemHidden,
|
||||
viewModel.$isMoreMenuBarButtonItemHidden
|
||||
)
|
||||
|
||||
editingAndUpdatingPublisher
|
||||
.receive(on: DispatchQueue.main)
|
||||
.sink { [weak self] isEditing, isUpdating in
|
||||
guard let self = self else { return }
|
||||
self.cancelEditingBarButtonItem.isEnabled = !isUpdating
|
||||
}
|
||||
.store(in: &disposeBag)
|
||||
|
||||
// build items
|
||||
Publishers.CombineLatest4(
|
||||
viewModel.$relationship,
|
||||
profileHeaderViewController.viewModel.$isTitleViewDisplaying,
|
||||
editingAndUpdatingPublisher,
|
||||
barButtonItemHiddenPublisher
|
||||
)
|
||||
.receive(on: DispatchQueue.main)
|
||||
.sink { [weak self] account, isTitleViewDisplaying, tuple1, tuple2 in
|
||||
guard let self else { return }
|
||||
let (isEditing, _) = tuple1
|
||||
let (isMeBarButtonItemsHidden, isReplyBarButtonItemHidden, isMoreMenuBarButtonItemHidden) = tuple2
|
||||
|
||||
var items: [UIBarButtonItem] = []
|
||||
defer {
|
||||
if items.isNotEmpty {
|
||||
self.navigationItem.rightBarButtonItems = items
|
||||
} else {
|
||||
self.navigationItem.rightBarButtonItems = nil
|
||||
}
|
||||
}
|
||||
|
||||
if let suspended = self.viewModel.account.suspended, suspended == true {
|
||||
return
|
||||
}
|
||||
|
||||
guard isEditing == false else {
|
||||
items.append(self.cancelEditingBarButtonItem)
|
||||
return
|
||||
}
|
||||
|
||||
guard isTitleViewDisplaying == false else {
|
||||
return
|
||||
}
|
||||
|
||||
guard isMeBarButtonItemsHidden else {
|
||||
items.append(self.settingBarButtonItem)
|
||||
items.append(self.shareBarButtonItem)
|
||||
items.append(self.favoriteBarButtonItem)
|
||||
items.append(self.bookmarkBarButtonItem)
|
||||
|
||||
if self.currentInstance?.canFollowTags == true {
|
||||
items.append(self.followedTagsBarButtonItem)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if !isMoreMenuBarButtonItemHidden {
|
||||
items.append(self.moreMenuBarButtonItem)
|
||||
}
|
||||
if !isReplyBarButtonItemHidden {
|
||||
items.append(self.replyBarButtonItem)
|
||||
}
|
||||
}
|
||||
.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)
|
||||
|
||||
}
|
||||
|
||||
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,11 +483,10 @@ extension ProfileViewController {
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
|
||||
self.profilePagingViewController.becomeFirstResponder()
|
||||
}
|
||||
// dismiss keyboard if needs
|
||||
self.view.endEditing(true)
|
||||
}
|
||||
|
||||
// dismiss keyboard if needs
|
||||
if !isEditing { self.view.endEditing(true) }
|
||||
|
||||
if isEditing,
|
||||
let index = self.profilePagingViewController.viewControllers.firstIndex(where: { type(of: $0) is ProfileAboutViewController.Type }),
|
||||
self.profilePagingViewController.canMoveTo(index: index)
|
||||
@ -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