diff --git a/submodules/ReactionSelectionNode/Sources/ReactionContextBackgroundNode.swift b/submodules/ReactionSelectionNode/Sources/ReactionContextBackgroundNode.swift index ebbd3ca2c6..605b7c937f 100644 --- a/submodules/ReactionSelectionNode/Sources/ReactionContextBackgroundNode.swift +++ b/submodules/ReactionSelectionNode/Sources/ReactionContextBackgroundNode.swift @@ -217,7 +217,8 @@ final class ReactionContextBackgroundNode: ASDisplayNode { func animateInFromAnchorRect(size: CGSize, sourceBackgroundFrame: CGRect) { let springDuration: Double = 0.5 let springDamping: CGFloat = 104.0 - let springDelay: Double = 0.05 + let springScaleDelay: Double = 0.1 + let springDelay: Double = springScaleDelay + 0.01 let shadowInset: CGFloat = 15.0 let contentBounds = self.backgroundView.frame @@ -225,6 +226,9 @@ final class ReactionContextBackgroundNode: ASDisplayNode { let visualSourceBackgroundFrame = sourceBackgroundFrame.offsetBy(dx: -contentBounds.minX, dy: -contentBounds.minY) let sourceShadowFrame = visualSourceBackgroundFrame.insetBy(dx: -shadowInset, dy: -shadowInset) + self.backgroundClippingLayer.animateScale(from: 0.001, to: 1.0, duration: 0.2, delay: springScaleDelay, timingFunction: CAMediaTimingFunctionName.easeInEaseOut.rawValue) + self.backgroundShadowLayer.animateScale(from: 0.001, to: 1.0, duration: 0.2, delay: springScaleDelay, timingFunction: CAMediaTimingFunctionName.easeInEaseOut.rawValue) + self.backgroundClippingLayer.animateSpring(from: NSValue(cgPoint: CGPoint(x: visualSourceBackgroundFrame.midX - size.width / 2.0, y: 0.0)), to: NSValue(cgPoint: CGPoint()), keyPath: "position", duration: springDuration, delay: springDelay, initialVelocity: 0.0, damping: springDamping, additive: true) self.backgroundClippingLayer.animateSpring(from: NSValue(cgRect: CGRect(origin: CGPoint(), size: visualSourceBackgroundFrame.size)), to: NSValue(cgRect: self.backgroundClippingLayer.bounds), keyPath: "bounds", duration: springDuration, delay: springDelay, initialVelocity: 0.0, damping: springDamping) self.backgroundShadowLayer.animateSpring(from: NSValue(cgPoint: CGPoint(x: sourceShadowFrame.midX - size.width / 2.0, y: 0.0)), to: NSValue(cgPoint: CGPoint()), keyPath: "position", duration: springDuration, delay: springDelay, initialVelocity: 0.0, damping: springDamping, additive: true) @@ -232,11 +236,12 @@ final class ReactionContextBackgroundNode: ASDisplayNode { } func animateOut() { - self.backgroundClippingLayer.animateAlpha(from: CGFloat(self.backgroundClippingLayer.opacity), to: 0.0, duration: 0.2, removeOnCompletion: false) + self.maskLayer.allowsGroupOpacity = true + self.maskLayer.animateAlpha(from: CGFloat(self.backgroundClippingLayer.opacity), to: 0.0, duration: 0.2, removeOnCompletion: false) self.backgroundShadowLayer.animateAlpha(from: CGFloat(self.backgroundShadowLayer.opacity), to: 0.0, duration: 0.1, removeOnCompletion: false) - self.largeCircleLayer.animateAlpha(from: CGFloat(self.largeCircleLayer.opacity), to: 0.0, duration: 0.2, removeOnCompletion: false) + //self.largeCircleLayer.animateAlpha(from: CGFloat(self.largeCircleLayer.opacity), to: 0.0, duration: 0.2, removeOnCompletion: false) self.largeCircleShadowLayer.animateAlpha(from: CGFloat(self.largeCircleShadowLayer.opacity), to: 0.0, duration: 0.1, removeOnCompletion: false) - self.smallCircleLayer.animateAlpha(from: CGFloat(self.smallCircleLayer.opacity), to: 0.0, duration: 0.2, removeOnCompletion: false) + //self.smallCircleLayer.animateAlpha(from: CGFloat(self.smallCircleLayer.opacity), to: 0.0, duration: 0.2, removeOnCompletion: false) self.smallCircleShadowLayer.animateAlpha(from: CGFloat(self.smallCircleShadowLayer.opacity), to: 0.0, duration: 0.1, removeOnCompletion: false) } } diff --git a/submodules/ReactionSelectionNode/Sources/ReactionContextNode.swift b/submodules/ReactionSelectionNode/Sources/ReactionContextNode.swift index 6c2d858c07..f5c1982f3a 100644 --- a/submodules/ReactionSelectionNode/Sources/ReactionContextNode.swift +++ b/submodules/ReactionSelectionNode/Sources/ReactionContextNode.swift @@ -191,6 +191,8 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate { private var horizontalExpandStartLocation: CGPoint? private var horizontalExpandDistance: CGFloat = 0.0 + private var animateInInfo: (centerX: CGFloat, width: CGFloat)? + public init(context: AccountContext, animationCache: AnimationCache, presentationData: PresentationData, items: [ReactionContextItem], getEmojiContent: ((AnimationCache, MultiAnimationRenderer) -> Signal)?, isExpandedUpdated: @escaping (ContainedViewLayoutTransition) -> Void, requestLayout: @escaping (ContainedViewLayoutTransition) -> Void) { self.context = context self.presentationData = presentationData @@ -876,14 +878,16 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate { if let animateInFromAnchorRect = animateInFromAnchorRect { let springDuration: Double = 0.5 let springDamping: CGFloat = 104.0 - let springDelay: Double = 0.05 + let springScaleDelay: Double = 0.1 + let springDelay: Double = springScaleDelay + 0.01 let sourceBackgroundFrame = self.calculateBackgroundFrame(containerSize: size, insets: backgroundInsets, anchorRect: animateInFromAnchorRect, contentSize: CGSize(width: visualBackgroundFrame.height, height: contentHeight)).0 self.backgroundNode.animateInFromAnchorRect(size: visualBackgroundFrame.size, sourceBackgroundFrame: sourceBackgroundFrame.offsetBy(dx: -visualBackgroundFrame.minX, dy: -visualBackgroundFrame.minY)) + self.animateInInfo = (visualBackgroundFrame.midX - sourceBackgroundFrame.midX, visualBackgroundFrame.width) self.contentContainer.layer.animateSpring(from: NSValue(cgPoint: CGPoint(x: sourceBackgroundFrame.midX - visualBackgroundFrame.midX, y: 0.0)), to: NSValue(cgPoint: CGPoint()), keyPath: "position", duration: springDuration, delay: springDelay, initialVelocity: 0.0, damping: springDamping, additive: true) - self.contentContainer.layer.animateSpring(from: NSValue(cgRect: CGRect(origin: CGPoint(), size: sourceBackgroundFrame.size)), to: NSValue(cgRect: CGRect(origin: CGPoint(), size: visualBackgroundFrame.size)), keyPath: "bounds", duration: springDuration, delay: springDelay, initialVelocity: 0.0, damping: springDamping) + self.contentContainer.layer.animateSpring(from: NSValue(cgRect: CGRect(origin: CGPoint(x: -(sourceBackgroundFrame.midX - visualBackgroundFrame.midX), y: 0.0), size: sourceBackgroundFrame.size)), to: NSValue(cgRect: CGRect(origin: CGPoint(), size: visualBackgroundFrame.size)), keyPath: "bounds", duration: springDuration, delay: springDelay, initialVelocity: 0.0, damping: springDamping) self.contentTintContainer.layer.animateSpring(from: NSValue(cgPoint: CGPoint(x: sourceBackgroundFrame.midX - visualBackgroundFrame.midX, y: 0.0)), to: NSValue(cgPoint: CGPoint()), keyPath: "position", duration: springDuration, delay: springDelay, initialVelocity: 0.0, damping: springDamping, additive: true) self.contentTintContainer.layer.animateSpring(from: NSValue(cgRect: CGRect(origin: CGPoint(), size: sourceBackgroundFrame.size)), to: NSValue(cgRect: CGRect(origin: CGPoint(), size: visualBackgroundFrame.size)), keyPath: "bounds", duration: springDuration, delay: springDelay, initialVelocity: 0.0, damping: springDamping) @@ -1002,7 +1006,6 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate { self.updateLayout(size: size, insets: insets, anchorRect: anchorRect, isAnimatingOut: false, transition: .immediate, animateInFromAnchorRect: sourceAnchorRect, animateOutToAnchorRect: nil) } - //let mainCircleDuration: Double = 0.5 let mainCircleDelay: Double = 0.01 self.backgroundNode.animateIn() @@ -1014,14 +1017,31 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate { guard let itemNode = self.visibleItemNodes[i] else { continue } - let itemDelay = mainCircleDelay + Double(i) * 0.06 - DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + itemDelay, execute: { [weak itemNode] in + + let itemDelay: Double + if let animateInInfo = self.animateInInfo { + let distance = abs(itemNode.frame.center.x - animateInInfo.centerX) + let distanceNorm = distance / animateInInfo.width + itemDelay = mainCircleDelay + distanceNorm * 0.4 + } else { + itemDelay = mainCircleDelay + Double(i) * 0.06 + } + + DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + itemDelay * UIView.animationDurationFactor(), execute: { [weak itemNode] in itemNode?.appear(animated: true) }) } - let itemDelay = mainCircleDelay + Double(self.visibleItemNodes.count) * 0.06 if let expandItemView = self.expandItemView { + let itemDelay: Double + if let animateInInfo = self.animateInInfo { + let distance = abs(expandItemView.frame.center.x - animateInInfo.centerX) + let distanceNorm = distance / animateInInfo.width + itemDelay = mainCircleDelay + distanceNorm * 0.4 + } else { + itemDelay = mainCircleDelay + Double(8) * 0.06 + } + expandItemView.layer.animateSpring(from: 0.01 as NSNumber, to: 1.0 as NSNumber, keyPath: "transform.scale", duration: 0.4, delay: itemDelay) expandItemView.tintView.layer.animateSpring(from: 0.01 as NSNumber, to: 1.0 as NSNumber, keyPath: "transform.scale", duration: 0.4, delay: itemDelay) } diff --git a/submodules/ReactionSelectionNode/Sources/ReactionSelectionNode.swift b/submodules/ReactionSelectionNode/Sources/ReactionSelectionNode.swift index 33833c1118..a1105de7b5 100644 --- a/submodules/ReactionSelectionNode/Sources/ReactionSelectionNode.swift +++ b/submodules/ReactionSelectionNode/Sources/ReactionSelectionNode.swift @@ -131,7 +131,11 @@ public final class ReactionNode: ASDisplayNode, ReactionItemNode { func appear(animated: Bool) { if animated { - self.animateInAnimationNode?.visibility = true + if self.item.isCustom { + self.layer.animateSpring(from: 0.01 as NSNumber, to: 1.0 as NSNumber, keyPath: "transform.scale", duration: 0.4) + } else { + self.animateInAnimationNode?.visibility = true + } } else { self.animateInAnimationNode?.completed(true) }