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
|
collectionView.translatesAutoresizingMaskIntoConstraints = false
|
||||||
view.addSubview(collectionView)
|
view.addSubview(collectionView)
|
||||||
collectionView.pinToParent()
|
collectionView.pinToParent()
|
||||||
|
|
||||||
collectionView.delegate = self
|
|
||||||
viewModel.setupDiffableDataSource(
|
|
||||||
collectionView: collectionView,
|
|
||||||
profileFieldCollectionViewCellDelegate: self,
|
|
||||||
profileFieldEditCollectionViewCellDelegate: self
|
|
||||||
)
|
|
||||||
|
|
||||||
let longPressReorderGesture = UILongPressGestureRecognizer(
|
let longPressReorderGesture = UILongPressGestureRecognizer(
|
||||||
target: self,
|
target: self,
|
||||||
action: #selector(ProfileAboutViewController.longPressReorderGestureHandler(_:))
|
action: #selector(ProfileAboutViewController.longPressReorderGestureHandler(_:))
|
||||||
)
|
)
|
||||||
collectionView.addGestureRecognizer(longPressReorderGesture)
|
collectionView.addGestureRecognizer(longPressReorderGesture)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override func viewWillAppear(_ animated: Bool) {
|
||||||
|
super.viewWillAppear(animated)
|
||||||
|
collectionView.delegate = self
|
||||||
|
viewModel.setupDiffableDataSource(
|
||||||
|
collectionView: collectionView,
|
||||||
|
profileFieldCollectionViewCellDelegate: self,
|
||||||
|
profileFieldEditCollectionViewCellDelegate: self
|
||||||
|
)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extension ProfileAboutViewController {
|
extension ProfileAboutViewController {
|
||||||
|
@ -51,7 +51,7 @@ extension ProfileAboutViewModel {
|
|||||||
diffableDataSource.apply(snapshot)
|
diffableDataSource.apply(snapshot)
|
||||||
|
|
||||||
let fields = Publishers.CombineLatest3(
|
let fields = Publishers.CombineLatest3(
|
||||||
$isEditing.removeDuplicates(),
|
$isEditing,
|
||||||
profileInfo.$fields.removeDuplicates(),
|
profileInfo.$fields.removeDuplicates(),
|
||||||
profileInfoEditing.$fields.removeDuplicates()
|
profileInfoEditing.$fields.removeDuplicates()
|
||||||
).map { isEditing, displayFields, editingFields in
|
).map { isEditing, displayFields, editingFields in
|
||||||
@ -60,7 +60,7 @@ extension ProfileAboutViewModel {
|
|||||||
|
|
||||||
|
|
||||||
Publishers.CombineLatest4(
|
Publishers.CombineLatest4(
|
||||||
$isEditing.removeDuplicates(),
|
$isEditing,
|
||||||
$createdAt.removeDuplicates(),
|
$createdAt.removeDuplicates(),
|
||||||
fields,
|
fields,
|
||||||
$emojiMeta.removeDuplicates()
|
$emojiMeta.removeDuplicates()
|
||||||
@ -68,7 +68,7 @@ extension ProfileAboutViewModel {
|
|||||||
.throttle(for: 0.3, scheduler: DispatchQueue.main, latest: true)
|
.throttle(for: 0.3, scheduler: DispatchQueue.main, latest: true)
|
||||||
.receive(on: DispatchQueue.main)
|
.receive(on: DispatchQueue.main)
|
||||||
.sink { [weak self] isEditing, createdAt, fields, emojiMeta in
|
.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 }
|
guard let diffableDataSource = self.diffableDataSource else { return }
|
||||||
|
|
||||||
var snapshot = NSDiffableDataSourceSnapshot<ProfileFieldSection, ProfileFieldItem>()
|
var snapshot = NSDiffableDataSourceSnapshot<ProfileFieldSection, ProfileFieldItem>()
|
||||||
|
@ -32,8 +32,19 @@ final class ProfileViewController: UIViewController, NeedsDependency, MediaPrevi
|
|||||||
|
|
||||||
var disposeBag = Set<AnyCancellable>()
|
var disposeBag = Set<AnyCancellable>()
|
||||||
//TODO: Replace with something better than !
|
//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()
|
let mediaPreviewTransitionController = MediaPreviewTransitionController()
|
||||||
|
|
||||||
private(set) lazy var cancelEditingBarButtonItem: UIBarButtonItem = {
|
private(set) lazy var cancelEditingBarButtonItem: UIBarButtonItem = {
|
||||||
@ -182,89 +193,6 @@ extension ProfileViewController {
|
|||||||
|
|
||||||
navigationItem.titleView = titleView
|
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)
|
addChild(tabBarPagerController)
|
||||||
tabBarPagerController.view.translatesAutoresizingMaskIntoConstraints = false
|
tabBarPagerController.view.translatesAutoresizingMaskIntoConstraints = false
|
||||||
view.addSubview(tabBarPagerController.view)
|
view.addSubview(tabBarPagerController.view)
|
||||||
@ -280,17 +208,17 @@ extension ProfileViewController {
|
|||||||
// setup delegate
|
// setup delegate
|
||||||
profileHeaderViewController.delegate = self
|
profileHeaderViewController.delegate = self
|
||||||
profilePagingViewController.viewModel.profileAboutViewController.delegate = self
|
profilePagingViewController.viewModel.profileAboutViewController.delegate = self
|
||||||
|
|
||||||
bindViewModel()
|
|
||||||
bindTitleView()
|
|
||||||
bindMoreBarButtonItem()
|
|
||||||
bindPager()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override func viewWillAppear(_ animated: Bool) {
|
override func viewWillAppear(_ animated: Bool) {
|
||||||
super.viewWillAppear(animated)
|
super.viewWillAppear(animated)
|
||||||
|
|
||||||
navigationController?.navigationBar.prefersLargeTitles = false
|
navigationController?.navigationBar.prefersLargeTitles = false
|
||||||
|
|
||||||
|
bindViewModel()
|
||||||
|
bindTitleView()
|
||||||
|
bindMoreBarButtonItem()
|
||||||
|
bindPager()
|
||||||
}
|
}
|
||||||
|
|
||||||
override func viewDidAppear(_ animated: Bool) {
|
override func viewDidAppear(_ animated: Bool) {
|
||||||
@ -356,6 +284,103 @@ extension ProfileViewController {
|
|||||||
viewModel.$accountForEdit
|
viewModel.$accountForEdit
|
||||||
.assign(to: \.accountForEdit, on: aboutViewModel)
|
.assign(to: \.accountForEdit, on: aboutViewModel)
|
||||||
.store(in: &disposeBag)
|
.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() {
|
private func bindTitleView() {
|
||||||
@ -443,7 +468,7 @@ extension ProfileViewController {
|
|||||||
viewModel.$isPagingEnabled
|
viewModel.$isPagingEnabled
|
||||||
.receive(on: DispatchQueue.main)
|
.receive(on: DispatchQueue.main)
|
||||||
.sink { [weak self] isPagingEnabled in
|
.sink { [weak self] isPagingEnabled in
|
||||||
guard let self = self else { return }
|
guard let self else { return }
|
||||||
self.profilePagingViewController.containerView.isScrollEnabled = isPagingEnabled
|
self.profilePagingViewController.containerView.isScrollEnabled = isPagingEnabled
|
||||||
self.profilePagingViewController.buttonBarView.isUserInteractionEnabled = isPagingEnabled
|
self.profilePagingViewController.buttonBarView.isUserInteractionEnabled = isPagingEnabled
|
||||||
}
|
}
|
||||||
@ -458,11 +483,10 @@ extension ProfileViewController {
|
|||||||
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
|
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
|
||||||
self.profilePagingViewController.becomeFirstResponder()
|
self.profilePagingViewController.becomeFirstResponder()
|
||||||
}
|
}
|
||||||
|
// dismiss keyboard if needs
|
||||||
|
self.view.endEditing(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
// dismiss keyboard if needs
|
|
||||||
if !isEditing { self.view.endEditing(true) }
|
|
||||||
|
|
||||||
if isEditing,
|
if isEditing,
|
||||||
let index = self.profilePagingViewController.viewControllers.firstIndex(where: { type(of: $0) is ProfileAboutViewController.Type }),
|
let index = self.profilePagingViewController.viewControllers.firstIndex(where: { type(of: $0) is ProfileAboutViewController.Type }),
|
||||||
self.profilePagingViewController.canMoveTo(index: index)
|
self.profilePagingViewController.canMoveTo(index: index)
|
||||||
@ -495,8 +519,7 @@ extension ProfileViewController {
|
|||||||
extension ProfileViewController {
|
extension ProfileViewController {
|
||||||
|
|
||||||
@objc private func cancelEditingBarButtonItemPressed(_ sender: UIBarButtonItem) {
|
@objc private func cancelEditingBarButtonItemPressed(_ sender: UIBarButtonItem) {
|
||||||
viewModel.isEditing = false
|
cancelEditing()
|
||||||
profileHeaderViewController.viewModel.isEditing = false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc private func settingBarButtonItemPressed(_ sender: UIBarButtonItem) {
|
@objc private func settingBarButtonItemPressed(_ sender: UIBarButtonItem) {
|
||||||
@ -714,6 +737,8 @@ extension ProfileViewController: ProfileHeaderViewControllerDelegate {
|
|||||||
aboutProfileInfo: profileAboutViewModel.profileInfoEditing
|
aboutProfileInfo: profileAboutViewModel.profileInfoEditing
|
||||||
).value
|
).value
|
||||||
self.viewModel.isEditing = false
|
self.viewModel.isEditing = false
|
||||||
|
self.profileHeaderViewController.viewModel.isEditing = false
|
||||||
|
profileAboutViewModel.isEditing = false
|
||||||
self.viewModel.account = updatedAccount
|
self.viewModel.account = updatedAccount
|
||||||
|
|
||||||
} catch {
|
} catch {
|
||||||
@ -757,15 +782,25 @@ extension ProfileViewController: ProfileHeaderViewControllerDelegate {
|
|||||||
// enter editing mode
|
// enter editing mode
|
||||||
self.viewModel.isEditing = true
|
self.viewModel.isEditing = true
|
||||||
self.profileHeaderViewController.viewModel.isEditing = true
|
self.profileHeaderViewController.viewModel.isEditing = true
|
||||||
|
profileAboutViewModel.isEditing = true
|
||||||
}
|
}
|
||||||
} receiveValue: { [weak self] response in
|
} receiveValue: { [weak self] response in
|
||||||
guard let self = self else { return }
|
guard let self = self else { return }
|
||||||
self.viewModel.accountForEdit = response.value
|
self.viewModel.accountForEdit = response.value
|
||||||
}
|
}
|
||||||
.store(in: &disposeBag)
|
.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() {
|
private func editRelationship() {
|
||||||
guard let relationship = viewModel.relationship, viewModel.isUpdating == false else {
|
guard let relationship = viewModel.relationship, viewModel.isUpdating == false else {
|
||||||
return
|
return
|
||||||
|
Loading…
x
Reference in New Issue
Block a user