import Foundation import UIKit import Display import AsyncDisplayKit import SwiftSignalKit import TelegramCore import Postbox import TelegramPresentationData import ProgressNavigationButtonNode import AccountContext import CountrySelectionUI import SettingsUI import PhoneNumberFormat import DebugSettingsUI final class AuthorizationSequencePhoneEntryController: ViewController { private var controllerNode: AuthorizationSequencePhoneEntryControllerNode { return self.displayNode as! AuthorizationSequencePhoneEntryControllerNode } private let sharedContext: SharedAccountContext private var account: UnauthorizedAccount private let isTestingEnvironment: Bool private let otherAccountPhoneNumbers: ((String, AccountRecordId, Bool)?, [(String, AccountRecordId, Bool)]) private let network: Network private let presentationData: PresentationData private let openUrl: (String) -> Void private let back: () -> Void private var currentData: (Int32, String?, String)? var inProgress: Bool = false { didSet { if self.inProgress { let item = UIBarButtonItem(customDisplayNode: ProgressNavigationButtonNode(color: self.presentationData.theme.rootController.navigationBar.accentTextColor)) self.navigationItem.rightBarButtonItem = item } else { self.navigationItem.rightBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Common_Next, style: .done, target: self, action: #selector(self.nextPressed)) } self.controllerNode.inProgress = self.inProgress } } var loginWithNumber: ((String, Bool) -> Void)? var accountUpdated: ((UnauthorizedAccount) -> Void)? private let termsDisposable = MetaDisposable() private let hapticFeedback = HapticFeedback() init(sharedContext: SharedAccountContext, account: UnauthorizedAccount, isTestingEnvironment: Bool, otherAccountPhoneNumbers: ((String, AccountRecordId, Bool)?, [(String, AccountRecordId, Bool)]), network: Network, presentationData: PresentationData, openUrl: @escaping (String) -> Void, back: @escaping () -> Void) { self.sharedContext = sharedContext self.account = account self.isTestingEnvironment = isTestingEnvironment self.otherAccountPhoneNumbers = otherAccountPhoneNumbers self.network = network self.presentationData = presentationData self.openUrl = openUrl self.back = back super.init(navigationBarPresentationData: NavigationBarPresentationData(theme: AuthorizationSequenceController.navigationBarTheme(presentationData.theme), strings: NavigationBarStrings(presentationStrings: presentationData.strings))) self.supportedOrientations = ViewControllerSupportedOrientations(regularSize: .all, compactSize: .portrait) self.hasActiveInput = true self.statusBar.statusBarStyle = presentationData.theme.intro.statusBarStyle.style self.attemptNavigation = { _ in return false } self.navigationBar?.backPressed = { back() } if !otherAccountPhoneNumbers.1.isEmpty { self.navigationItem.leftBarButtonItem = UIBarButtonItem(title: presentationData.strings.Common_Cancel, style: .plain, target: self, action: #selector(self.cancelPressed)) } self.navigationItem.rightBarButtonItem = UIBarButtonItem(title: presentationData.strings.Common_Next, style: .done, target: self, action: #selector(self.nextPressed)) } required init(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } deinit { self.termsDisposable.dispose() } @objc private func cancelPressed() { self.back() } func updateData(countryCode: Int32, countryName: String?, number: String) { self.currentData = (countryCode, countryName, number) if self.isNodeLoaded { self.controllerNode.codeAndNumber = (countryCode, countryName, number) } } override public func loadDisplayNode() { self.displayNode = AuthorizationSequencePhoneEntryControllerNode(sharedContext: self.sharedContext, account: self.account, strings: self.presentationData.strings, theme: self.presentationData.theme, debugAction: { [weak self] in guard let strongSelf = self else { return } strongSelf.view.endEditing(true) self?.present(debugController(sharedContext: strongSelf.sharedContext, context: nil, modal: true), in: .window(.root), with: ViewControllerPresentationArguments(presentationAnimation: .modalSheet)) }, hasOtherAccounts: self.otherAccountPhoneNumbers.0 != nil) self.controllerNode.accountUpdated = { [weak self] account in guard let strongSelf = self else { return } strongSelf.account = account strongSelf.accountUpdated?(account) } if let (code, name, number) = self.currentData { self.controllerNode.codeAndNumber = (code, name, number) } self.displayNodeDidLoad() self.controllerNode.view.disableAutomaticKeyboardHandling = [.forward, .backward] self.controllerNode.selectCountryCode = { [weak self] in if let strongSelf = self { let controller = AuthorizationSequenceCountrySelectionController(strings: strongSelf.presentationData.strings, theme: strongSelf.presentationData.theme) controller.completeWithCountryCode = { code, name in if let strongSelf = self, let currentData = strongSelf.currentData { strongSelf.updateData(countryCode: Int32(code), countryName: name, number: currentData.2) strongSelf.controllerNode.activateInput() } } controller.dismissed = { self?.controllerNode.activateInput() } strongSelf.push(controller) } } self.controllerNode.checkPhone = { [weak self] in self?.nextPressed() } loadServerCountryCodes(accountManager: sharedContext.accountManager, engine: TelegramEngineUnauthorized(account: self.account), completion: { [weak self] in if let strongSelf = self { strongSelf.controllerNode.updateCountryCode() } }) } override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) self.controllerNode.activateInput() } override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) self.controllerNode.activateInput() } override func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) { super.containerLayoutUpdated(layout, transition: transition) self.controllerNode.containerLayoutUpdated(layout, navigationBarHeight: self.navigationLayout(layout: layout).navigationFrame.maxY, transition: transition) } @objc func nextPressed() { let (_, _, number) = self.controllerNode.codeAndNumber if !number.isEmpty { let logInNumber = formatPhoneNumber(self.controllerNode.currentNumber) var existing: (String, AccountRecordId)? for (number, id, isTestingEnvironment) in self.otherAccountPhoneNumbers.1 { if isTestingEnvironment == self.isTestingEnvironment && formatPhoneNumber(number) == logInNumber { existing = (number, id) } } if let (_, id) = existing { var actions: [TextAlertAction] = [] if let (current, _, _) = self.otherAccountPhoneNumbers.0, logInNumber != formatPhoneNumber(current) { actions.append(TextAlertAction(type: .genericAction, title: self.presentationData.strings.Login_PhoneNumberAlreadyAuthorizedSwitch, action: { [weak self] in self?.sharedContext.switchToAccount(id: id, fromSettingsController: nil, withChatListController: nil) self?.back() })) } actions.append(TextAlertAction(type: .defaultAction, title: self.presentationData.strings.Common_OK, action: {})) self.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: self.presentationData), title: nil, text: self.presentationData.strings.Login_PhoneNumberAlreadyAuthorized, actions: actions), in: .window(.root)) } else { self.loginWithNumber?(self.controllerNode.currentNumber, self.controllerNode.syncContacts) } } else { self.hapticFeedback.error() self.controllerNode.animateError() } } }