Фикс: блокировка восстановления клавиатуры при свайп-бэк и скип read receipt для системных аккаунтов
This commit is contained in:
@@ -560,6 +560,12 @@ final class SessionManager {
|
||||
for item in encryptedAttachments {
|
||||
if item.original.type == .image, let image = UIImage(data: item.original.data) {
|
||||
AttachmentCache.shared.saveImage(image, forAttachmentId: item.original.id)
|
||||
} else if item.original.type == .file {
|
||||
AttachmentCache.shared.saveFile(
|
||||
item.original.data,
|
||||
forAttachmentId: item.original.id,
|
||||
fileName: item.original.fileName ?? "file"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -998,6 +1004,7 @@ final class SessionManager {
|
||||
let connState = ProtocolManager.shared.connectionState
|
||||
guard normalized != currentPublicKey,
|
||||
!normalized.isEmpty,
|
||||
!SystemAccounts.isSystemAccount(normalized),
|
||||
let hash = privateKeyHash,
|
||||
connState == .authenticated
|
||||
else {
|
||||
|
||||
@@ -29,6 +29,11 @@ final class ComposerView: UIView, UITextViewDelegate {
|
||||
|
||||
private(set) var currentHeight: CGFloat = 0
|
||||
|
||||
/// When true, blocks becomeFirstResponder via textViewShouldBeginEditing.
|
||||
/// Set by NativeMessageListController during swipe-back to prevent UIKit
|
||||
/// from auto-restoring first responder on transition cancellation.
|
||||
var isFocusBlocked = false
|
||||
|
||||
// MARK: - Subviews
|
||||
|
||||
// Attach button (glass circle, 42×42)
|
||||
@@ -495,6 +500,10 @@ final class ComposerView: UIView, UITextViewDelegate {
|
||||
|
||||
// MARK: - UITextViewDelegate
|
||||
|
||||
func textViewShouldBeginEditing(_ textView: UITextView) -> Bool {
|
||||
!isFocusBlocked
|
||||
}
|
||||
|
||||
func textViewDidBeginEditing(_ textView: UITextView) {
|
||||
delegate?.composerFocusDidChange(self, isFocused: true)
|
||||
}
|
||||
|
||||
@@ -81,6 +81,10 @@ final class NativeMessageListController: UIViewController {
|
||||
private var composerBottomConstraint: NSLayoutConstraint?
|
||||
private var composerHeightConstraint: NSLayoutConstraint?
|
||||
private var isKeyboardAnimating = false
|
||||
private(set) var isDisappearing = false
|
||||
/// Blocks programmatic re-focus after swipe-back dismisses keyboard.
|
||||
/// Cleared only when isInputFocused becomes true (user tap or reply action).
|
||||
fileprivate(set) var keyboardBlockedUntilUserTap = false
|
||||
private var currentKeyboardHeight: CGFloat = 0
|
||||
|
||||
// MARK: - Scroll-to-Bottom Button
|
||||
@@ -147,7 +151,26 @@ final class NativeMessageListController: UIViewController {
|
||||
)
|
||||
}
|
||||
|
||||
// Phase 7: No viewWillAppear/viewWillDisappear — CADisplayLink removed entirely.
|
||||
// Dismiss keyboard on swipe-back. Let keyboardWillChangeFrame update insets
|
||||
// normally so content slides down, but skip offset compensation (isDisappearing flag).
|
||||
override func viewWillDisappear(_ animated: Bool) {
|
||||
super.viewWillDisappear(animated)
|
||||
isDisappearing = true
|
||||
keyboardBlockedUntilUserTap = true
|
||||
// Block UIKit first-responder restoration at the UITextView level.
|
||||
composerView?.isFocusBlocked = true
|
||||
view.endEditing(true)
|
||||
onComposerFocusChange?(false)
|
||||
}
|
||||
|
||||
override func viewDidAppear(_ animated: Bool) {
|
||||
super.viewDidAppear(animated)
|
||||
isDisappearing = false
|
||||
// UIKit's first-responder restoration has already been blocked
|
||||
// by isFocusBlocked during the transition. Safe to unblock now
|
||||
// for future user taps.
|
||||
composerView?.isFocusBlocked = false
|
||||
}
|
||||
|
||||
override func viewDidLayoutSubviews() {
|
||||
super.viewDidLayoutSubviews()
|
||||
@@ -849,8 +872,10 @@ final class NativeMessageListController: UIViewController {
|
||||
let delta = newInsetTop - oldInsetTop
|
||||
|
||||
// Capture offset BEFORE animation — UIKit may auto-clamp after inset change.
|
||||
// Skip compensation during swipe-back — let content slide down naturally.
|
||||
let oldOffset = collectionView.contentOffset.y
|
||||
let shouldCompensate = abs(delta) > 0.5
|
||||
let shouldCompensate = !isDisappearing
|
||||
&& abs(delta) > 0.5
|
||||
&& !collectionView.isDragging
|
||||
&& !collectionView.isDecelerating
|
||||
|
||||
@@ -1204,6 +1229,18 @@ struct NativeMessageListView: UIViewControllerRepresentable {
|
||||
}
|
||||
#endif
|
||||
composer.setReply(senderName: replySenderName, previewText: replyPreviewText)
|
||||
|
||||
// After swipe-back dismisses keyboard, block programmatic re-focus
|
||||
// until user taps text field OR SwiftUI sets isInputFocused=true (reply).
|
||||
if controller.keyboardBlockedUntilUserTap {
|
||||
if isInputFocused {
|
||||
controller.keyboardBlockedUntilUserTap = false
|
||||
// Fall through to setFocused below
|
||||
} else {
|
||||
return // Don't touch focus while blocked
|
||||
}
|
||||
}
|
||||
|
||||
composer.setFocused(isInputFocused)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user