mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
149 lines
7.7 KiB
Swift
149 lines
7.7 KiB
Swift
import Foundation
|
|
import AsyncDisplayKit
|
|
import Display
|
|
import SwiftSignalKit
|
|
|
|
final class UndoOverlayControllerNode: ViewControllerTracingNode {
|
|
private let statusNode: RadialStatusNode
|
|
private let timerTextNode: ImmediateTextNode
|
|
private let textNode: ImmediateTextNode
|
|
private let buttonTextNode: ImmediateTextNode
|
|
private let buttonNode: HighlightTrackingButtonNode
|
|
private let panelNode: ASDisplayNode
|
|
private let action: (Bool) -> Void
|
|
private let dismiss: () -> Void
|
|
|
|
private var remainingSeconds = 5
|
|
private var timer: SwiftSignalKit.Timer?
|
|
|
|
private var validLayout: ContainerViewLayout?
|
|
|
|
init(presentationData: PresentationData, text: String, action: @escaping (Bool) -> Void, dismiss: @escaping () -> Void) {
|
|
self.action = action
|
|
self.dismiss = dismiss
|
|
|
|
self.statusNode = RadialStatusNode(backgroundNodeColor: .clear)
|
|
|
|
self.timerTextNode = ImmediateTextNode()
|
|
self.timerTextNode.displaysAsynchronously = false
|
|
|
|
self.textNode = ImmediateTextNode()
|
|
self.textNode.displaysAsynchronously = false
|
|
|
|
self.textNode.attributedText = NSAttributedString(string: text, font: Font.regular(15.0), textColor: .white)
|
|
|
|
self.buttonTextNode = ImmediateTextNode()
|
|
self.buttonTextNode.displaysAsynchronously = false
|
|
self.buttonTextNode.attributedText = NSAttributedString(string: presentationData.strings.Undo_Undo, font: Font.regular(17.0), textColor: UIColor(rgb: 0x5ac8fa))
|
|
|
|
self.buttonNode = HighlightTrackingButtonNode()
|
|
|
|
self.panelNode = ASDisplayNode()
|
|
self.panelNode.backgroundColor = UIColor(rgb: 0x2e2f30)
|
|
|
|
super.init()
|
|
|
|
self.panelNode.addSubnode(self.timerTextNode)
|
|
self.panelNode.addSubnode(self.statusNode)
|
|
self.panelNode.addSubnode(self.textNode)
|
|
self.panelNode.addSubnode(self.buttonTextNode)
|
|
self.panelNode.addSubnode(self.buttonNode)
|
|
self.addSubnode(self.panelNode)
|
|
|
|
self.buttonNode.highligthedChanged = { [weak self] highlighted in
|
|
if let strongSelf = self {
|
|
if highlighted {
|
|
strongSelf.buttonTextNode.layer.removeAnimation(forKey: "opacity")
|
|
strongSelf.buttonTextNode.alpha = 0.4
|
|
} else {
|
|
strongSelf.buttonTextNode.alpha = 1.0
|
|
strongSelf.buttonTextNode.layer.animateAlpha(from: 0.4, to: 1.0, duration: 0.2)
|
|
}
|
|
}
|
|
}
|
|
self.buttonNode.addTarget(self, action: #selector(self.buttonPressed), forControlEvents: .touchUpInside)
|
|
|
|
self.checkTimer()
|
|
}
|
|
|
|
@objc private func buttonPressed() {
|
|
self.action(false)
|
|
self.dismiss()
|
|
}
|
|
|
|
private func checkTimer() {
|
|
if self.timer != nil {
|
|
self.remainingSeconds -= 1
|
|
}
|
|
if self.remainingSeconds == 0 {
|
|
self.action(true)
|
|
self.dismiss()
|
|
} else {
|
|
if !self.timerTextNode.bounds.size.width.isZero, let snapshot = self.timerTextNode.view.snapshotContentTree() {
|
|
self.panelNode.view.insertSubview(snapshot, aboveSubview: self.timerTextNode.view)
|
|
snapshot.frame = self.timerTextNode.frame
|
|
self.timerTextNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.12)
|
|
self.timerTextNode.layer.animatePosition(from: CGPoint(x: 0.0, y: -10.0), to: CGPoint(), duration: 0.12, removeOnCompletion: false, additive: true)
|
|
snapshot.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.12, removeOnCompletion: false)
|
|
snapshot.layer.animatePosition(from: CGPoint(), to: CGPoint(x: 0.0, y: 10.0), duration: 0.12, removeOnCompletion: false, additive: true, completion: { [weak snapshot] _ in
|
|
snapshot?.removeFromSuperview()
|
|
})
|
|
}
|
|
self.timerTextNode.attributedText = NSAttributedString(string: "\(self.remainingSeconds)", font: Font.regular(16.0), textColor: .white)
|
|
if let validLayout = self.validLayout {
|
|
self.containerLayoutUpdated(layout: validLayout, transition: .immediate)
|
|
}
|
|
let timer = SwiftSignalKit.Timer(timeout: 1.0, repeat: false, completion: { [weak self] in
|
|
self?.checkTimer()
|
|
}, queue: .mainQueue())
|
|
self.timer = timer
|
|
timer.start()
|
|
}
|
|
}
|
|
|
|
func containerLayoutUpdated(layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
|
|
let firstLayout = self.validLayout == nil
|
|
self.validLayout = layout
|
|
|
|
let leftInset: CGFloat = 50.0
|
|
let rightInset: CGFloat = 16.0
|
|
let contentHeight: CGFloat = 50.0
|
|
let panelHeight = contentHeight + layout.intrinsicInsets.bottom
|
|
|
|
transition.updateFrame(node: self.panelNode, frame: CGRect(origin: CGPoint(x: 0.0, y: layout.size.height - panelHeight), size: CGSize(width: layout.size.width, height: panelHeight)))
|
|
|
|
let buttonTextSize = self.buttonTextNode.updateLayout(CGSize(width: 200.0, height: .greatestFiniteMagnitude))
|
|
let buttonTextFrame = CGRect(origin: CGPoint(x: layout.size.width - layout.safeInsets.right - rightInset - buttonTextSize.width, y: floor((panelHeight - buttonTextSize.height) / 2.0)), size: buttonTextSize)
|
|
transition.updateFrame(node: self.buttonTextNode, frame: buttonTextFrame)
|
|
self.buttonNode.frame = CGRect(origin: CGPoint(x: layout.size.width - layout.safeInsets.right - rightInset - buttonTextSize.width - 8.0, y: 0.0), size: CGSize(width: layout.safeInsets.right + rightInset + buttonTextSize.width + 8.0, height: contentHeight))
|
|
|
|
let textSize = self.textNode.updateLayout(CGSize(width: buttonTextFrame.minX - 8.0 - leftInset, height: .greatestFiniteMagnitude))
|
|
transition.updateFrame(node: self.textNode, frame: CGRect(origin: CGPoint(x: leftInset, y: floor((panelHeight - textSize.height) / 2.0)), size: textSize))
|
|
|
|
let timerTextSize = self.timerTextNode.updateLayout(CGSize(width: 100.0, height: 100.0))
|
|
transition.updateFrame(node: self.timerTextNode, frame: CGRect(origin: CGPoint(x: layout.safeInsets.left + floor((leftInset - timerTextSize.width) / 2.0), y: floor((panelHeight - timerTextSize.height) / 2.0)), size: timerTextSize))
|
|
let statusSize: CGFloat = 30.0
|
|
transition.updateFrame(node: self.statusNode, frame: CGRect(origin: CGPoint(x: layout.safeInsets.left + floor((leftInset - statusSize) / 2.0), y: floor((panelHeight - statusSize) / 2.0)), size: CGSize(width: statusSize, height: statusSize)))
|
|
if firstLayout {
|
|
self.statusNode.transitionToState(.secretTimeout(color: .white, icon: nil, beginTime: CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970, timeout: Double(self.remainingSeconds), sparks: false), completion: {})
|
|
}
|
|
}
|
|
|
|
func animateIn() {
|
|
self.panelNode.layer.animatePosition(from: CGPoint(x: 0.0, y: self.panelNode.bounds.height), to: CGPoint(), duration: 0.3, timingFunction: kCAMediaTimingFunctionEaseOut, additive: true)
|
|
}
|
|
|
|
func animateOut(completion: @escaping () -> Void) {
|
|
self.panelNode.layer.animatePosition(from: CGPoint(), to: CGPoint(x: 0.0, y: self.panelNode.bounds.height), duration: 0.25, timingFunction: kCAMediaTimingFunctionEaseOut, removeOnCompletion: false, additive: true, completion: { _ in
|
|
completion()
|
|
})
|
|
}
|
|
|
|
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
|
if !self.panelNode.frame.contains(point) {
|
|
return nil
|
|
}
|
|
return super.hitTest(point, with: event)
|
|
}
|
|
}
|