mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-10-08 19:10:53 +00:00
Various Improvements
This commit is contained in:
parent
d8ec49897d
commit
0cc01c5280
@ -17,6 +17,7 @@ public class ImmediateTextNode: TextNode {
|
||||
public var textShadowColor: UIColor?
|
||||
public var textStroke: (UIColor, CGFloat)?
|
||||
public var cutout: TextNodeCutout?
|
||||
public var displaySpoilers = false
|
||||
|
||||
public var truncationMode: NSLineBreakMode {
|
||||
get {
|
||||
@ -89,7 +90,7 @@ public class ImmediateTextNode: TextNode {
|
||||
self.constrainedSize = constrainedSize
|
||||
|
||||
let makeLayout = TextNode.asyncLayout(self)
|
||||
let (layout, apply) = makeLayout(TextNodeLayoutArguments(attributedString: self.attributedText, backgroundColor: nil, maximumNumberOfLines: self.maximumNumberOfLines, truncationType: self.truncationType, constrainedSize: constrainedSize, alignment: self.textAlignment, verticalAlignment: self.verticalAlignment, lineSpacing: self.lineSpacing, cutout: self.cutout, insets: self.insets, textShadowColor: self.textShadowColor, textStroke: self.textStroke))
|
||||
let (layout, apply) = makeLayout(TextNodeLayoutArguments(attributedString: self.attributedText, backgroundColor: nil, maximumNumberOfLines: self.maximumNumberOfLines, truncationType: self.truncationType, constrainedSize: constrainedSize, alignment: self.textAlignment, verticalAlignment: self.verticalAlignment, lineSpacing: self.lineSpacing, cutout: self.cutout, insets: self.insets, textShadowColor: self.textShadowColor, textStroke: self.textStroke, displaySpoilers: self.displaySpoilers))
|
||||
let _ = apply()
|
||||
if layout.numberOfLines > 1 {
|
||||
self.trailingLineWidth = layout.trailingLineWidth
|
||||
@ -103,7 +104,7 @@ public class ImmediateTextNode: TextNode {
|
||||
self.constrainedSize = constrainedSize
|
||||
|
||||
let makeLayout = TextNode.asyncLayout(self)
|
||||
let (layout, apply) = makeLayout(TextNodeLayoutArguments(attributedString: self.attributedText, backgroundColor: nil, maximumNumberOfLines: self.maximumNumberOfLines, truncationType: self.truncationType, constrainedSize: constrainedSize, alignment: self.textAlignment, verticalAlignment: self.verticalAlignment, lineSpacing: self.lineSpacing, cutout: self.cutout, insets: self.insets))
|
||||
let (layout, apply) = makeLayout(TextNodeLayoutArguments(attributedString: self.attributedText, backgroundColor: nil, maximumNumberOfLines: self.maximumNumberOfLines, truncationType: self.truncationType, constrainedSize: constrainedSize, alignment: self.textAlignment, verticalAlignment: self.verticalAlignment, lineSpacing: self.lineSpacing, cutout: self.cutout, insets: self.insets, displaySpoilers: self.displaySpoilers))
|
||||
let _ = apply()
|
||||
return ImmediateTextNodeLayoutInfo(size: layout.size, truncated: layout.truncated)
|
||||
}
|
||||
@ -112,7 +113,7 @@ public class ImmediateTextNode: TextNode {
|
||||
self.constrainedSize = constrainedSize
|
||||
|
||||
let makeLayout = TextNode.asyncLayout(self)
|
||||
let (layout, apply) = makeLayout(TextNodeLayoutArguments(attributedString: self.attributedText, backgroundColor: nil, maximumNumberOfLines: self.maximumNumberOfLines, truncationType: self.truncationType, constrainedSize: constrainedSize, alignment: self.textAlignment, verticalAlignment: self.verticalAlignment, lineSpacing: self.lineSpacing, cutout: self.cutout, insets: self.insets))
|
||||
let (layout, apply) = makeLayout(TextNodeLayoutArguments(attributedString: self.attributedText, backgroundColor: nil, maximumNumberOfLines: self.maximumNumberOfLines, truncationType: self.truncationType, constrainedSize: constrainedSize, alignment: self.textAlignment, verticalAlignment: self.verticalAlignment, lineSpacing: self.lineSpacing, cutout: self.cutout, insets: self.insets, displaySpoilers: self.displaySpoilers))
|
||||
let _ = apply()
|
||||
return layout
|
||||
}
|
||||
|
@ -973,13 +973,30 @@ public class TextNode: ASDisplayNode {
|
||||
|
||||
let lineCharacterCount = CTTypesetterSuggestLineBreak(typesetter, lastLineCharacterIndex, Double(lineConstrainedWidth))
|
||||
|
||||
func addSpoiler(line: CTLine, ascent: CGFloat, descent: CGFloat, startIndex: Int, endIndex: Int) {
|
||||
var secondaryLeftOffset: CGFloat = 0.0
|
||||
let rawLeftOffset = CTLineGetOffsetForStringIndex(line, startIndex, &secondaryLeftOffset)
|
||||
var leftOffset = floor(rawLeftOffset)
|
||||
if !rawLeftOffset.isEqual(to: secondaryLeftOffset) {
|
||||
leftOffset = floor(secondaryLeftOffset)
|
||||
}
|
||||
|
||||
var secondaryRightOffset: CGFloat = 0.0
|
||||
let rawRightOffset = CTLineGetOffsetForStringIndex(line, endIndex, &secondaryRightOffset)
|
||||
var rightOffset = ceil(rawRightOffset)
|
||||
if !rawRightOffset.isEqual(to: secondaryRightOffset) {
|
||||
rightOffset = ceil(secondaryRightOffset)
|
||||
}
|
||||
|
||||
spoilers.append(TextNodeSpoiler(range: NSMakeRange(startIndex, endIndex - startIndex + 1), frame: CGRect(x: min(leftOffset, rightOffset), y: descent - (ascent + descent), width: abs(rightOffset - leftOffset), height: ascent + descent)))
|
||||
}
|
||||
|
||||
var isLastLine = false
|
||||
if maximumNumberOfLines != 0 && lines.count == maximumNumberOfLines - 1 && lineCharacterCount > 0 {
|
||||
isLastLine = true
|
||||
} else if layoutSize.height + (fontLineSpacing + fontLineHeight) * 2.0 > constrainedSize.height {
|
||||
isLastLine = true
|
||||
}
|
||||
|
||||
if isLastLine {
|
||||
if first {
|
||||
first = false
|
||||
@ -1022,25 +1039,27 @@ public class TextNode: ASDisplayNode {
|
||||
var descent: CGFloat = 0.0
|
||||
CTLineGetTypographicBounds(coreTextLine, &ascent, &descent, nil)
|
||||
|
||||
(attributedString.string as NSString).enumerateSubstrings(in: range, options: .byWords) { _, range, _, _ in
|
||||
let startIndex = range.location
|
||||
let endIndex = range.location + range.length
|
||||
|
||||
var secondaryLeftOffset: CGFloat = 0.0
|
||||
let rawLeftOffset = CTLineGetOffsetForStringIndex(coreTextLine, startIndex, &secondaryLeftOffset)
|
||||
var leftOffset = ceil(rawLeftOffset)
|
||||
if !rawLeftOffset.isEqual(to: secondaryLeftOffset) {
|
||||
leftOffset = ceil(secondaryLeftOffset)
|
||||
var startIndex: Int?
|
||||
var currentIndex: Int?
|
||||
|
||||
let nsString = (attributedString.string as NSString)
|
||||
nsString.enumerateSubstrings(in: range, options: .byComposedCharacterSequences) { substring, range, _, _ in
|
||||
if let substring = substring, substring.rangeOfCharacter(from: .whitespacesAndNewlines) != nil {
|
||||
if let currentStartIndex = startIndex {
|
||||
startIndex = nil
|
||||
let endIndex = range.location
|
||||
addSpoiler(line: coreTextLine, ascent: ascent, descent: descent, startIndex: currentStartIndex, endIndex: endIndex)
|
||||
}
|
||||
} else if startIndex == nil {
|
||||
startIndex = range.location
|
||||
}
|
||||
|
||||
var secondaryRightOffset: CGFloat = 0.0
|
||||
let rawRighOffset = CTLineGetOffsetForStringIndex(coreTextLine, endIndex, &secondaryRightOffset)
|
||||
var rightOffset = ceil(rawRighOffset)
|
||||
if !rawRighOffset.isEqual(to: secondaryRightOffset) {
|
||||
rightOffset = ceil(secondaryRightOffset)
|
||||
}
|
||||
|
||||
spoilers.append(TextNodeSpoiler(range: range, frame: CGRect(x: min(leftOffset, rightOffset), y: descent - (ascent + descent), width: abs(rightOffset - leftOffset), height: ascent + descent)))
|
||||
currentIndex = range.location + range.length
|
||||
}
|
||||
|
||||
if let currentStartIndex = startIndex, let currentIndex = currentIndex {
|
||||
startIndex = nil
|
||||
let endIndex = currentIndex
|
||||
addSpoiler(line: coreTextLine, ascent: ascent, descent: descent, startIndex: currentStartIndex, endIndex: endIndex)
|
||||
}
|
||||
} else if let _ = attributes[NSAttributedString.Key.strikethroughStyle] {
|
||||
let lowerX = floor(CTLineGetOffsetForStringIndex(coreTextLine, range.location, nil))
|
||||
@ -1098,26 +1117,28 @@ public class TextNode: ASDisplayNode {
|
||||
var ascent: CGFloat = 0.0
|
||||
var descent: CGFloat = 0.0
|
||||
CTLineGetTypographicBounds(coreTextLine, &ascent, &descent, nil)
|
||||
|
||||
var startIndex: Int?
|
||||
var currentIndex: Int?
|
||||
|
||||
(attributedString.string as NSString).enumerateSubstrings(in: range, options: .byWords) { _, range, _, _ in
|
||||
let startIndex = range.location
|
||||
let endIndex = range.location + range.length
|
||||
|
||||
var secondaryLeftOffset: CGFloat = 0.0
|
||||
let rawLeftOffset = CTLineGetOffsetForStringIndex(coreTextLine, startIndex, &secondaryLeftOffset)
|
||||
var leftOffset = ceil(rawLeftOffset)
|
||||
if !rawLeftOffset.isEqual(to: secondaryLeftOffset) {
|
||||
leftOffset = ceil(secondaryLeftOffset)
|
||||
let nsString = (attributedString.string as NSString)
|
||||
nsString.enumerateSubstrings(in: range, options: .byComposedCharacterSequences) { substring, range, _, _ in
|
||||
if let substring = substring, substring.rangeOfCharacter(from: .whitespacesAndNewlines) != nil {
|
||||
if let currentStartIndex = startIndex {
|
||||
startIndex = nil
|
||||
let endIndex = range.location
|
||||
addSpoiler(line: coreTextLine, ascent: ascent, descent: descent, startIndex: currentStartIndex, endIndex: endIndex)
|
||||
}
|
||||
} else if startIndex == nil {
|
||||
startIndex = range.location
|
||||
}
|
||||
|
||||
var secondaryRightOffset: CGFloat = 0.0
|
||||
let rawRighOffset = CTLineGetOffsetForStringIndex(coreTextLine, endIndex, &secondaryRightOffset)
|
||||
var rightOffset = ceil(rawRighOffset)
|
||||
if !rawRighOffset.isEqual(to: secondaryRightOffset) {
|
||||
rightOffset = ceil(secondaryRightOffset)
|
||||
}
|
||||
|
||||
spoilers.append(TextNodeSpoiler(range: range, frame: CGRect(x: min(leftOffset, rightOffset), y: descent - (ascent + descent), width: abs(rightOffset - leftOffset), height: ascent + descent)))
|
||||
currentIndex = range.location + range.length
|
||||
}
|
||||
|
||||
if let currentStartIndex = startIndex, let currentIndex = currentIndex {
|
||||
startIndex = nil
|
||||
let endIndex = currentIndex
|
||||
addSpoiler(line: coreTextLine, ascent: ascent, descent: descent, startIndex: currentStartIndex, endIndex: endIndex)
|
||||
}
|
||||
} else if let _ = attributes[NSAttributedString.Key.strikethroughStyle] {
|
||||
let lowerX = floor(CTLineGetOffsetForStringIndex(coreTextLine, range.location, nil))
|
||||
|
@ -38,6 +38,7 @@ swift_library(
|
||||
"//submodules/TextSelectionNode:TextSelectionNode",
|
||||
"//submodules/Speak:Speak",
|
||||
"//submodules/UndoUI:UndoUI",
|
||||
"//submodules/InvisibleInkDustNode:InvisibleInkDustNode",
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
|
@ -21,6 +21,7 @@ import UrlEscaping
|
||||
import UndoUI
|
||||
import ManagedAnimationNode
|
||||
import TelegramUniversalVideoContent
|
||||
import InvisibleInkDustNode
|
||||
|
||||
private let deleteImage = generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Accessory Panels/MessageSelectionTrash"), color: .white)
|
||||
private let actionImage = generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Accessory Panels/MessageSelectionForward"), color: .white)
|
||||
@ -130,6 +131,9 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll
|
||||
private let scrollNode: ASScrollNode
|
||||
|
||||
private let textNode: ImmediateTextNode
|
||||
private var spoilerTextNode: ImmediateTextNode?
|
||||
private var dustNode: InvisibleInkDustNode?
|
||||
|
||||
private let authorNameNode: ASTextNode
|
||||
private let dateNode: ASTextNode
|
||||
private let backwardButton: PlaybackButtonNode
|
||||
@ -713,6 +717,41 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll
|
||||
}
|
||||
}
|
||||
|
||||
private func updateSpoilers(textFrame: CGRect) {
|
||||
if let textLayout = self.textNode.cachedLayout, !textLayout.spoilers.isEmpty {
|
||||
if self.spoilerTextNode == nil {
|
||||
let spoilerTextNode = ImmediateTextNode()
|
||||
spoilerTextNode.attributedText = textNode.attributedText
|
||||
spoilerTextNode.linkHighlightColor = UIColor(rgb: 0x5ac8fa, alpha: 0.2)
|
||||
spoilerTextNode.displaySpoilers = true
|
||||
spoilerTextNode.isHidden = false
|
||||
spoilerTextNode.alpha = 0.0
|
||||
spoilerTextNode.isUserInteractionEnabled = false
|
||||
|
||||
self.spoilerTextNode = spoilerTextNode
|
||||
self.textNode.supernode?.insertSubnode(spoilerTextNode, aboveSubnode: self.textNode)
|
||||
|
||||
let dustNode = InvisibleInkDustNode(textNode: spoilerTextNode)
|
||||
self.dustNode = dustNode
|
||||
spoilerTextNode.supernode?.insertSubnode(dustNode, aboveSubnode: spoilerTextNode)
|
||||
|
||||
}
|
||||
if let dustNode = self.dustNode {
|
||||
dustNode.update(size: textFrame.size, color: .white, rects: textLayout.spoilers.map { $0.offsetBy(dx: 3.0, dy: 3.0).insetBy(dx: 0.0, dy: 1.0) })
|
||||
dustNode.frame = textFrame.insetBy(dx: -3.0, dy: -3.0).offsetBy(dx: 0.0, dy: 3.0)
|
||||
}
|
||||
} else {
|
||||
if let spoilerTextNode = self.spoilerTextNode {
|
||||
self.spoilerTextNode = nil
|
||||
spoilerTextNode.removeFromSupernode()
|
||||
}
|
||||
if let dustNode = self.dustNode {
|
||||
self.dustNode = nil
|
||||
dustNode.removeFromSupernode()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func setWebPage(_ webPage: TelegramMediaWebpage, media: Media) {
|
||||
self.currentWebPageAndMedia = (webPage, media)
|
||||
}
|
||||
@ -763,7 +802,9 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll
|
||||
let sideInset: CGFloat = 8.0 + leftInset
|
||||
let topInset: CGFloat = 8.0
|
||||
let textBottomInset: CGFloat = 8.0
|
||||
let textSize = self.textNode.updateLayout(CGSize(width: width - sideInset * 2.0, height: CGFloat.greatestFiniteMagnitude))
|
||||
|
||||
let constrainSize = CGSize(width: width - sideInset * 2.0, height: CGFloat.greatestFiniteMagnitude)
|
||||
let textSize = self.textNode.updateLayout(constrainSize)
|
||||
|
||||
var textOffset: CGFloat = 0.0
|
||||
if displayCaption {
|
||||
@ -809,8 +850,14 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll
|
||||
}
|
||||
}
|
||||
textFrame = CGRect(origin: CGPoint(x: sideInset, y: topInset + textOffset), size: textSize)
|
||||
|
||||
self.updateSpoilers(textFrame: textFrame)
|
||||
|
||||
let _ = self.spoilerTextNode?.updateLayout(constrainSize)
|
||||
|
||||
if self.textNode.frame != textFrame {
|
||||
self.textNode.frame = textFrame
|
||||
self.spoilerTextNode?.frame = textFrame
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -764,6 +764,12 @@ final class ChatImageGalleryItemNode: ZoomableContentGalleryItemNode {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override func adjustForPreviewing() {
|
||||
super.adjustForPreviewing()
|
||||
|
||||
self.recognitionOverlayContentNode.isHidden = true
|
||||
}
|
||||
}
|
||||
|
||||
/*private func tileRectForImage(_ mappedImage: CGImage, rect: CGRect) -> CGRect {
|
||||
|
@ -276,9 +276,9 @@ public struct RecognizedContent: Codable {
|
||||
}
|
||||
}
|
||||
|
||||
private func recognizeContent(in image: UIImage) -> Signal<[RecognizedContent], NoError> {
|
||||
private func recognizeContent(in image: UIImage?) -> Signal<[RecognizedContent], NoError> {
|
||||
if #available(iOS 11.0, *) {
|
||||
guard let cgImage = image.cgImage else {
|
||||
guard let cgImage = image?.cgImage else {
|
||||
return .complete()
|
||||
}
|
||||
return Signal { subscriber in
|
||||
@ -339,13 +339,15 @@ public func recognizedContent(postbox: Postbox, image: @escaping () -> UIImage?,
|
||||
|> mapToSignal { cachedContent -> Signal<[RecognizedContent], NoError> in
|
||||
if let cachedContent = cachedContent {
|
||||
return .single(cachedContent.results)
|
||||
} else if let image = image() {
|
||||
return recognizeContent(in: image)
|
||||
|> beforeNext { results in
|
||||
let _ = updateCachedImageRecognizedContent(postbox: postbox, messageId: messageId, content: CachedImageRecognizedContent(results: results)).start()
|
||||
}
|
||||
} else {
|
||||
return .single([])
|
||||
return (.complete()
|
||||
|> delay(0.3, queue: Queue.concurrentDefaultQueue()))
|
||||
|> then(
|
||||
recognizeContent(in: image())
|
||||
|> beforeNext { results in
|
||||
let _ = updateCachedImageRecognizedContent(postbox: postbox, messageId: messageId, content: CachedImageRecognizedContent(results: results)).start()
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -60,6 +60,8 @@ public class InvisibleInkDustNode: ASDisplayNode {
|
||||
|
||||
public var isRevealedUpdated: (Bool) -> Void = { _ in }
|
||||
|
||||
public var isRevealed = false
|
||||
|
||||
public init(textNode: TextNode) {
|
||||
self.textNode = textNode
|
||||
|
||||
@ -141,13 +143,12 @@ public class InvisibleInkDustNode: ASDisplayNode {
|
||||
self.view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.tap(_:))))
|
||||
}
|
||||
|
||||
private var revealed = false
|
||||
@objc private func tap(_ gestureRecognizer: UITapGestureRecognizer) {
|
||||
guard let (size, _, _) = self.currentParams, !self.revealed else {
|
||||
guard let (size, _, _) = self.currentParams, !self.isRevealed else {
|
||||
return
|
||||
}
|
||||
|
||||
self.revealed = true
|
||||
self.isRevealed = true
|
||||
|
||||
let position = gestureRecognizer.location(in: self.view)
|
||||
self.emitterLayer?.setValue(true, forKeyPath: "emitterBehaviors.fingerAttractor.enabled")
|
||||
@ -185,8 +186,11 @@ public class InvisibleInkDustNode: ASDisplayNode {
|
||||
self.emitterMaskFillNode.layer.removeAllAnimations()
|
||||
}
|
||||
|
||||
Queue.mainQueue().after(4.0 * UIView.animationDurationFactor()) {
|
||||
self.revealed = false
|
||||
|
||||
let textLength = CGFloat((self.textNode?.cachedLayout?.attributedString?.string ?? "").count)
|
||||
let timeToRead = min(45.0, ceil(max(4.0, textLength * 0.04)))
|
||||
Queue.mainQueue().after(timeToRead * UIView.animationDurationFactor()) {
|
||||
self.isRevealed = false
|
||||
self.isRevealedUpdated(false)
|
||||
|
||||
let transition = ContainedViewLayoutTransition.animated(duration: 0.4, curve: .linear)
|
||||
|
@ -69,7 +69,7 @@ public final class SolidRoundedButtonNode: ASDisplayNode {
|
||||
|
||||
public var icon: UIImage? {
|
||||
didSet {
|
||||
self.iconNode.image = icon
|
||||
self.iconNode.image = generateTintedImage(image: self.iconNode.image, color: self.theme.foregroundColor)
|
||||
}
|
||||
}
|
||||
|
||||
@ -111,7 +111,7 @@ public final class SolidRoundedButtonNode: ASDisplayNode {
|
||||
|
||||
self.iconNode = ASImageNode()
|
||||
self.iconNode.displaysAsynchronously = false
|
||||
self.iconNode.image = icon
|
||||
self.iconNode.image = generateTintedImage(image: icon, color: self.theme.foregroundColor)
|
||||
|
||||
super.init()
|
||||
|
||||
@ -215,6 +215,8 @@ public final class SolidRoundedButtonNode: ASDisplayNode {
|
||||
self.titleNode.attributedText = NSAttributedString(string: self.title ?? "", font: self.font == .bold ? Font.semibold(self.fontSize) : Font.regular(self.fontSize), textColor: theme.foregroundColor)
|
||||
self.subtitleNode.attributedText = NSAttributedString(string: self.subtitle ?? "", font: Font.regular(14.0), textColor: theme.foregroundColor)
|
||||
|
||||
self.iconNode.image = generateTintedImage(image: self.iconNode.image, color: theme.foregroundColor)
|
||||
|
||||
if let width = self.validLayout {
|
||||
_ = self.updateLayout(width: width, transition: .immediate)
|
||||
}
|
||||
|
@ -10244,6 +10244,9 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
return nil
|
||||
}
|
||||
}
|
||||
controller.getCaptionPanelView = { [weak self] in
|
||||
return self?.getCaptionPanelView()
|
||||
}
|
||||
strongSelf.effectiveNavigationController?.pushViewController(controller)
|
||||
}
|
||||
}, presentSelectionLimitExceeded: {
|
||||
@ -10350,6 +10353,9 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
return nil
|
||||
}
|
||||
}
|
||||
controller.getCaptionPanelView = { [weak self] in
|
||||
return self?.getCaptionPanelView()
|
||||
}
|
||||
strongSelf.present(controller, in: .window(.root), with: ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
|
||||
}
|
||||
})
|
||||
|
@ -460,7 +460,9 @@ class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
override func tapActionAtPoint(_ point: CGPoint, gesture: TapLongTapOrDoubleTapGesture, isEstimating: Bool) -> ChatMessageBubbleContentTapAction {
|
||||
let textNodeFrame = self.textNode.frame
|
||||
if let (index, attributes) = self.textNode.attributesAtPoint(CGPoint(x: point.x - textNodeFrame.minX, y: point.y - textNodeFrame.minY)) {
|
||||
if let url = attributes[NSAttributedString.Key(rawValue: TelegramTextAttributes.URL)] as? String {
|
||||
if let _ = attributes[NSAttributedString.Key(rawValue: TelegramTextAttributes.Spoiler)], !(self.dustNode?.isRevealed ?? true) {
|
||||
return .none
|
||||
} else if let url = attributes[NSAttributedString.Key(rawValue: TelegramTextAttributes.URL)] as? String {
|
||||
var concealed = true
|
||||
if let (attributeText, fullText) = self.textNode.attributeSubstring(name: TelegramTextAttributes.URL, index: index) {
|
||||
concealed = !doesUrlMatchText(url: url, text: attributeText, fullText: fullText)
|
||||
@ -517,6 +519,7 @@ class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
override func updateTouchesAtPoint(_ point: CGPoint?) {
|
||||
if let item = self.item {
|
||||
var rects: [CGRect]?
|
||||
var spoilerRects: [CGRect]?
|
||||
if let point = point {
|
||||
let textNodeFrame = self.textNode.frame
|
||||
if let (index, attributes) = self.textNode.attributesAtPoint(CGPoint(x: point.x - textNodeFrame.minX, y: point.y - textNodeFrame.minY)) {
|
||||
@ -535,10 +538,15 @@ class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
break
|
||||
}
|
||||
}
|
||||
if let _ = attributes[NSAttributedString.Key(rawValue: TelegramTextAttributes.Spoiler)] {
|
||||
spoilerRects = self.textNode.attributeRects(name: TelegramTextAttributes.Spoiler, at: index)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let rects = rects {
|
||||
if let spoilerRects = spoilerRects, !spoilerRects.isEmpty, !(self.dustNode?.isRevealed ?? true) {
|
||||
|
||||
} else if let rects = rects {
|
||||
let linkHighlightingNode: LinkHighlightingNode
|
||||
if let current = self.linkHighlightingNode {
|
||||
linkHighlightingNode = current
|
||||
|
@ -31,9 +31,9 @@ final class ChatTextInputMenu {
|
||||
UIMenuItem(title: self.stringItalic, action: Selector(("formatAttributesItalic:"))),
|
||||
UIMenuItem(title: self.stringMonospace, action: Selector(("formatAttributesMonospace:"))),
|
||||
UIMenuItem(title: self.stringLink, action: Selector(("formatAttributesLink:"))),
|
||||
UIMenuItem(title: self.stringSpoiler, action: Selector(("formatAttributesSpoiler:"))),
|
||||
UIMenuItem(title: self.stringStrikethrough, action: Selector(("formatAttributesStrikethrough:"))),
|
||||
UIMenuItem(title: self.stringUnderline, action: Selector(("formatAttributesUnderline:"))),
|
||||
UIMenuItem(title: self.stringSpoiler, action: Selector(("formatAttributesSpoiler:")))
|
||||
UIMenuItem(title: self.stringUnderline, action: Selector(("formatAttributesUnderline:")))
|
||||
]
|
||||
}
|
||||
|
||||
|
@ -984,7 +984,7 @@ private func infoItems(data: PeerInfoScreenData?, context: AccountContext, prese
|
||||
}
|
||||
|
||||
if let aboutText = aboutText {
|
||||
items[.peerInfo]!.append(PeerInfoScreenLabeledValueItem(id: ItemAbout, label: presentationData.strings.Channel_AboutItem, text: aboutText, textColor: .primary, textBehavior: .multiLine(maxLines: 100, enabledEntities: enabledPublicBioEntities), action: nil, longTapAction: bioContextAction, linkItemAction: bioLinkAction, requestLayout: {
|
||||
items[.peerInfo]!.append(PeerInfoScreenLabeledValueItem(id: ItemAbout, label: presentationData.strings.Channel_Info_Description, text: aboutText, textColor: .primary, textBehavior: .multiLine(maxLines: 100, enabledEntities: enabledPublicBioEntities), action: nil, longTapAction: bioContextAction, linkItemAction: bioLinkAction, requestLayout: {
|
||||
interaction.requestLayout()
|
||||
}))
|
||||
}
|
||||
@ -1034,7 +1034,7 @@ private func infoItems(data: PeerInfoScreenData?, context: AccountContext, prese
|
||||
}
|
||||
|
||||
if let aboutText = aboutText {
|
||||
items[.peerInfo]!.append(PeerInfoScreenLabeledValueItem(id: 0, label: presentationData.strings.PeerInfo_GroupAboutItem, text: aboutText, textColor: .primary, textBehavior: .multiLine(maxLines: 100, enabledEntities: enabledPublicBioEntities), action: nil, longTapAction: bioContextAction, linkItemAction: bioLinkAction, requestLayout: {
|
||||
items[.peerInfo]!.append(PeerInfoScreenLabeledValueItem(id: 0, label: presentationData.strings.Channel_Info_Description, text: aboutText, textColor: .primary, textBehavior: .multiLine(maxLines: 100, enabledEntities: enabledPublicBioEntities), action: nil, longTapAction: bioContextAction, linkItemAction: bioLinkAction, requestLayout: {
|
||||
interaction.requestLayout()
|
||||
}))
|
||||
}
|
||||
|
@ -86,7 +86,7 @@ public func textAttributedStringForStateText(_ stateText: NSAttributedString, fo
|
||||
result.addAttribute(NSAttributedString.Key.underlineStyle, value: NSUnderlineStyle.single.rawValue as NSNumber, range: range)
|
||||
} else if key == ChatTextInputAttributes.spoiler {
|
||||
result.addAttribute(key, value: value, range: range)
|
||||
result.addAttribute(NSAttributedString.Key.backgroundColor, value: textColor.withAlphaComponent(0.15), range: fullRange)
|
||||
result.addAttribute(NSAttributedString.Key.backgroundColor, value: textColor.withAlphaComponent(0.15), range: range)
|
||||
}
|
||||
}
|
||||
|
||||
@ -472,7 +472,7 @@ public func refreshChatTextInputAttributes(_ textNode: ASEditableTextNode, theme
|
||||
textNode.textView.textStorage.addAttribute(NSAttributedString.Key.underlineStyle, value: NSUnderlineStyle.single.rawValue as NSNumber, range: range)
|
||||
} else if key == ChatTextInputAttributes.spoiler {
|
||||
textNode.textView.textStorage.addAttribute(key, value: value, range: range)
|
||||
textNode.textView.textStorage.addAttribute(NSAttributedString.Key.backgroundColor, value: theme.chat.inputPanel.primaryTextColor.withAlphaComponent(0.15), range: fullRange)
|
||||
textNode.textView.textStorage.addAttribute(NSAttributedString.Key.backgroundColor, value: theme.chat.inputPanel.primaryTextColor.withAlphaComponent(0.15), range: range)
|
||||
}
|
||||
}
|
||||
|
||||
@ -564,7 +564,7 @@ public func refreshGenericTextInputAttributes(_ textNode: ASEditableTextNode, th
|
||||
textNode.textView.textStorage.addAttribute(NSAttributedString.Key.underlineStyle, value: NSUnderlineStyle.single.rawValue as NSNumber, range: range)
|
||||
} else if key == ChatTextInputAttributes.spoiler {
|
||||
textNode.textView.textStorage.addAttribute(key, value: value, range: range)
|
||||
textNode.textView.textStorage.addAttribute(NSAttributedString.Key.backgroundColor, value: theme.chat.inputPanel.primaryTextColor.withAlphaComponent(0.15), range: fullRange)
|
||||
textNode.textView.textStorage.addAttribute(NSAttributedString.Key.backgroundColor, value: UIColor.clear, range: range)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -312,11 +312,14 @@ private func galleryItems(account: Account, results: [ChatContextResult], curren
|
||||
return (galleryItems, focusItem)
|
||||
}
|
||||
|
||||
func presentLegacyWebSearchGallery(context: AccountContext, peer: EnginePeer?, chatLocation: ChatLocation?, presentationData: PresentationData, results: [ChatContextResult], current: ChatContextResult, selectionContext: TGMediaSelectionContext?, editingContext: TGMediaEditingContext, updateHiddenMedia: @escaping (String?) -> Void, initialLayout: ContainerViewLayout?, transitionHostView: @escaping () -> UIView?, transitionView: @escaping (ChatContextResult) -> UIView?, completed: @escaping (ChatContextResult) -> Void, presentStickers: ((@escaping (TelegramMediaFile, Bool, UIView, CGRect) -> Void) -> TGPhotoPaintStickersScreen?)?, present: (ViewController, Any?) -> Void) {
|
||||
func presentLegacyWebSearchGallery(context: AccountContext, peer: EnginePeer?, chatLocation: ChatLocation?, presentationData: PresentationData, results: [ChatContextResult], current: ChatContextResult, selectionContext: TGMediaSelectionContext?, editingContext: TGMediaEditingContext, updateHiddenMedia: @escaping (String?) -> Void, initialLayout: ContainerViewLayout?, transitionHostView: @escaping () -> UIView?, transitionView: @escaping (ChatContextResult) -> UIView?, completed: @escaping (ChatContextResult) -> Void, presentStickers: ((@escaping (TelegramMediaFile, Bool, UIView, CGRect) -> Void) -> TGPhotoPaintStickersScreen?)?, getCaptionPanelView: @escaping () -> TGCaptionPanelView?, present: (ViewController, Any?) -> Void) {
|
||||
let legacyController = LegacyController(presentation: .custom, theme: presentationData.theme, initialLayout: nil)
|
||||
legacyController.statusBar.statusBarStyle = presentationData.theme.rootController.statusBarStyle.style
|
||||
|
||||
let paintStickersContext = LegacyPaintStickersContext(context: context)
|
||||
paintStickersContext.captionPanelView = {
|
||||
return getCaptionPanelView()
|
||||
}
|
||||
paintStickersContext.presentStickersController = { completion in
|
||||
if let presentStickers = presentStickers {
|
||||
return presentStickers({ file, animated, view, rect in
|
||||
|
@ -155,6 +155,12 @@ public final class WebSearchController: ViewController {
|
||||
}
|
||||
}
|
||||
|
||||
public var getCaptionPanelView: () -> TGCaptionPanelView? = { return nil } {
|
||||
didSet {
|
||||
self.controllerNode.getCaptionPanelView = self.getCaptionPanelView
|
||||
}
|
||||
}
|
||||
|
||||
public init(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, peer: EnginePeer?, chatLocation: ChatLocation?, configuration: SearchBotsConfiguration, mode: WebSearchControllerMode) {
|
||||
self.context = context
|
||||
self.mode = mode
|
||||
|
@ -170,6 +170,7 @@ class WebSearchControllerNode: ASDisplayNode {
|
||||
var dismissInput: (() -> Void)?
|
||||
|
||||
var presentStickers: ((@escaping (TelegramMediaFile, Bool, UIView, CGRect) -> Void) -> TGPhotoPaintStickersScreen?)?
|
||||
var getCaptionPanelView: () -> TGCaptionPanelView? = { return nil }
|
||||
|
||||
init(context: AccountContext, presentationData: PresentationData, controllerInteraction: WebSearchControllerInteraction, peer: EnginePeer?, chatLocation: ChatLocation?, mode: WebSearchMode) {
|
||||
self.context = context
|
||||
@ -700,7 +701,7 @@ class WebSearchControllerNode: ASDisplayNode {
|
||||
strongSelf.controllerInteraction.sendSelected(results, result)
|
||||
strongSelf.cancel?()
|
||||
}
|
||||
}, presentStickers: self.presentStickers, present: present)
|
||||
}, presentStickers: self.presentStickers, getCaptionPanelView: self.getCaptionPanelView, present: present)
|
||||
}
|
||||
} else {
|
||||
if let results = self.currentProcessedResults?.results {
|
||||
|
Loading…
x
Reference in New Issue
Block a user