Various improvements

This commit is contained in:
Ali 2023-10-23 17:41:52 +04:00
parent b43fa0ecb5
commit 75ee418716
14 changed files with 228 additions and 40 deletions

View File

@ -147,11 +147,12 @@ public final class DrawingTextEntityView: DrawingEntityView, UITextViewDelegate
return true
}
private var emojiRects: [(CGRect, ChatTextInputTextCustomEmojiAttribute)] = []
private var emojiRects: [(CGRect, ChatTextInputTextCustomEmojiAttribute, CGFloat)] = []
func updateEntities() {
self.textView.drawingLayoutManager.ensureLayout(for: self.textView.textContainer)
var customEmojiRects: [(CGRect, ChatTextInputTextCustomEmojiAttribute)] = []
var customEmojiRects: [(CGRect, ChatTextInputTextCustomEmojiAttribute, CGFloat)] = []
let fontSize = self.displayFontSize * 0.78
var shouldRepeat = false
if let attributedText = self.textView.attributedText {
@ -160,7 +161,11 @@ public final class DrawingTextEntityView: DrawingEntityView, UITextViewDelegate
if let value = attributes[ChatTextInputAttributes.customEmoji] as? ChatTextInputTextCustomEmojiAttribute {
if let start = self.textView.position(from: beginning, offset: range.location), let end = self.textView.position(from: start, offset: range.length), let textRange = self.textView.textRange(from: start, to: end) {
let rect = self.textView.firstRect(for: textRange)
customEmojiRects.append((rect, value))
var emojiFontSize = fontSize
if let font = attributes[.font] as? UIFont {
emojiFontSize = font.pointSize
}
customEmojiRects.append((rect, value, emojiFontSize))
if rect.origin.x.isInfinite {
shouldRepeat = true
}
@ -202,7 +207,7 @@ public final class DrawingTextEntityView: DrawingEntityView, UITextViewDelegate
self.customEmojiContainerView = customEmojiContainerView
}
customEmojiContainerView.update(fontSize: self.displayFontSize * 0.78, textColor: textColor, emojiRects: customEmojiRects)
customEmojiContainerView.update(fontSize: fontSize, textColor: textColor, emojiRects: customEmojiRects)
} else if let customEmojiContainerView = self.customEmojiContainerView {
customEmojiContainerView.removeFromSuperview()
self.customEmojiContainerView = nil
@ -739,13 +744,12 @@ public final class DrawingTextEntityView: DrawingEntityView, UITextViewDelegate
let scale = self.textEntity.scale
let rotation = self.textEntity.rotation
let itemSize: CGFloat = floor(24.0 * self.displayFontSize * 0.78 / 17.0)
var entities: [DrawingEntity] = []
for (emojiRect, emojiAttribute) in self.emojiRects {
for (emojiRect, emojiAttribute, fontSize) in self.emojiRects {
guard let file = emojiAttribute.file else {
continue
}
let itemSize: CGFloat = floor(24.0 * fontSize * 0.78 / 17.0)
let emojiTextPosition = emojiRect.center.offsetBy(dx: -textSize.width / 2.0, dy: -textSize.height / 2.0)
let entity = DrawingStickerEntity(content: .file(file, .sticker))

View File

@ -1802,7 +1802,7 @@ public final class ChatMessageInteractiveFileNode: ASDisplayNode {
}
item.controllerInteraction.performTextSelectionAction(item.message, true, text, action)
})
textSelectionNode.enableQuote = true
textSelectionNode.enableQuote = false
self.textSelectionNode = textSelectionNode
self.textClippingNode.addSubnode(textSelectionNode)
self.textClippingNode.insertSubnode(textSelectionNode.highlightAreaNode, belowSubnode: self.textNode)

View File

@ -616,8 +616,8 @@ public class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode {
if case let .reply(info) = info {
if strongSelf.textSelectionNode == nil {
strongSelf.updateIsExtractedToContextPreview(true)
if let initialQuote = info.quote, item.message.id == initialQuote.messageId, let string = strongSelf.textNode.textNode.cachedLayout?.attributedString {
let nsString = string.string as NSString
if let initialQuote = info.quote, item.message.id == initialQuote.messageId {
let nsString = item.message.text as NSString
let subRange = nsString.range(of: initialQuote.text)
if subRange.location != NSNotFound {
strongSelf.beginTextSelection(range: subRange, displayMenu: true)
@ -1119,6 +1119,9 @@ public class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode {
if !item.controllerInteraction.canSendMessages() && !enableCopy {
enableQuote = false
}
if item.message.id.peerId.namespace == Namespaces.Peer.SecretChat {
enableQuote = false
}
textSelectionNode.enableQuote = enableQuote
textSelectionNode.enableTranslate = enableOtherActions

View File

@ -136,6 +136,13 @@ public final class ChatMessageWebpageBubbleContentNode: ChatMessageBubbleContent
guard let self, let item = self.item, let webPage = self.webPage, case let .Loaded(content) = webPage.content else {
return ChatMessageBubbleContentTapAction(content: .none)
}
if let file = content.file {
if !file.isVideo, !file.isVideoSticker, !file.isAnimated, !file.isAnimatedSticker, !file.isSticker, !file.isMusic {
return ChatMessageBubbleContentTapAction(content: .openMessage)
}
}
var isConcealed = true
if item.message.text.contains(content.url) {
isConcealed = false

View File

@ -75,7 +75,6 @@ public final class ReplyAccessoryPanelNode: AccessoryPanelNode {
self.iconView.tintColor = theme.chat.inputPanel.panelControlAccentColor
self.titleNode = CompositeTextNode()
self.titleNode.imageTintColor = theme.chat.inputPanel.panelControlAccentColor
self.textNode = ImmediateTextNodeWithEntities()
self.textNode.maximumNumberOfLines = 1
@ -243,29 +242,30 @@ public final class ReplyAccessoryPanelNode: AccessoryPanelNode {
let icon: UIImage?
icon = UIImage(bundleImageName: "Chat/Input/Accessory Panels/PanelTextChannelIcon")?.withRenderingMode(.alwaysTemplate)
//TODO:localize
if let _ = strongSelf.quote {
if let icon {
let string = "Reply to Quote by "
titleText = [.text(NSAttributedString(string: string, font: Font.medium(15.0), textColor: .white))]
titleText = [.text(NSAttributedString(string: string, font: Font.medium(15.0), textColor: strongSelf.theme.chat.inputPanel.panelControlAccentColor))]
titleText.append(.icon(icon))
titleText.append(.text(NSAttributedString(string: peer.debugDisplayTitle, font: Font.medium(15.0), textColor: .white)))
titleText.append(.text(NSAttributedString(string: peer.debugDisplayTitle, font: Font.medium(15.0), textColor: strongSelf.theme.chat.inputPanel.panelControlAccentColor)))
}
} else {
if let icon {
let string = "Reply to "
titleText = [.text(NSAttributedString(string: string, font: Font.medium(15.0), textColor: .white))]
titleText = [.text(NSAttributedString(string: string, font: Font.medium(15.0), textColor: strongSelf.theme.chat.inputPanel.panelControlAccentColor))]
titleText.append(.icon(icon))
titleText.append(.text(NSAttributedString(string: peer.debugDisplayTitle, font: Font.medium(15.0), textColor: .white)))
titleText.append(.text(NSAttributedString(string: peer.debugDisplayTitle, font: Font.medium(15.0), textColor: strongSelf.theme.chat.inputPanel.panelControlAccentColor)))
}
}
} else {
if let _ = strongSelf.quote {
//TODO:localize
let string = "Reply to Quote by \(authorName)"
titleText = [.text(NSAttributedString(string: string, font: Font.medium(15.0), textColor: .white))]
titleText = [.text(NSAttributedString(string: string, font: Font.medium(15.0), textColor: strongSelf.theme.chat.inputPanel.panelControlAccentColor))]
} else {
let string = strongSelf.strings.Conversation_ReplyMessagePanelTitle(authorName).string
titleText = [.text(NSAttributedString(string: string, font: Font.medium(15.0), textColor: .white))]
titleText = [.text(NSAttributedString(string: string, font: Font.medium(15.0), textColor: strongSelf.theme.chat.inputPanel.panelControlAccentColor))]
}
if strongSelf.messageId.peerId != strongSelf.chatPeerId {
@ -276,9 +276,9 @@ public final class ReplyAccessoryPanelNode: AccessoryPanelNode {
} else {
icon = UIImage(bundleImageName: "Chat/Input/Accessory Panels/PanelTextGroupIcon")?.withRenderingMode(.alwaysTemplate)
}
if let icon {
titleText.append(.icon(icon))
titleText.append(.text(NSAttributedString(string: peer.debugDisplayTitle, font: Font.medium(15.0), textColor: .white)))
if let iconImage = generateTintedImage(image: icon, color: strongSelf.theme.chat.inputPanel.panelControlAccentColor) {
titleText.append(.icon(iconImage))
titleText.append(.text(NSAttributedString(string: peer.debugDisplayTitle, font: Font.medium(15.0), textColor: theme.chat.inputPanel.panelControlAccentColor)))
}
}
}
@ -387,10 +387,25 @@ public final class ReplyAccessoryPanelNode: AccessoryPanelNode {
self.lineNode.image = PresentationResourcesChat.chatInputPanelVerticalSeparatorLineImage(theme)
self.iconView.tintColor = theme.chat.inputPanel.panelControlAccentColor
self.titleNode.imageTintColor = theme.chat.inputPanel.panelControlAccentColor
self.titleNode.components = self.titleNode.components.map { item in
switch item {
case let .text(text):
let updatedText = NSMutableAttributedString(attributedString: text)
updatedText.addAttribute(.foregroundColor, value: theme.chat.inputPanel.panelControlAccentColor, range: NSRange(location: 0, length: updatedText.length))
return .text(updatedText)
case let .icon(icon):
if let iconImage = generateTintedImage(image: icon, color: theme.chat.inputPanel.panelControlAccentColor) {
return .icon(iconImage)
} else {
return .icon(icon)
}
}
}
if let text = self.textNode.attributedText?.string {
self.textNode.attributedText = NSAttributedString(string: text, font: Font.regular(15.0), textColor: self.textIsOptions ? self.theme.chat.inputPanel.secondaryTextColor : self.theme.chat.inputPanel.primaryTextColor)
if let text = self.textNode.attributedText {
let updatedText = NSMutableAttributedString(attributedString: text)
updatedText.addAttribute(.foregroundColor, value: self.textIsOptions ? self.theme.chat.inputPanel.secondaryTextColor : self.theme.chat.inputPanel.primaryTextColor, range: NSRange(location: 0, length: updatedText.length))
self.textNode.attributedText = updatedText
}
self.textNode.spoilerColor = self.theme.chat.inputPanel.secondaryTextColor

View File

@ -606,11 +606,11 @@ public final class CustomEmojiContainerView: UIView {
preconditionFailure()
}
public func update(fontSize: CGFloat, textColor: UIColor, emojiRects: [(CGRect, ChatTextInputTextCustomEmojiAttribute)]) {
public func update(fontSize: CGFloat, textColor: UIColor, emojiRects: [(CGRect, ChatTextInputTextCustomEmojiAttribute, CGFloat)]) {
var nextIndexById: [Int64: Int] = [:]
var validKeys = Set<InlineStickerItemLayer.Key>()
for (rect, emoji) in emojiRects {
for (rect, emoji, fontSize) in emojiRects {
let index: Int
if let nextIndex = nextIndexById[emoji.fileId] {
index = nextIndex

View File

@ -663,7 +663,7 @@ public final class TextFieldComponent: Component {
}
var spoilerRects: [CGRect] = []
var customEmojiRects: [(CGRect, ChatTextInputTextCustomEmojiAttribute)] = []
var customEmojiRects: [(CGRect, ChatTextInputTextCustomEmojiAttribute, CGFloat)] = []
let textView = self.textView
if let attributedText = textView.attributedText {
@ -707,9 +707,13 @@ public final class TextFieldComponent: Component {
if let value = attributes[ChatTextInputAttributes.customEmoji] as? ChatTextInputTextCustomEmojiAttribute {
if let start = textView.position(from: beginning, offset: range.location), let end = textView.position(from: start, offset: range.length), let textRange = textView.textRange(from: start, to: end) {
var emojiFontSize = component.fontSize
if let font = attributes[.font] as? UIFont {
emojiFontSize = font.pointSize
}
let textRects = textView.selectionRects(for: textRange)
for textRect in textRects {
customEmojiRects.append((textRect.rect, value))
customEmojiRects.append((textRect.rect, value, emojiFontSize))
break
}
}

View File

@ -132,6 +132,7 @@ public final class TextNodeWithEntities {
let string = NSMutableAttributedString(attributedString: sourceString)
var fullRange = NSRange(location: 0, length: string.length)
var originalTextId = 0
while true {
var found = false
string.enumerateAttribute(ChatTextInputAttributes.customEmoji, in: fullRange, options: [], using: { value, range, stop in
@ -141,7 +142,8 @@ public final class TextNodeWithEntities {
let replacementRange = NSRange(location: 0, length: updatedSubstring.length)
updatedSubstring.addAttributes(string.attributes(at: range.location, effectiveRange: nil), range: replacementRange)
updatedSubstring.addAttribute(NSAttributedString.Key("Attribute__EmbeddedItem"), value: InlineStickerItem(emoji: value, file: value.file, fontSize: font.pointSize), range: replacementRange)
updatedSubstring.addAttribute(originalTextAttributeKey, value: string.attributedSubstring(from: range).string, range: replacementRange)
updatedSubstring.addAttribute(originalTextAttributeKey, value: OriginalTextAttribute(id: originalTextId, string: string.attributedSubstring(from: range).string), range: replacementRange)
originalTextId += 1
let itemSize = (font.pointSize * 24.0 / 17.0)

View File

@ -404,6 +404,7 @@ private func generateChatReplyOptionItems(selfController: ChatControllerImpl, ch
}
if selfController.presentationInterfaceState.copyProtectionEnabled || messages.first?.isCopyProtected() == true {
} else if messages.first?.id.peerId.namespace == Namespaces.Peer.SecretChat {
} else {
//TODO:localize
items.append(.action(ContextMenuActionItem(text: "Reply in Another Chat", icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Replace"), color: theme.contextMenu.primaryColor) }, action: { [weak selfController] c, f in
@ -746,7 +747,17 @@ private func chatLinkOptions(selfController: ChatControllerImpl, sourceNode: ASD
if case let .Loaded(content) = linkOptions.webpage.content, let isMediaLargeByDefault = content.isMediaLargeByDefault, isMediaLargeByDefault {
//TODO:localize
items.append(.action(ContextMenuActionItem(text: linkOptions.largeMedia ? "Shrink Photo" : "Enlarge Photo", icon: { theme in
let shrinkTitle: String
let enlargeTitle: String
if let file = content.file, file.isVideo {
shrinkTitle = "Shrink Video"
enlargeTitle = "Enlarge Video"
} else {
shrinkTitle = "Shrink Photo"
enlargeTitle = "Enlarge Photo"
}
items.append(.action(ContextMenuActionItem(text: linkOptions.largeMedia ? shrinkTitle : enlargeTitle, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: !linkOptions.largeMedia ? "Chat/Context Menu/ImageEnlarge" : "Chat/Context Menu/ImageShrink"), color: theme.contextMenu.primaryColor)
}, action: { [weak selfController] _, f in
selfController?.updateChatPresentationInterfaceState(animated: true, interactive: true, { state in

View File

@ -3819,7 +3819,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
}
}
}
if let messageId = message?.id, let message = strongSelf.chatDisplayNode.historyNode.messageInCurrentHistoryView(messageId) {
if let messageId = message?.id, let message = strongSelf.chatDisplayNode.historyNode.messageInCurrentHistoryView(messageId) ?? message {
var quoteData: EngineMessageReplyQuote?
let nsRange = NSRange(location: range.lowerBound, length: range.upperBound - range.lowerBound)
@ -10765,9 +10765,16 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
let inputText = NSMutableAttributedString(attributedString: textInputState.inputText)
let range = textInputState.selectionRange
inputText.replaceCharacters(in: NSMakeRange(range.lowerBound, range.count), with: text)
let selectionPosition = range.lowerBound + (text.string as NSString).length
let updatedText = NSMutableAttributedString(attributedString: text)
if range.lowerBound < inputText.length {
if let quote = inputText.attribute(ChatTextInputAttributes.quote, at: range.lowerBound, effectiveRange: nil) {
updatedText.addAttribute(ChatTextInputAttributes.quote, value: quote, range: NSRange(location: 0, length: updatedText.length))
}
}
inputText.replaceCharacters(in: NSMakeRange(range.lowerBound, range.count), with: updatedText)
let selectionPosition = range.lowerBound + (updatedText.string as NSString).length
return (ChatTextInputState(inputText: inputText, selectionRange: selectionPosition ..< selectionPosition), inputMode)
}

View File

@ -3382,7 +3382,25 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
if let replyMessageSubject = self.chatPresentationInterfaceState.interfaceState.replyMessageSubject, let quote = replyMessageSubject.quote {
if let replyMessage = self.chatPresentationInterfaceState.replyMessage {
if !replyMessage.text.contains(quote.text) {
let nsText = replyMessage.text as NSString
var startIndex = 0
var found = false
while true {
let range = nsText.range(of: quote.text, range: NSRange(location: startIndex, length: nsText.length - startIndex))
if range.location != NSNotFound {
let subEntities = messageTextEntitiesInRange(entities: replyMessage.textEntitiesAttribute?.entities ?? [], range: range, onlyQuoteable: true)
if subEntities == quote.entities {
found = true
break
}
startIndex = range.upperBound
} else {
break
}
}
if !found {
//TODO:localize
let authorName: String = (replyMessage.author.flatMap(EnginePeer.init))?.compactDisplayTitle ?? ""
let errorTextData = self.chatPresentationInterfaceState.strings.Chat_ErrorQuoteOutdatedText(authorName)

View File

@ -2572,7 +2572,7 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate, Ch
let textColor = presentationInterfaceState.theme.chat.inputPanel.inputTextColor
var rects: [CGRect] = []
var customEmojiRects: [(CGRect, ChatTextInputTextCustomEmojiAttribute)] = []
var customEmojiRects: [(CGRect, ChatTextInputTextCustomEmojiAttribute, CGFloat)] = []
let fontSize = max(minInputFontSize, presentationInterfaceState.fontSize.baseDisplaySize)
@ -2619,7 +2619,11 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate, Ch
if let start = textInputNode.textView.position(from: beginning, offset: range.location), let end = textInputNode.textView.position(from: start, offset: range.length), let textRange = textInputNode.textView.textRange(from: start, to: end) {
let textRects = textInputNode.textView.selectionRects(for: textRange)
for textRect in textRects {
customEmojiRects.append((textRect.rect, value))
var emojiFontSize = fontSize
if let font = attributes[.font] as? UIFont {
emojiFontSize = font.pointSize
}
customEmojiRects.append((textRect.rect, value, emojiFontSize))
break
}
}

View File

@ -26,6 +26,15 @@ public struct ChatTextInputAttributes {
}
public let originalTextAttributeKey = NSAttributedString.Key(rawValue: "Attribute__OriginalText")
public final class OriginalTextAttribute: NSObject {
public let id: Int
public let string: String
public init(id: Int, string: String) {
self.id = id
self.string = string
}
}
public func stateAttributedStringForText(_ text: NSAttributedString) -> NSAttributedString {
let sourceString = NSMutableAttributedString(attributedString: text)

View File

@ -446,6 +446,11 @@ public final class TextSelectionNode: ASDisplayNode {
}
public func setSelection(range: NSRange, displayMenu: Bool) {
guard let cachedLayout = self.textNode.cachedLayout, let attributedString = cachedLayout.attributedString else {
return
}
let range = self.convertSelectionFromOriginalText(attributedString: attributedString, range: range)
self.currentRange = (range.lowerBound, range.upperBound)
self.updateSelection(range: range, animateIn: true)
self.updateIsActive(true)
@ -455,12 +460,109 @@ public final class TextSelectionNode: ASDisplayNode {
}
}
private func convertSelectionToOriginalText(attributedString: NSAttributedString, range: NSRange) -> NSRange {
var adjustedRange = range
do {
attributedString.enumerateAttribute(originalTextAttributeKey, in: NSRange(location: 0, length: range.lowerBound), options: [], using: { value, range, stop in
guard let value = value as? OriginalTextAttribute else {
return
}
let updatedSubstring = NSMutableAttributedString(string: value.string)
let difference = updatedSubstring.length - range.length
adjustedRange.location += difference
})
}
do {
attributedString.enumerateAttribute(originalTextAttributeKey, in: range, options: [], using: { value, range, stop in
guard let value = value as? OriginalTextAttribute else {
return
}
let updatedSubstring = NSMutableAttributedString(string: value.string)
let difference = updatedSubstring.length - range.length
adjustedRange.length += difference
})
}
return adjustedRange
}
private func convertSelectionFromOriginalText(attributedString: NSAttributedString, range: NSRange) -> NSRange {
var adjustedRange = range
final class PreviousText: NSObject {
let id: Int
let string: String
init(id: Int, string: String) {
self.id = id
self.string = string
}
}
var nextId = 0
let attributedString = NSMutableAttributedString(attributedString: attributedString)
var fullRange = NSRange(location: 0, length: attributedString.length)
while true {
var found = false
attributedString.enumerateAttribute(originalTextAttributeKey, in: fullRange, options: [], using: { value, range, stop in
if let value = value as? OriginalTextAttribute {
let updatedSubstring = NSMutableAttributedString(string: value.string)
let replacementRange = NSRange(location: 0, length: updatedSubstring.length)
updatedSubstring.addAttributes(attributedString.attributes(at: range.location, effectiveRange: nil), range: replacementRange)
updatedSubstring.addAttribute(NSAttributedString.Key(rawValue: "__previous_text"), value: PreviousText(id: nextId, string: attributedString.attributedSubstring(from: range).string), range: replacementRange)
nextId += 1
attributedString.replaceCharacters(in: range, with: updatedSubstring)
let updatedRange = NSRange(location: range.location, length: updatedSubstring.length)
found = true
stop.pointee = ObjCBool(true)
fullRange = NSRange(location: updatedRange.upperBound, length: fullRange.upperBound - range.upperBound)
}
})
if !found {
break
}
}
do {
attributedString.enumerateAttribute(NSAttributedString.Key(rawValue: "__previous_text"), in: NSRange(location: 0, length: range.lowerBound), options: [], using: { value, range, stop in
guard let value = value as? PreviousText else {
return
}
let updatedSubstring = NSMutableAttributedString(string: value.string)
let difference = updatedSubstring.length - range.length
adjustedRange.location += difference
})
}
do {
attributedString.enumerateAttribute(NSAttributedString.Key(rawValue: "__previous_text"), in: range, options: [], using: { value, range, stop in
guard let value = value as? PreviousText else {
return
}
let updatedSubstring = NSMutableAttributedString(string: value.string)
let difference = updatedSubstring.length - range.length
adjustedRange.length += difference
})
}
return adjustedRange
}
public func getSelection() -> NSRange? {
guard let currentRange = self.currentRange else {
guard let currentRange = self.currentRange, let cachedLayout = self.textNode.cachedLayout, let attributedString = cachedLayout.attributedString else {
return nil
}
let range = NSRange(location: min(currentRange.0, currentRange.1), length: max(currentRange.0, currentRange.1) - min(currentRange.0, currentRange.1))
return range
return self.convertSelectionToOriginalText(attributedString: attributedString, range: range)
}
private func updateSelection(range: NSRange?, animateIn: Bool) {
@ -578,8 +680,8 @@ public final class TextSelectionNode: ASDisplayNode {
while true {
var found = false
string.enumerateAttribute(originalTextAttributeKey, in: fullRange, options: [], using: { value, range, stop in
if let value = value as? String {
let updatedSubstring = NSMutableAttributedString(string: value)
if let value = value as? OriginalTextAttribute {
let updatedSubstring = NSMutableAttributedString(string: value.string)
let replacementRange = NSRange(location: 0, length: updatedSubstring.length)
updatedSubstring.addAttributes(string.attributes(at: range.location, effectiveRange: nil), range: replacementRange)
@ -597,6 +699,8 @@ public final class TextSelectionNode: ASDisplayNode {
}
}
let adjustedRange = self.convertSelectionToOriginalText(attributedString: attributedString, range: range)
var actions: [ContextMenuAction] = []
if self.enableCopy {
actions.append(ContextMenuAction(content: .text(title: self.strings.Conversation_ContextMenuCopy, accessibilityLabel: self.strings.Conversation_ContextMenuCopy), action: { [weak self] in
@ -606,7 +710,7 @@ public final class TextSelectionNode: ASDisplayNode {
}
if self.enableQuote {
actions.append(ContextMenuAction(content: .text(title: self.strings.Conversation_ContextMenuQuote, accessibilityLabel: self.strings.Conversation_ContextMenuQuote), action: { [weak self] in
self?.performAction(string, .quote(range: range.lowerBound ..< range.upperBound))
self?.performAction(string, .quote(range: adjustedRange.lowerBound ..< adjustedRange.upperBound))
self?.cancelSelection()
}))
} else if self.enableLookup {