mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
118 lines
4.1 KiB
Swift
118 lines
4.1 KiB
Swift
import Foundation
|
|
import UIKit
|
|
import Display
|
|
import AsyncDisplayKit
|
|
|
|
public class CompositeTextNode: ASDisplayNode {
|
|
public enum Component: Equatable {
|
|
case text(NSAttributedString)
|
|
case icon(UIImage)
|
|
}
|
|
|
|
public var components: [Component] = []
|
|
|
|
private var textNodes: [Int: ImmediateTextNode] = [:]
|
|
private var iconViews: [Int: UIImageView] = [:]
|
|
|
|
public var imageTintColor: UIColor? {
|
|
didSet {
|
|
for (_, textNode) in self.textNodes {
|
|
textNode.layer.layerTintColor = self.imageTintColor?.cgColor
|
|
}
|
|
for (_, iconView) in self.iconViews {
|
|
iconView.tintColor = self.imageTintColor
|
|
}
|
|
}
|
|
}
|
|
|
|
public func update(constrainedSize: CGSize) -> CGSize {
|
|
var validTextIds: [Int] = []
|
|
var validIconIds: [Int] = []
|
|
|
|
var size = CGSize()
|
|
|
|
var nextTextId = 0
|
|
var nextIconId = 0
|
|
for component in self.components {
|
|
switch component {
|
|
case let .text(text):
|
|
let id = nextTextId
|
|
nextTextId += 1
|
|
validTextIds.append(id)
|
|
|
|
let textNode: ImmediateTextNode
|
|
if let current = self.textNodes[id] {
|
|
textNode = current
|
|
} else {
|
|
textNode = ImmediateTextNode()
|
|
textNode.maximumNumberOfLines = 1
|
|
textNode.insets = UIEdgeInsets(top: 3.0, left: 0.0, bottom: 3.0, right: 0.0)
|
|
textNode.layer.layerTintColor = self.imageTintColor?.cgColor
|
|
self.textNodes[id] = textNode
|
|
self.addSubnode(textNode)
|
|
}
|
|
textNode.attributedText = text
|
|
|
|
let textSize = textNode.updateLayout(CGSize(width: max(1.0, constrainedSize.width - size.width), height: constrainedSize.height))
|
|
|
|
textNode.frame = CGRect(origin: CGPoint(x: size.width - textNode.insets.left, y: -textNode.insets.top), size: textSize)
|
|
size.width += textSize.width - textNode.insets.left - textNode.insets.right
|
|
size.height = max(size.height, textSize.height - textNode.insets.top - textNode.insets.bottom)
|
|
case let .icon(icon):
|
|
let id = nextIconId
|
|
nextIconId += 1
|
|
validIconIds.append(id)
|
|
|
|
let iconView: UIImageView
|
|
if let current = self.iconViews[id] {
|
|
iconView = current
|
|
} else {
|
|
iconView = UIImageView()
|
|
self.iconViews[id] = iconView
|
|
self.view.addSubview(iconView)
|
|
}
|
|
iconView.image = icon
|
|
iconView.tintColor = self.imageTintColor
|
|
|
|
let iconSize = icon.size
|
|
if size.width != 0.0 {
|
|
size.width += 3.0
|
|
}
|
|
iconView.frame = CGRect(origin: CGPoint(x: size.width, y: 3.0 + UIScreenPixel), size: iconSize)
|
|
size.width += iconSize.width
|
|
size.width += 3.0
|
|
size.height = max(size.height, iconSize.height)
|
|
}
|
|
|
|
if size.width >= constrainedSize.width {
|
|
size.width = constrainedSize.width
|
|
break
|
|
}
|
|
}
|
|
|
|
var removeTextIds: [Int] = []
|
|
for (id, textNode) in self.textNodes {
|
|
if !validTextIds.contains(id) {
|
|
textNode.removeFromSupernode()
|
|
removeTextIds.append(id)
|
|
}
|
|
}
|
|
for id in removeTextIds {
|
|
self.textNodes.removeValue(forKey: id)
|
|
}
|
|
|
|
var removeIconIds: [Int] = []
|
|
for (id, iconView) in self.iconViews {
|
|
if !validIconIds.contains(id) {
|
|
iconView.removeFromSuperview()
|
|
removeIconIds.append(id)
|
|
}
|
|
}
|
|
for id in removeIconIds {
|
|
self.iconViews.removeValue(forKey: id)
|
|
}
|
|
|
|
return size
|
|
}
|
|
}
|