Fix stickers search

This commit is contained in:
Ilya Laktyushin 2023-07-12 20:17:01 +02:00
parent e2afc7304c
commit 6c7b921030
9 changed files with 75 additions and 81 deletions

View File

@ -295,7 +295,6 @@ private final class StickerSelectionComponent: Component {
},
peekBehavior: stickerPeekBehavior
)
return searchContainerNode
},
contentIdUpdated: { _ in },

View File

@ -31,6 +31,8 @@ swift_library(
"//submodules/StickerResources:StickerResources",
"//submodules/AnimatedStickerNode:AnimatedStickerNode",
"//submodules/TelegramAnimatedStickerNode:TelegramAnimatedStickerNode",
"//submodules/TelegramUI/Components/EmojiTextAttachmentView",
"//submodules/TextFormat",
],
visibility = [
"//visibility:public",

View File

@ -1059,8 +1059,8 @@ private enum FeaturedSearchEntry: Identifiable, Comparable {
func item(context: AccountContext, theme: PresentationTheme, strings: PresentationStrings, interaction: StickerPaneSearchInteraction, inputNodeInteraction: ChatMediaInputNodeInteraction, itemContext: StickerPaneSearchGlobalItemContext) -> GridItem {
switch self {
case let .sticker(_, code, stickerItem, theme):
return StickerPaneSearchStickerItem(context: context, code: code, stickerItem: stickerItem, inputNodeInteraction: inputNodeInteraction, theme: theme, selected: { node, rect in
interaction.sendSticker(.standalone(media: stickerItem.file), node.view, rect)
return StickerPaneSearchStickerItem(context: context, theme: theme, code: code, stickerItem: stickerItem, inputNodeInteraction: inputNodeInteraction, selected: { node, layer, rect in
interaction.sendSticker(.standalone(media: stickerItem.file), node.view, layer, rect)
})
case let .global(_, info, topItems, installed, topSeparator):
return StickerPaneSearchGlobalItem(context: context, theme: theme, strings: strings, listAppearance: true, fillsRow: true, info: info, topItems: topItems, topSeparator: topSeparator, regularInsets: false, installed: installed, unread: false, open: {
@ -1201,7 +1201,7 @@ private final class FeaturedPaneSearchContentNode: ASDisplayNode {
|> deliverOnMainQueue).start(next: { _ in
})
}
}, sendSticker: { [weak self] file, sourceView, sourceRect in
}, sendSticker: { [weak self] file, sourceView, layer, sourceRect in
if let strongSelf = self {
let _ = strongSelf.sendSticker?(file, sourceView, sourceRect)
}
@ -1521,10 +1521,10 @@ private final class FeaturedPaneSearchContentNode: ASDisplayNode {
public final class StickerPaneSearchInteraction {
public let open: (StickerPackCollectionInfo) -> Void
public let install: (StickerPackCollectionInfo, [ItemCollectionItem], Bool) -> Void
public let sendSticker: (FileMediaReference, UIView, CGRect) -> Void
public let sendSticker: (FileMediaReference, UIView, CALayer, CGRect) -> Void
public let getItemIsPreviewed: (StickerPackItem) -> Bool
public init(open: @escaping (StickerPackCollectionInfo) -> Void, install: @escaping (StickerPackCollectionInfo, [ItemCollectionItem], Bool) -> Void, sendSticker: @escaping (FileMediaReference, UIView, CGRect) -> Void, getItemIsPreviewed: @escaping (StickerPackItem) -> Bool) {
public init(open: @escaping (StickerPackCollectionInfo) -> Void, install: @escaping (StickerPackCollectionInfo, [ItemCollectionItem], Bool) -> Void, sendSticker: @escaping (FileMediaReference, UIView, CALayer, CGRect) -> Void, getItemIsPreviewed: @escaping (StickerPackItem) -> Bool) {
self.open = open
self.install = install
self.sendSticker = sendSticker

View File

@ -11,6 +11,8 @@ import AccountContext
import AnimatedStickerNode
import TelegramAnimatedStickerNode
import ChatPresentationInterfaceState
import EmojiTextAttachmentView
import TextFormat
final class StickerPaneSearchStickerSection: GridSection {
let code: String
@ -50,10 +52,11 @@ final class StickerPaneSearchStickerSectionNode: ASDisplayNode {
super.init()
self.addSubnode(self.titleNode)
self.titleNode.attributedText = NSAttributedString(string: code, font: sectionTitleFont, textColor: theme.chat.inputMediaPanel.stickersSectionTextColor)
self.titleNode.maximumNumberOfLines = 1
self.titleNode.truncationMode = .byTruncatingTail
self.addSubnode(self.titleNode)
}
override func layout() {
@ -68,15 +71,17 @@ final class StickerPaneSearchStickerSectionNode: ASDisplayNode {
public final class StickerPaneSearchStickerItem: GridItem {
public let context: AccountContext
public let theme: PresentationTheme
public let code: String?
public let stickerItem: FoundStickerItem
public let selected: (ASDisplayNode, CGRect) -> Void
public let selected: (ASDisplayNode, CALayer, CGRect) -> Void
public let inputNodeInteraction: ChatMediaInputNodeInteraction
public let section: GridSection?
public init(context: AccountContext, code: String?, stickerItem: FoundStickerItem, inputNodeInteraction: ChatMediaInputNodeInteraction, theme: PresentationTheme, selected: @escaping (ASDisplayNode, CGRect) -> Void) {
public init(context: AccountContext, theme: PresentationTheme, code: String?, stickerItem: FoundStickerItem, inputNodeInteraction: ChatMediaInputNodeInteraction, selected: @escaping (ASDisplayNode, CALayer, CGRect) -> Void) {
self.context = context
self.theme = theme
self.stickerItem = stickerItem
self.inputNodeInteraction = inputNodeInteraction
self.selected = selected
@ -87,7 +92,7 @@ public final class StickerPaneSearchStickerItem: GridItem {
public func node(layout: GridNodeLayout, synchronousLoad: Bool) -> GridItemNode {
let node = StickerPaneSearchStickerItemNode()
node.inputNodeInteraction = self.inputNodeInteraction
node.setup(context: self.context, stickerItem: self.stickerItem, code: self.code)
node.setup(context: self.context, theme: self.theme, stickerItem: self.stickerItem, code: self.code)
node.selected = self.selected
return node
}
@ -98,7 +103,7 @@ public final class StickerPaneSearchStickerItem: GridItem {
return
}
node.inputNodeInteraction = self.inputNodeInteraction
node.setup(context: self.context, stickerItem: self.stickerItem, code: self.code)
node.setup(context: self.context, theme: self.theme, stickerItem: self.stickerItem, code: self.code)
node.selected = self.selected
}
}
@ -107,8 +112,7 @@ private let textFont = Font.regular(20.0)
public final class StickerPaneSearchStickerItemNode: GridItemNode {
private var currentState: (AccountContext, FoundStickerItem, CGSize)?
public let imageNode: TransformImageNode
public private(set) var animationNode: AnimatedStickerNode?
var itemLayer: InlineStickerItemLayer?
private let textNode: ASTextNode
private let stickerFetchedDisposable = MetaDisposable()
@ -124,22 +128,21 @@ public final class StickerPaneSearchStickerItemNode: GridItemNode {
private var isPlaying = false
public var inputNodeInteraction: ChatMediaInputNodeInteraction?
public var selected: ((ASDisplayNode, CGRect) -> Void)?
public var selected: ((ASDisplayNode, CALayer, CGRect) -> Void)?
public var stickerItem: FoundStickerItem? {
return self.currentState?.1
}
public override init() {
self.imageNode = TransformImageNode()
self.textNode = ASTextNode()
self.textNode.isUserInteractionEnabled = false
super.init()
self.addSubnode(self.imageNode)
self.addSubnode(self.textNode)
self.textNode.maximumNumberOfLines = 1
self.addSubnode(self.textNode)
}
deinit {
@ -149,39 +152,43 @@ public final class StickerPaneSearchStickerItemNode: GridItemNode {
public override func didLoad() {
super.didLoad()
self.imageNode.view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.imageNodeTap(_:))))
self.view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.imageNodeTap(_:))))
}
func setup(context: AccountContext, stickerItem: FoundStickerItem, code: String?) {
func setup(context: AccountContext, theme: PresentationTheme, stickerItem: FoundStickerItem, code: String?) {
if self.currentState == nil || self.currentState!.0 !== context || self.currentState!.1 != stickerItem {
self.textNode.attributedText = NSAttributedString(string: code ?? "", font: textFont, textColor: .black)
if let dimensions = stickerItem.file.dimensions {
if stickerItem.file.isAnimatedSticker || stickerItem.file.isVideoSticker {
if self.animationNode == nil {
let animationNode = DefaultAnimatedStickerNodeImpl()
animationNode.view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.imageNodeTap(_:))))
self.animationNode = animationNode
self.insertSubnode(animationNode, belowSubnode: self.textNode)
}
let dimensions = stickerItem.file.dimensions ?? PixelDimensions(width: 512, height: 512)
let fittedDimensions = dimensions.cgSize.aspectFitted(CGSize(width: 160.0, height: 160.0))
self.animationNode?.setup(source: AnimatedStickerResourceSource(account: context.account, resource: stickerItem.file.resource, isVideo: stickerItem.file.isVideoSticker), width: Int(fittedDimensions.width), height: Int(fittedDimensions.height), playbackMode: .loop, mode: .cached)
self.animationNode?.visibility = self.isVisibleInGrid && context.sharedContext.energyUsageSettings.loopStickers
self.stickerFetchedDisposable.set(freeMediaFileResourceInteractiveFetched(account: context.account, userLocation: .other, fileReference: stickerPackFileReference(stickerItem.file), resource: stickerItem.file.resource).start())
let file = stickerItem.file
let itemDimensions = file.dimensions?.cgSize ?? CGSize(width: 512.0, height: 512.0)
let playbackItemSize = CGSize(width: 96.0, height: 96.0)
let itemPlaybackSize = itemDimensions.aspectFitted(playbackItemSize)
let itemLayer: InlineStickerItemLayer
if let current = self.itemLayer {
itemLayer = current
itemLayer.dynamicColor = .white
} else {
if let animationNode = self.animationNode {
animationNode.visibility = false
self.animationNode = nil
animationNode.removeFromSupernode()
}
self.imageNode.setSignal(chatMessageSticker(account: context.account, userLocation: .other, file: stickerItem.file, small: true))
self.stickerFetchedDisposable.set(freeMediaFileResourceInteractiveFetched(account: context.account, userLocation: .other, fileReference: stickerPackFileReference(stickerItem.file), resource: chatMessageStickerResource(file: stickerItem.file, small: true)).start())
itemLayer = InlineStickerItemLayer(
context: context,
userLocation: .other,
attemptSynchronousLoad: false,
emoji: ChatTextInputTextCustomEmojiAttribute(interactivelySelectedFromPackId: nil, fileId: file.fileId.id, file: file),
file: file,
cache: context.animationCache,
renderer: context.animationRenderer,
placeholderColor: theme.chat.inputPanel.primaryTextColor.withMultipliedAlpha(0.1),
pointSize: itemPlaybackSize,
dynamicColor: .white
)
self.itemLayer = itemLayer
self.layer.insertSublayer(itemLayer, at: 0)
}
self.currentState = (context, stickerItem, dimensions.cgSize)
self.currentState = (context, stickerItem, itemDimensions)
self.setNeedsLayout()
}
self.updateVisibility()
}
}
@ -191,29 +198,26 @@ public final class StickerPaneSearchStickerItemNode: GridItemNode {
let bounds = self.bounds
let boundingSize = bounds.insetBy(dx: 6.0, dy: 6.0).size
if let (_, _, mediaDimensions) = self.currentState {
let imageSize = mediaDimensions.aspectFitted(boundingSize)
self.imageNode.asyncLayout()(TransformImageArguments(corners: ImageCorners(), imageSize: imageSize, boundingSize: imageSize, intrinsicInsets: UIEdgeInsets()))()
let imageFrame = CGRect(origin: CGPoint(x: floor((bounds.size.width - imageSize.width) / 2.0), y: (bounds.size.height - imageSize.height) / 2.0), size: imageSize)
self.imageNode.frame = imageFrame
if let animationNode = self.animationNode {
animationNode.frame = imageFrame
animationNode.updateLayout(size: imageSize)
if let (_, _, itemDimensions) = self.currentState {
let itemSize = itemDimensions.aspectFitted(boundingSize)
let itemFrame = CGRect(origin: CGPoint(x: floor((bounds.size.width - itemSize.width) / 2.0), y: (bounds.size.height - itemSize.height) / 2.0), size: itemSize)
if let itemLayer = self.itemLayer {
itemLayer.frame = itemFrame
}
let textSize = self.textNode.measure(CGSize(width: bounds.size.width - 24.0, height: CGFloat.greatestFiniteMagnitude))
self.textNode.frame = CGRect(origin: CGPoint(x: bounds.size.width - textSize.width, y: bounds.size.height - textSize.height), size: textSize)
}
}
@objc func imageNodeTap(_ recognizer: UITapGestureRecognizer) {
self.selected?(self, self.bounds)
guard let itemLayer = self.itemLayer else {
return
}
self.selected?(self, itemLayer, self.bounds)
}
public func transitionNode() -> ASDisplayNode? {
return self.imageNode
return self
}
public func updateVisibility() {
@ -222,9 +226,9 @@ public final class StickerPaneSearchStickerItemNode: GridItemNode {
}
let isPlaying = self.isVisibleInGrid && context.sharedContext.energyUsageSettings.loopStickers
if self.isPlaying != isPlaying {
if self.isPlaying != isPlaying, let itemLayer = self.itemLayer {
self.isPlaying = isPlaying
self.animationNode?.visibility = isPlaying
itemLayer.isVisibleForAnimations = isPlaying
}
}

View File

@ -89,8 +89,8 @@ private enum StickerSearchEntry: Identifiable, Comparable {
func item(context: AccountContext, theme: PresentationTheme, strings: PresentationStrings, interaction: StickerPaneSearchInteraction, inputNodeInteraction: ChatMediaInputNodeInteraction) -> GridItem {
switch self {
case let .sticker(_, code, stickerItem, theme):
return StickerPaneSearchStickerItem(context: context, code: code, stickerItem: stickerItem, inputNodeInteraction: inputNodeInteraction, theme: theme, selected: { node, rect in
interaction.sendSticker(.standalone(media: stickerItem.file), node.view, rect)
return StickerPaneSearchStickerItem(context: context, theme: theme, code: code, stickerItem: stickerItem, inputNodeInteraction: inputNodeInteraction, selected: { node, layer, rect in
interaction.sendSticker(.standalone(media: stickerItem.file), node.view, layer, rect)
})
case let .global(_, info, topItems, installed, topSeparator):
let itemContext = StickerPaneSearchGlobalItemContext()
@ -316,9 +316,10 @@ final class StickerPaneSearchContentNode: ASDisplayNode, PaneSearchContentNode {
|> deliverOnMainQueue).start(next: { _ in
})
}
}, sendSticker: { [weak self] file, sourceView, sourceRect in
if let strongSelf = self {
let _ = strongSelf.interaction.sendSticker(file, false, false, nil, false, sourceView, sourceRect, nil, [])
}, sendSticker: { [weak self] file, sourceView, sourceLayer, sourceRect in
if let self {
let sourceRect = sourceView.convert(sourceRect, to: self.view)
let _ = self.interaction.sendSticker(file, false, false, nil, false, self.view, sourceRect, sourceLayer, [])
}
}, getItemIsPreviewed: { item in
return inputNodeInteraction.previewedStickerPackItemFile?.id == item.file.id

View File

@ -743,10 +743,11 @@ public final class EntityKeyboardComponent: Component {
panelHideBehavior = .hideOnScroll
}
let isContentInFocus = component.isContentInFocus && self.searchComponent == nil
let pagerSize = self.pagerView.update(
transition: transition,
component: AnyComponent(PagerComponent(
isContentInFocus: component.isContentInFocus,
isContentInFocus: isContentInFocus,
contentInsets: component.containerInsets,
contents: contents,
contentTopPanels: contentTopPanels,
@ -801,7 +802,7 @@ public final class EntityKeyboardComponent: Component {
EntityKeyboardChildEnvironment(
theme: component.theme,
strings: component.strings,
isContentInFocus: component.isContentInFocus,
isContentInFocus: isContentInFocus,
getContentActiveItemUpdated: { id in
if id == AnyHashable("gifs") {
return gifsContentItemIdUpdated
@ -950,7 +951,7 @@ public final class EntityKeyboardComponent: Component {
}
)
}
//self.state?.updated(transition: Transition(animation: .curve(duration: 0.3, curve: .spring)))
component.hideInputUpdated(true, true, Transition(animation: .curve(duration: 0.3, curve: .spring)))
}
}

View File

@ -295,12 +295,7 @@ final class StickersResultPanelComponent: Component {
let controller = PeekController(presentationData: presentationData, content: content, sourceView: {
return (sourceView, sourceRect)
})
// controller.visibilityUpdated = { [weak self] visible in
// self?.previewingStickersPromise.set(visible)
// }
component.presentInGlobalOverlay(controller)
// strongSelf.peekController = controller
// strongSelf.getControllerInteraction?()?.presentGlobalOverlayController(controller, nil)
return controller
}
return nil

View File

@ -2160,8 +2160,6 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
})
} else if let sourceNode = sourceView.asyncdisplaykit_node as? HorizontalStickerGridItemNode {
strongSelf.chatDisplayNode.messageTransitionNode.add(correlationId: correlationId, source: .stickerMediaInput(input: .mediaPanel(itemNode: sourceNode), replyPanel: replyPanel), initiated: {})
} else if let sourceNode = sourceView.asyncdisplaykit_node as? StickerPaneSearchStickerItemNode {
strongSelf.chatDisplayNode.messageTransitionNode.add(correlationId: correlationId, source: .stickerMediaInput(input: .inputPanelSearch(itemNode: sourceNode), replyPanel: replyPanel), initiated: {})
} else if let sourceNode = sourceView.asyncdisplaykit_node as? ChatEmptyNodeStickerContentNode {
strongSelf.chatDisplayNode.messageTransitionNode.add(correlationId: correlationId, source: .stickerMediaInput(input: .emptyPanel(itemNode: sourceNode), replyPanel: nil), initiated: {})
} else if let sourceLayer = sourceLayer {

View File

@ -188,7 +188,6 @@ public final class ChatMessageTransitionNode: ASDisplayNode, ChatMessageTransiti
case inputPanel(itemNode: ChatMediaInputStickerGridItemNode)
case mediaPanel(itemNode: HorizontalStickerGridItemNode)
case universal(sourceContainerView: UIView, sourceRect: CGRect, sourceLayer: CALayer)
case inputPanelSearch(itemNode: StickerPaneSearchStickerItemNode)
case emptyPanel(itemNode: ChatEmptyNodeStickerContentNode)
}
@ -442,9 +441,6 @@ public final class ChatMessageTransitionNode: ASDisplayNode, ChatMessageTransiti
case let .universal(sourceContainerView, sourceRect, sourceLayer):
stickerSource = Sticker(imageNode: nil, animationNode: nil, placeholderNode: nil, imageLayer: sourceLayer, relativeSourceRect: sourceLayer.frame)
sourceAbsoluteRect = convertAnimatingSourceRect(sourceRect, fromView: sourceContainerView, toView: self.view)
case let .inputPanelSearch(sourceItemNode):
stickerSource = Sticker(imageNode: sourceItemNode.imageNode, animationNode: sourceItemNode.animationNode, placeholderNode: nil, imageLayer: nil, relativeSourceRect: sourceItemNode.imageNode.frame)
sourceAbsoluteRect = sourceItemNode.view.convert(sourceItemNode.imageNode.frame, to: self.view)
case let .emptyPanel(sourceItemNode):
stickerSource = Sticker(imageNode: sourceItemNode.stickerNode.imageNode, animationNode: sourceItemNode.stickerNode.animationNode, placeholderNode: nil, imageLayer: nil, relativeSourceRect: sourceItemNode.stickerNode.imageNode.frame)
sourceAbsoluteRect = sourceItemNode.stickerNode.view.convert(sourceItemNode.stickerNode.imageNode.frame, to: self.view)
@ -495,8 +491,6 @@ public final class ChatMessageTransitionNode: ASDisplayNode, ChatMessageTransiti
break
case let .mediaPanel(sourceItemNode):
sourceItemNode.isHidden = true
case let .inputPanelSearch(sourceItemNode):
sourceItemNode.isHidden = true
case let .emptyPanel(sourceItemNode):
sourceItemNode.isHidden = true
}