Sticker pack preview updates

This commit is contained in:
Ali
2020-04-07 17:55:39 +04:00
parent 728d68dc6d
commit 78e12ad45e
22 changed files with 459 additions and 129 deletions

View File

@@ -7,17 +7,20 @@ import AnimatedStickerNode
import AppBundle
private final class TooltipScreenNode: ViewControllerTracingNode {
private let location: CGPoint
private let icon: TooltipScreen.Icon
private let location: CGRect
private let shouldDismissOnTouch: (CGPoint) -> Bool
private let requestDismiss: () -> Void
private let containerNode: ASDisplayNode
private let backgroundNode: ASImageNode
private let arrowNode: ASImageNode
private let arrowContainer: ASDisplayNode
private let animatedStickerNode: AnimatedStickerNode
private let textNode: ImmediateTextNode
init(text: String, location: CGPoint, shouldDismissOnTouch: @escaping (CGPoint) -> Bool, requestDismiss: @escaping () -> Void) {
init(text: String, icon: TooltipScreen.Icon, location: CGRect, shouldDismissOnTouch: @escaping (CGPoint) -> Bool, requestDismiss: @escaping () -> Void) {
self.icon = icon
self.location = location
self.shouldDismissOnTouch = shouldDismissOnTouch
self.requestDismiss = requestDismiss
@@ -39,20 +42,31 @@ private final class TooltipScreenNode: ViewControllerTracingNode {
context.fillPath()
})
self.arrowContainer = ASDisplayNode()
self.textNode = ImmediateTextNode()
self.textNode.displaysAsynchronously = false
self.textNode.maximumNumberOfLines = 0
self.textNode.attributedText = NSAttributedString(string: text, font: Font.regular(14.0), textColor: .white)
self.animatedStickerNode = AnimatedStickerNode()
if let path = getAppBundle().path(forResource: "ChatListFoldersTooltip", ofType: "json") {
self.animatedStickerNode.setup(source: AnimatedStickerNodeLocalFileSource(path: path), width: Int(70 * UIScreenScale), height: Int(70 * UIScreenScale), playbackMode: .once, mode: .direct)
self.animatedStickerNode.automaticallyLoadFirstFrame = true
switch icon {
case .chatListPress:
if let path = getAppBundle().path(forResource: "ChatListFoldersTooltip", ofType: "json") {
self.animatedStickerNode.setup(source: AnimatedStickerNodeLocalFileSource(path: path), width: Int(70 * UIScreenScale), height: Int(70 * UIScreenScale), playbackMode: .once, mode: .direct)
self.animatedStickerNode.automaticallyLoadFirstFrame = true
}
case .info:
if let path = getAppBundle().path(forResource: "anim_infotip", ofType: "json") {
self.animatedStickerNode.setup(source: AnimatedStickerNodeLocalFileSource(path: path), width: Int(70 * UIScreenScale), height: Int(70 * UIScreenScale), playbackMode: .once, mode: .direct)
self.animatedStickerNode.automaticallyLoadFirstFrame = true
}
}
super.init()
self.backgroundNode.addSubnode(self.arrowNode)
self.arrowContainer.addSubnode(self.arrowNode)
self.backgroundNode.addSubnode(self.arrowContainer)
self.containerNode.addSubnode(self.backgroundNode)
self.containerNode.addSubnode(self.textNode)
self.containerNode.addSubnode(self.animatedStickerNode)
@@ -64,19 +78,48 @@ private final class TooltipScreenNode: ViewControllerTracingNode {
let bottomInset: CGFloat = 10.0
let contentInset: CGFloat = 9.0
let contentVerticalInset: CGFloat = 11.0
let animationSize = CGSize(width: 32.0, height: 32.0)
let animationInset: CGFloat = (70 - animationSize.width) / 2.0
let animationSize: CGSize
let animationInset: CGFloat
switch self.icon {
case .chatListPress:
animationSize = CGSize(width: 32.0, height: 32.0)
animationInset = (70.0 - animationSize.width) / 2.0
case .info:
animationSize = CGSize(width: 32.0, height: 32.0)
animationInset = 0.0
}
let animationSpacing: CGFloat = 8.0
let textSize = self.textNode.updateLayout(CGSize(width: layout.size.width - contentInset * 2.0 - sideInset * 2.0 - animationSize.width - animationSpacing, height: .greatestFiniteMagnitude))
let backgroundHeight = max(animationSize.height, textSize.height) + contentVerticalInset * 2.0
let backgroundFrame = CGRect(origin: CGPoint(x: sideInset, y: self.location.y - bottomInset - backgroundHeight), size: CGSize(width: layout.size.width - sideInset * 2.0, height: backgroundHeight))
var backgroundFrame = CGRect(origin: CGPoint(x: sideInset, y: self.location.minY - bottomInset - backgroundHeight), size: CGSize(width: layout.size.width - sideInset * 2.0, height: backgroundHeight))
var invertArrow = false
if backgroundFrame.minY < layout.insets(options: .statusBar).top {
backgroundFrame.origin.y = self.location.maxY + bottomInset
invertArrow = true
}
transition.updateFrame(node: self.containerNode, frame: backgroundFrame)
transition.updateFrame(node: self.backgroundNode, frame: CGRect(origin: CGPoint(), size: backgroundFrame.size))
if let image = self.arrowNode.image {
let arrowSize = image.size
let arrowCenterX = self.location.x
transition.updateFrame(node: self.arrowNode, frame: CGRect(origin: CGPoint(x: floor(arrowCenterX - arrowSize.width / 2.0), y: backgroundFrame.height), size: arrowSize))
let arrowCenterX = self.location.midX
let arrowFrame: CGRect
if invertArrow {
arrowFrame = CGRect(origin: CGPoint(x: floor(arrowCenterX - arrowSize.width / 2.0), y: -arrowSize.height), size: arrowSize)
} else {
arrowFrame = CGRect(origin: CGPoint(x: floor(arrowCenterX - arrowSize.width / 2.0), y: backgroundFrame.height), size: arrowSize)
}
transition.updateFrame(node: self.arrowContainer, frame: arrowFrame)
ContainedViewLayoutTransition.immediate.updateTransformScale(node: self.arrowContainer, scale: CGPoint(x: 1.0, y: invertArrow ? -1.0 : 1.0))
self.arrowNode.frame = CGRect(origin: CGPoint(), size: arrowFrame.size)
}
transition.updateFrame(node: self.textNode, frame: CGRect(origin: CGPoint(x: contentInset + animationSize.width + animationSpacing, y: floor((backgroundHeight - textSize.height) / 2.0)), size: textSize))
@@ -103,10 +146,18 @@ private final class TooltipScreenNode: ViewControllerTracingNode {
func animateIn() {
self.containerNode.layer.animateSpring(from: NSNumber(value: Float(0.01)), to: NSNumber(value: Float(1.0)), keyPath: "transform.scale", duration: 0.6)
self.containerNode.layer.animateSpring(from: NSValue(cgPoint: CGPoint(x: self.arrowNode.frame.midX - self.containerNode.bounds.width / 2.0, y: self.arrowNode.frame.maxY - self.containerNode.bounds.height / 2.0)), to: NSValue(cgPoint: CGPoint()), keyPath: "position", duration: 0.6, additive: true)
self.containerNode.layer.animateSpring(from: NSValue(cgPoint: CGPoint(x: self.arrowContainer.frame.midX - self.containerNode.bounds.width / 2.0, y: self.arrowContainer.frame.maxY - self.containerNode.bounds.height / 2.0)), to: NSValue(cgPoint: CGPoint()), keyPath: "position", duration: 0.6, additive: true)
self.containerNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.6, execute: { [weak self] in
let animationDelay: Double
switch self.icon {
case .chatListPress:
animationDelay = 0.6
case .info:
animationDelay = 0.2
}
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + animationDelay, execute: { [weak self] in
self?.animatedStickerNode.visibility = true
})
}
@@ -116,13 +167,19 @@ private final class TooltipScreenNode: ViewControllerTracingNode {
completion()
})
self.containerNode.layer.animateScale(from: 1.0, to: 0.01, duration: 0.2, removeOnCompletion: false)
self.containerNode.layer.animatePosition(from: CGPoint(), to: CGPoint(x: self.arrowNode.frame.midX - self.containerNode.bounds.width / 2.0, y: self.arrowNode.frame.maxY - self.containerNode.bounds.height / 2.0), duration: 0.2, removeOnCompletion: false, additive: true)
self.containerNode.layer.animatePosition(from: CGPoint(), to: CGPoint(x: self.arrowContainer.frame.midX - self.containerNode.bounds.width / 2.0, y: self.arrowContainer.frame.maxY - self.containerNode.bounds.height / 2.0), duration: 0.2, removeOnCompletion: false, additive: true)
}
}
public final class TooltipScreen: ViewController {
public enum Icon {
case info
case chatListPress
}
private let text: String
private let location: CGPoint
private let icon: TooltipScreen.Icon
private let location: CGRect
private let shouldDismissOnTouch: (CGPoint) -> Bool
private var controllerNode: TooltipScreenNode {
@@ -132,8 +189,9 @@ public final class TooltipScreen: ViewController {
private var validLayout: ContainerViewLayout?
private var isDismissed: Bool = false
public init(text: String, location: CGPoint, shouldDismissOnTouch: @escaping (CGPoint) -> Bool) {
public init(text: String, icon: TooltipScreen.Icon, location: CGRect, shouldDismissOnTouch: @escaping (CGPoint) -> Bool) {
self.text = text
self.icon = icon
self.location = location
self.shouldDismissOnTouch = shouldDismissOnTouch
@@ -151,13 +209,13 @@ public final class TooltipScreen: ViewController {
self.controllerNode.animateIn()
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 5.0, execute: { [weak self] in
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 8.0, execute: { [weak self] in
self?.dismiss()
})
}
override public func loadDisplayNode() {
self.displayNode = TooltipScreenNode(text: self.text, location: self.location, shouldDismissOnTouch: self.shouldDismissOnTouch, requestDismiss: { [weak self] in
self.displayNode = TooltipScreenNode(text: self.text, icon: self.icon, location: self.location, shouldDismissOnTouch: self.shouldDismissOnTouch, requestDismiss: { [weak self] in
guard let strongSelf = self else {
return
}