mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
189 lines
8.6 KiB
Swift
189 lines
8.6 KiB
Swift
import Foundation
|
|
import AsyncDisplayKit
|
|
import Display
|
|
|
|
private let checkmarkImage = generateTintedImage(image: UIImage(bundleImageName: "List Menu/Checkmark")?.precomposed(), color: UIColor(0x007ee5))
|
|
|
|
private final class PeerMediaCollectionModeSelectionCaseNode: ASDisplayNode {
|
|
fileprivate let mode: PeerMediaCollectionMode
|
|
private let selected: () -> Void
|
|
|
|
private let button: HighlightTrackingButton
|
|
private let selectionBackgroundNode: ASDisplayNode
|
|
private let separatorNode: ASDisplayNode
|
|
private let titleNode: ASTextNode
|
|
private let checkmarkView: UIImageView
|
|
|
|
var isSelected = false {
|
|
didSet {
|
|
if self.isSelected != oldValue {
|
|
self.titleNode.attributedText = NSAttributedString(string: titleForPeerMediaCollectionMode(self.mode), font: Font.regular(17.0), textColor: isSelected ? UIColor(0x007ee5) : UIColor.black)
|
|
self.checkmarkView.isHidden = !self.isSelected
|
|
}
|
|
}
|
|
}
|
|
|
|
init(mode: PeerMediaCollectionMode, selected: @escaping () -> Void) {
|
|
self.mode = mode
|
|
self.selected = selected
|
|
|
|
self.button = HighlightTrackingButton()
|
|
|
|
self.selectionBackgroundNode = ASDisplayNode()
|
|
self.selectionBackgroundNode.backgroundColor = UIColor(0xd9d9d9)
|
|
|
|
self.separatorNode = ASDisplayNode()
|
|
self.separatorNode.backgroundColor = UIColor(0xc8c7cc)
|
|
|
|
self.titleNode = ASTextNode()
|
|
self.titleNode.displaysAsynchronously = false
|
|
self.titleNode.maximumNumberOfLines = 1
|
|
self.titleNode.truncationMode = .byTruncatingTail
|
|
self.titleNode.isOpaque = false
|
|
|
|
self.checkmarkView = UIImageView(image: checkmarkImage)
|
|
|
|
super.init()
|
|
|
|
self.addSubnode(self.separatorNode)
|
|
|
|
self.selectionBackgroundNode.alpha = 0.0
|
|
self.addSubnode(self.selectionBackgroundNode)
|
|
|
|
self.titleNode.attributedText = NSAttributedString(string: titleForPeerMediaCollectionMode(mode), font: Font.regular(17.0), textColor: UIColor.black)
|
|
self.addSubnode(self.titleNode)
|
|
|
|
self.checkmarkView.isHidden = true
|
|
self.view.addSubview(self.checkmarkView)
|
|
|
|
self.button.highligthedChanged = { [weak self] highlighted in
|
|
if let strongSelf = self {
|
|
if highlighted {
|
|
strongSelf.selectionBackgroundNode.layer.removeAnimation(forKey: "opacity")
|
|
strongSelf.selectionBackgroundNode.alpha = 1.0
|
|
} else {
|
|
strongSelf.selectionBackgroundNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3)
|
|
strongSelf.selectionBackgroundNode.layer.opacity = 0.0
|
|
}
|
|
}
|
|
}
|
|
self.button.addTarget(self, action: #selector(self.buttonPressed), for: [.touchUpInside])
|
|
self.view.addSubview(self.button)
|
|
}
|
|
|
|
func updateFrames(size: CGSize, transition: ContainedViewLayoutTransition) {
|
|
transition.updateFrame(layer: self.button.layer, frame: CGRect(origin: CGPoint(), size: size))
|
|
|
|
let leftInset: CGFloat = 15.0
|
|
|
|
transition.updateFrame(node: self.selectionBackgroundNode, frame: CGRect(origin: CGPoint(x: 0.0, y: -UIScreenPixel), size: CGSize(width: size.width, height: size.height + UIScreenPixel)))
|
|
transition.updateFrame(node: self.separatorNode, frame: CGRect(origin: CGPoint(x: leftInset, y: -UIScreenPixel), size: CGSize(width: size.width - leftInset, height: UIScreenPixel)))
|
|
|
|
let titleSize = self.titleNode.measure(CGSize(width: size.width - leftInset - 44.0, height: size.height))
|
|
transition.updateFrame(node: self.titleNode, frame: CGRect(origin: CGPoint(x: leftInset, y: floor((size.height - titleSize.height) / 2.0)), size: titleSize))
|
|
|
|
let checkmarkSize = self.checkmarkView.bounds.size
|
|
transition.updateFrame(layer: self.checkmarkView.layer, frame: CGRect(origin: CGPoint(x: size.width - checkmarkSize.width - 14.0, y: floor((size.height - checkmarkSize.height) / 2.0)), size: checkmarkSize))
|
|
}
|
|
|
|
@objc func buttonPressed() {
|
|
self.selected()
|
|
}
|
|
}
|
|
|
|
final class PeerMediaCollectionModeSelectionNode: ASDisplayNode {
|
|
private let dimNode: ASDisplayNode
|
|
private let backgroundNode: ASDisplayNode
|
|
|
|
private var caseNodes: [PeerMediaCollectionModeSelectionCaseNode] = []
|
|
|
|
var selectedMode: ((PeerMediaCollectionMode) -> Void)?
|
|
var dismiss: (() -> Void)?
|
|
|
|
var mediaCollectionInterfaceState = PeerMediaCollectionInterfaceState() {
|
|
didSet {
|
|
for caseNode in self.caseNodes {
|
|
caseNode.isSelected = self.mediaCollectionInterfaceState.mode == caseNode.mode
|
|
}
|
|
}
|
|
}
|
|
|
|
override init() {
|
|
self.dimNode = ASDisplayNode()
|
|
self.dimNode.backgroundColor = UIColor(white: 0.0, alpha: 0.4)
|
|
|
|
self.backgroundNode = ASDisplayNode()
|
|
self.backgroundNode.backgroundColor = UIColor.white
|
|
|
|
super.init()
|
|
|
|
let modes: [PeerMediaCollectionMode] = [.photoOrVideo, .file, .webpage, .music]
|
|
let selected: (PeerMediaCollectionMode) -> Void = { [weak self] mode in
|
|
if let selectedMode = self?.selectedMode {
|
|
selectedMode(mode)
|
|
}
|
|
}
|
|
self.caseNodes = modes.map { mode in
|
|
return PeerMediaCollectionModeSelectionCaseNode(mode: mode, selected: {
|
|
selected(mode)
|
|
})
|
|
}
|
|
|
|
self.addSubnode(self.dimNode)
|
|
self.addSubnode(self.backgroundNode)
|
|
|
|
for caseNode in self.caseNodes {
|
|
self.addSubnode(caseNode)
|
|
}
|
|
|
|
self.dimNode.view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.dimNodeTap(_:))))
|
|
}
|
|
|
|
func animateIn() {
|
|
self.dimNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
|
|
|
|
let backgrounNodePosition = self.backgroundNode.layer.position
|
|
self.backgroundNode.layer.animatePosition(from: CGPoint(x: backgrounNodePosition.x, y: backgrounNodePosition.y - self.backgroundNode.bounds.size.height), to: backgrounNodePosition, duration: 0.3, timingFunction: kCAMediaTimingFunctionSpring)
|
|
|
|
for caseNode in self.caseNodes {
|
|
let caseNodePosition = caseNode.layer.position
|
|
caseNode.layer.animatePosition(from: CGPoint(x: caseNodePosition.x, y: caseNodePosition.y - self.backgroundNode.bounds.size.height), to: caseNodePosition, duration: 0.3, timingFunction: kCAMediaTimingFunctionSpring)
|
|
}
|
|
}
|
|
|
|
func animateOut(completion: @escaping () -> Void) {
|
|
self.dimNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false)
|
|
|
|
let backgrounNodePosition = self.backgroundNode.layer.position
|
|
self.backgroundNode.layer.animatePosition(from: backgrounNodePosition, to: CGPoint(x: backgrounNodePosition.x, y: backgrounNodePosition.y - self.backgroundNode.bounds.size.height), duration: 0.2, removeOnCompletion: false, completion: { _ in
|
|
completion()
|
|
})
|
|
|
|
for caseNode in self.caseNodes {
|
|
let caseNodePosition = caseNode.layer.position
|
|
caseNode.layer.animatePosition(from: caseNodePosition, to: CGPoint(x: caseNodePosition.x, y: caseNodePosition.y - self.backgroundNode.bounds.size.height), duration: 0.2, removeOnCompletion: false)
|
|
}
|
|
}
|
|
|
|
func containerLayoutUpdated(_ layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition: ContainedViewLayoutTransition) {
|
|
transition.updateFrame(node: self.dimNode, frame: CGRect(origin: CGPoint(x: 0.0, y: navigationBarHeight), size: CGSize(width: layout.size.width, height: layout.size.height - navigationBarHeight)))
|
|
|
|
var nextCaseNodeOrigin = CGPoint(x: 0.0, y: navigationBarHeight)
|
|
for caseNode in self.caseNodes {
|
|
transition.updateFrame(node: caseNode, frame: CGRect(origin: nextCaseNodeOrigin, size: CGSize(width: layout.size.width, height: 44.0)))
|
|
caseNode.updateFrames(size: CGSize(width: layout.size.width, height: 44.0), transition: transition)
|
|
nextCaseNodeOrigin.y += 44.0
|
|
}
|
|
|
|
transition.updateFrame(node: self.backgroundNode, frame: CGRect(origin: CGPoint(x: 0.0, y: navigationBarHeight), size: CGSize(width: layout.size.width, height: CGFloat(self.caseNodes.count) * 44.0)))
|
|
}
|
|
|
|
@objc func dimNodeTap(_ recognizer: UITapGestureRecognizer) {
|
|
if case .ended = recognizer.state {
|
|
if let dismiss = self.dismiss {
|
|
dismiss()
|
|
}
|
|
}
|
|
}
|
|
}
|