Swiftgram/TelegramUI/ItemListRevealOptionsNode.swift
Peter Iakovlev 1c6cfdb7f6 no message
2018-03-21 00:56:38 +04:00

185 lines
7.0 KiB
Swift

import Foundation
import AsyncDisplayKit
import Display
//import Lottie
struct ItemListRevealOption: Equatable {
let key: Int32
let title: String
let icon: UIImage?
let color: UIColor
let textColor: UIColor
static func ==(lhs: ItemListRevealOption, rhs: ItemListRevealOption) -> Bool {
if lhs.key != rhs.key {
return false
}
if lhs.title != rhs.title {
return false
}
if !lhs.color.isEqual(rhs.color) {
return false
}
if !lhs.textColor.isEqual(rhs.textColor) {
return false
}
if lhs.icon !== rhs.icon {
return false
}
return true
}
}
private let titleFontWithIcon = Font.regular(13.0)
private let titleFontWithoutIcon = Font.regular(17.0)
final class ItemListRevealOptionNode: ASDisplayNode {
private let titleNode: ASTextNode
private let iconNode: ASImageNode?
//private var animView: LOTView?
init(title: String, icon: UIImage?, color: UIColor, textColor: UIColor) {
self.titleNode = ASTextNode()
self.titleNode.attributedText = NSAttributedString(string: title, font: icon == nil ? titleFontWithoutIcon : titleFontWithIcon, textColor: textColor)
if let icon = icon {
let iconNode = ASImageNode()
iconNode.image = generateTintedImage(image: icon, color: textColor)
self.iconNode = iconNode
} else {
self.iconNode = nil
}
super.init()
self.addSubnode(self.titleNode)
if let iconNode = self.iconNode {
self.addSubnode(iconNode)
}
self.backgroundColor = color
}
override func didLoad() {
super.didLoad()
/*if let url = frameworkBundle.url(forResource: "mute", withExtension: "json") {
let animView = LOTAnimationView(contentsOf: url)
animView.frame = CGRect(origin: CGPoint(), size: CGSize(width: 50.0, height: 50.0))
self.animView = animView
self.view.addSubview(animView)
animView.loopAnimation = true
animView.logHierarchyKeypaths()
animView.setValue(UIColor.green, forKeypath: "Outlines.Group 1.Fill 1.Color", atFrame: 0)
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 2.0, execute: {
animView.play()
})
}*/
}
override func calculateSizeThatFits(_ constrainedSize: CGSize) -> CGSize {
let titleSize = self.titleNode.measure(constrainedSize)
var maxWidth = titleSize.width
if let iconNode = self.iconNode, let image = iconNode.image {
maxWidth = max(image.size.width, maxWidth)
}
return CGSize(width: max(74.0, maxWidth + 20.0), height: constrainedSize.height)
}
override func layout() {
super.layout()
let size = self.bounds.size
let titleSize = self.titleNode.calculatedSize
if let iconNode = self.iconNode, let image = iconNode.image {
let titleIconSpacing: CGFloat = 3.0
iconNode.frame = CGRect(origin: CGPoint(x: floor((size.width - image.size.width) / 2.0), y: floor((size.height - image.size.height - titleIconSpacing - titleSize.height) / 2.0)), size: image.size)
self.titleNode.frame = CGRect(origin: CGPoint(x: floor((size.width - titleSize.width) / 2.0), y: floor((size.height - image.size.height - titleIconSpacing - titleSize.height) / 2.0) + image.size.height + titleIconSpacing), size: titleSize)
} else {
self.titleNode.frame = CGRect(origin: CGPoint(x: floor((size.width - titleSize.width) / 2.0), y: floor((size.height - titleSize.height) / 2.0)), size: titleSize)
}
}
}
final class ItemListRevealOptionsNode: ASDisplayNode {
private let optionSelected: (ItemListRevealOption) -> Void
private var options: [ItemListRevealOption] = []
private var optionNodes: [ItemListRevealOptionNode] = []
private var revealOffset: CGFloat = 0.0
private var rightInset: CGFloat = 0.0
init(optionSelected: @escaping (ItemListRevealOption) -> Void) {
self.optionSelected = optionSelected
super.init()
}
override func didLoad() {
super.didLoad()
self.view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.tapGesture(_:))))
}
func setOptions(_ options: [ItemListRevealOption]) {
if self.options != options {
self.options = options
for node in self.optionNodes {
node.removeFromSupernode()
}
self.optionNodes = options.map { option in
return ItemListRevealOptionNode(title: option.title, icon: option.icon, color: option.color, textColor: option.textColor)
}
for node in self.optionNodes {
self.addSubnode(node)
}
self.invalidateCalculatedLayout()
}
}
override func calculateSizeThatFits(_ constrainedSize: CGSize) -> CGSize {
var maxWidth: CGFloat = 0.0
for node in self.optionNodes {
let nodeSize = node.measure(constrainedSize)
maxWidth = max(nodeSize.width, maxWidth)
}
return CGSize(width: maxWidth * CGFloat(self.optionNodes.count), height: constrainedSize.height)
}
func updateRevealOffset(offset: CGFloat, rightInset: CGFloat, transition: ContainedViewLayoutTransition) {
self.revealOffset = offset
self.rightInset = rightInset
self.updateNodesLayout(transition: transition)
}
private func updateNodesLayout(transition: ContainedViewLayoutTransition) {
let size = self.bounds.size
if size.width.isLessThanOrEqualTo(0.0) || self.optionNodes.isEmpty {
return
}
let basicNodeWidth = floorToScreenPixels(size.width / CGFloat(self.optionNodes.count))
let lastNodeWidth = size.width - basicNodeWidth * CGFloat(self.optionNodes.count - 1)
let revealFactor = min(1.0, self.revealOffset / (size.width + self.rightInset))
var leftOffset: CGFloat = 0.0
for i in 0 ..< self.optionNodes.count {
let node = self.optionNodes[i]
let nodeWidth = i == (self.optionNodes.count - 1) ? lastNodeWidth : basicNodeWidth
transition.updateFrame(node: node, frame: CGRect(origin: CGPoint(x: floorToScreenPixels(leftOffset * revealFactor), y: 0.0), size: CGSize(width: nodeWidth, height: size.height)))
leftOffset += nodeWidth
}
}
@objc func tapGesture(_ recognizer: UITapGestureRecognizer) {
if case .ended = recognizer.state {
let location = recognizer.location(in: self.view)
for i in 0 ..< self.optionNodes.count {
if self.optionNodes[i].frame.contains(location) {
self.optionSelected(self.options[i])
break
}
}
}
}
}