mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
174 lines
6.3 KiB
Swift
174 lines
6.3 KiB
Swift
import Foundation
|
|
import UIKit
|
|
import Display
|
|
import AsyncDisplayKit
|
|
import SwiftSignalKit
|
|
import TelegramPresentationData
|
|
|
|
private final class NotificationContainerControllerNodeView: UITracingLayerView {
|
|
var hitTestImpl: ((CGPoint, UIEvent?) -> UIView?)?
|
|
|
|
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
|
return self.hitTestImpl?(point, event)
|
|
}
|
|
}
|
|
|
|
final class NotificationContainerControllerNode: ASDisplayNode {
|
|
private var validLayout: ContainerViewLayout?
|
|
private var topItemAndNode: (NotificationItem, NotificationItemContainerNode)?
|
|
|
|
var displayingItemsUpdated: ((Bool) -> Void)?
|
|
|
|
private var timeoutTimer: SwiftSignalKit.Timer?
|
|
|
|
private var presentationData: PresentationData
|
|
|
|
init(presentationData: PresentationData) {
|
|
self.presentationData = presentationData
|
|
|
|
super.init()
|
|
|
|
self.setViewBlock({
|
|
return NotificationContainerControllerNodeView()
|
|
})
|
|
|
|
self.backgroundColor = nil
|
|
self.isOpaque = false
|
|
}
|
|
|
|
func updatePresentationData(_ presentationData: PresentationData) {
|
|
self.presentationData = presentationData
|
|
}
|
|
|
|
override func didLoad() {
|
|
super.didLoad()
|
|
|
|
(self.view as! NotificationContainerControllerNodeView).hitTestImpl = { [weak self] point, event in
|
|
return self?.hitTest(point, with: event)
|
|
}
|
|
}
|
|
|
|
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
|
if let (_, topItemNode) = self.topItemAndNode {
|
|
return topItemNode.hitTest(point, with: event)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
|
|
self.validLayout = layout
|
|
|
|
if let (_, topItemNode) = self.topItemAndNode {
|
|
transition.updateFrame(node: topItemNode, frame: CGRect(origin: CGPoint(), size: layout.size))
|
|
topItemNode.updateLayout(layout: layout, transition: transition)
|
|
}
|
|
}
|
|
|
|
func removeItemsWithGroupingKey(_ key: AnyHashable) {
|
|
if let (item, topItemNode) = self.topItemAndNode {
|
|
if item.groupingKey == key {
|
|
self.topItemAndNode = nil
|
|
self.displayingItemsUpdated?(false)
|
|
topItemNode.animateOut(completion: { [weak self, weak topItemNode] in
|
|
topItemNode?.removeFromSupernode()
|
|
})
|
|
}
|
|
}
|
|
}
|
|
|
|
func enqueue(_ item: NotificationItem) {
|
|
if let (_, topItemNode) = self.topItemAndNode {
|
|
topItemNode.animateOut(completion: { [weak self, weak topItemNode] in
|
|
topItemNode?.removeFromSupernode()
|
|
})
|
|
}
|
|
|
|
var useCompactLayout = false
|
|
if let validLayout = self.validLayout {
|
|
useCompactLayout = min(validLayout.size.width, validLayout.size.height) < 375.0
|
|
}
|
|
|
|
let itemNode = item.node(compact: useCompactLayout)
|
|
let containerNode = NotificationItemContainerNode(theme: self.presentationData.theme)
|
|
containerNode.item = item
|
|
containerNode.contentNode = itemNode
|
|
containerNode.dismissed = { [weak self] item in
|
|
if let strongSelf = self {
|
|
if let (topItem, topItemNode) = strongSelf.topItemAndNode, topItem.groupingKey != nil && topItem.groupingKey == item.groupingKey {
|
|
topItemNode.removeFromSupernode()
|
|
strongSelf.topItemAndNode = nil
|
|
|
|
if let strongSelf = self, strongSelf.topItemAndNode == nil {
|
|
strongSelf.displayingItemsUpdated?(false)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
containerNode.cancelTimeout = { [weak self] item in
|
|
if let strongSelf = self {
|
|
if let (topItem, _) = strongSelf.topItemAndNode, topItem.groupingKey != nil && topItem.groupingKey == item.groupingKey {
|
|
strongSelf.timeoutTimer?.invalidate()
|
|
strongSelf.timeoutTimer = nil
|
|
}
|
|
}
|
|
}
|
|
containerNode.resumeTimeout = { [weak self] item in
|
|
if let strongSelf = self {
|
|
if let (topItem, _) = strongSelf.topItemAndNode, topItem.groupingKey != nil && topItem.groupingKey == item.groupingKey {
|
|
strongSelf.resetTimeoutTimer()
|
|
}
|
|
}
|
|
}
|
|
self.topItemAndNode = (item, containerNode)
|
|
self.addSubnode(containerNode)
|
|
|
|
if let validLayout = self.validLayout {
|
|
containerNode.updateLayout(layout: validLayout, transition: .immediate)
|
|
containerNode.frame = CGRect(origin: CGPoint(), size: validLayout.size)
|
|
containerNode.animateIn()
|
|
}
|
|
|
|
self.displayingItemsUpdated?(true)
|
|
|
|
self.resetTimeoutTimer()
|
|
}
|
|
|
|
func removeItems(_ f: (NotificationItem) -> Bool) {
|
|
if let (topItem, topItemNode) = self.topItemAndNode {
|
|
if f(topItem) {
|
|
self.topItemAndNode = nil
|
|
topItemNode.animateOut(completion: { [weak self, weak topItemNode] in
|
|
topItemNode?.removeFromSupernode()
|
|
|
|
if let strongSelf = self, strongSelf.topItemAndNode == nil {
|
|
strongSelf.displayingItemsUpdated?(false)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
}
|
|
|
|
private func resetTimeoutTimer() {
|
|
self.timeoutTimer?.invalidate()
|
|
let timeout: Double
|
|
#if DEBUG
|
|
timeout = 6.0
|
|
#else
|
|
timeout = 5.0
|
|
#endif
|
|
let timeoutTimer = SwiftSignalKit.Timer(timeout: 5.0, repeat: false, completion: { [weak self] in
|
|
if let strongSelf = self {
|
|
if let (_, topItemNode) = strongSelf.topItemAndNode {
|
|
strongSelf.topItemAndNode = nil
|
|
strongSelf.displayingItemsUpdated?(false)
|
|
topItemNode.animateOut(completion: { [weak topItemNode] in
|
|
topItemNode?.removeFromSupernode()
|
|
})
|
|
}
|
|
}
|
|
}, queue: Queue.mainQueue())
|
|
self.timeoutTimer = timeoutTimer
|
|
timeoutTimer.start()
|
|
}
|
|
}
|