mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
129 lines
5.0 KiB
Swift
129 lines
5.0 KiB
Swift
import Foundation
|
|
import AsyncDisplayKit
|
|
import Display
|
|
|
|
struct EditableTokenListToken {
|
|
let id: AnyHashable
|
|
let title: String
|
|
}
|
|
|
|
private final class TokenNode: ASDisplayNode {
|
|
let token: EditableTokenListToken
|
|
let titleNode: ASTextNode
|
|
|
|
init(token: EditableTokenListToken) {
|
|
self.token = token
|
|
self.titleNode = ASTextNode()
|
|
self.titleNode.isLayerBacked = true
|
|
self.titleNode.maximumNumberOfLines = 1
|
|
|
|
super.init()
|
|
|
|
self.titleNode.attributedText = NSAttributedString(string: token.title + ",", font: Font.regular(15.0), textColor: .black)
|
|
self.addSubnode(self.titleNode)
|
|
}
|
|
|
|
override func calculateSizeThatFits(_ constrainedSize: CGSize) -> CGSize {
|
|
let titleSize = self.titleNode.measure(CGSize(width: constrainedSize.width - 8.0, height: constrainedSize.height))
|
|
return CGSize(width: titleSize.width + 8.0, height: 26.0)
|
|
}
|
|
|
|
override func layout() {
|
|
let titleSize = self.titleNode.calculatedSize
|
|
if titleSize.width.isZero {
|
|
return
|
|
}
|
|
self.titleNode.frame = CGRect(origin: CGPoint(x: 4.0, y: floor((self.bounds.size.height - titleSize.height) / 2.0)), size: titleSize)
|
|
}
|
|
}
|
|
|
|
final class EditableTokenListNode: ASDisplayNode {
|
|
private let placeholderNode: ASTextNode
|
|
private var tokenNodes: [TokenNode] = []
|
|
private let separatorNode: ASDisplayNode
|
|
|
|
override init() {
|
|
self.placeholderNode = ASTextNode()
|
|
self.placeholderNode.isLayerBacked = true
|
|
self.placeholderNode.maximumNumberOfLines = 1
|
|
self.placeholderNode.attributedText = NSAttributedString(string: "Whom would you like to message?", font: Font.regular(15.0), textColor: UIColor(0x8e8e92))
|
|
|
|
self.separatorNode = ASDisplayNode()
|
|
self.separatorNode.isLayerBacked = true
|
|
self.separatorNode.backgroundColor = UIColor(0xc7c6cb)
|
|
|
|
super.init()
|
|
|
|
self.backgroundColor = UIColor(0xf7f7f7)
|
|
self.addSubnode(self.placeholderNode)
|
|
self.addSubnode(self.separatorNode)
|
|
self.clipsToBounds = true
|
|
}
|
|
|
|
func updateLayout(tokens: [EditableTokenListToken], width: CGFloat, transition: ContainedViewLayoutTransition) -> CGFloat {
|
|
let validTokens = Set<AnyHashable>(tokens.map { $0.id })
|
|
|
|
for i in (0 ..< self.tokenNodes.count).reversed() {
|
|
let tokenNode = tokenNodes[i]
|
|
if !validTokens.contains(tokenNode.token.id) {
|
|
self.tokenNodes.remove(at: i)
|
|
transition.updateAlpha(node: tokenNode, alpha: 0.0, completion: { [weak tokenNode] _ in
|
|
tokenNode?.removeFromSupernode()
|
|
})
|
|
}
|
|
}
|
|
|
|
let sideInset: CGFloat = 4.0
|
|
let verticalInset: CGFloat = 7.0
|
|
|
|
let placeholderSize = self.placeholderNode.measure(CGSize(width: max(1.0, width - sideInset - sideInset), height: CGFloat.greatestFiniteMagnitude))
|
|
self.placeholderNode.frame = CGRect(origin: CGPoint(x: sideInset + 4.0, y: verticalInset + floor((26.0 - placeholderSize.height) / 2.0)), size: placeholderSize)
|
|
|
|
transition.updateAlpha(node: self.placeholderNode, alpha: tokens.isEmpty ? 1.0 : 0.0)
|
|
|
|
var currentOffset = CGPoint(x: sideInset, y: verticalInset)
|
|
for token in tokens {
|
|
var currentNode: TokenNode?
|
|
for node in self.tokenNodes {
|
|
if node.token.id == token.id {
|
|
currentNode = node
|
|
break
|
|
}
|
|
}
|
|
let tokenNode: TokenNode
|
|
var animateIn = false
|
|
if let currentNode = currentNode {
|
|
tokenNode = currentNode
|
|
} else {
|
|
tokenNode = TokenNode(token: token)
|
|
self.tokenNodes.append(tokenNode)
|
|
self.addSubnode(tokenNode)
|
|
animateIn = true
|
|
}
|
|
|
|
let tokenSize = tokenNode.measure(CGSize(width: max(1.0, width - sideInset - sideInset), height: CGFloat.greatestFiniteMagnitude))
|
|
if tokenSize.width + currentOffset.x >= width - sideInset {
|
|
currentOffset.x = sideInset
|
|
currentOffset.y += tokenSize.height
|
|
}
|
|
let tokenFrame = CGRect(origin: CGPoint(x: currentOffset.x, y: currentOffset.y), size: tokenSize)
|
|
currentOffset.x += tokenSize.width
|
|
|
|
if animateIn {
|
|
tokenNode.frame = tokenFrame
|
|
tokenNode.alpha = 0.0
|
|
transition.updateAlpha(node: tokenNode, alpha: 1.0)
|
|
} else {
|
|
transition.updateFrame(node: tokenNode, frame: tokenFrame)
|
|
}
|
|
}
|
|
|
|
let nodeHeight = currentOffset.y + 28.0 + verticalInset
|
|
|
|
let separatorHeight = UIScreenPixel
|
|
transition.updateFrame(node: self.separatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: nodeHeight - separatorHeight), size: CGSize(width: width, height: separatorHeight)))
|
|
|
|
return nodeHeight
|
|
}
|
|
}
|