diff --git a/submodules/AccountContext/Sources/ChatController.swift b/submodules/AccountContext/Sources/ChatController.swift index c84ba4fa76..d109585136 100644 --- a/submodules/AccountContext/Sources/ChatController.swift +++ b/submodules/AccountContext/Sources/ChatController.swift @@ -383,7 +383,7 @@ public enum ChatTextInputStateTextAttributeType: Codable, Equatable { case .spoiler: try container.encode(8 as Int32, forKey: "t") case .quote: - try container.encode(0 as Int32, forKey: "t") + try container.encode(9 as Int32, forKey: "t") } } } diff --git a/submodules/AsyncDisplayKit/Source/ASEditableTextNode.mm b/submodules/AsyncDisplayKit/Source/ASEditableTextNode.mm index 5ddf0da07a..ba05b9d895 100644 --- a/submodules/AsyncDisplayKit/Source/ASEditableTextNode.mm +++ b/submodules/AsyncDisplayKit/Source/ASEditableTextNode.mm @@ -244,11 +244,6 @@ [super scrollRectToVisible:rect animated:false]; } -- (CGRect)caretRectForPosition:(UITextPosition *)position { - CGRect rect = [super caretRectForPosition:position]; - return rect; -} - #endif - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer @@ -506,9 +501,6 @@ - (void)setTextContainerInset:(UIEdgeInsets)textContainerInset { AS::MutexLocker l(_textKitLock); - - textContainerInset.top += 12.0; - textContainerInset.bottom += 12.0; _textContainerInset = textContainerInset; _textKitComponents.textView.textContainerInset = textContainerInset; @@ -1070,68 +1062,8 @@ return [_wordKerner layoutManager:layoutManager boundingBoxForControlGlyphAtIndex:glyphIndex forTextContainer:textContainer proposedLineFragment:proposedRect glyphPosition:glyphPosition characterIndex:characterIndex]; } -- (CGFloat)layoutManager:(NSLayoutManager *)layoutManager paragraphSpacingBeforeGlyphAtIndex:(NSUInteger)glyphIndex withProposedLineFragmentRect:(CGRect)rect { - int characterIndex = (int)[layoutManager characterIndexForGlyphAtIndex:glyphIndex]; - if (characterIndex < 0 || characterIndex >= layoutManager.textStorage.length) { - return 0.0; - } - - NSDictionary *attributes = [layoutManager.textStorage attributesAtIndex:characterIndex effectiveRange:nil]; - NSObject *blockQuote = attributes[@"Attribute__Blockquote"]; - if (blockQuote == nil) { - return 0.0f; - } - - if (characterIndex != 0) { - NSDictionary *previousAttributes = [layoutManager.textStorage attributesAtIndex:characterIndex - 1 effectiveRange:nil]; - NSObject *previousBlockQuote = previousAttributes[@"Attribute__Blockquote"]; - if (previousBlockQuote != nil && [blockQuote isEqual:previousBlockQuote]) { - return 0.0f; - } - } - - return 12.0f; -} - -- (CGFloat)layoutManager:(NSLayoutManager *)layoutManager paragraphSpacingAfterGlyphAtIndex:(NSUInteger)glyphIndex withProposedLineFragmentRect:(CGRect)rect { - int characterIndex = (int)[layoutManager characterIndexForGlyphAtIndex:glyphIndex]; - characterIndex--; - if (characterIndex < 0) { - characterIndex = 0; - } - if (characterIndex < 0 || characterIndex >= layoutManager.textStorage.length) { - return 0.0; - } - - NSDictionary *attributes = [layoutManager.textStorage attributesAtIndex:characterIndex effectiveRange:nil]; - NSObject *blockQuote = attributes[@"Attribute__Blockquote"]; - if (blockQuote == nil) { - return 0.0f; - } - - if (characterIndex + 1 < layoutManager.textStorage.length) { - NSDictionary *nextAttributes = [layoutManager.textStorage attributesAtIndex:characterIndex + 1 effectiveRange:nil]; - NSObject *nextBlockQuote = nextAttributes[@"Attribute__Blockquote"]; - if (nextBlockQuote != nil && [blockQuote isEqual:nextBlockQuote]) { - return 0.0f; - } - } - - return 12.0f; -} - - (BOOL)layoutManager:(NSLayoutManager *)layoutManager shouldSetLineFragmentRect:(inout CGRect *)lineFragmentRect lineFragmentUsedRect:(inout CGRect *)lineFragmentUsedRect baselineOffset:(inout CGFloat *)baselineOffset inTextContainer:(NSTextContainer *)textContainer forGlyphRange:(NSRange)glyphRange { - /*if (layoutManager.textStorage.length != 0) { - NSDictionary *attributes = [layoutManager.textStorage attributesAtIndex:0 effectiveRange:nil]; - NSObject *blockQuote = attributes[@"Attribute__Blockquote"]; - if (blockQuote != nil) { - CGRect rect = *lineFragmentRect; - rect.origin.y += 12.0; - CGRect usedRect = *lineFragmentUsedRect; - usedRect.origin.y += 12.0; - } - }*/ - /*CGFloat fontLineHeight; + CGFloat fontLineHeight; UIFont *baseFont = _baseFont; if (_typingAttributes[NSFontAttributeName] != nil) { baseFont = _typingAttributes[NSFontAttributeName]; @@ -1154,7 +1086,7 @@ *lineFragmentRect = rect; *lineFragmentUsedRect = usedRect; - *baselineOffset = *baselineOffset + baselineNudge;*/ + *baselineOffset = *baselineOffset + baselineNudge; return true; } diff --git a/submodules/ChatPresentationInterfaceState/Sources/ChatTextFormat.swift b/submodules/ChatPresentationInterfaceState/Sources/ChatTextFormat.swift index 43fdbff026..68b3c7170a 100644 --- a/submodules/ChatPresentationInterfaceState/Sources/ChatTextFormat.swift +++ b/submodules/ChatPresentationInterfaceState/Sources/ChatTextFormat.swift @@ -8,33 +8,89 @@ public func chatTextInputAddFormattingAttribute(_ state: ChatTextInputState, att let nsRange = NSRange(location: state.selectionRange.lowerBound, length: state.selectionRange.count) var addAttribute = true var attributesToRemove: [NSAttributedString.Key] = [] - state.inputText.enumerateAttributes(in: nsRange, options: .longestEffectiveRangeNotRequired) { attributes, range, stop in + state.inputText.enumerateAttributes(in: nsRange, options: .longestEffectiveRangeNotRequired) { attributes, range, _ in for (key, _) in attributes { - if key == attribute && range == nsRange { + if key == attribute { addAttribute = false attributesToRemove.append(key) } } } + var selectionRange = state.selectionRange + let result = NSMutableAttributedString(attributedString: state.inputText) for attribute in attributesToRemove { - result.removeAttribute(attribute, range: nsRange) - } - if addAttribute { if attribute == ChatTextInputAttributes.quote { - result.addAttribute(attribute, value: ChatTextInputTextQuoteAttribute(), range: nsRange) + var removeRange = nsRange + + var selectionIndex = nsRange.upperBound if nsRange.upperBound != result.length && (result.string as NSString).character(at: nsRange.upperBound) != 0x0a { result.insert(NSAttributedString(string: "\n"), at: nsRange.upperBound) + selectionIndex += 1 + removeRange.length += 1 } if nsRange.lowerBound != 0 && (result.string as NSString).character(at: nsRange.lowerBound - 1) != 0x0a { result.insert(NSAttributedString(string: "\n"), at: nsRange.lowerBound) + selectionIndex += 1 + removeRange.location += 1 + } else if nsRange.lowerBound != 0 { + removeRange.location -= 1 + removeRange.length += 1 } + + if removeRange.lowerBound > result.length { + removeRange = NSRange(location: result.length, length: 0) + } else if removeRange.upperBound > result.length { + removeRange = NSRange(location: removeRange.lowerBound, length: result.length - removeRange.lowerBound) + } + result.removeAttribute(attribute, range: removeRange) + + if selectionRange.lowerBound > result.length { + selectionRange = result.length ..< result.length + } else if selectionRange.upperBound > result.length { + selectionRange = selectionRange.lowerBound ..< result.length + } + + // Prevent merge back + result.enumerateAttributes(in: NSRange(location: selectionIndex, length: result.length - selectionIndex), options: .longestEffectiveRangeNotRequired) { attributes, range, _ in + for (key, value) in attributes { + if let _ = value as? ChatTextInputTextQuoteAttribute { + result.removeAttribute(key, range: range) + result.addAttribute(key, value: ChatTextInputTextQuoteAttribute(), range: range) + } + } + } + + selectionRange = selectionIndex ..< selectionIndex + } else { + result.removeAttribute(attribute, range: nsRange) + } + } + + if addAttribute { + if attribute == ChatTextInputAttributes.quote { + result.addAttribute(attribute, value: ChatTextInputTextQuoteAttribute(), range: nsRange) + var selectionIndex = nsRange.upperBound + if nsRange.upperBound != result.length && (result.string as NSString).character(at: nsRange.upperBound) != 0x0a { + result.insert(NSAttributedString(string: "\n"), at: nsRange.upperBound) + selectionIndex += 1 + } + if nsRange.lowerBound != 0 && (result.string as NSString).character(at: nsRange.lowerBound - 1) != 0x0a { + result.insert(NSAttributedString(string: "\n"), at: nsRange.lowerBound) + selectionIndex += 1 + } + selectionRange = selectionIndex ..< selectionIndex } else { result.addAttribute(attribute, value: true as Bool, range: nsRange) } } - return ChatTextInputState(inputText: result, selectionRange: state.selectionRange) + if selectionRange.lowerBound > result.length { + selectionRange = result.length ..< result.length + } else if selectionRange.upperBound > result.length { + selectionRange = selectionRange.lowerBound ..< result.length + } + return ChatTextInputState(inputText: result, selectionRange: selectionRange) } else { return state } diff --git a/submodules/Display/Source/TextNode.swift b/submodules/Display/Source/TextNode.swift index 3e37ae6145..64eb847ee2 100644 --- a/submodules/Display/Source/TextNode.swift +++ b/submodules/Display/Source/TextNode.swift @@ -68,12 +68,10 @@ public struct TextRangeRectEdge: Equatable { } public final class TextNodeBlockQuoteData: NSObject { - public let id: Int public let title: NSAttributedString? public let color: UIColor - public init(id: Int, title: NSAttributedString?, color: UIColor) { - self.id = id + public init(title: NSAttributedString?, color: UIColor) { self.title = title self.color = color @@ -85,9 +83,6 @@ public final class TextNodeBlockQuoteData: NSObject { return false } - if self.id != other.id { - return false - } if let lhsTitle = self.title, let rhsTitle = other.title { if !lhsTitle.isEqual(to: rhsTitle) { return false @@ -1142,8 +1137,10 @@ open class TextNode: ASDisplayNode { var segmentCharacterOffset = 0 while true { var found = false - attributedString.enumerateAttribute(NSAttributedString.Key("Attribute__Blockquote"), in: NSRange(location: segmentCharacterOffset, length: wholeStringLength - segmentCharacterOffset), using: { value, effectiveRange, _ in + attributedString.enumerateAttribute(NSAttributedString.Key("Attribute__Blockquote"), in: NSRange(location: segmentCharacterOffset, length: wholeStringLength - segmentCharacterOffset), using: { value, effectiveRange, stop in found = true + stop.pointee = ObjCBool(true) + if segmentCharacterOffset != effectiveRange.location { stringSegments.append(StringSegment( title: nil, @@ -1167,6 +1164,10 @@ open class TextNode: ASDisplayNode { tintColor: value.color )) } + segmentCharacterOffset = effectiveRange.location + effectiveRange.length + if segmentCharacterOffset < wholeStringLength && rawWholeString.character(at: segmentCharacterOffset) == 0x0a { + segmentCharacterOffset += 1 + } } else { stringSegments.append(StringSegment( title: nil, @@ -1175,9 +1176,8 @@ open class TextNode: ASDisplayNode { isBlockQuote: false, tintColor: nil )) + segmentCharacterOffset = effectiveRange.location + effectiveRange.length } - - segmentCharacterOffset = effectiveRange.location + effectiveRange.length }) if !found { if segmentCharacterOffset != wholeStringLength { @@ -1992,6 +1992,9 @@ open class TextNode: ASDisplayNode { context.setFillColor((layout.backgroundColor ?? UIColor.clear).cgColor) context.fill(bounds) + + context.setBlendMode(.normal) + blendMode = .normal } let alignment = layout.resolvedAlignment @@ -2803,6 +2806,7 @@ open class TextView: UIView { context.setBlendMode(.copy) context.setFillColor((layout.backgroundColor ?? UIColor.clear).cgColor) context.fill(bounds) + context.setBlendMode(.copy) } if let textShadowColor = layout.textShadowColor { diff --git a/submodules/TelegramUI/Components/Chat/ChatInputTextNode/ChatInputTextViewImpl/Sources/ChatInputTextViewImpl.m b/submodules/TelegramUI/Components/Chat/ChatInputTextNode/ChatInputTextViewImpl/Sources/ChatInputTextViewImpl.m index 0160c809b9..3f87ea0066 100755 --- a/submodules/TelegramUI/Components/Chat/ChatInputTextNode/ChatInputTextViewImpl/Sources/ChatInputTextViewImpl.m +++ b/submodules/TelegramUI/Components/Chat/ChatInputTextNode/ChatInputTextViewImpl/Sources/ChatInputTextViewImpl.m @@ -47,8 +47,6 @@ return false; } - return false; - return [super canPerformAction:action withSender:sender]; } diff --git a/submodules/TelegramUI/Components/Chat/ChatInputTextNode/Sources/ChatInputTextNode.swift b/submodules/TelegramUI/Components/Chat/ChatInputTextNode/Sources/ChatInputTextNode.swift index 336cf9cc8b..47e91183f5 100644 --- a/submodules/TelegramUI/Components/Chat/ChatInputTextNode/Sources/ChatInputTextNode.swift +++ b/submodules/TelegramUI/Components/Chat/ChatInputTextNode/Sources/ChatInputTextNode.swift @@ -110,7 +110,7 @@ open class ChatInputTextNode: ASDisplayNode, UITextViewDelegate { get { return self.textView.defaultTextContainerInset } set(value) { - let targetValue = UIEdgeInsets(top: value.top, left: 0.0, bottom: value.bottom, right: 0.0) + let targetValue = UIEdgeInsets(top: value.top, left: value.left, bottom: value.bottom, right: value.right) if self.textView.defaultTextContainerInset != value { self.textView.defaultTextContainerInset = targetValue } @@ -183,6 +183,8 @@ open class ChatInputTextNode: ASDisplayNode, UITextViewDelegate { } private final class ChatInputTextContainer: NSTextContainer { + var rightInset: CGFloat = 0.0 + override var isSimpleRectangularTextContainer: Bool { return false } @@ -200,6 +202,7 @@ private final class ChatInputTextContainer: NSTextContainer { result.origin.x -= 5.0 result.size.width -= 5.0 + result.size.width -= self.rightInset if let textStorage = self.layoutManager?.textStorage { let string: NSString = textStorage.string as NSString @@ -234,6 +237,8 @@ private final class ChatInputTextContainer: NSTextContainer { } } + result.size.width = max(1.0, result.size.width) + return result } } @@ -453,6 +458,19 @@ public final class ChatInputTextView: ChatInputTextViewImpl, NSLayoutManagerDele public func updateTextContainerInset() { var result = self.defaultTextContainerInset + var horizontalInsetsUpdated = false + if self.customTextContainer.rightInset != result.right { + horizontalInsetsUpdated = true + self.customTextContainer.rightInset = result.right + } + if self.measurementTextContainer.rightInset != result.right { + horizontalInsetsUpdated = true + self.measurementTextContainer.rightInset = result.right + } + + result.left = 0.0 + result.right = 0.0 + if self.customTextStorage.length != 0 { let topAttributes = self.customTextStorage.attributes(at: 0, effectiveRange: nil) let bottomAttributes = self.customTextStorage.attributes(at: self.customTextStorage.length - 1, effectiveRange: nil) @@ -468,6 +486,11 @@ public final class ChatInputTextView: ChatInputTextViewImpl, NSLayoutManagerDele if self.textContainerInset != result { self.textContainerInset = result } + if horizontalInsetsUpdated { + self.customLayoutManager.invalidateLayout(forCharacterRange: NSRange(location: 0, length: self.customTextStorage.length), actualCharacterRange: nil) + self.customLayoutManager.ensureLayout(for: self.customTextContainer) + } + self.updateTextElements() } @@ -578,6 +601,11 @@ public final class ChatInputTextView: ChatInputTextViewImpl, NSLayoutManagerDele override public func caretRect(for position: UITextPosition) -> CGRect { var result = super.caretRect(for: position) + + if "".isEmpty { + return result + } + guard let textStorage = self.customLayoutManager.textStorage else { return result } diff --git a/submodules/TelegramUI/Sources/ChatTextInputPanelNode.swift b/submodules/TelegramUI/Sources/ChatTextInputPanelNode.swift index 99c757fc59..4388d07d31 100644 --- a/submodules/TelegramUI/Sources/ChatTextInputPanelNode.swift +++ b/submodules/TelegramUI/Sources/ChatTextInputPanelNode.swift @@ -3682,8 +3682,14 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate, Ch var actions = suggestedActions - if let index = actions.firstIndex(where: { $0.description.contains("identifier = com.apple.menu.replace;") }) { - actions.remove(at: index) + if #available(iOS 16.0, *) { + if let index = actions.firstIndex(where: { $0.description.contains("identifier = com.apple.menu.replace;") }), let subMenu = actions[index] as? UIMenu { + var filteredChildren = subMenu.children + if let subIndex = filteredChildren.firstIndex(where: { $0.description.contains("identifier = com.apple.menu.autofill;") }) { + filteredChildren.remove(at: subIndex) + } + actions[index] = UIMenu(title: subMenu.title, subtitle: subMenu.subtitle, image: subMenu.image, identifier: subMenu.identifier, options: subMenu.options, children: filteredChildren) + } } if editableTextNode.attributedText == nil || editableTextNode.attributedText!.length == 0 || editableTextNode.selectedRange.length == 0 { @@ -3745,11 +3751,7 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate, Ch ] as [UIAction]) let formatMenu = UIMenu(title: self.strings?.TextFormat_Format ?? "Format", image: nil, children: children) - if let index = actions.firstIndex(where: { $0.description.contains("identifier = com.apple.menu.format;") }) { - actions[index] = formatMenu - } else { - actions.insert(formatMenu, at: 2) - } + actions.insert(formatMenu, at: 1) } return UIMenu(children: actions) } diff --git a/submodules/TextFormat/Sources/ChatTextInputAttributes.swift b/submodules/TextFormat/Sources/ChatTextInputAttributes.swift index 87e9402dff..5d8a75f45f 100644 --- a/submodules/TextFormat/Sources/ChatTextInputAttributes.swift +++ b/submodules/TextFormat/Sources/ChatTextInputAttributes.swift @@ -133,6 +133,7 @@ public func textAttributedStringForStateText(_ stateText: NSAttributedString, fo var font: UIFont? var fontSize = fontSize if fontAttributes.contains(.blockQuote) { + fontAttributes.remove(.blockQuote) fontSize = round(fontSize * 0.8235294117647058) } if fontAttributes == [.bold, .italic, .monospace] { @@ -553,108 +554,53 @@ private func quoteRangesEqual(_ lhs: [(NSRange, ChatTextInputTextQuoteAttribute) private func refreshBlockQuotes(text: NSString, initialAttributedText: NSAttributedString, attributedText: NSMutableAttributedString, fullRange: NSRange) { var quoteRanges: [(NSRange, ChatTextInputTextQuoteAttribute)] = [] - initialAttributedText.enumerateAttribute(ChatTextInputAttributes.quote, in: fullRange, options: [], using: { value, range, _ in - if let value = value as? ChatTextInputTextQuoteAttribute { + initialAttributedText.enumerateAttributes(in: fullRange, using: { dict, range, _ in + if let value = dict[ChatTextInputAttributes.quote] as? ChatTextInputTextQuoteAttribute { quoteRanges.append((range, value)) } }) quoteRanges.sort(by: { $0.0.location < $1.0.location }) let initialQuoteRanges = quoteRanges - - for i in 0 ..< quoteRanges.count { - let range = quoteRanges[i].0 - - var validLower = range.lowerBound - inner1: for i in range.lowerBound ..< range.upperBound { - if let c = UnicodeScalar(text.character(at: i)) { - if textUrlCharacters.contains(c) { - validLower = i - break inner1 - } - } else { - break inner1 - } - } - var validUpper = range.upperBound - inner2: for i in (validLower ..< range.upperBound).reversed() { - if let c = UnicodeScalar(text.character(at: i)) { - if textUrlCharacters.contains(c) { - validUpper = i + 1 - break inner2 - } - } else { - break inner2 - } - } - - let minLower = (i == 0) ? fullRange.lowerBound : quoteRanges[i - 1].0.upperBound - inner3: for i in (minLower ..< validLower).reversed() { - if let c = UnicodeScalar(text.character(at: i)) { - if textUrlEdgeCharacters.contains(c) { - validLower = i - } else { - break inner3 - } - } else { - break inner3 - } - } - - let maxUpper = (i == quoteRanges.count - 1) ? fullRange.upperBound : quoteRanges[i + 1].0.lowerBound - inner3: for i in validUpper ..< maxUpper { - if let c = UnicodeScalar(text.character(at: i)) { - if textUrlEdgeCharacters.contains(c) { - validUpper = i + 1 - } else { - break inner3 - } - } else { - break inner3 - } - } - - quoteRanges[i] = (NSRange(location: validLower, length: validUpper - validLower), quoteRanges[i].1) - } - quoteRanges = quoteRanges.filter({ $0.0.length > 0 }) - while quoteRanges.count > 1 { - var hadReductions = false - outer: for i in 0 ..< quoteRanges.count - 1 { - if quoteRanges[i].1 === quoteRanges[i + 1].1 { - var combine = true - inner: for j in quoteRanges[i].0.upperBound ..< quoteRanges[i + 1].0.lowerBound { - if let c = UnicodeScalar(text.character(at: j)) { - if textUrlCharacters.contains(c) { - } else { - combine = false - break inner - } - } else { - combine = false - break inner - } - } - if combine { - hadReductions = true - quoteRanges[i] = (NSRange(location: quoteRanges[i].0.lowerBound, length: quoteRanges[i + 1].0.upperBound - quoteRanges[i].0.lowerBound), quoteRanges[i].1) - quoteRanges.remove(at: i + 1) - break outer - } + for i in 0 ..< quoteRanges.count { + var backIndex = quoteRanges[i].0.lowerBound + innerBack: while backIndex >= 0 { + let character = text.character(at: backIndex) + if character == 0x0a { + backIndex += 1 + break innerBack } + backIndex -= 1 } - if !hadReductions { - break + backIndex = max(backIndex, 0) + + if backIndex < quoteRanges[i].0.lowerBound { + quoteRanges[i].0 = NSRange(location: backIndex, length: quoteRanges[i].0.upperBound - backIndex) + } + + var forwardIndex = quoteRanges[i].0.upperBound + innerForward: while forwardIndex < text.length { + let character = text.character(at: forwardIndex) + if character == 0x0a { + forwardIndex -= 1 + break innerForward + } + forwardIndex += 1 + } + forwardIndex = min(forwardIndex, text.length - 1) + + if forwardIndex > quoteRanges[i].0.upperBound - 1 { + quoteRanges[i].0 = NSRange(location: quoteRanges[i].0.lowerBound, length: forwardIndex + 1 - quoteRanges[i].0.lowerBound) } } - if quoteRanges.count > 1 { - outer: for i in (1 ..< quoteRanges.count).reversed() { - for j in 0 ..< i { - if quoteRanges[j].1 === quoteRanges[i].1 { - quoteRanges.remove(at: i) - continue outer - } + for i in (0 ..< quoteRanges.count).reversed() { + inner: for mergeIndex in (i + 1 ..< quoteRanges.count).reversed() { + if quoteRanges[mergeIndex].1 === quoteRanges[i].1 || quoteRanges[mergeIndex].0.intersection(quoteRanges[i].0) != nil { + quoteRanges[i].0 = NSRange(location: quoteRanges[i].0.location, length: quoteRanges[mergeIndex].0.location + quoteRanges[mergeIndex].0.length - quoteRanges[i].0.location) + quoteRanges.removeSubrange((i + 1) ..< (mergeIndex + 1)) + break inner } } } @@ -777,6 +723,7 @@ public func refreshChatTextInputAttributes(textView: UITextView, primaryTextColo var font: UIFont? var baseFontSize = baseFontSize if fontAttributes.contains(.blockQuote) { + fontAttributes.remove(.blockQuote) baseFontSize = round(baseFontSize * 0.8235294117647058) } if fontAttributes == [.bold, .italic, .monospace] { diff --git a/submodules/TextFormat/Sources/StringWithAppliedEntities.swift b/submodules/TextFormat/Sources/StringWithAppliedEntities.swift index 4437168043..4e887d378e 100644 --- a/submodules/TextFormat/Sources/StringWithAppliedEntities.swift +++ b/submodules/TextFormat/Sources/StringWithAppliedEntities.swift @@ -67,9 +67,6 @@ public func stringWithAppliedEntities(_ text: String, entities: [MessageTextEnti } var fontAttributes: [NSRange: ChatTextFontAttributes] = [:] - var nextBlockId = 0 - - var rangeOffset: Int = 0 for i in 0 ..< entities.count { if skipEntity { skipEntity = false @@ -77,7 +74,7 @@ public func stringWithAppliedEntities(_ text: String, entities: [MessageTextEnti } let stringLength = string.length let entity = entities[i] - var range = NSRange(location: entity.range.lowerBound + rangeOffset, length: entity.range.upperBound - entity.range.lowerBound) + var range = NSRange(location: entity.range.lowerBound, length: entity.range.upperBound - entity.range.lowerBound) if nsString == nil { nsString = text as NSString } @@ -223,38 +220,7 @@ public func stringWithAppliedEntities(_ text: String, entities: [MessageTextEnti fontAttributes[range] = .blockQuote } - let paragraphBreak = "\n" - - var nsString = string.string as NSString - var stringLength = nsString.length - - let paragraphRange: NSRange - if range.lowerBound == 0 { - paragraphRange = NSRange(location: range.lowerBound, length: range.upperBound - range.lowerBound) - } else if nsString.character(at: range.lowerBound) == 0x0a { - paragraphRange = NSRange(location: range.lowerBound + 1, length: range.upperBound - range.lowerBound - 1) - } else if nsString.character(at: range.lowerBound - 1) == 0x0a { - paragraphRange = NSRange(location: range.lowerBound, length: range.upperBound - range.lowerBound) - } else { - string.insert(NSAttributedString(string: paragraphBreak), at: range.lowerBound) - paragraphRange = NSRange(location: range.lowerBound + paragraphBreak.count, length: range.upperBound - range.lowerBound) - } - - string.addAttribute(NSAttributedString.Key(rawValue: "Attribute__Blockquote"), value: TextNodeBlockQuoteData(id: nextBlockId, title: nil, color: baseQuoteTintColor), range: paragraphRange) - nextBlockId += 1 - - nsString = string.string as NSString - stringLength = nsString.length - - if paragraphRange.upperBound < stringLength { - if nsString.character(at: paragraphRange.upperBound) == 0x0a { - string.replaceCharacters(in: NSMakeRange(paragraphRange.upperBound, 1), with: "") - rangeOffset -= 1 - } - } - - rangeOffset += 0 - //rangeOffset += paragraphBreak.count + string.addAttribute(NSAttributedString.Key(rawValue: "Attribute__Blockquote"), value: TextNodeBlockQuoteData(title: nil, color: baseQuoteTintColor), range: range) case .BankCard: string.addAttribute(NSAttributedString.Key.foregroundColor, value: linkColor, range: range) if underlineLinks && underlineAllLinks { @@ -302,6 +268,12 @@ public func stringWithAppliedEntities(_ text: String, entities: [MessageTextEnti for range in ranges { var font: UIFont? + var fontAttributes = fontAttributes + var isQuote = false + if fontAttributes.contains(.blockQuote) { + isQuote = true + fontAttributes.remove(.blockQuote) + } if fontAttributes == [.bold, .italic] { font = boldItalicFont } else if fontAttributes == [.bold] { @@ -314,7 +286,7 @@ public func stringWithAppliedEntities(_ text: String, entities: [MessageTextEnti font = baseFont } - if adjustQuoteFontSize, let fontValue = font, fontAttributes.contains(.blockQuote) { + if adjustQuoteFontSize, let fontValue = font, isQuote { font = fontValue.withSize(round(fontValue.pointSize * 0.8235294117647058)) }