mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
123 lines
4.8 KiB
Swift
123 lines
4.8 KiB
Swift
import Foundation
|
|
import AsyncDisplayKit
|
|
import Display
|
|
|
|
private let backgroundImageWithShadow = generateImage(CGSize(width: 30.0 + 8.0 * 2.0, height: 30.0 + 8.0 + 20.0), rotatedContext: { size, context in
|
|
context.clear(CGRect(origin: CGPoint(), size: size))
|
|
context.setShadow(offset: CGSize(width: 0.0, height: -4.0), blur: 40.0, color: UIColor(white: 0.0, alpha: 0.3).cgColor)
|
|
context.setFillColor(UIColor.white.cgColor)
|
|
context.fillEllipse(in: CGRect(origin: CGPoint(x: 8.0, y: 8.0), size: CGSize(width: 30.0, height: 30.0)))
|
|
})?.stretchableImage(withLeftCapWidth: 8 + 15, topCapHeight: 8 + 15)
|
|
|
|
final class NotificationItemContainerNode: ASDisplayNode {
|
|
private let backgroundNode: ASImageNode
|
|
|
|
private var validLayout: ContainerViewLayout?
|
|
|
|
var item: NotificationItem?
|
|
|
|
var contentNode: NotificationItemNode? {
|
|
didSet {
|
|
if self.contentNode !== oldValue {
|
|
oldValue?.removeFromSupernode()
|
|
}
|
|
|
|
if let contentNode = self.contentNode {
|
|
self.addSubnode(contentNode)
|
|
|
|
if let validLayout = self.validLayout {
|
|
self.updateLayout(layout: validLayout, transition: .immediate)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
var dismissed: ((NotificationItem) -> Void)?
|
|
|
|
override init() {
|
|
self.backgroundNode = ASImageNode()
|
|
self.backgroundNode.displayWithoutProcessing = true
|
|
self.backgroundNode.displaysAsynchronously = false
|
|
self.backgroundNode.image = backgroundImageWithShadow
|
|
|
|
super.init()
|
|
|
|
self.addSubnode(self.backgroundNode)
|
|
}
|
|
|
|
override func didLoad() {
|
|
super.didLoad()
|
|
|
|
self.view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.tapGesture(_:))))
|
|
let panRecognizer = UIPanGestureRecognizer(target: self, action: #selector(self.panGesture(_:)))
|
|
panRecognizer.delaysTouchesBegan = false
|
|
panRecognizer.cancelsTouchesInView = false
|
|
self.view.addGestureRecognizer(panRecognizer)
|
|
}
|
|
|
|
func animateIn() {
|
|
self.layer.animatePosition(from: CGPoint(x: 0.0, y: -100.0), to: CGPoint(), duration: 0.4, additive: true)
|
|
}
|
|
|
|
func animateOut(completion: @escaping () -> Void) {
|
|
self.layer.animatePosition(from: CGPoint(), to: CGPoint(x: 0.0, y: -100.0), duration: 0.4, removeOnCompletion: false, additive: true, completion: { _ in
|
|
completion()
|
|
})
|
|
}
|
|
|
|
func updateLayout(layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
|
|
self.validLayout = layout
|
|
|
|
if let contentNode = self.contentNode {
|
|
let contentInsets = UIEdgeInsets(top: 8.0, left: 8.0, bottom: 8.0, right: 8.0)
|
|
let contentWidth = layout.size.width - contentInsets.left - contentInsets.right
|
|
let contentHeight = contentNode.updateLayout(width: contentWidth, transition: transition)
|
|
|
|
transition.updateFrame(node: self.backgroundNode, frame: CGRect(origin: CGPoint(), size: CGSize(width: layout.size.width, height: 8.0 + contentHeight + 20.0)))
|
|
|
|
transition.updateFrame(node: contentNode, frame: CGRect(origin: CGPoint(x: contentInsets.left, y: contentInsets.top), size: CGSize(width: contentWidth, height: contentHeight)))
|
|
}
|
|
}
|
|
|
|
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
|
if let contentNode = self.contentNode, contentNode.frame.contains(point) {
|
|
return self.view
|
|
}
|
|
return nil
|
|
}
|
|
|
|
@objc func tapGesture(_ recognizer: UITapGestureRecognizer) {
|
|
if case .ended = recognizer.state {
|
|
if let item = self.item {
|
|
item.tapped()
|
|
}
|
|
}
|
|
}
|
|
|
|
@objc func panGesture(_ recognizer: UIPanGestureRecognizer) {
|
|
switch recognizer.state {
|
|
case .began:
|
|
break
|
|
case .changed:
|
|
let translation = recognizer.translation(in: self.view)
|
|
var bounds = self.bounds
|
|
bounds.origin.y = max(0.0, -translation.y)
|
|
self.bounds = bounds
|
|
case .ended:
|
|
self.animateOut(completion: { [weak self] in
|
|
if let strongSelf = self, let item = strongSelf.item {
|
|
strongSelf.dismissed?(item)
|
|
}
|
|
})
|
|
case .cancelled:
|
|
let previousBounds = self.bounds
|
|
var bounds = self.bounds
|
|
bounds.origin.y = 0.0
|
|
self.bounds = bounds
|
|
self.layer.animateBounds(from: previousBounds, to: self.bounds, duration: 0.3, timingFunction: kCAMediaTimingFunctionEaseInEaseOut)
|
|
default:
|
|
break
|
|
}
|
|
}
|
|
}
|