mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-23 06:35:51 +00:00
Reaction improvements
This commit is contained in:
@@ -393,16 +393,16 @@ public extension ContainedViewLayoutTransition {
|
||||
}
|
||||
}
|
||||
|
||||
func animatePositionWithKeyframes(node: ASDisplayNode, keyframes: [AnyObject], removeOnCompletion: Bool = true, additive: Bool = false, completion: ((Bool) -> Void)? = nil) {
|
||||
func animatePositionWithKeyframes(node: ASDisplayNode, keyframes: [CGPoint], removeOnCompletion: Bool = true, additive: Bool = false, completion: ((Bool) -> Void)? = nil) {
|
||||
self.animatePositionWithKeyframes(layer: node.layer, keyframes: keyframes, removeOnCompletion: removeOnCompletion, additive: additive, completion: completion)
|
||||
}
|
||||
|
||||
func animatePositionWithKeyframes(layer: CALayer, keyframes: [AnyObject], removeOnCompletion: Bool = true, additive: Bool = false, completion: ((Bool) -> Void)? = nil) {
|
||||
func animatePositionWithKeyframes(layer: CALayer, keyframes: [CGPoint], removeOnCompletion: Bool = true, additive: Bool = false, completion: ((Bool) -> Void)? = nil) {
|
||||
switch self {
|
||||
case .immediate:
|
||||
completion?(true)
|
||||
case let .animated(duration, curve):
|
||||
layer.animateKeyframes(values: keyframes, duration: duration, keyPath: "position", timingFunction: curve.timingFunction, mediaTimingFunction: curve.mediaTimingFunction, removeOnCompletion: removeOnCompletion, completion: { value in
|
||||
layer.animateKeyframes(values: keyframes.map(NSValue.init(cgPoint:)), duration: duration, keyPath: "position", timingFunction: curve.timingFunction, mediaTimingFunction: curve.mediaTimingFunction, removeOnCompletion: removeOnCompletion, completion: { value in
|
||||
completion?(value)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -41,6 +41,7 @@ private let largeCircleSize: CGFloat = 16.0
|
||||
private let smallCircleSize: CGFloat = 8.0
|
||||
|
||||
public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
private let context: AccountContext
|
||||
private let theme: PresentationTheme
|
||||
private let items: [ReactionContextItem]
|
||||
|
||||
@@ -49,7 +50,7 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
private let contentContainer: ASDisplayNode
|
||||
private let contentContainerMask: UIImageView
|
||||
private let scrollNode: ASScrollNode
|
||||
private var itemNodes: [ReactionNode] = []
|
||||
private var visibleItemNodes: [Int: ReactionNode] = [:]
|
||||
|
||||
private var isExpanded: Bool = true
|
||||
private var highlightedReaction: ReactionContextItem.Reaction?
|
||||
@@ -64,7 +65,10 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
private weak var animationTargetView: UIView?
|
||||
private var animationHideNode: Bool = false
|
||||
|
||||
private var didAnimateIn: Bool = false
|
||||
|
||||
public init(context: AccountContext, theme: PresentationTheme, items: [ReactionContextItem]) {
|
||||
self.context = context
|
||||
self.theme = theme
|
||||
self.items = items
|
||||
|
||||
@@ -116,11 +120,6 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
|
||||
self.scrollNode.view.delegate = self
|
||||
|
||||
self.itemNodes = self.items.map { item in
|
||||
return ReactionNode(context: context, theme: theme, item: item)
|
||||
}
|
||||
self.itemNodes.forEach(self.scrollNode.addSubnode)
|
||||
|
||||
self.addSubnode(self.contentContainer)
|
||||
}
|
||||
|
||||
@@ -180,30 +179,61 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
}
|
||||
|
||||
private func updateScrolling(transition: ContainedViewLayoutTransition) {
|
||||
let sideInset: CGFloat = 14.0
|
||||
let minScale: CGFloat = 0.6
|
||||
let scaleDistance: CGFloat = 30.0
|
||||
let sideInset: CGFloat = 11.0
|
||||
let itemSpacing: CGFloat = 9.0
|
||||
let itemSize: CGFloat = 40.0
|
||||
let verticalInset: CGFloat = 13.0
|
||||
let rowHeight: CGFloat = 30.0
|
||||
|
||||
let visibleBounds = self.scrollNode.view.bounds
|
||||
|
||||
for itemNode in self.itemNodes {
|
||||
if itemNode.isExtracted {
|
||||
continue
|
||||
}
|
||||
let itemScale: CGFloat
|
||||
let itemFrame = itemNode.frame.offsetBy(dx: -visibleBounds.minX, dy: 0.0)
|
||||
if itemFrame.minX < sideInset || itemFrame.maxX > visibleBounds.width - sideInset {
|
||||
let edgeDistance: CGFloat
|
||||
if itemFrame.minX < sideInset {
|
||||
edgeDistance = sideInset - itemFrame.minX
|
||||
var validIndices = Set<Int>()
|
||||
for i in 0 ..< self.items.count {
|
||||
let columnIndex = i
|
||||
let column = CGFloat(columnIndex)
|
||||
|
||||
let itemOffsetY: CGFloat = -1.0
|
||||
|
||||
let itemFrame = CGRect(origin: CGPoint(x: sideInset + column * (itemSize + itemSpacing), y: verticalInset + floor((rowHeight - itemSize) / 2.0) + itemOffsetY), size: CGSize(width: itemSize, height: itemSize))
|
||||
/*if self.highlightedReaction == self.items[i].reaction {
|
||||
itemFrame = itemFrame.insetBy(dx: -6.0, dy: -6.0)
|
||||
}*/
|
||||
if visibleBounds.intersects(itemFrame) {
|
||||
validIndices.insert(i)
|
||||
|
||||
var animateIn = false
|
||||
|
||||
let itemNode: ReactionNode
|
||||
if let current = self.visibleItemNodes[i] {
|
||||
itemNode = current
|
||||
} else {
|
||||
edgeDistance = itemFrame.maxX - (visibleBounds.width - sideInset)
|
||||
animateIn = self.didAnimateIn
|
||||
|
||||
itemNode = ReactionNode(context: self.context, theme: self.theme, item: self.items[i])
|
||||
self.visibleItemNodes[i] = itemNode
|
||||
self.scrollNode.addSubnode(itemNode)
|
||||
}
|
||||
let edgeFactor: CGFloat = min(1.0, edgeDistance / scaleDistance)
|
||||
itemScale = edgeFactor * minScale + (1.0 - edgeFactor) * 1.0
|
||||
} else {
|
||||
itemScale = 1.0
|
||||
|
||||
if !itemNode.isExtracted {
|
||||
transition.updateFrame(node: itemNode, frame: itemFrame, beginWithCurrentState: true)
|
||||
itemNode.updateLayout(size: itemFrame.size, isExpanded: false, transition: transition)
|
||||
|
||||
if animateIn {
|
||||
itemNode.animateIn()
|
||||
}
|
||||
transition.updateSublayerTransformScale(node: itemNode, scale: itemScale)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var removedIndices: [Int] = []
|
||||
for (index, itemNode) in self.visibleItemNodes {
|
||||
if !validIndices.contains(index) {
|
||||
removedIndices.append(index)
|
||||
itemNode.removeFromSupernode()
|
||||
}
|
||||
}
|
||||
for index in removedIndices {
|
||||
self.visibleItemNodes.removeValue(forKey: index)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -237,22 +267,6 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
transition.updateFrame(node: self.scrollNode, frame: CGRect(origin: CGPoint(), size: backgroundFrame.size))
|
||||
self.scrollNode.view.contentSize = CGSize(width: completeContentWidth, height: backgroundFrame.size.height)
|
||||
|
||||
for i in 0 ..< self.items.count {
|
||||
let columnIndex = i
|
||||
let column = CGFloat(columnIndex)
|
||||
|
||||
let itemOffsetY: CGFloat = -1.0
|
||||
|
||||
var itemFrame = CGRect(origin: CGPoint(x: sideInset + column * (itemSize + itemSpacing), y: verticalInset + floor((rowHeight - itemSize) / 2.0) + itemOffsetY), size: CGSize(width: itemSize, height: itemSize))
|
||||
if self.highlightedReaction == self.items[i].reaction {
|
||||
itemFrame = itemFrame.insetBy(dx: -6.0, dy: -6.0)
|
||||
}
|
||||
if !self.itemNodes[i].isExtracted {
|
||||
transition.updateFrame(node: self.itemNodes[i], frame: itemFrame, beginWithCurrentState: true)
|
||||
self.itemNodes[i].updateLayout(size: itemFrame.size, isExpanded: false, transition: transition)
|
||||
}
|
||||
}
|
||||
|
||||
self.updateScrolling(transition: transition)
|
||||
|
||||
transition.updateFrame(node: self.backgroundNode, frame: backgroundFrame)
|
||||
@@ -291,23 +305,28 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
self.updateLayout(size: size, insets: insets, anchorRect: anchorRect, transition: .immediate, animateInFromAnchorRect: sourceAnchorRect, animateOutToAnchorRect: nil)
|
||||
}
|
||||
|
||||
let mainCircleDuration: Double = 0.5
|
||||
//let mainCircleDuration: Double = 0.5
|
||||
let mainCircleDelay: Double = 0.1
|
||||
|
||||
self.backgroundNode.animateIn()
|
||||
|
||||
for i in 0 ..< self.itemNodes.count {
|
||||
let itemNode = self.itemNodes[i]
|
||||
self.didAnimateIn = true
|
||||
|
||||
for i in 0 ..< self.items.count {
|
||||
guard let itemNode = self.visibleItemNodes[i] else {
|
||||
continue
|
||||
}
|
||||
let itemDelay = mainCircleDelay + 0.1 + Double(i) * 0.03
|
||||
itemNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.15, delay: itemDelay)
|
||||
itemNode.layer.animateSpring(from: 0.1 as NSNumber, to: 1.0 as NSNumber, keyPath: "transform.scale", duration: mainCircleDuration, delay: itemDelay, initialVelocity: 0.0)
|
||||
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + itemDelay, execute: { [weak itemNode] in
|
||||
itemNode?.animateIn()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
public func animateOut(to targetAnchorRect: CGRect?, animatingOutToReaction: Bool) {
|
||||
self.backgroundNode.animateOut()
|
||||
|
||||
for itemNode in self.itemNodes {
|
||||
for (_, itemNode) in self.visibleItemNodes {
|
||||
if itemNode.isExtracted {
|
||||
continue
|
||||
}
|
||||
@@ -367,7 +386,7 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
}
|
||||
|
||||
public func willAnimateOutToReaction(value: String) {
|
||||
for itemNode in self.itemNodes {
|
||||
for (_, itemNode) in self.visibleItemNodes {
|
||||
if itemNode.item.reaction.rawValue != value {
|
||||
continue
|
||||
}
|
||||
@@ -376,7 +395,7 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
}
|
||||
|
||||
public func animateOutToReaction(value: String, targetView: UIView, hideNode: Bool, completion: @escaping () -> Void) {
|
||||
for itemNode in self.itemNodes {
|
||||
for (_, itemNode) in self.visibleItemNodes {
|
||||
if itemNode.item.reaction.rawValue != value {
|
||||
continue
|
||||
}
|
||||
@@ -400,7 +419,7 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
let selfSourceRect = itemNode.view.convert(itemNode.view.bounds, to: self.view)
|
||||
let selfTargetRect = self.view.convert(targetView.bounds, from: targetView)
|
||||
|
||||
let expandedScale: CGFloat = 3.0
|
||||
let expandedScale: CGFloat = 4.0
|
||||
let expandedSize = CGSize(width: floor(selfSourceRect.width * expandedScale), height: floor(selfSourceRect.height * expandedScale))
|
||||
|
||||
var expandedFrame = CGRect(origin: CGPoint(x: floor(selfTargetRect.midX - expandedSize.width / 2.0), y: floor(selfTargetRect.midY - expandedSize.height / 2.0)), size: expandedSize)
|
||||
@@ -411,10 +430,11 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
let transition: ContainedViewLayoutTransition = .animated(duration: 0.2, curve: .linear)
|
||||
|
||||
self.addSubnode(itemNode)
|
||||
itemNode.frame = selfSourceRect
|
||||
//itemNode.position = selfSourceRect.center
|
||||
itemNode.position = expandedFrame.center
|
||||
transition.updateBounds(node: itemNode, bounds: CGRect(origin: CGPoint(), size: expandedFrame.size))
|
||||
itemNode.updateLayout(size: expandedFrame.size, isExpanded: true, transition: transition)
|
||||
|
||||
transition.animatePositionWithKeyframes(node: itemNode, keyframes: generateParabollicMotionKeyframes(from: selfSourceRect.center, to: expandedFrame.center, elevation: 30.0))
|
||||
|
||||
let additionalAnimationNode = AnimatedStickerNode()
|
||||
@@ -507,7 +527,7 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
public func reaction(at point: CGPoint) -> ReactionContextItem? {
|
||||
for i in 0 ..< 2 {
|
||||
let touchInset: CGFloat = i == 0 ? 0.0 : 8.0
|
||||
for itemNode in self.itemNodes {
|
||||
for (_, itemNode) in self.visibleItemNodes {
|
||||
let itemPoint = self.view.convert(point, to: itemNode.view)
|
||||
if itemNode.bounds.insetBy(dx: -touchInset, dy: -touchInset).contains(itemPoint) {
|
||||
return itemNode.item
|
||||
@@ -518,7 +538,7 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
}
|
||||
|
||||
public func performReactionSelection(reaction: ReactionContextItem.Reaction) {
|
||||
for itemNode in self.itemNodes {
|
||||
for (_, itemNode) in self.visibleItemNodes {
|
||||
if itemNode.item.reaction == reaction {
|
||||
self.reactionSelected?(itemNode.item)
|
||||
break
|
||||
@@ -782,7 +802,7 @@ public final class StandaloneDismissReactionAnimation: ASDisplayNode {
|
||||
}
|
||||
}
|
||||
|
||||
private func generateParabollicMotionKeyframes(from sourcePoint: CGPoint, to targetPosition: CGPoint, elevation: CGFloat) -> [AnyObject] {
|
||||
private func generateParabollicMotionKeyframes(from sourcePoint: CGPoint, to targetPosition: CGPoint, elevation: CGFloat) -> [CGPoint] {
|
||||
let midPoint = CGPoint(x: (sourcePoint.x + targetPosition.x) / 2.0, y: sourcePoint.y - elevation)
|
||||
|
||||
let x1 = sourcePoint.x
|
||||
@@ -792,13 +812,13 @@ private func generateParabollicMotionKeyframes(from sourcePoint: CGPoint, to tar
|
||||
let x3 = targetPosition.x
|
||||
let y3 = targetPosition.y
|
||||
|
||||
var keyframes: [AnyObject] = []
|
||||
var keyframes: [CGPoint] = []
|
||||
if abs(y1 - y3) < 5.0 && abs(x1 - x3) < 5.0 {
|
||||
for i in 0 ..< 10 {
|
||||
let k = CGFloat(i) / CGFloat(10 - 1)
|
||||
let x = sourcePoint.x * (1.0 - k) + targetPosition.x * k
|
||||
let y = sourcePoint.y * (1.0 - k) + targetPosition.y * k
|
||||
keyframes.append(NSValue(cgPoint: CGPoint(x: x, y: y)))
|
||||
keyframes.append(CGPoint(x: x, y: y))
|
||||
}
|
||||
} else {
|
||||
let a = (x3 * (y2 - y1) + x2 * (y1 - y3) + x1 * (y3 - y2)) / ((x1 - x2) * (x1 - x3) * (x2 - x3))
|
||||
@@ -809,7 +829,7 @@ private func generateParabollicMotionKeyframes(from sourcePoint: CGPoint, to tar
|
||||
let k = CGFloat(i) / CGFloat(10 - 1)
|
||||
let x = sourcePoint.x * (1.0 - k) + targetPosition.x * k
|
||||
let y = a * x * x + b * x + c
|
||||
keyframes.append(NSValue(cgPoint: CGPoint(x: x, y: y)))
|
||||
keyframes.append(CGPoint(x: x, y: y))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -38,8 +38,10 @@ private let font = Font.medium(13.0)
|
||||
final class ReactionNode: ASDisplayNode {
|
||||
let context: AccountContext
|
||||
let item: ReactionContextItem
|
||||
private let staticImageNode: TransformImageNode
|
||||
private let stillAnimationNode: AnimatedStickerNode
|
||||
|
||||
private var animateInAnimationNode: AnimatedStickerNode?
|
||||
private let staticAnimationNode: AnimatedStickerNode
|
||||
private var stillAnimationNode: AnimatedStickerNode?
|
||||
private var animationNode: AnimatedStickerNode?
|
||||
|
||||
private var fetchStickerDisposable: Disposable?
|
||||
@@ -55,22 +57,40 @@ final class ReactionNode: ASDisplayNode {
|
||||
self.context = context
|
||||
self.item = item
|
||||
|
||||
self.staticImageNode = TransformImageNode()
|
||||
self.staticAnimationNode = AnimatedStickerNode()
|
||||
self.staticAnimationNode.isHidden = true
|
||||
|
||||
self.animateInAnimationNode = AnimatedStickerNode()
|
||||
self.stillAnimationNode = AnimatedStickerNode()
|
||||
|
||||
super.init()
|
||||
|
||||
self.addSubnode(self.staticImageNode)
|
||||
if let animateInAnimationNode = self.animateInAnimationNode {
|
||||
self.addSubnode(animateInAnimationNode)
|
||||
}
|
||||
self.addSubnode(self.staticAnimationNode)
|
||||
|
||||
self.addSubnode(self.stillAnimationNode)
|
||||
|
||||
self.stillAnimationNode.started = { [weak self] in
|
||||
self.animateInAnimationNode?.completed = { [weak self] _ in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.staticImageNode.isHidden = true
|
||||
if strongSelf.animationNode == nil {
|
||||
strongSelf.staticAnimationNode.isHidden = false
|
||||
}
|
||||
|
||||
strongSelf.animateInAnimationNode?.removeFromSupernode()
|
||||
strongSelf.animateInAnimationNode = nil
|
||||
}
|
||||
|
||||
/*self.stillAnimationNode.started = { [weak self] in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.animateInAnimationNode.isHidden = true
|
||||
strongSelf.animateInAnimationNode.visibility = false
|
||||
}*/
|
||||
|
||||
self.fetchStickerDisposable = fetchedMediaResource(mediaBox: context.account.postbox.mediaBox, reference: .standalone(resource: item.appearAnimation.resource)).start()
|
||||
self.fetchStickerDisposable = fetchedMediaResource(mediaBox: context.account.postbox.mediaBox, reference: .standalone(resource: item.stillAnimation.resource)).start()
|
||||
self.fetchStickerDisposable = fetchedMediaResource(mediaBox: context.account.postbox.mediaBox, reference: .standalone(resource: item.listAnimation.resource)).start()
|
||||
self.fetchFullAnimationDisposable = fetchedMediaResource(mediaBox: context.account.postbox.mediaBox, reference: .standalone(resource: item.applicationAnimation.resource)).start()
|
||||
@@ -81,6 +101,10 @@ final class ReactionNode: ASDisplayNode {
|
||||
self.fetchFullAnimationDisposable?.dispose()
|
||||
}
|
||||
|
||||
func animateIn() {
|
||||
self.animateInAnimationNode?.visibility = true
|
||||
}
|
||||
|
||||
func updateLayout(size: CGSize, isExpanded: Bool, transition: ContainedViewLayoutTransition) {
|
||||
let intrinsicSize = size
|
||||
|
||||
@@ -101,60 +125,102 @@ final class ReactionNode: ASDisplayNode {
|
||||
self.animationNode = animationNode
|
||||
self.addSubnode(animationNode)
|
||||
|
||||
animationNode.started = { [weak self] in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.staticImageNode.isHidden = true
|
||||
}
|
||||
|
||||
animationNode.setup(source: AnimatedStickerResourceSource(account: self.context.account, resource: self.item.listAnimation.resource), width: Int(animationDisplaySize.width * 2.0), height: Int(animationDisplaySize.height * 2.0), playbackMode: .once, mode: .direct(cachePathPrefix: self.context.account.postbox.mediaBox.shortLivedResourceCachePathPrefix(self.item.listAnimation.resource.id)))
|
||||
animationNode.frame = animationFrame
|
||||
animationNode.updateLayout(size: animationFrame.size)
|
||||
if transition.isAnimated, !self.staticImageNode.frame.isEmpty {
|
||||
transition.animateTransformScale(node: animationNode, from: self.staticImageNode.bounds.width / animationFrame.width)
|
||||
transition.animatePositionAdditive(node: animationNode, offset: CGPoint(x: self.staticImageNode.frame.midX - animationFrame.midX, y: self.staticImageNode.frame.midY - animationFrame.midY))
|
||||
}
|
||||
animationNode.visibility = true
|
||||
|
||||
self.stillAnimationNode.alpha = 0.0
|
||||
if transition.isAnimated {
|
||||
self.stillAnimationNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, completion: { [weak self] _ in
|
||||
self?.stillAnimationNode.visibility = false
|
||||
if let stillAnimationNode = self.stillAnimationNode, !stillAnimationNode.frame.isEmpty {
|
||||
stillAnimationNode.alpha = 0.0
|
||||
stillAnimationNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, completion: { [weak self] _ in
|
||||
guard let strongSelf = self, let stillAnimationNode = strongSelf.stillAnimationNode else {
|
||||
return
|
||||
}
|
||||
strongSelf.stillAnimationNode = nil
|
||||
stillAnimationNode.removeFromSupernode()
|
||||
})
|
||||
}
|
||||
if let animateInAnimationNode = self.animateInAnimationNode {
|
||||
animateInAnimationNode.alpha = 0.0
|
||||
animateInAnimationNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, completion: { [weak self] _ in
|
||||
guard let strongSelf = self, let animateInAnimationNode = strongSelf.animateInAnimationNode else {
|
||||
return
|
||||
}
|
||||
strongSelf.animateInAnimationNode = nil
|
||||
animateInAnimationNode.removeFromSupernode()
|
||||
})
|
||||
}
|
||||
|
||||
var referenceNode: ASDisplayNode?
|
||||
if let animateInAnimationNode = self.animateInAnimationNode {
|
||||
referenceNode = animateInAnimationNode
|
||||
} else if !self.staticAnimationNode.isHidden {
|
||||
referenceNode = self.staticAnimationNode
|
||||
}
|
||||
|
||||
if let referenceNode = referenceNode {
|
||||
transition.animateTransformScale(node: animationNode, from: referenceNode.bounds.width / animationFrame.width)
|
||||
transition.animatePositionAdditive(node: animationNode, offset: CGPoint(x: referenceNode.frame.midX - animationFrame.midX, y: referenceNode.frame.midY - animationFrame.midY))
|
||||
}
|
||||
|
||||
if !self.staticAnimationNode.isHidden {
|
||||
transition.animateTransformScale(node: self.staticAnimationNode, from: self.staticAnimationNode.bounds.width / animationFrame.width)
|
||||
transition.animatePositionAdditive(node: self.staticAnimationNode, offset: CGPoint(x: self.staticAnimationNode.frame.midX - animationFrame.midX, y: self.staticAnimationNode.frame.midY - animationFrame.midY))
|
||||
|
||||
self.staticAnimationNode.alpha = 0.0
|
||||
self.staticAnimationNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2)
|
||||
}
|
||||
|
||||
animationNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.15)
|
||||
} else {
|
||||
self.stillAnimationNode.visibility = false
|
||||
if let stillAnimationNode = self.stillAnimationNode {
|
||||
self.stillAnimationNode = nil
|
||||
stillAnimationNode.removeFromSupernode()
|
||||
}
|
||||
self.staticAnimationNode.isHidden = true
|
||||
}
|
||||
animationNode.visibility = true
|
||||
}
|
||||
|
||||
if self.validSize != size {
|
||||
self.validSize = size
|
||||
|
||||
if !self.staticImageNode.isHidden {
|
||||
self.staticImageNode.setSignal(chatMessageAnimatedSticker(postbox: self.context.account.postbox, file: item.stillAnimation, small: false, size: CGSize(width: animationDisplaySize.width * UIScreenScale, height: animationDisplaySize.height * UIScreenScale), fitzModifier: nil, fetched: false, onlyFullSize: false, thumbnail: false, synchronousLoad: false))
|
||||
let imageApply = self.staticImageNode.asyncLayout()(TransformImageArguments(corners: ImageCorners(), imageSize: animationDisplaySize, boundingSize: animationDisplaySize, intrinsicInsets: UIEdgeInsets()))
|
||||
imageApply()
|
||||
}
|
||||
transition.updateFrame(node: self.staticImageNode, frame: animationFrame)
|
||||
}
|
||||
|
||||
if !self.didSetupStillAnimation {
|
||||
if self.animationNode == nil {
|
||||
self.didSetupStillAnimation = true
|
||||
|
||||
self.stillAnimationNode.setup(source: AnimatedStickerResourceSource(account: self.context.account, resource: self.item.stillAnimation.resource), width: Int(animationDisplaySize.width * 2.5), height: Int(animationDisplaySize.height * 2.5), playbackMode: .loop, mode: .direct(cachePathPrefix: self.context.account.postbox.mediaBox.shortLivedResourceCachePathPrefix(self.item.stillAnimation.resource.id)))
|
||||
self.stillAnimationNode.position = animationFrame.center
|
||||
self.stillAnimationNode.bounds = CGRect(origin: CGPoint(), size: animationFrame.size)
|
||||
self.stillAnimationNode.updateLayout(size: animationFrame.size)
|
||||
self.stillAnimationNode.visibility = true
|
||||
}
|
||||
} else {
|
||||
transition.updatePosition(node: self.stillAnimationNode, position: animationFrame.center, beginWithCurrentState: true)
|
||||
transition.updateTransformScale(node: self.stillAnimationNode, scale: animationFrame.size.width / self.stillAnimationNode.bounds.width, beginWithCurrentState: true)
|
||||
}
|
||||
self.staticAnimationNode.setup(source: AnimatedStickerResourceSource(account: self.context.account, resource: self.item.stillAnimation.resource), width: Int(animationDisplaySize.width * 2.5), height: Int(animationDisplaySize.height * 2.5), playbackMode: .still(.start), mode: .direct(cachePathPrefix: self.context.account.postbox.mediaBox.shortLivedResourceCachePathPrefix(self.item.stillAnimation.resource.id)))
|
||||
self.staticAnimationNode.position = animationFrame.center
|
||||
self.staticAnimationNode.bounds = CGRect(origin: CGPoint(), size: animationFrame.size)
|
||||
self.staticAnimationNode.updateLayout(size: animationFrame.size)
|
||||
self.staticAnimationNode.visibility = true
|
||||
|
||||
if let animateInAnimationNode = self.animateInAnimationNode {
|
||||
animateInAnimationNode.setup(source: AnimatedStickerResourceSource(account: self.context.account, resource: self.item.appearAnimation.resource), width: Int(animationDisplaySize.width * 2.5), height: Int(animationDisplaySize.height * 2.5), playbackMode: .once, mode: .direct(cachePathPrefix: self.context.account.postbox.mediaBox.shortLivedResourceCachePathPrefix(self.item.appearAnimation.resource.id)))
|
||||
animateInAnimationNode.position = animationFrame.center
|
||||
animateInAnimationNode.bounds = CGRect(origin: CGPoint(), size: animationFrame.size)
|
||||
animateInAnimationNode.updateLayout(size: animationFrame.size)
|
||||
}
|
||||
|
||||
func didAppear() {
|
||||
/*self.stillAnimationNode.setup(source: AnimatedStickerResourceSource(account: self.context.account, resource: self.item.stillAnimation.resource), width: Int(animationDisplaySize.width * 2.5), height: Int(animationDisplaySize.height * 2.5), playbackMode: .once, mode: .direct(cachePathPrefix: self.context.account.postbox.mediaBox.shortLivedResourceCachePathPrefix(self.item.stillAnimation.resource.id)))
|
||||
self.stillAnimationNode.position = animationFrame.center
|
||||
self.stillAnimationNode.bounds = CGRect(origin: CGPoint(), size: animationFrame.size)
|
||||
self.stillAnimationNode.updateLayout(size: animationFrame.size)*/
|
||||
}
|
||||
} else {
|
||||
transition.updatePosition(node: self.staticAnimationNode, position: animationFrame.center, beginWithCurrentState: true)
|
||||
transition.updateTransformScale(node: self.staticAnimationNode, scale: animationFrame.size.width / self.staticAnimationNode.bounds.width, beginWithCurrentState: true)
|
||||
|
||||
if let animateInAnimationNode = self.animateInAnimationNode {
|
||||
transition.updatePosition(node: animateInAnimationNode, position: animationFrame.center, beginWithCurrentState: true)
|
||||
transition.updateTransformScale(node: animateInAnimationNode, scale: animationFrame.size.width / animateInAnimationNode.bounds.width, beginWithCurrentState: true)
|
||||
}
|
||||
|
||||
if let stillAnimationNode = self.stillAnimationNode {
|
||||
transition.updatePosition(node: stillAnimationNode, position: animationFrame.center, beginWithCurrentState: true)
|
||||
transition.updateTransformScale(node: stillAnimationNode, scale: animationFrame.size.width / stillAnimationNode.bounds.width, beginWithCurrentState: true)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user