mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
148 lines
7.7 KiB
Swift
148 lines
7.7 KiB
Swift
import Foundation
|
|
import Display
|
|
import AsyncDisplayKit
|
|
import Postbox
|
|
import TelegramCore
|
|
|
|
final class SecureIdAuthControllerNode: ViewControllerTracingNode {
|
|
private let account: Account
|
|
private var presentationData: PresentationData
|
|
private let requestLayout: (ContainedViewLayoutTransition) -> Void
|
|
private let interaction: SecureIdAuthControllerInteraction
|
|
|
|
private var validLayout: (ContainerViewLayout, CGFloat)?
|
|
|
|
private let headerNode: SecureIdAuthHeaderNode
|
|
private var contentNode: (ASDisplayNode & SecureIdAuthContentNode)?
|
|
|
|
private var scheduledLayoutTransitionRequestId: Int = 0
|
|
private var scheduledLayoutTransitionRequest: (Int, ContainedViewLayoutTransition)?
|
|
|
|
init(account: Account, presentationData: PresentationData, requestLayout: @escaping (ContainedViewLayoutTransition) -> Void, interaction: SecureIdAuthControllerInteraction) {
|
|
self.account = account
|
|
self.presentationData = presentationData
|
|
self.requestLayout = requestLayout
|
|
self.interaction = interaction
|
|
|
|
self.headerNode = SecureIdAuthHeaderNode(account: account, theme: presentationData.theme, strings: presentationData.strings)
|
|
|
|
super.init()
|
|
|
|
self.backgroundColor = presentationData.theme.list.blocksBackgroundColor
|
|
}
|
|
|
|
func animateIn() {
|
|
self.layer.animatePosition(from: CGPoint(x: self.layer.position.x, y: self.layer.position.y + self.layer.bounds.size.height), to: self.layer.position, duration: 0.5, timingFunction: kCAMediaTimingFunctionSpring)
|
|
}
|
|
|
|
func animateOut(completion: (() -> Void)? = nil) {
|
|
self.view.endEditing(true)
|
|
self.layer.animatePosition(from: self.layer.position, to: CGPoint(x: self.layer.position.x, y: self.layer.position.y + self.layer.bounds.size.height), duration: 0.2, timingFunction: kCAMediaTimingFunctionEaseInEaseOut, removeOnCompletion: false, completion: { _ in
|
|
completion?()
|
|
})
|
|
}
|
|
|
|
func containerLayoutUpdated(_ layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition: ContainedViewLayoutTransition) {
|
|
self.validLayout = (layout, navigationBarHeight)
|
|
|
|
var insets = layout.insets(options: [.input])
|
|
insets.bottom = max(insets.bottom, layout.safeInsets.bottom)
|
|
|
|
let contentRect = CGRect(origin: CGPoint(x: 0.0, y: navigationBarHeight), size: CGSize(width: layout.size.width, height: layout.size.height - insets.bottom - navigationBarHeight))
|
|
|
|
let headerNodeTransition: ContainedViewLayoutTransition = headerNode.bounds.isEmpty ? .immediate : transition
|
|
let headerHeight = self.headerNode.updateLayout(width: layout.size.width, transition: headerNodeTransition)
|
|
|
|
if let contentNode = self.contentNode {
|
|
let contentNodeTransition: ContainedViewLayoutTransition = contentNode.bounds.isEmpty ? .immediate : transition
|
|
let contentLayout = contentNode.updateLayout(width: layout.size.width, transition: contentNodeTransition)
|
|
|
|
let contentSpacing: CGFloat = 70.0
|
|
|
|
let boundingHeight = headerHeight + contentLayout.height + contentSpacing
|
|
|
|
let boundingRect = CGRect(origin: CGPoint(x: 0.0, y: contentRect.minY + floor((contentRect.height - boundingHeight) / 2.0)), size: CGSize(width: layout.size.width, height: boundingHeight))
|
|
|
|
headerNodeTransition.updateFrame(node: self.headerNode, frame: CGRect(origin: CGPoint(x: 0.0, y: boundingRect.minY), size: CGSize(width: boundingRect.width, height: headerHeight)))
|
|
|
|
contentNodeTransition.updateFrame(node: contentNode, frame: CGRect(origin: CGPoint(x: 0.0, y: boundingRect.minY + headerHeight + contentSpacing), size: CGSize(width: boundingRect.width, height: contentLayout.height)))
|
|
}
|
|
}
|
|
|
|
func transitionToContentNode(_ contentNode: (ASDisplayNode & SecureIdAuthContentNode)?, transition: ContainedViewLayoutTransition) {
|
|
if let current = self.contentNode {
|
|
current.willDisappear()
|
|
current.animateOut { [weak current] in
|
|
current?.removeFromSupernode()
|
|
}
|
|
}
|
|
|
|
self.contentNode = contentNode
|
|
|
|
if let contentNode = self.contentNode {
|
|
self.addSubnode(contentNode)
|
|
if let (layout, navigationBarHeight) = self.validLayout {
|
|
self.scheduleLayoutTransitionRequest(.animated(duration: 0.5, curve: .spring))
|
|
contentNode.didAppear()
|
|
contentNode.animateIn()
|
|
}
|
|
}
|
|
}
|
|
|
|
func updateState(_ state: SecureIdAuthControllerState, transition: ContainedViewLayoutTransition) {
|
|
if let formData = state.formData, let verificationState = state.verificationState {
|
|
if self.headerNode.supernode == nil {
|
|
self.addSubnode(self.headerNode)
|
|
self.headerNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3)
|
|
}
|
|
self.headerNode.updateState(formData: formData, verificationState: verificationState)
|
|
|
|
switch verificationState {
|
|
case let .passwordChallenge(challengeState):
|
|
if let contentNode = self.contentNode as? SecureIdAuthPasswordOptionContentNode {
|
|
contentNode.updateIsChecking(challengeState == .checking)
|
|
} else {
|
|
let contentNode = SecureIdAuthPasswordOptionContentNode(theme: presentationData.theme, strings: presentationData.strings, checkPassword: { [weak self] password in
|
|
if let strongSelf = self {
|
|
strongSelf.interaction.checkPassword(password)
|
|
}
|
|
})
|
|
contentNode.updateIsChecking(challengeState == .checking)
|
|
self.transitionToContentNode(contentNode, transition: transition)
|
|
|
|
}
|
|
case .noChallenge:
|
|
if self.contentNode != nil {
|
|
self.transitionToContentNode(nil, transition: transition)
|
|
}
|
|
case .verified:
|
|
if let contentNode = self.contentNode as? SecureIdAuthFormContentNode {
|
|
|
|
} else {
|
|
let contentNode = SecureIdAuthFormContentNode(theme: self.presentationData.theme, strings: self.presentationData.strings, form: formData.form, openField: { [weak self] type in
|
|
if let strongSelf = self {
|
|
strongSelf.interaction.present(SecureIdIdentityFormController(account: strongSelf.account, data: nil), nil)
|
|
}
|
|
})
|
|
self.transitionToContentNode(contentNode, transition: transition)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private func scheduleLayoutTransitionRequest(_ transition: ContainedViewLayoutTransition) {
|
|
let requestId = self.scheduledLayoutTransitionRequestId
|
|
self.scheduledLayoutTransitionRequestId += 1
|
|
self.scheduledLayoutTransitionRequest = (requestId, transition)
|
|
(self.view as? UITracingLayerView)?.schedule(layout: { [weak self] in
|
|
if let strongSelf = self {
|
|
if let (currentRequestId, currentRequestTransition) = strongSelf.scheduledLayoutTransitionRequest, currentRequestId == requestId {
|
|
strongSelf.scheduledLayoutTransitionRequest = nil
|
|
strongSelf.requestLayout(currentRequestTransition)
|
|
}
|
|
}
|
|
})
|
|
self.setNeedsLayout()
|
|
}
|
|
}
|