Swiftgram/submodules/TelegramCallsUI/Sources/CallControllerKeyButton.swift
2020-08-05 01:23:05 +03:00

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) })
}
}