Emoji animations improvements

This commit is contained in:
Ilya Laktyushin
2021-09-10 23:26:54 +03:00
parent d592c8a0f3
commit 655600adb3
21 changed files with 350 additions and 37 deletions

View File

@@ -172,6 +172,54 @@ public final class ChatMessageTransitionNode: ASDisplayNode {
case videoMessage(VideoMessage)
case mediaInput(MediaInput)
}
final class DecorationItemNode: ASDisplayNode {
let itemNode: ChatMessageItemView
private let contentNode: ASDisplayNode
private let getContentAreaInScreenSpace: () -> CGRect
private let scrollingContainer: ASDisplayNode
private let containerNode: ASDisplayNode
private let clippingNode: ASDisplayNode
init(itemNode: ChatMessageItemView, contentNode: ASDisplayNode, getContentAreaInScreenSpace: @escaping () -> CGRect) {
self.itemNode = itemNode
self.contentNode = contentNode
self.getContentAreaInScreenSpace = getContentAreaInScreenSpace
self.clippingNode = ASDisplayNode()
self.clippingNode.clipsToBounds = true
self.scrollingContainer = ASDisplayNode()
self.containerNode = ASDisplayNode()
super.init()
self.addSubnode(self.clippingNode)
self.clippingNode.addSubnode(self.scrollingContainer)
self.scrollingContainer.addSubnode(self.containerNode)
self.containerNode.addSubnode(self.contentNode)
}
func updateLayout(size: CGSize) {
self.clippingNode.frame = CGRect(origin: CGPoint(), size: size)
let absoluteRect = self.itemNode.view.convert(self.itemNode.view.bounds, to: self.view)
self.containerNode.frame = absoluteRect
}
func addExternalOffset(offset: CGFloat, transition: ContainedViewLayoutTransition) {
if transition.isAnimated {
assert(true)
}
self.scrollingContainer.bounds = self.scrollingContainer.bounds.offsetBy(dx: 0.0, dy: -offset)
transition.animateOffsetAdditive(node: self.scrollingContainer, offset: offset)
}
func addContentOffset(offset: CGFloat) {
self.scrollingContainer.bounds = self.scrollingContainer.bounds.offsetBy(dx: 0.0, dy: offset)
}
}
private final class AnimatingItemNode: ASDisplayNode {
let itemNode: ChatMessageItemView
@@ -553,6 +601,7 @@ public final class ChatMessageTransitionNode: ASDisplayNode {
private var currentPendingItem: (Int64, Source, () -> Void)?
private var animatingItemNodes: [AnimatingItemNode] = []
private var decorationItemNodes: [DecorationItemNode] = []
var hasScheduledTransitions: Bool {
return self.currentPendingItem != nil
@@ -585,6 +634,20 @@ public final class ChatMessageTransitionNode: ASDisplayNode {
self.currentPendingItem = (correlationId, source, initiated)
self.listNode.setCurrentSendAnimationCorrelationId(correlationId)
}
func add(decorationNode: ASDisplayNode, itemNode: ChatMessageItemView) -> DecorationItemNode {
let decorationItemNode = DecorationItemNode(itemNode: itemNode, contentNode: decorationNode, getContentAreaInScreenSpace: self.getContentAreaInScreenSpace)
decorationItemNode.updateLayout(size: self.bounds.size)
self.decorationItemNodes.append(decorationItemNode)
self.addSubnode(decorationItemNode)
return decorationItemNode
}
func remove(decorationNode: DecorationItemNode) {
self.decorationItemNodes.removeAll(where: { $0 === decorationNode })
decorationNode.removeFromSupernode()
}
private func beginAnimation(itemNode: ChatMessageItemView, source: Source) {
var contextSourceNode: ContextExtractedContentContainingNode?
@@ -646,12 +709,22 @@ public final class ChatMessageTransitionNode: ASDisplayNode {
for animatingItemNode in self.animatingItemNodes {
animatingItemNode.addExternalOffset(offset: offset, transition: transition, itemNode: itemNode)
}
if itemNode == nil {
for decorationItemNode in self.decorationItemNodes {
decorationItemNode.addExternalOffset(offset: offset, transition: transition)
}
}
}
func addContentOffset(offset: CGFloat, itemNode: ListViewItemNode?) {
for animatingItemNode in self.animatingItemNodes {
animatingItemNode.addContentOffset(offset: offset, itemNode: itemNode)
}
if itemNode == nil {
for decorationItemNode in self.decorationItemNodes {
decorationItemNode.addContentOffset(offset: offset)
}
}
}
func isAnimatingMessage(stableId: UInt32) -> Bool {