Swiftgram/submodules/Display/Source/ActionSheetItemGroupsContainerNode.swift
2022-07-30 03:51:46 +03:00

190 lines
6.4 KiB
Swift

import UIKit
import AsyncDisplayKit
private let groupSpacing: CGFloat = 8.0
final class ActionSheetItemGroupsContainerNode: ASDisplayNode {
var theme: ActionSheetControllerTheme {
didSet {
self.setGroups(self.groups)
if let size = self.validSize {
let _ = self.updateLayout(constrainedSize: size, transition: .immediate)
}
}
}
private var highlightedItemIndex: Int? = nil
private var groups: [ActionSheetItemGroup] = []
var groupNodes: [ActionSheetItemGroupNode] = []
var requestLayout: (() -> Void)?
private var validSize: CGSize?
init(theme: ActionSheetControllerTheme) {
self.theme = theme
super.init()
}
func setHighlightedItemIndex(_ index: Int?, update: Bool = false) {
self.highlightedItemIndex = index
if update {
var groupIndex = 0
var i = 0
for _ in self.groups {
for itemNode in self.groupNodes[groupIndex].itemNodes {
if i == index {
itemNode.setHighlighted(true, animated: false)
} else {
itemNode.setHighlighted(false, animated: false)
}
i += 1
}
groupIndex += 1
}
}
}
func decreaseHighlightedIndex() {
let currentHighlightedIndex = self.highlightedItemIndex ?? 0
self.setHighlightedItemIndex(max(0, currentHighlightedIndex - 1), update: true)
}
func increaseHighlightedIndex() {
let currentHighlightedIndex = self.highlightedItemIndex ?? -1
var groupIndex = 0
var maxAvailabledIndex = 0
for _ in self.groups {
for _ in self.groupNodes[groupIndex].itemNodes {
maxAvailabledIndex += 1
}
groupIndex += 1
}
self.setHighlightedItemIndex(min(maxAvailabledIndex - 1, currentHighlightedIndex + 1), update: true)
}
func performHighlightedAction() {
guard let highlightedItemIndex = self.highlightedItemIndex else {
return
}
var i = 0
var groupIndex = 0
for _ in self.groups {
for itemNode in self.groupNodes[groupIndex].itemNodes {
if i == highlightedItemIndex {
itemNode.performAction()
return
}
i += 1
}
groupIndex += 1
}
}
func setGroups(_ groups: [ActionSheetItemGroup]) {
self.groups = groups
for groupNode in self.groupNodes {
groupNode.removeFromSupernode()
}
self.groupNodes.removeAll()
var i = 0
for group in groups {
let groupNode = ActionSheetItemGroupNode(theme: self.theme)
let itemNodes = group.items.map({ $0.node(theme: self.theme) })
for node in itemNodes {
node.requestLayout = { [weak self] in
self?.requestLayout?()
}
let index = i
node.highlightedUpdated = { [weak self] highlighted in
if highlighted {
self?.highlightedItemIndex = index
}
}
i += 1
}
groupNode.updateItemNodes(itemNodes, leadingVisibleNodeCount: group.leadingVisibleNodeCount ?? 1000.0)
self.groupNodes.append(groupNode)
self.addSubnode(groupNode)
}
}
func updateLayout(constrainedSize: CGSize, transition: ContainedViewLayoutTransition) -> CGSize {
self.validSize = constrainedSize
var groupsHeight: CGFloat = 0.0
var calculatedSizes: [CGSize] = []
for groupNode in self.groupNodes.reversed() {
if CGFloat(0.0).isLess(than: groupsHeight) {
groupsHeight += groupSpacing
}
let size = groupNode.updateLayout(constrainedSize: CGSize(width: constrainedSize.width, height: max(0.0, constrainedSize.height - groupsHeight)), transition: transition)
calculatedSizes.insert(size, at: 0)
groupsHeight += size.height
}
var itemGroupsHeight: CGFloat = 0.0
for i in 0 ..< self.groupNodes.count {
let groupNode = self.groupNodes[i]
let size = calculatedSizes[i]
if i != 0 {
itemGroupsHeight += groupSpacing
transition.updateFrame(view: self.groupNodes[i - 1].trailingDimView, frame: CGRect(x: 0.0, y: groupNodes[i - 1].bounds.size.height, width: size.width, height: groupSpacing))
}
transition.updateFrame(node: groupNode, frame: CGRect(origin: CGPoint(x: 0.0, y: itemGroupsHeight), size: size))
transition.updateFrame(view: groupNode.trailingDimView, frame: CGRect())
itemGroupsHeight += size.height
}
return CGSize(width: constrainedSize.width, height: min(groupsHeight, constrainedSize.height))
}
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
guard self.isUserInteractionEnabled else {
return nil
}
for groupNode in self.groupNodes {
if groupNode.frame.contains(point) {
return groupNode.hitTest(self.convert(point, to: groupNode), with: event)
}
}
return nil
}
func animateDimViewsAlpha(from: CGFloat, to: CGFloat, duration: Double) {
for node in self.groupNodes {
node.animateDimViewsAlpha(from: from, to: to, duration: duration)
}
}
public func updateItem(groupIndex: Int, itemIndex: Int, _ f: (ActionSheetItem) -> ActionSheetItem) {
var item = self.groups[groupIndex].items[itemIndex]
let itemNode = self.groupNodes[groupIndex].itemNode(at: itemIndex)
item = f(item)
item.updateNode(itemNode)
var groupItems = self.groups[groupIndex].items
groupItems[itemIndex] = item
self.groups[groupIndex] = ActionSheetItemGroup(items: groupItems)
}
func setItemGroupOverlayNode(groupIndex: Int, node: ActionSheetGroupOverlayNode) {
self.groupNodes[groupIndex].setOverlayNode(node)
}
}