From 6c973ed17c745072736924ee1d3f0acaa3cb7399 Mon Sep 17 00:00:00 2001 From: CMK Date: Wed, 14 Apr 2021 18:11:59 +0800 Subject: [PATCH] fix: resolve #83 the text editor input content offset reset after input character issue --- Mastodon.xcodeproj/project.pbxproj | 8 +-- .../Section/ComposeStatusSection.swift | 6 ++ ...eStatusAttachmentCollectionViewCell.swift} | 2 +- ...mposeStatusContentCollectionViewCell.swift | 2 +- .../Scene/Compose/ComposeViewController.swift | 55 ++++++++++++------- 5 files changed, 48 insertions(+), 25 deletions(-) rename Mastodon/Scene/Compose/CollectionViewCell/{ComposeStatusAttachmentTableViewCell.swift => ComposeStatusAttachmentCollectionViewCell.swift} (98%) diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index ea937b52d..f6bf54a2b 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -220,7 +220,7 @@ DB68A05D25E9055900CFDF14 /* Settings.bundle in Resources */ = {isa = PBXBuildFile; fileRef = DB68A05C25E9055900CFDF14 /* Settings.bundle */; }; DB68A06325E905E000CFDF14 /* UIApplication.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB68A06225E905E000CFDF14 /* UIApplication.swift */; }; DB6B35182601FA3400DC1E11 /* MastodonAttachmentService.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB6B35172601FA3400DC1E11 /* MastodonAttachmentService.swift */; }; - DB6B351E2601FAEE00DC1E11 /* ComposeStatusAttachmentTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB6B351D2601FAEE00DC1E11 /* ComposeStatusAttachmentTableViewCell.swift */; }; + DB6B351E2601FAEE00DC1E11 /* ComposeStatusAttachmentCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB6B351D2601FAEE00DC1E11 /* ComposeStatusAttachmentCollectionViewCell.swift */; }; DB6C8C0F25F0A6AE00AAA452 /* Mastodon+Entity+Error.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB6C8C0E25F0A6AE00AAA452 /* Mastodon+Entity+Error.swift */; }; DB71FD2C25F86A5100512AE1 /* AvatarStackContainerButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB71FD2B25F86A5100512AE1 /* AvatarStackContainerButton.swift */; }; DB71FD3625F8A16C00512AE1 /* APIService+Persist+PersistMemo.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB71FD3525F8A16C00512AE1 /* APIService+Persist+PersistMemo.swift */; }; @@ -618,7 +618,7 @@ DB68A05C25E9055900CFDF14 /* Settings.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = Settings.bundle; sourceTree = ""; }; DB68A06225E905E000CFDF14 /* UIApplication.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIApplication.swift; sourceTree = ""; }; DB6B35172601FA3400DC1E11 /* MastodonAttachmentService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonAttachmentService.swift; sourceTree = ""; }; - DB6B351D2601FAEE00DC1E11 /* ComposeStatusAttachmentTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeStatusAttachmentTableViewCell.swift; sourceTree = ""; }; + DB6B351D2601FAEE00DC1E11 /* ComposeStatusAttachmentCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeStatusAttachmentCollectionViewCell.swift; sourceTree = ""; }; DB6C8C0E25F0A6AE00AAA452 /* Mastodon+Entity+Error.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Mastodon+Entity+Error.swift"; sourceTree = ""; }; DB71FD2B25F86A5100512AE1 /* AvatarStackContainerButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AvatarStackContainerButton.swift; sourceTree = ""; }; DB71FD3525F8A16C00512AE1 /* APIService+Persist+PersistMemo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "APIService+Persist+PersistMemo.swift"; sourceTree = ""; }; @@ -1458,7 +1458,7 @@ children = ( DB789A2A25F9F7AB0071ACA0 /* ComposeRepliedToStatusContentCollectionViewCell.swift */, DB789A1B25F9F76A0071ACA0 /* ComposeStatusContentCollectionViewCell.swift */, - DB6B351D2601FAEE00DC1E11 /* ComposeStatusAttachmentTableViewCell.swift */, + DB6B351D2601FAEE00DC1E11 /* ComposeStatusAttachmentCollectionViewCell.swift */, DB87D4442609BE0500D12C0D /* ComposeStatusPollOptionCollectionViewCell.swift */, DB87D4502609CF1E00D12C0D /* ComposeStatusPollOptionAppendEntryCollectionViewCell.swift */, DB2FF50F260B113300ADA9FE /* ComposeStatusPollExpiresOptionCollectionViewCell.swift */, @@ -2296,7 +2296,7 @@ 0FAA101C25E10E760017CCDE /* UIFont.swift in Sources */, 2D38F1D525CD465300561493 /* HomeTimelineViewController.swift in Sources */, DB98338825C945ED00AD9700 /* Assets.swift in Sources */, - DB6B351E2601FAEE00DC1E11 /* ComposeStatusAttachmentTableViewCell.swift in Sources */, + DB6B351E2601FAEE00DC1E11 /* ComposeStatusAttachmentCollectionViewCell.swift in Sources */, 2DA7D04425CA52B200804E11 /* TimelineLoaderTableViewCell.swift in Sources */, DB87D44B2609C11900D12C0D /* PollOptionView.swift in Sources */, DBE3CDFB261C6CA500430CC6 /* FavoriteViewModel.swift in Sources */, diff --git a/Mastodon/Diffiable/Section/ComposeStatusSection.swift b/Mastodon/Diffiable/Section/ComposeStatusSection.swift index 4b0b5aa57..49f4fb5b7 100644 --- a/Mastodon/Diffiable/Section/ComposeStatusSection.swift +++ b/Mastodon/Diffiable/Section/ComposeStatusSection.swift @@ -92,7 +92,12 @@ extension ComposeStatusSection { .receive(on: DispatchQueue.main) .sink { text in // self size input cell + // needs restore content offset to resolve issue #83 + let oldContentOffset = collectionView.contentOffset collectionView.collectionViewLayout.invalidateLayout() + collectionView.layoutIfNeeded() + collectionView.contentOffset = oldContentOffset + // bind input data attribute.composeContent.value = text } @@ -187,6 +192,7 @@ extension ComposeStatusSection { case .pollOption(let attribute): let cell = collectionView.dequeueReusableCell(withReuseIdentifier: String(describing: ComposeStatusPollOptionCollectionViewCell.self), for: indexPath) as! ComposeStatusPollOptionCollectionViewCell cell.pollOptionView.optionTextField.text = attribute.option.value + cell.pollOptionView.optionTextField.placeholder = L10n.Scene.Compose.Poll.optionNumber(indexPath.item + 1) cell.pollOption .receive(on: DispatchQueue.main) .assign(to: \.value, on: attribute.option) diff --git a/Mastodon/Scene/Compose/CollectionViewCell/ComposeStatusAttachmentTableViewCell.swift b/Mastodon/Scene/Compose/CollectionViewCell/ComposeStatusAttachmentCollectionViewCell.swift similarity index 98% rename from Mastodon/Scene/Compose/CollectionViewCell/ComposeStatusAttachmentTableViewCell.swift rename to Mastodon/Scene/Compose/CollectionViewCell/ComposeStatusAttachmentCollectionViewCell.swift index bc087c990..141a944fd 100644 --- a/Mastodon/Scene/Compose/CollectionViewCell/ComposeStatusAttachmentTableViewCell.swift +++ b/Mastodon/Scene/Compose/CollectionViewCell/ComposeStatusAttachmentCollectionViewCell.swift @@ -1,5 +1,5 @@ // -// ComposeStatusAttachmentTableViewCell.swift +// ComposeStatusAttachmentCollectionViewCell.swift // Mastodon // // Created by MainasuK Cirno on 2021-3-17. diff --git a/Mastodon/Scene/Compose/CollectionViewCell/ComposeStatusContentCollectionViewCell.swift b/Mastodon/Scene/Compose/CollectionViewCell/ComposeStatusContentCollectionViewCell.swift index f1fe6b541..2b71e55f3 100644 --- a/Mastodon/Scene/Compose/CollectionViewCell/ComposeStatusContentCollectionViewCell.swift +++ b/Mastodon/Scene/Compose/CollectionViewCell/ComposeStatusContentCollectionViewCell.swift @@ -91,7 +91,7 @@ extension ComposeStatusContentCollectionViewCell { statusContentWarningEditorView.containerView.isHidden = true } - + } // MARK: - TextEditorViewChangeObserver diff --git a/Mastodon/Scene/Compose/ComposeViewController.swift b/Mastodon/Scene/Compose/ComposeViewController.swift index 29b8850b9..e56caf81f 100644 --- a/Mastodon/Scene/Compose/ComposeViewController.swift +++ b/Mastodon/Scene/Compose/ComposeViewController.swift @@ -68,18 +68,7 @@ final class ComposeViewController: UIViewController, NeedsDependency { let composeToolbarView = ComposeToolbarView() var composeToolbarViewBottomLayoutConstraint: NSLayoutConstraint! - let composeToolbarBackgroundView: UIView = { - let backgroundView = UIView() - // set keyboard background to make the keyboard blurred color fixed - backgroundView.backgroundColor = UIColor(dynamicProvider: { traitCollection -> UIColor in - // avoid elevated color - switch traitCollection.userInterfaceStyle { - case .light: return .white - default: return .black - } - }) - return backgroundView - }() + let composeToolbarBackgroundView = UIView() private(set) lazy var imagePicker: PHPickerViewController = { var configuration = PHPickerConfiguration() @@ -202,14 +191,27 @@ extension ComposeViewController { ) .sink(receiveValue: { [weak self] isShow, state, endFrame, isCustomEmojiComposing in guard let self = self else { return } + + let extraMargin: CGFloat = { + if self.view.safeAreaInsets.bottom == .zero { + // needs extra margin for zero inset device to workaround UIKit issue + return self.composeToolbarView.frame.height + } else { + // default some magic 16 extra margin + return 16 + } + }() + + // update keyboard background color guard isShow, state == .dock else { - self.collectionView.contentInset.bottom = self.view.safeAreaInsets.bottom - self.collectionView.verticalScrollIndicatorInsets.bottom = self.view.safeAreaInsets.bottom + self.collectionView.contentInset.bottom = self.view.safeAreaInsets.bottom + extraMargin + self.collectionView.verticalScrollIndicatorInsets.bottom = self.view.safeAreaInsets.bottom + extraMargin UIView.animate(withDuration: 0.3) { self.composeToolbarViewBottomLayoutConstraint.constant = self.view.safeAreaInsets.bottom self.view.layoutIfNeeded() } + self.updateKeyboardBackground(isKeyboardDisplay: isShow) return } // isShow AND dock state @@ -218,22 +220,23 @@ extension ComposeViewController { let contentFrame = self.view.convert(self.collectionView.frame, to: nil) let padding = contentFrame.maxY - endFrame.minY guard padding > 0 else { - self.collectionView.contentInset.bottom = self.view.safeAreaInsets.bottom - self.collectionView.verticalScrollIndicatorInsets.bottom = self.view.safeAreaInsets.bottom + self.collectionView.contentInset.bottom = self.view.safeAreaInsets.bottom + extraMargin + self.collectionView.verticalScrollIndicatorInsets.bottom = self.view.safeAreaInsets.bottom + extraMargin UIView.animate(withDuration: 0.3) { self.composeToolbarViewBottomLayoutConstraint.constant = self.view.safeAreaInsets.bottom self.view.layoutIfNeeded() } + self.updateKeyboardBackground(isKeyboardDisplay: false) return } - // add 16pt margin - self.collectionView.contentInset.bottom = padding + 16 - self.collectionView.verticalScrollIndicatorInsets.bottom = padding + 16 + self.collectionView.contentInset.bottom = padding + extraMargin + self.collectionView.verticalScrollIndicatorInsets.bottom = padding + extraMargin UIView.animate(withDuration: 0.3) { self.composeToolbarViewBottomLayoutConstraint.constant = padding self.view.layoutIfNeeded() } + self.updateKeyboardBackground(isKeyboardDisplay: isShow) }) .store(in: &disposeBag) @@ -473,6 +476,20 @@ extension ComposeViewController { imagePicker.delegate = self return imagePicker } + + private func updateKeyboardBackground(isKeyboardDisplay: Bool) { + guard isKeyboardDisplay else { + composeToolbarBackgroundView.backgroundColor = Asset.Scene.Compose.toolbarBackground.color + return + } + composeToolbarBackgroundView.backgroundColor = UIColor(dynamicProvider: { traitCollection -> UIColor in + // avoid elevated color + switch traitCollection.userInterfaceStyle { + case .light: return .white + default: return .black + } + }) + } }