mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Quote improvements
This commit is contained in:
parent
16b6083b6e
commit
17d9d6caf3
@ -550,18 +550,24 @@ public struct ChatTextInputStateText: Codable, Equatable {
|
||||
parsedAttributes.append(ChatTextInputStateTextAttribute(type: .underline, range: range.location ..< (range.location + range.length)))
|
||||
} else if key == ChatTextInputAttributes.spoiler {
|
||||
parsedAttributes.append(ChatTextInputStateTextAttribute(type: .spoiler, range: range.location ..< (range.location + range.length)))
|
||||
} else if key == ChatTextInputAttributes.block, let value = value as? ChatTextInputTextQuoteAttribute {
|
||||
switch value.kind {
|
||||
case .quote:
|
||||
parsedAttributes.append(ChatTextInputStateTextAttribute(type: .quote(isCollapsed: value.isCollapsed), range: range.location ..< (range.location + range.length)))
|
||||
case let .code(language):
|
||||
parsedAttributes.append(ChatTextInputStateTextAttribute(type: .codeBlock(language: language), range: range.location ..< (range.location + range.length)))
|
||||
}
|
||||
} else if key == ChatTextInputAttributes.collapsedBlock, let value = value as? NSAttributedString {
|
||||
parsedAttributes.append(ChatTextInputStateTextAttribute(type: .collapsedQuote(text: ChatTextInputStateText(attributedText: value)), range: range.location ..< (range.location + range.length)))
|
||||
}
|
||||
}
|
||||
})
|
||||
attributedText.enumerateAttribute(ChatTextInputAttributes.block, in: NSRange(location: 0, length: attributedText.length), options: [], using: { value, range, _ in
|
||||
if let value = value as? ChatTextInputTextQuoteAttribute {
|
||||
switch value.kind {
|
||||
case .quote:
|
||||
parsedAttributes.append(ChatTextInputStateTextAttribute(type: .quote(isCollapsed: value.isCollapsed), range: range.location ..< (range.location + range.length)))
|
||||
case let .code(language):
|
||||
parsedAttributes.append(ChatTextInputStateTextAttribute(type: .codeBlock(language: language), range: range.location ..< (range.location + range.length)))
|
||||
}
|
||||
}
|
||||
})
|
||||
attributedText.enumerateAttribute(ChatTextInputAttributes.collapsedBlock, in: NSRange(location: 0, length: attributedText.length), options: [], using: { value, range, _ in
|
||||
if let value = value as? NSAttributedString {
|
||||
parsedAttributes.append(ChatTextInputStateTextAttribute(type: .collapsedQuote(text: ChatTextInputStateText(attributedText: value)), range: range.location ..< (range.location + range.length)))
|
||||
}
|
||||
})
|
||||
self.attributes = parsedAttributes
|
||||
}
|
||||
|
||||
|
@ -470,7 +470,8 @@ public final class ChatInterfaceState: Codable, Equatable {
|
||||
if self.composeInputState.inputText.string.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty && self.replyMessageSubject == nil {
|
||||
return nil
|
||||
} else {
|
||||
return SynchronizeableChatInputState(replySubject: self.replyMessageSubject?.subjectModel, text: self.composeInputState.inputText.string, entities: generateChatInputTextEntities(self.composeInputState.inputText), timestamp: self.timestamp, textSelection: self.composeInputState.selectionRange)
|
||||
let sourceText = expandedInputStateAttributedString(self.composeInputState.inputText)
|
||||
return SynchronizeableChatInputState(replySubject: self.replyMessageSubject?.subjectModel, text: sourceText.string, entities: generateChatInputTextEntities(sourceText), timestamp: self.timestamp, textSelection: self.composeInputState.selectionRange)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -16,6 +16,7 @@ swift_library(
|
||||
"//submodules/TelegramUI/Components/Chat/ChatInputTextNode/ChatInputTextViewImpl",
|
||||
"//submodules/TelegramUI/Components/Chat/MessageInlineBlockBackgroundView",
|
||||
"//submodules/AccountContext",
|
||||
"//submodules/TelegramUI/Components/TextNodeWithEntities",
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
|
@ -7,6 +7,7 @@ import ChatInputTextViewImpl
|
||||
import MessageInlineBlockBackgroundView
|
||||
import TextFormat
|
||||
import AccountContext
|
||||
import TextNodeWithEntities
|
||||
|
||||
public protocol ChatInputTextNodeDelegate: AnyObject {
|
||||
func chatInputTextNodeDidUpdateText()
|
||||
@ -540,7 +541,19 @@ private final class ChatInputTextLegacyInternal: NSObject, ChatInputTextInternal
|
||||
var startIndex = glyphRange.lowerBound
|
||||
while startIndex < glyphRange.upperBound {
|
||||
var effectiveRange = NSRange(location: NSNotFound, length: 0)
|
||||
let rect = self.customLayoutManager.lineFragmentUsedRect(forGlyphAt: startIndex, effectiveRange: &effectiveRange)
|
||||
var rect = self.customLayoutManager.lineFragmentUsedRect(forGlyphAt: startIndex, effectiveRange: &effectiveRange)
|
||||
|
||||
let characterRange = self.customLayoutManager.characterRange(forGlyphRange: NSRange(location: startIndex, length: 1), actualGlyphRange: nil)
|
||||
if characterRange.location != NSNotFound {
|
||||
if let attribute = self.customTextStorage.attribute(NSAttributedString.Key("Attribute__Blockquote"), at: characterRange.location, effectiveRange: nil) {
|
||||
let _ = attribute
|
||||
rect.size.width += 13.0
|
||||
} else if let attribute = self.customTextStorage.attribute(.attachment, at: characterRange.location, effectiveRange: nil) as? ChatInputTextCollapsedQuoteAttachment {
|
||||
let _ = attribute
|
||||
rect.size.width += 8.0
|
||||
}
|
||||
}
|
||||
|
||||
if boundingRect.isEmpty {
|
||||
boundingRect = rect
|
||||
} else {
|
||||
@ -552,6 +565,7 @@ private final class ChatInputTextLegacyInternal: NSObject, ChatInputTextInternal
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return boundingRect
|
||||
}
|
||||
|
||||
@ -804,11 +818,12 @@ private let registeredViewProvider: Void = {
|
||||
public final class ChatInputTextCollapsedQuoteAttachmentImpl: NSTextAttachment, ChatInputTextCollapsedQuoteAttachment {
|
||||
final class View: UIView {
|
||||
let attachment: ChatInputTextCollapsedQuoteAttachmentImpl
|
||||
let textNode: ImmediateTextNode
|
||||
let textNode: ImmediateTextNodeWithEntities
|
||||
|
||||
init(attachment: ChatInputTextCollapsedQuoteAttachmentImpl) {
|
||||
self.attachment = attachment
|
||||
self.textNode = ImmediateTextNode()
|
||||
self.textNode = ImmediateTextNodeWithEntities()
|
||||
self.textNode.displaysAsynchronously = false
|
||||
self.textNode.maximumNumberOfLines = 3
|
||||
|
||||
super.init(frame: CGRect())
|
||||
@ -825,10 +840,6 @@ public final class ChatInputTextCollapsedQuoteAttachmentImpl: NSTextAttachment,
|
||||
return CGSize(width: 10.0, height: 10.0)
|
||||
}
|
||||
|
||||
/*let renderingText = NSMutableAttributedString(attributedString: attachment.text)
|
||||
renderingText.addAttribute(.font, value: attachment.attributes.font, range: NSRange(location: 0, length: renderingText.length))
|
||||
renderingText.addAttribute(.foregroundColor, value: attachment.attributes.textColor, range: NSRange(location: 0, length: renderingText.length))*/
|
||||
|
||||
let renderingText = textAttributedStringForStateText(
|
||||
context: context,
|
||||
stateText: attachment.text,
|
||||
@ -846,11 +857,11 @@ public final class ChatInputTextCollapsedQuoteAttachmentImpl: NSTextAttachment,
|
||||
textNode.maximumNumberOfLines = 3
|
||||
|
||||
textNode.attributedText = renderingText
|
||||
textNode.cutout = TextNodeCutout(topRight: CGSize(width: 40.0, height: 10.0))
|
||||
textNode.cutout = TextNodeCutout(topRight: CGSize(width: 30.0, height: 10.0))
|
||||
|
||||
let layoutInfo = textNode.updateLayoutFullInfo(CGSize(width: constrainedSize.width - 9.0, height: constrainedSize.height))
|
||||
let layoutSize = textNode.updateLayout(CGSize(width: constrainedSize.width - 9.0, height: constrainedSize.height))
|
||||
|
||||
return CGSize(width: constrainedSize.width, height: 8.0 + layoutInfo.size.height + 8.0)
|
||||
return CGSize(width: constrainedSize.width, height: 8.0 + layoutSize.height + 8.0)
|
||||
}
|
||||
|
||||
override func layoutSubviews() {
|
||||
@ -876,13 +887,24 @@ public final class ChatInputTextCollapsedQuoteAttachmentImpl: NSTextAttachment,
|
||||
renderingText.addAttribute(.font, value: attachment.attributes.font, range: NSRange(location: 0, length: renderingText.length))
|
||||
renderingText.addAttribute(.foregroundColor, value: attachment.attributes.textColor, range: NSRange(location: 0, length: renderingText.length))*/
|
||||
|
||||
self.textNode.arguments = TextNodeWithEntities.Arguments(
|
||||
context: context,
|
||||
cache: context.animationCache,
|
||||
renderer: context.animationRenderer,
|
||||
placeholderColor: .gray,
|
||||
attemptSynchronous: true
|
||||
)
|
||||
|
||||
self.textNode.attributedText = renderingText
|
||||
self.textNode.cutout = TextNodeCutout(topRight: CGSize(width: 10.0, height: 8.0))
|
||||
self.textNode.cutout = TextNodeCutout(topRight: CGSize(width: 30.0, height: 10.0))
|
||||
|
||||
self.textNode.displaySpoilerEffect = true
|
||||
self.textNode.visibility = true
|
||||
|
||||
let maxTextSize = CGSize(width: self.bounds.size.width - 9.0, height: self.bounds.size.height)
|
||||
let layoutInfo = self.textNode.updateLayoutFullInfo(maxTextSize)
|
||||
let layoutSize = self.textNode.updateLayout(maxTextSize)
|
||||
|
||||
self.textNode.frame = CGRect(origin: CGPoint(x: 9.0, y: 8.0), size: layoutInfo.size)
|
||||
self.textNode.frame = CGRect(origin: CGPoint(x: 9.0, y: 8.0), size: layoutSize)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1450,16 +1472,17 @@ private final class QuoteBackgroundView: UIView {
|
||||
self.iconView.frame = CGRect(origin: CGPoint(x: size.width - 4.0 - quoteIcon.size.width, y: 4.0), size: quoteIcon.size)
|
||||
|
||||
let collapseButtonSize = CGSize(width: 18.0, height: 18.0)
|
||||
self.collapseButton.frame = CGRect(origin: CGPoint(x: size.width - 2.0 - collapseButtonSize.width, y: 2.0), size: collapseButtonSize)
|
||||
|
||||
if isCollapsed {
|
||||
self.collapseButtonIconView.image = quoteExpandImage
|
||||
self.collapseButton.frame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: size)
|
||||
} else {
|
||||
self.collapseButtonIconView.image = quoteCollapseImage
|
||||
self.collapseButton.frame = CGRect(origin: CGPoint(x: size.width - 2.0 - collapseButtonSize.width, y: 2.0), size: collapseButtonSize)
|
||||
}
|
||||
if let image = self.collapseButtonIconView.image {
|
||||
let iconSize = image.size.aspectFitted(collapseButtonSize)
|
||||
self.collapseButtonIconView.frame = CGRect(origin: CGPoint(x: floorToScreenPixels((collapseButtonSize.width - iconSize.width) * 0.5), y: floorToScreenPixels((collapseButtonSize.height - iconSize.height) * 0.5)), size: iconSize)
|
||||
self.collapseButtonIconView.frame = CGRect(origin: CGPoint(x: self.collapseButton.bounds.width - 2.0 - collapseButtonSize.width + floorToScreenPixels((collapseButtonSize.width - iconSize.width) * 0.5), y: 2.0 + floorToScreenPixels((collapseButtonSize.height - iconSize.height) * 0.5)), size: iconSize)
|
||||
}
|
||||
|
||||
var primaryColor: UIColor
|
||||
@ -1469,7 +1492,7 @@ private final class QuoteBackgroundView: UIView {
|
||||
|
||||
switch kind {
|
||||
case .quote:
|
||||
if size.height >= 100.0 || isCollapsed {
|
||||
if size.height >= 60.0 || isCollapsed {
|
||||
self.iconView.isHidden = true
|
||||
self.collapseButton.isHidden = false
|
||||
} else {
|
||||
|
@ -45,7 +45,7 @@ private func generateBlockMaskImage() -> UIImage {
|
||||
gradient = CGGradient(colorsSpace: colorSpace, colors: colors as CFArray, locations: &locations)!
|
||||
|
||||
context.setBlendMode(.destinationIn)
|
||||
context.drawLinearGradient(gradient, start: CGPoint(x: 0.0, y: size.height), end: CGPoint(x: 0.0, y: size.height - 7.0), options: CGGradientDrawingOptions())
|
||||
context.drawLinearGradient(gradient, start: CGPoint(x: 0.0, y: size.height), end: CGPoint(x: 0.0, y: size.height - 18.0), options: CGGradientDrawingOptions())
|
||||
})!.resizableImage(withCapInsets: UIEdgeInsets(top: 0.0, left: 0.0, bottom: size.height - 1.0, right: size.width - 1.0), resizingMode: .stretch)
|
||||
}
|
||||
|
||||
|
@ -1212,13 +1212,23 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate, Ch
|
||||
|
||||
self.interfaceInteraction?.updateTextInputStateAndMode { current, inputMode in
|
||||
let result = NSMutableAttributedString(attributedString: current.inputText)
|
||||
var selectionRange = current.selectionRange
|
||||
|
||||
if let _ = result.attribute(ChatTextInputAttributes.block, at: range.lowerBound, effectiveRange: nil) as? ChatTextInputTextQuoteAttribute {
|
||||
let blockString = result.attributedSubstring(from: range)
|
||||
let blockString = NSMutableAttributedString(attributedString: result.attributedSubstring(from: range))
|
||||
blockString.removeAttribute(ChatTextInputAttributes.block, range: NSRange(location: 0, length: blockString.length))
|
||||
|
||||
result.replaceCharacters(in: range, with: "")
|
||||
result.insert(NSAttributedString(string: " ", attributes: [
|
||||
ChatTextInputAttributes.collapsedBlock: blockString
|
||||
]), at: range.lowerBound)
|
||||
|
||||
if selectionRange.lowerBound >= range.lowerBound && selectionRange.upperBound < range.upperBound {
|
||||
selectionRange = range.lowerBound ..< range.lowerBound
|
||||
} else if selectionRange.lowerBound >= range.upperBound {
|
||||
let deltaLength = 1 - range.length
|
||||
selectionRange = (selectionRange.lowerBound + deltaLength) ..< (selectionRange.lowerBound + deltaLength)
|
||||
}
|
||||
} else if let current = result.attribute(ChatTextInputAttributes.collapsedBlock, at: range.lowerBound, effectiveRange: nil) as? NSAttributedString {
|
||||
result.replaceCharacters(in: range, with: "")
|
||||
|
||||
@ -1226,13 +1236,24 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate, Ch
|
||||
updatedBlockString.addAttribute(ChatTextInputAttributes.block, value: ChatTextInputTextQuoteAttribute(kind: .quote, isCollapsed: false), range: NSRange(location: 0, length: updatedBlockString.length))
|
||||
|
||||
result.insert(updatedBlockString, at: range.lowerBound)
|
||||
|
||||
if selectionRange.lowerBound >= range.upperBound {
|
||||
let deltaLength = updatedBlockString.length - 1
|
||||
selectionRange = (selectionRange.lowerBound + deltaLength) ..< (selectionRange.lowerBound + deltaLength)
|
||||
}
|
||||
}
|
||||
|
||||
let stateResult = stateAttributedStringForText(result)
|
||||
if selectionRange.lowerBound < 0 {
|
||||
selectionRange = 0 ..< selectionRange.upperBound
|
||||
}
|
||||
if selectionRange.upperBound > stateResult.length {
|
||||
selectionRange = selectionRange.lowerBound ..< stateResult.length
|
||||
}
|
||||
|
||||
return (ChatTextInputState(
|
||||
inputText: stateResult,
|
||||
selectionRange: current.selectionRange
|
||||
selectionRange: selectionRange
|
||||
), inputMode)
|
||||
}
|
||||
}
|
||||
|
@ -179,7 +179,7 @@ public struct ChatTextFontAttributes: OptionSet, Hashable, Sequence {
|
||||
public func textAttributedStringForStateText(context: AnyObject, stateText: NSAttributedString, fontSize: CGFloat, textColor: UIColor, accentTextColor: UIColor, writingDirection: NSWritingDirection?, spoilersRevealed: Bool, availableEmojis: Set<String>, emojiViewProvider: ((ChatTextInputTextCustomEmojiAttribute) -> UIView)?, makeCollapsedQuoteAttachment: ((NSAttributedString, ChatInputTextCollapsedQuoteAttributes) -> ChatInputTextCollapsedQuoteAttachment)?) -> NSAttributedString {
|
||||
let quoteAttributes = ChatInputTextCollapsedQuoteAttributes(
|
||||
context: context,
|
||||
fontSize: fontSize,
|
||||
fontSize: round(fontSize * 0.8235294117647058),
|
||||
textColor: textColor,
|
||||
accentTextColor: accentTextColor
|
||||
)
|
||||
|
Loading…
x
Reference in New Issue
Block a user