[WIP] Quotes

This commit is contained in:
Ali
2023-10-07 00:33:12 +04:00
parent 3cada5996b
commit eae866c77e
77 changed files with 2103 additions and 552 deletions

View File

@@ -23,6 +23,7 @@ import LottieAnimationComponent
import AnimationCache
import MultiAnimationRenderer
import TextNodeWithEntities
import ChatInputTextNode
private let counterFont = Font.with(size: 14.0, design: .regular, traits: [.monospacedNumbers])
private let minInputFontSize: CGFloat = 5.0
@@ -112,7 +113,7 @@ private func textInputBackgroundImage(backgroundColor: UIColor?, inputBackground
}
}
private class CaptionEditableTextNode: EditableTextNode {
private class CaptionEditableTextNode: ChatInputTextNode {
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
let previousAlpha = self.alpha
self.alpha = 1.0
@@ -190,7 +191,7 @@ final class CustomEmojiContainerView: UIView {
}
}
public class AttachmentTextInputPanelNode: ASDisplayNode, TGCaptionPanelView, ASEditableTextNodeDelegate {
public class AttachmentTextInputPanelNode: ASDisplayNode, TGCaptionPanelView, ASEditableTextNodeDelegate, ChatInputTextNodeDelegate {
private let context: AccountContext
private let isCaption: Bool
@@ -202,7 +203,7 @@ public class AttachmentTextInputPanelNode: ASDisplayNode, TGCaptionPanelView, AS
private var textPlaceholderNode: ImmediateTextNode
private let textInputContainerBackgroundNode: ASImageNode
private let textInputContainer: ASDisplayNode
public var textInputNode: EditableTextNode?
public var textInputNode: ChatInputTextNode?
private var dustNode: InvisibleInkDustNode?
private var customEmojiContainerView: CustomEmojiContainerView?
private var oneLineNode: TextNodeWithEntities
@@ -249,7 +250,7 @@ public class AttachmentTextInputPanelNode: ASDisplayNode, TGCaptionPanelView, AS
var storedInputLanguage: String?
var effectiveInputLanguage: String? {
if let textInputNode = textInputNode, textInputNode.isFirstResponder() {
return textInputNode.textInputMode.primaryLanguage
return textInputNode.textInputMode?.primaryLanguage
} else {
return self.storedInputLanguage
}
@@ -308,7 +309,7 @@ public class AttachmentTextInputPanelNode: ASDisplayNode, TGCaptionPanelView, AS
baseFontSize = max(minInputFontSize, presentationInterfaceState.fontSize.baseDisplaySize)
}
textInputNode.attributedText = NSAttributedString(string: value, font: Font.regular(baseFontSize), textColor: textColor)
self.editableTextNodeDidUpdateText(textInputNode)
self.chatInputTextNodeDidUpdateText()
}
}
}
@@ -516,7 +517,7 @@ public class AttachmentTextInputPanelNode: ASDisplayNode, TGCaptionPanelView, AS
paragraphStyle.maximumLineHeight = 20.0
paragraphStyle.minimumLineHeight = 20.0
textInputNode.typingAttributes = [NSAttributedString.Key.font.rawValue: Font.regular(max(minInputFontSize, baseFontSize)), NSAttributedString.Key.foregroundColor.rawValue: textColor, NSAttributedString.Key.paragraphStyle.rawValue: paragraphStyle]
textInputNode.textView.typingAttributes = [NSAttributedString.Key.font: Font.regular(max(minInputFontSize, baseFontSize)), NSAttributedString.Key.foregroundColor: textColor, NSAttributedString.Key.paragraphStyle: paragraphStyle]
textInputNode.clipsToBounds = false
textInputNode.textView.clipsToBounds = false
textInputNode.delegate = self
@@ -532,7 +533,7 @@ public class AttachmentTextInputPanelNode: ASDisplayNode, TGCaptionPanelView, AS
textInputNode.textView.inputAssistantItem.trailingBarButtonGroups = []
if let presentationInterfaceState = self.presentationInterfaceState {
refreshChatTextInputTypingAttributes(textInputNode, theme: presentationInterfaceState.theme, baseFontSize: baseFontSize)
refreshChatTextInputTypingAttributes(textInputNode.textView, theme: presentationInterfaceState.theme, baseFontSize: baseFontSize)
textInputNode.textContainerInset = calculateTextFieldRealInsets(presentationInterfaceState)
}
@@ -541,6 +542,7 @@ public class AttachmentTextInputPanelNode: ASDisplayNode, TGCaptionPanelView, AS
textInputNode.frame = CGRect(origin: CGPoint(x: self.textInputViewInternalInsets.left, y: self.textInputViewInternalInsets.top), size: CGSize(width: textInputFrame.size.width - (self.textInputViewInternalInsets.left + self.textInputViewInternalInsets.right), height: textInputFrame.size.height - self.textInputViewInternalInsets.top - self.textInputViewInternalInsets.bottom))
textInputNode.view.layoutIfNeeded()
textInputNode.textView.updateLayout(size: textInputNode.bounds.size)
self.updateSpoiler()
}
@@ -587,8 +589,8 @@ public class AttachmentTextInputPanelNode: ASDisplayNode, TGCaptionPanelView, AS
let textFieldHeight: CGFloat
if let textInputNode = self.textInputNode {
let maxTextWidth = width - textFieldInsets.left - textFieldInsets.right - self.textInputViewInternalInsets.left - self.textInputViewInternalInsets.right
let measuredHeight = textInputNode.measure(CGSize(width: maxTextWidth, height: CGFloat.greatestFiniteMagnitude))
let unboundTextFieldHeight = max(textFieldMinHeight, ceil(measuredHeight.height))
let measuredHeight = textInputNode.textHeightForWidth(maxTextWidth)
let unboundTextFieldHeight = max(textFieldMinHeight, ceil(measuredHeight))
let maxNumberOfLines = min(12, (Int(fieldMaxHeight - 11.0) - 33) / 22)
@@ -674,7 +676,7 @@ public class AttachmentTextInputPanelNode: ASDisplayNode, TGCaptionPanelView, AS
textInputNode.attributedText = updatedText
textInputNode.selectedRange = selectedRange
}
textInputNode.typingAttributes = [NSAttributedString.Key.font.rawValue: Font.regular(baseFontSize), NSAttributedString.Key.foregroundColor.rawValue: textColor]
textInputNode.textView.typingAttributes = [NSAttributedString.Key.font: Font.regular(baseFontSize), NSAttributedString.Key.foregroundColor: textColor]
self.updateSpoiler()
}
@@ -960,11 +962,11 @@ public class AttachmentTextInputPanelNode: ASDisplayNode, TGCaptionPanelView, AS
}
private var skipUpdate = false
@objc public func editableTextNodeDidUpdateText(_ editableTextNode: ASEditableTextNode) {
public func chatInputTextNodeDidUpdateText() {
if let textInputNode = self.textInputNode, let presentationInterfaceState = self.presentationInterfaceState {
let baseFontSize = max(minInputFontSize, presentationInterfaceState.fontSize.baseDisplaySize)
refreshChatTextInputAttributes(textInputNode, theme: presentationInterfaceState.theme, baseFontSize: baseFontSize, spoilersRevealed: self.spoilersRevealed, availableEmojis: Set(self.context.animatedEmojiStickers.keys), emojiViewProvider: self.emojiViewProvider)
refreshChatTextInputTypingAttributes(textInputNode, theme: presentationInterfaceState.theme, baseFontSize: baseFontSize)
refreshChatTextInputAttributes(textInputNode.textView, theme: presentationInterfaceState.theme, baseFontSize: baseFontSize, spoilersRevealed: self.spoilersRevealed, availableEmojis: Set(self.context.animatedEmojiStickers.keys), emojiViewProvider: self.emojiViewProvider)
refreshChatTextInputTypingAttributes(textInputNode.textView, theme: presentationInterfaceState.theme, baseFontSize: baseFontSize)
self.updateSpoiler()
@@ -973,7 +975,7 @@ public class AttachmentTextInputPanelNode: ASDisplayNode, TGCaptionPanelView, AS
self.skipUpdate = true
self.interfaceInteraction?.updateTextInputStateAndMode({ _, inputMode in return (inputTextState, inputMode) })
self.interfaceInteraction?.updateInputLanguage({ _ in return textInputNode.textInputMode.primaryLanguage })
self.interfaceInteraction?.updateInputLanguage({ _ in return textInputNode.textInputMode?.primaryLanguage })
if self.isCaption, let presentationInterfaceState = self.presentationInterfaceState {
self.presentationInterfaceState = presentationInterfaceState.updatedInterfaceState({
return $0.withUpdatedComposeInputState(inputTextState)
@@ -988,6 +990,10 @@ public class AttachmentTextInputPanelNode: ASDisplayNode, TGCaptionPanelView, AS
}
}
@objc public func editableTextNodeDidUpdateText(_ editableTextNode: ASEditableTextNode) {
self.chatInputTextNodeDidUpdateText()
}
private func updateSpoiler() {
guard let textInputNode = self.textInputNode, let presentationInterfaceState = self.presentationInterfaceState else {
return
@@ -1131,7 +1137,7 @@ public class AttachmentTextInputPanelNode: ASDisplayNode, TGCaptionPanelView, AS
textInputNode.textView.isScrollEnabled = false
refreshChatTextInputAttributes(textInputNode, theme: presentationInterfaceState.theme, baseFontSize: baseFontSize, spoilersRevealed: self.spoilersRevealed, availableEmojis: Set(self.context.animatedEmojiStickers.keys), emojiViewProvider: self.emojiViewProvider)
refreshChatTextInputAttributes(textInputNode.textView, theme: presentationInterfaceState.theme, baseFontSize: baseFontSize, spoilersRevealed: self.spoilersRevealed, availableEmojis: Set(self.context.animatedEmojiStickers.keys), emojiViewProvider: self.emojiViewProvider)
textInputNode.attributedText = textAttributedStringForStateText(self.inputTextState.inputText, fontSize: baseFontSize, textColor: textColor, accentTextColor: accentTextColor, writingDirection: nil, spoilersRevealed: self.spoilersRevealed, availableEmojis: Set(self.context.animatedEmojiStickers.keys), emojiViewProvider: self.emojiViewProvider)
@@ -1345,13 +1351,17 @@ public class AttachmentTextInputPanelNode: ASDisplayNode, TGCaptionPanelView, AS
}
}
@objc public func editableTextNodeShouldReturn(_ editableTextNode: ASEditableTextNode) -> Bool {
public func chatInputTextNodeShouldReturn() -> Bool {
if self.actionButtons.sendButton.supernode != nil && !self.actionButtons.sendButton.isHidden && !self.actionButtons.sendButton.alpha.isZero {
self.sendButtonPressed()
}
return false
}
@objc public func editableTextNodeShouldReturn(_ editableTextNode: ASEditableTextNode) -> Bool {
return self.chatInputTextNodeShouldReturn()
}
private func applyUpdateSendButtonIcon() {
if let interfaceState = self.presentationInterfaceState {
let sendButtonHasApplyIcon = interfaceState.interfaceState.editMessage != nil
@@ -1371,7 +1381,7 @@ public class AttachmentTextInputPanelNode: ASDisplayNode, TGCaptionPanelView, AS
}
}
@objc public func editableTextNodeDidChangeSelection(_ editableTextNode: ASEditableTextNode, fromSelectedRange: NSRange, toSelectedRange: NSRange, dueToEditing: Bool) {
public func chatInputTextNodeDidChangeSelection(dueToEditing: Bool) {
if !dueToEditing && !self.updatingInputState {
let inputTextState = self.inputTextState
self.skipUpdate = true
@@ -1385,13 +1395,17 @@ public class AttachmentTextInputPanelNode: ASDisplayNode, TGCaptionPanelView, AS
}
let baseFontSize = max(minInputFontSize, presentationInterfaceState.fontSize.baseDisplaySize)
refreshChatTextInputTypingAttributes(textInputNode, theme: presentationInterfaceState.theme, baseFontSize: baseFontSize)
refreshChatTextInputTypingAttributes(textInputNode.textView, theme: presentationInterfaceState.theme, baseFontSize: baseFontSize)
self.updateSpoilersRevealed()
}
}
@objc public func editableTextNodeDidBeginEditing(_ editableTextNode: ASEditableTextNode) {
@objc public func editableTextNodeDidChangeSelection(_ editableTextNode: ASEditableTextNode, fromSelectedRange: NSRange, toSelectedRange: NSRange, dueToEditing: Bool) {
self.chatInputTextNodeDidChangeSelection(dueToEditing: dueToEditing)
}
public func chatInputTextNodeDidBeginEditing() {
self.interfaceInteraction?.updateInputModeAndDismissedButtonKeyboardMessageId({ state in
return (.text, state.keyboardButtonsMessage?.id)
})
@@ -1404,8 +1418,15 @@ public class AttachmentTextInputPanelNode: ASDisplayNode, TGCaptionPanelView, AS
}
}
public func editableTextNodeDidFinishEditing(_ editableTextNode: ASEditableTextNode) {
self.storedInputLanguage = editableTextNode.textInputMode.primaryLanguage
@objc public func editableTextNodeDidBeginEditing(_ editableTextNode: ASEditableTextNode) {
self.chatInputTextNodeDidBeginEditing()
}
public func chatInputTextNodeDidFinishEditing() {
guard let editableTextNode = self.textInputNode else {
return
}
self.storedInputLanguage = editableTextNode.textInputMode?.primaryLanguage
self.inputMenu.deactivate()
self.focusUpdated?(false)
@@ -1415,6 +1436,10 @@ public class AttachmentTextInputPanelNode: ASDisplayNode, TGCaptionPanelView, AS
}
}
public func editableTextNodeDidFinishEditing(_ editableTextNode: ASEditableTextNode) {
self.chatInputTextNodeDidFinishEditing()
}
public func editableTextNodeTarget(forAction action: Selector) -> ASEditableTextNodeTargetForAction? {
if action == makeSelectorFromString("_accessibilitySpeak:") {
if case .format = self.inputMenu.state {
@@ -1461,8 +1486,12 @@ public class AttachmentTextInputPanelNode: ASDisplayNode, TGCaptionPanelView, AS
return nil
}
@available(iOS 16.0, *)
public func editableTextNodeMenu(_ editableTextNode: ASEditableTextNode, forTextRange textRange: NSRange, suggestedActions: [UIMenuElement]) -> UIMenu {
@available(iOS 13.0, *)
public func chatInputTextNodeMenu(forTextRange textRange: NSRange, suggestedActions: [UIMenuElement]) -> UIMenu {
guard let editableTextNode = self.textInputNode else {
return UIMenu(children: suggestedActions)
}
var actions = suggestedActions
if editableTextNode.attributedText == nil || editableTextNode.attributedText!.length == 0 || editableTextNode.selectedRange.length == 0 {
@@ -1520,6 +1549,11 @@ public class AttachmentTextInputPanelNode: ASDisplayNode, TGCaptionPanelView, AS
return UIMenu(children: actions)
}
@available(iOS 16.0, *)
public func editableTextNodeMenu(_ editableTextNode: ASEditableTextNode, forTextRange textRange: NSRange, suggestedActions: [UIMenuElement]) -> UIMenu {
return self.chatInputTextNodeMenu(forTextRange: textRange, suggestedActions: suggestedActions)
}
private var currentSpeechHolder: SpeechSynthesizerHolder?
@objc func _accessibilitySpeak(_ sender: Any) {
var text = ""
@@ -1612,7 +1646,11 @@ public class AttachmentTextInputPanelNode: ASDisplayNode, TGCaptionPanelView, AS
self.updateSpoilersRevealed(animated: animated)
}
@objc public func editableTextNode(_ editableTextNode: ASEditableTextNode, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
public func chatInputTextNode(shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
guard let editableTextNode = self.textInputNode else {
return true
}
var cleanText = text
let removeSequences: [String] = ["\u{202d}", "\u{202c}"]
for sequence in removeSequences {
@@ -1645,7 +1683,11 @@ public class AttachmentTextInputPanelNode: ASDisplayNode, TGCaptionPanelView, AS
return true
}
@objc public func editableTextNodeShouldCopy(_ editableTextNode: ASEditableTextNode) -> Bool {
@objc public func editableTextNode(_ editableTextNode: ASEditableTextNode, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
return self.chatInputTextNode(shouldChangeTextIn: range, replacementText: text)
}
public func chatInputTextNodeShouldCopy() -> Bool {
self.interfaceInteraction?.updateTextInputStateAndMode { current, inputMode in
storeInputTextInPasteboard(current.inputText.attributedSubstring(from: NSMakeRange(current.selectionRange.lowerBound, current.selectionRange.count)))
return (current, inputMode)
@@ -1653,7 +1695,11 @@ public class AttachmentTextInputPanelNode: ASDisplayNode, TGCaptionPanelView, AS
return false
}
@objc public func editableTextNodeShouldPaste(_ editableTextNode: ASEditableTextNode) -> Bool {
@objc public func editableTextNodeShouldCopy(_ editableTextNode: ASEditableTextNode) -> Bool {
return self.chatInputTextNodeShouldCopy()
}
public func chatInputTextNodeShouldPaste() -> Bool {
let pasteboard = UIPasteboard.general
var attributedString: NSAttributedString?
@@ -1678,6 +1724,13 @@ public class AttachmentTextInputPanelNode: ASDisplayNode, TGCaptionPanelView, AS
return true
}
@objc public func editableTextNodeShouldPaste(_ editableTextNode: ASEditableTextNode) -> Bool {
return self.chatInputTextNodeShouldPaste()
}
public func chatInputTextNodeBackspaceWhileEmpty() {
}
@objc func sendButtonPressed() {
let inputTextMaxLength: Int32?
if let maxCaptionLength = self.maxCaptionLength {