Skip to content

Commit

Permalink
Fix Profile Editing again (IOS-239, #1244) (#1259)
Browse files Browse the repository at this point in the history
* 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)
zeitschlag authored Mar 21, 2024

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
1 parent 83fd4a8 commit ab39c6e
Showing 3 changed files with 146 additions and 107 deletions.
20 changes: 12 additions & 8 deletions Mastodon/Scene/Profile/About/ProfileAboutViewController.swift
Original file line number Diff line number Diff line change
@@ -48,21 +48,25 @@ extension ProfileAboutViewController {
collectionView.translatesAutoresizingMaskIntoConstraints = false
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,
profileFieldCollectionViewCellDelegate: self,
profileFieldEditCollectionViewCellDelegate: self
)

let longPressReorderGesture = UILongPressGestureRecognizer(
target: self,
action: #selector(ProfileAboutViewController.longPressReorderGestureHandler(_:))
)
collectionView.addGestureRecognizer(longPressReorderGesture)

}

}

extension ProfileAboutViewController {
Original file line number Diff line number Diff line change
@@ -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,15 +60,15 @@ extension ProfileAboutViewModel {


Publishers.CombineLatest4(
$isEditing.removeDuplicates(),
$isEditing,
$createdAt.removeDuplicates(),
fields,
$emojiMeta.removeDuplicates()
)
.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>()
227 changes: 131 additions & 96 deletions Mastodon/Scene/Profile/ProfileViewController.swift
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit ab39c6e

Please sign in to comment.