2023-10-19 20:25:41 +04:00

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