Add global search query cache

This commit is contained in:
Isaac
2024-05-28 17:50:56 +04:00
parent afb417334c
commit 7ea8fa0a1e
9 changed files with 333 additions and 57 deletions

View File

@@ -1073,6 +1073,14 @@ private func addAttachment(attachment: UIImage, line: InteractiveTextNodeLine, a
}
open class InteractiveTextNode: ASDisplayNode, TextNodeProtocol, UIGestureRecognizerDelegate {
public final class AnimationArguments {
public let spoilerExpandRect: CGRect?
public init(spoilerExpandRect: CGRect?) {
self.spoilerExpandRect = spoilerExpandRect
}
}
public struct RenderContentTypes: OptionSet {
public var rawValue: Int
@@ -1106,7 +1114,7 @@ open class InteractiveTextNode: ASDisplayNode, TextNodeProtocol, UIGestureRecogn
public var canHandleTapAtPoint: ((CGPoint) -> Bool)?
public var requestToggleBlockCollapsed: ((Int) -> Void)?
public var requestDisplayContentsUnderSpoilers: (() -> Void)?
public var requestDisplayContentsUnderSpoilers: ((CGPoint?) -> Void)?
private var tapRecognizer: UITapGestureRecognizer?
public var currentText: NSAttributedString? {
@@ -1676,7 +1684,7 @@ open class InteractiveTextNode: ASDisplayNode, TextNodeProtocol, UIGestureRecogn
return calculateLayoutV2(attributedString: attributedString, minimumNumberOfLines: minimumNumberOfLines, maximumNumberOfLines: maximumNumberOfLines, truncationType: truncationType, backgroundColor: backgroundColor, constrainedSize: constrainedSize, alignment: alignment, verticalAlignment: verticalAlignment, lineSpacingFactor: lineSpacingFactor, cutout: cutout, insets: insets, lineColor: lineColor, textShadowColor: textShadowColor, textShadowBlur: textShadowBlur, textStroke: textStroke, displayContentsUnderSpoilers: displayContentsUnderSpoilers, customTruncationToken: customTruncationToken, expandedBlocks: expandedBlocks)
}
private func updateContentItems(animation: ListViewItemUpdateAnimation) {
private func updateContentItems(animation: ListViewItemUpdateAnimation, animationArguments: AnimationArguments?) {
guard let cachedLayout = self.cachedLayout else {
return
}
@@ -1729,8 +1737,15 @@ open class InteractiveTextNode: ASDisplayNode, TextNodeProtocol, UIGestureRecogn
var contentItemAnimation = animation
let contentItemLayer: TextContentItemLayer
var itemSpoilerExpandRect: CGRect?
var itemAnimateContents = animateContents && contentItemAnimation.isAnimated
if let current = self.contentItemLayers[itemId] {
contentItemLayer = current
if animation.isAnimated, let spoilerExpandRect = animationArguments?.spoilerExpandRect {
itemSpoilerExpandRect = spoilerExpandRect.offsetBy(dx: -contentItemFrame.minX, dy: -contentItemFrame.minY)
itemAnimateContents = true
}
} else {
contentItemAnimation = .None
contentItemLayer = TextContentItemLayer()
@@ -1738,7 +1753,13 @@ open class InteractiveTextNode: ASDisplayNode, TextNodeProtocol, UIGestureRecogn
self.layer.addSublayer(contentItemLayer)
}
contentItemLayer.update(item: contentItem, animation: contentItemAnimation, synchronously: synchronous, animateContents: animateContents && contentItemAnimation.isAnimated)
contentItemLayer.update(
item: contentItem,
animation: contentItemAnimation,
synchronously: synchronous,
animateContents: itemAnimateContents,
spoilerExpandRect: itemSpoilerExpandRect
)
contentItemAnimation.animator.updateFrame(layer: contentItemLayer, frame: contentItemFrame, completion: nil)
}
@@ -1779,7 +1800,7 @@ open class InteractiveTextNode: ASDisplayNode, TextNodeProtocol, UIGestureRecogn
let point = recognizer.location(in: self.view)
if let cachedLayout = self.cachedLayout, !cachedLayout.displayContentsUnderSpoilers, let (_, attributes) = self.attributesAtPoint(point) {
if attributes[NSAttributedString.Key(rawValue: "Attribute__Spoiler")] != nil || attributes[NSAttributedString.Key(rawValue: "TelegramSpoiler")] != nil {
self.requestDisplayContentsUnderSpoilers?()
self.requestDisplayContentsUnderSpoilers?(point)
return
}
}
@@ -1789,7 +1810,7 @@ open class InteractiveTextNode: ASDisplayNode, TextNodeProtocol, UIGestureRecogn
}
}
public static func asyncLayout(_ maybeNode: InteractiveTextNode?) -> (InteractiveTextNodeLayoutArguments) -> (InteractiveTextNodeLayout, (ListViewItemUpdateAnimation) -> InteractiveTextNode) {
public static func asyncLayout(_ maybeNode: InteractiveTextNode?) -> (InteractiveTextNodeLayoutArguments) -> (InteractiveTextNodeLayout, (ListViewItemUpdateAnimation, AnimationArguments?) -> InteractiveTextNode) {
let existingLayout: InteractiveTextNodeLayout? = maybeNode?.cachedLayout
return { arguments in
@@ -1831,10 +1852,10 @@ open class InteractiveTextNode: ASDisplayNode, TextNodeProtocol, UIGestureRecogn
let node = maybeNode ?? InteractiveTextNode()
return (layout, { animation in
return (layout, { animation, animationArguments in
if node.cachedLayout !== layout {
node.cachedLayout = layout
node.updateContentItems(animation: animation)
node.updateContentItems(animation: animation, animationArguments: animationArguments)
}
return node
@@ -2202,7 +2223,13 @@ final class TextContentItemLayer: SimpleLayer {
fatalError("init(coder:) has not been implemented")
}
func update(item: TextContentItem, animation: ListViewItemUpdateAnimation, synchronously: Bool = false, animateContents: Bool = false) {
func update(
item: TextContentItem,
animation: ListViewItemUpdateAnimation,
synchronously: Bool,
animateContents: Bool,
spoilerExpandRect: CGRect?
) {
self.item = item
let contentFrame = CGRect(origin: CGPoint(), size: item.size)
@@ -2241,7 +2268,13 @@ final class TextContentItemLayer: SimpleLayer {
return
}
self.isAnimating = false
self.update(item: item, animation: .None, synchronously: true)
self.update(
item: item,
animation: .None,
synchronously: true,
animateContents: false,
spoilerExpandRect: nil
)
})
} else {
blockBackgroundView.layer.frame = blockBackgroundFrame
@@ -2362,13 +2395,61 @@ final class TextContentItemLayer: SimpleLayer {
self.renderNode.params = RenderParams(size: contentFrame.size, item: item, mask: staticContentMask)
if synchronously {
let previousContents = self.renderNode.layer.contents
self.renderNode.displayImmediately()
if animateContents, let previousContents {
animation.transition.animateContents(layer: self.renderNode.layer, from: previousContents)
if let spoilerExpandRect {
let _ = spoilerExpandRect
self.renderNode.displayImmediately()
let maskFrame = self.renderNode.frame
let maskLayer = SimpleLayer()
maskLayer.frame = maskFrame
self.addSublayer(maskLayer)
let maskGradientLayer = SimpleGradientLayer()
maskGradientLayer.frame = CGRect(origin: CGPoint(), size: maskFrame.size)
setupSpoilerExpansionMaskGradient(
gradientLayer: maskGradientLayer,
centerLocation: CGPoint(
x: 0.5,
y: 0.5
),
radius: CGSize(
width: 1.5,
height: 1.5
),
inverse: false
)
} else {
let previousContents = self.renderNode.layer.contents
self.renderNode.displayImmediately()
if animateContents, let previousContents {
animation.transition.animateContents(layer: self.renderNode.layer, from: previousContents)
}
}
} else {
self.renderNode.setNeedsDisplay()
}
}
}
private func setupSpoilerExpansionMaskGradient(gradientLayer: SimpleGradientLayer, centerLocation: CGPoint, radius: CGSize, inverse: Bool) {
let startAlpha: CGFloat = inverse ? 0.0 : 1.0
let endAlpha: CGFloat = inverse ? 1.0 : 0.0
let locations: [CGFloat] = [0.0, 0.7, 0.95, 1.0]
let colors: [CGColor] = [
UIColor(rgb: 0xff0000, alpha: startAlpha).cgColor,
UIColor(rgb: 0xff0000, alpha: startAlpha).cgColor,
UIColor(rgb: 0xff0000, alpha: endAlpha).cgColor,
UIColor(rgb: 0xff0000, alpha: endAlpha).cgColor
]
gradientLayer.type = .radial
gradientLayer.colors = colors
gradientLayer.locations = locations.map { $0 as NSNumber }
gradientLayer.startPoint = centerLocation
let endEndPoint = CGPoint(x: (gradientLayer.startPoint.x + radius.width) * 1.0, y: (gradientLayer.startPoint.y + radius.height) * 1.0)
gradientLayer.endPoint = endEndPoint
}

View File

@@ -65,6 +65,7 @@ public final class InteractiveTextNodeWithEntities {
public let textColor: UIColor
public let spoilerEffectColor: UIColor
public let animation: ListViewItemUpdateAnimation
public let animationArguments: InteractiveTextNode.AnimationArguments?
public init(
context: AccountContext,
@@ -74,7 +75,8 @@ public final class InteractiveTextNodeWithEntities {
attemptSynchronous: Bool,
textColor: UIColor,
spoilerEffectColor: UIColor,
animation: ListViewItemUpdateAnimation
animation: ListViewItemUpdateAnimation,
animationArguments: InteractiveTextNode.AnimationArguments?
) {
self.context = context
self.cache = cache
@@ -84,6 +86,7 @@ public final class InteractiveTextNodeWithEntities {
self.textColor = textColor
self.spoilerEffectColor = spoilerEffectColor
self.animation = animation
self.animationArguments = animationArguments
}
public func withUpdatedPlaceholderColor(_ color: UIColor) -> Arguments {
@@ -95,7 +98,8 @@ public final class InteractiveTextNodeWithEntities {
attemptSynchronous: self.attemptSynchronous,
textColor: self.textColor,
spoilerEffectColor: self.spoilerEffectColor,
animation: self.animation
animation: self.animation,
animationArguments: self.animationArguments
)
}
}
@@ -113,6 +117,7 @@ public final class InteractiveTextNodeWithEntities {
private var inlineStickerItemLayers: [InlineStickerItemLayer.Key: InlineStickerItemLayerData] = [:]
private var dustEffectNodes: [Int: InvisibleInkDustNode] = [:]
private var displayContentsUnderSpoilers: Bool?
private var enableLooping: Bool = true
@@ -215,11 +220,22 @@ public final class InteractiveTextNodeWithEntities {
return (layout, { applyArguments in
let animation: ListViewItemUpdateAnimation = applyArguments?.animation ?? .None
let result = apply(animation)
let result = apply(animation, applyArguments?.animationArguments)
if let maybeNode = maybeNode {
if let applyArguments = applyArguments {
maybeNode.updateInteractiveContents(context: applyArguments.context, cache: applyArguments.cache, renderer: applyArguments.renderer, textLayout: layout, placeholderColor: applyArguments.placeholderColor, attemptSynchronousLoad: false, textColor: applyArguments.textColor, spoilerEffectColor: applyArguments.spoilerEffectColor, animation: animation)
maybeNode.updateInteractiveContents(
context: applyArguments.context,
cache: applyArguments.cache,
renderer: applyArguments.renderer,
textLayout: layout,
placeholderColor: applyArguments.placeholderColor,
attemptSynchronousLoad: false,
textColor: applyArguments.textColor,
spoilerEffectColor: applyArguments.spoilerEffectColor,
animation: animation,
animationArguments: applyArguments.animationArguments
)
}
return maybeNode
@@ -227,7 +243,18 @@ public final class InteractiveTextNodeWithEntities {
let resultNode = InteractiveTextNodeWithEntities(textNode: result)
if let applyArguments = applyArguments {
resultNode.updateInteractiveContents(context: applyArguments.context, cache: applyArguments.cache, renderer: applyArguments.renderer, textLayout: layout, placeholderColor: applyArguments.placeholderColor, attemptSynchronousLoad: false, textColor: applyArguments.textColor, spoilerEffectColor: applyArguments.spoilerEffectColor, animation: .None)
resultNode.updateInteractiveContents(
context: applyArguments.context,
cache: applyArguments.cache,
renderer: applyArguments.renderer,
textLayout: layout,
placeholderColor: applyArguments.placeholderColor,
attemptSynchronousLoad: false,
textColor: applyArguments.textColor,
spoilerEffectColor: applyArguments.spoilerEffectColor,
animation: .None,
animationArguments: nil
)
}
return resultNode
@@ -253,7 +280,8 @@ public final class InteractiveTextNodeWithEntities {
attemptSynchronousLoad: Bool,
textColor: UIColor,
spoilerEffectColor: UIColor,
animation: ListViewItemUpdateAnimation
animation: ListViewItemUpdateAnimation,
animationArguments: InteractiveTextNode.AnimationArguments?
) {
self.enableLooping = context.sharedContext.energyUsageSettings.loopEmoji
@@ -261,6 +289,8 @@ public final class InteractiveTextNodeWithEntities {
if let textLayout {
displayContentsUnderSpoilers = textLayout.displayContentsUnderSpoilers
}
let previousDisplayContentsUnderSpoilers = self.displayContentsUnderSpoilers
self.displayContentsUnderSpoilers = displayContentsUnderSpoilers
var nextIndexById: [Int64: Int] = [:]
var validIds: [InlineStickerItemLayer.Key] = []
@@ -345,7 +375,12 @@ public final class InteractiveTextNodeWithEntities {
wordRects: segment.spoilerWords.map { $0.1.offsetBy(dx: segmentItem.contentOffset.x + 3.0, dy: segmentItem.contentOffset.y + 3.0).insetBy(dx: 1.0, dy: 1.0) }
)
animation.transition.updateAlpha(node: dustEffectNode, alpha: displayContentsUnderSpoilers ? 0.0 : 1.0)
if let previousDisplayContentsUnderSpoilers, previousDisplayContentsUnderSpoilers != displayContentsUnderSpoilers, displayContentsUnderSpoilers, let currentSpoilerExpandRect = animationArguments?.spoilerExpandRect {
let spoilerLocalPosition = self.textNode.layer.convert(currentSpoilerExpandRect.center, to: dustEffectNode.layer)
dustEffectNode.revealAtLocation(spoilerLocalPosition)
} else {
dustEffectNode.update(revealed: displayContentsUnderSpoilers, animated: previousDisplayContentsUnderSpoilers != nil && animation.isAnimated)
}
}
}
}