mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
128 lines
4.6 KiB
Swift
128 lines
4.6 KiB
Swift
import Foundation
|
|
import UIKit
|
|
import Display
|
|
import AsyncDisplayKit
|
|
import CallsEmoji
|
|
|
|
private let labelFont = Font.regular(22.0)
|
|
private let animationNodesCount = 3
|
|
|
|
private class EmojiSlotNode: ASDisplayNode {
|
|
var emoji: String = "" {
|
|
didSet {
|
|
self.node.attributedText = NSAttributedString(string: emoji, font: labelFont, textColor: .black)
|
|
let _ = self.node.updateLayout(CGSize(width: 100.0, height: 100.0))
|
|
}
|
|
}
|
|
|
|
private let maskNode: ASDisplayNode
|
|
private let containerNode: ASDisplayNode
|
|
private let node: ImmediateTextNode
|
|
private let animationNodes: [ImmediateTextNode]
|
|
|
|
override init() {
|
|
self.maskNode = ASDisplayNode()
|
|
self.containerNode = ASDisplayNode()
|
|
self.node = ImmediateTextNode()
|
|
self.animationNodes = (0 ..< animationNodesCount).map { _ in ImmediateTextNode() }
|
|
|
|
super.init()
|
|
|
|
let maskLayer = CAGradientLayer()
|
|
maskLayer.colors = [UIColor.clear.cgColor, UIColor.white.cgColor, UIColor.white.cgColor, UIColor.clear.cgColor]
|
|
maskLayer.locations = [0.0, 0.2, 0.8, 1.0]
|
|
maskLayer.startPoint = CGPoint(x: 0.5, y: 0.0)
|
|
maskLayer.endPoint = CGPoint(x: 0.5, y: 1.0)
|
|
self.maskNode.layer.mask = maskLayer
|
|
|
|
self.addSubnode(self.maskNode)
|
|
self.maskNode.addSubnode(self.containerNode)
|
|
self.containerNode.addSubnode(self.node)
|
|
self.animationNodes.forEach({ self.containerNode.addSubnode($0) })
|
|
}
|
|
|
|
func animateIn(duration: Double) {
|
|
for node in self.animationNodes {
|
|
node.attributedText = NSAttributedString(string: randomCallsEmoji(), font: labelFont, textColor: .black)
|
|
let _ = node.updateLayout(CGSize(width: 100.0, height: 100.0))
|
|
}
|
|
self.containerNode.layer.animatePosition(from: CGPoint(x: 0.0, y: -self.containerNode.frame.height + self.bounds.height), to: CGPoint(), duration: duration, delay: 0.1, timingFunction: kCAMediaTimingFunctionSpring, additive: true)
|
|
}
|
|
|
|
override func layout() {
|
|
super.layout()
|
|
|
|
let maskInset: CGFloat = 4.0
|
|
let maskFrame = self.bounds.insetBy(dx: 0.0, dy: -maskInset)
|
|
self.maskNode.frame = maskFrame
|
|
self.maskNode.layer.mask?.frame = CGRect(origin: CGPoint(), size: maskFrame.size)
|
|
|
|
let spacing: CGFloat = 2.0
|
|
let containerSize = CGSize(width: self.bounds.width, height: self.bounds.height * CGFloat(animationNodesCount + 1) + spacing * CGFloat(animationNodesCount))
|
|
self.containerNode.frame = CGRect(origin: CGPoint(x: 0.0, y: maskInset), size: containerSize)
|
|
|
|
self.node.frame = CGRect(origin: CGPoint(), size: self.bounds.size)
|
|
var offset: CGFloat = self.bounds.height + spacing
|
|
for node in self.animationNodes {
|
|
node.frame = CGRect(origin: CGPoint(x: 0.0, y: offset), size: self.bounds.size)
|
|
offset += self.bounds.height + spacing
|
|
}
|
|
}
|
|
}
|
|
|
|
final class CallControllerKeyButton: HighlightableButtonNode {
|
|
private let containerNode: ASDisplayNode
|
|
private let nodes: [EmojiSlotNode]
|
|
|
|
var key: String = "" {
|
|
didSet {
|
|
var index = 0
|
|
for emoji in self.key {
|
|
guard index < 4 else {
|
|
return
|
|
}
|
|
self.nodes[index].emoji = String(emoji)
|
|
index += 1
|
|
}
|
|
}
|
|
}
|
|
|
|
init() {
|
|
self.containerNode = ASDisplayNode()
|
|
self.nodes = (0 ..< 4).map { _ in EmojiSlotNode() }
|
|
|
|
super.init(pointerStyle: nil)
|
|
|
|
self.addSubnode(self.containerNode)
|
|
self.nodes.forEach({ self.containerNode.addSubnode($0) })
|
|
}
|
|
|
|
func animateIn() {
|
|
self.layoutIfNeeded()
|
|
self.containerNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
|
|
|
|
var duration: Double = 0.75
|
|
for node in self.nodes {
|
|
node.animateIn(duration: duration)
|
|
duration += 0.3
|
|
}
|
|
}
|
|
|
|
override func measure(_ constrainedSize: CGSize) -> CGSize {
|
|
return CGSize(width: 114.0, height: 26.0)
|
|
}
|
|
|
|
override func layout() {
|
|
super.layout()
|
|
|
|
self.containerNode.frame = self.bounds
|
|
var index = 0
|
|
let nodeSize = CGSize(width: 29.0, height: self.bounds.size.height)
|
|
for node in self.nodes {
|
|
node.frame = CGRect(origin: CGPoint(x: CGFloat(index) * nodeSize.width, y: 0.0), size: nodeSize)
|
|
index += 1
|
|
}
|
|
self.nodes.forEach({ self.containerNode.addSubnode($0) })
|
|
}
|
|
}
|