From c2f42f03e5112ddc6d1fb176ad5c4a999023f3b2 Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Sun, 27 Nov 2022 21:48:44 +0400 Subject: [PATCH 1/2] Phone number change improvements --- .../Telegram-iOS/en.lproj/Localizable.strings | 2 + ...orizationSequenceCodeEntryController.swift | 4 +- .../AuthorizationSequenceController.swift | 64 ++- ...rizationSequencePhoneEntryController.swift | 47 +- ...tionSequencePhoneEntryControllerNode.swift | 87 ++-- ...onSequenceCountrySelectionController.swift | 9 +- .../Sources/PhoneInputNode.swift | 14 +- .../ChangePhoneNumberCodeController.swift | 2 +- .../Sources/ChangePhoneNumberController.swift | 485 +++++++++++------- .../ChangePhoneNumberIntroController.swift | 153 ------ .../PrivacyAndSecurityController.swift | 2 +- .../TelegramUI/Sources/OpenResolvedUrl.swift | 5 +- 12 files changed, 452 insertions(+), 422 deletions(-) delete mode 100644 submodules/SettingsUI/Sources/ChangePhoneNumberIntroController.swift diff --git a/Telegram/Telegram-iOS/en.lproj/Localizable.strings b/Telegram/Telegram-iOS/en.lproj/Localizable.strings index db8c32ea81..acbad4386c 100644 --- a/Telegram/Telegram-iOS/en.lproj/Localizable.strings +++ b/Telegram/Telegram-iOS/en.lproj/Localizable.strings @@ -8335,3 +8335,5 @@ Sorry for the inconvenience."; "UserInfo.AnonymousNumberLabel" = "anonymous number"; "UserInfo.AnonymousNumberInfo" = "This number is not tied to a SIM card and was acquired on [Fragment]()."; + +"Login.NewNumber" = "New Number"; diff --git a/submodules/AuthorizationUI/Sources/AuthorizationSequenceCodeEntryController.swift b/submodules/AuthorizationUI/Sources/AuthorizationSequenceCodeEntryController.swift index b769887bd8..25fa5f7bf7 100644 --- a/submodules/AuthorizationUI/Sources/AuthorizationSequenceCodeEntryController.swift +++ b/submodules/AuthorizationUI/Sources/AuthorizationSequenceCodeEntryController.swift @@ -15,7 +15,6 @@ public final class AuthorizationSequenceCodeEntryController: ViewController { private let strings: PresentationStrings private let theme: PresentationTheme - private let openUrl: (String) -> Void public var loginWithCode: ((String) -> Void)? public var signInWithApple: (() -> Void)? @@ -38,10 +37,9 @@ public final class AuthorizationSequenceCodeEntryController: ViewController { } } - public init(presentationData: PresentationData, openUrl: @escaping (String) -> Void, back: @escaping () -> Void) { + public init(presentationData: PresentationData, back: @escaping () -> Void) { self.strings = presentationData.strings self.theme = presentationData.theme - self.openUrl = openUrl super.init(navigationBarPresentationData: NavigationBarPresentationData(theme: AuthorizationSequenceController.navigationBarTheme(theme), strings: NavigationBarStrings(presentationStrings: strings))) diff --git a/submodules/AuthorizationUI/Sources/AuthorizationSequenceController.swift b/submodules/AuthorizationUI/Sources/AuthorizationSequenceController.swift index 2bd3097765..54e4bd4a04 100644 --- a/submodules/AuthorizationUI/Sources/AuthorizationSequenceController.swift +++ b/submodules/AuthorizationUI/Sources/AuthorizationSequenceController.swift @@ -120,7 +120,7 @@ public final class AuthorizationSequenceController: NavigationController, MFMail let masterDatacenterId = strongSelf.account.masterDatacenterId let isTestingEnvironment = strongSelf.account.testingEnvironment - let countryCode = defaultCountryCode() + let countryCode = AuthorizationSequenceController.defaultCountryCode() let _ = TelegramEngineUnauthorized(account: strongSelf.account).auth.setState(state: UnauthorizedAccountState(isTestingEnvironment: isTestingEnvironment, masterDatacenterId: masterDatacenterId, contents: .phoneEntry(countryCode: countryCode, number: ""))).start() } @@ -275,13 +275,11 @@ public final class AuthorizationSequenceController: NavigationController, MFMail if let currentController = currentController { controller = currentController } else { - controller = AuthorizationSequenceCodeEntryController(presentationData: self.presentationData, openUrl: { [weak self] url in - self?.openUrl(url) - }, back: { [weak self] in + controller = AuthorizationSequenceCodeEntryController(presentationData: self.presentationData, back: { [weak self] in guard let strongSelf = self else { return } - let countryCode = defaultCountryCode() + let countryCode = AuthorizationSequenceController.defaultCountryCode() let _ = TelegramEngineUnauthorized(account: strongSelf.account).auth.setState(state: UnauthorizedAccountState(isTestingEnvironment: strongSelf.account.testingEnvironment, masterDatacenterId: strongSelf.account.masterDatacenterId, contents: .phoneEntry(countryCode: countryCode, number: ""))).start() }) @@ -542,7 +540,7 @@ public final class AuthorizationSequenceController: NavigationController, MFMail guard let strongSelf = self else { return } - let countryCode = defaultCountryCode() + let countryCode = AuthorizationSequenceController.defaultCountryCode() let _ = TelegramEngineUnauthorized(account: strongSelf.account).auth.setState(state: UnauthorizedAccountState(isTestingEnvironment: strongSelf.account.testingEnvironment, masterDatacenterId: strongSelf.account.masterDatacenterId, contents: .phoneEntry(countryCode: countryCode, number: ""))).start() }) @@ -707,7 +705,7 @@ public final class AuthorizationSequenceController: NavigationController, MFMail guard let strongSelf = self else { return } - let countryCode = defaultCountryCode() + let countryCode = AuthorizationSequenceController.defaultCountryCode() let _ = TelegramEngineUnauthorized(account: strongSelf.account).auth.setState(state: UnauthorizedAccountState(isTestingEnvironment: strongSelf.account.testingEnvironment, masterDatacenterId: strongSelf.account.masterDatacenterId, contents: .phoneEntry(countryCode: countryCode, number: ""))).start() }) @@ -852,7 +850,7 @@ public final class AuthorizationSequenceController: NavigationController, MFMail guard let strongSelf = self else { return } - let countryCode = defaultCountryCode() + let countryCode = AuthorizationSequenceController.defaultCountryCode() let _ = TelegramEngineUnauthorized(account: strongSelf.account).auth.setState(state: UnauthorizedAccountState(isTestingEnvironment: strongSelf.account.testingEnvironment, masterDatacenterId: strongSelf.account.masterDatacenterId, contents: .phoneEntry(countryCode: countryCode, number: ""))).start() }) @@ -912,7 +910,7 @@ public final class AuthorizationSequenceController: NavigationController, MFMail guard let strongSelf = self else { return } - let countryCode = defaultCountryCode() + let countryCode = AuthorizationSequenceController.defaultCountryCode() let _ = TelegramEngineUnauthorized(account: strongSelf.account).auth.setState(state: UnauthorizedAccountState(isTestingEnvironment: strongSelf.account.testingEnvironment, masterDatacenterId: strongSelf.account.masterDatacenterId, contents: .phoneEntry(countryCode: countryCode, number: ""))).start() }, displayCancel: displayCancel) @@ -1022,7 +1020,7 @@ public final class AuthorizationSequenceController: NavigationController, MFMail if self.otherAccountPhoneNumbers.1.isEmpty { controllers.append(self.splashController()) } else { - controllers.append(self.phoneEntryController(countryCode: defaultCountryCode(), number: "", splashController: nil)) + controllers.append(self.phoneEntryController(countryCode: AuthorizationSequenceController.defaultCountryCode(), number: "", splashController: nil)) } self.setViewControllers(controllers, animated: !self.viewControllers.isEmpty) } @@ -1050,7 +1048,7 @@ public final class AuthorizationSequenceController: NavigationController, MFMail if !self.otherAccountPhoneNumbers.1.isEmpty { controllers.append(self.splashController()) } - controllers.append(self.phoneEntryController(countryCode: defaultCountryCode(), number: "", splashController: nil)) + controllers.append(self.phoneEntryController(countryCode: AuthorizationSequenceController.defaultCountryCode(), number: "", splashController: nil)) if case let .emailSetupRequired(appleSignInAllowed) = type { self.appleSignInAllowed = appleSignInAllowed controllers.append(self.emailSetupController(number: number, appleSignInAllowed: appleSignInAllowed)) @@ -1156,30 +1154,30 @@ public final class AuthorizationSequenceController: NavigationController, MFMail self?.presentingViewController?.dismiss(animated: false, completion: nil) }) } -} - -private func defaultCountryCode() -> Int32 { - var countryId: String? = nil - let networkInfo = CTTelephonyNetworkInfo() - if let carrier = networkInfo.subscriberCellularProvider { - countryId = carrier.isoCountryCode - } - if countryId == nil { - countryId = (Locale.current as NSLocale).object(forKey: .countryCode) as? String - } - - var countryCode: Int32 = 1 - - if let countryId = countryId { - let normalizedId = countryId.uppercased() - for (code, idAndName) in countryCodeToIdAndName { - if idAndName.0 == normalizedId { - countryCode = Int32(code) - break + public static func defaultCountryCode() -> Int32 { + var countryId: String? = nil + let networkInfo = CTTelephonyNetworkInfo() + if let carrier = networkInfo.subscriberCellularProvider { + countryId = carrier.isoCountryCode + } + + if countryId == nil { + countryId = (Locale.current as NSLocale).object(forKey: .countryCode) as? String + } + + var countryCode: Int32 = 1 + + if let countryId = countryId { + let normalizedId = countryId.uppercased() + for (code, idAndName) in countryCodeToIdAndName { + if idAndName.0 == normalizedId { + countryCode = Int32(code) + break + } } } + + return countryCode } - - return countryCode } diff --git a/submodules/AuthorizationUI/Sources/AuthorizationSequencePhoneEntryController.swift b/submodules/AuthorizationUI/Sources/AuthorizationSequencePhoneEntryController.swift index 4a0b573690..94f20e431e 100644 --- a/submodules/AuthorizationUI/Sources/AuthorizationSequencePhoneEntryController.swift +++ b/submodules/AuthorizationUI/Sources/AuthorizationSequencePhoneEntryController.swift @@ -11,8 +11,9 @@ import AccountContext import CountrySelectionUI import PhoneNumberFormat import DebugSettingsUI +import MessageUI -final class AuthorizationSequencePhoneEntryController: ViewController { +public final class AuthorizationSequencePhoneEntryController: ViewController, MFMailComposeViewControllerDelegate { private var controllerNode: AuthorizationSequencePhoneEntryControllerNode { return self.displayNode as! AuthorizationSequencePhoneEntryControllerNode } @@ -20,7 +21,7 @@ final class AuthorizationSequencePhoneEntryController: ViewController { private var validLayout: ContainerViewLayout? private let sharedContext: SharedAccountContext - private var account: UnauthorizedAccount + private var account: UnauthorizedAccount? private let isTestingEnvironment: Bool private let otherAccountPhoneNumbers: ((String, AccountRecordId, Bool)?, [(String, AccountRecordId, Bool)]) private let network: Network @@ -43,14 +44,14 @@ final class AuthorizationSequencePhoneEntryController: ViewController { return self.controllerNode.buttonNode } - var inProgress: Bool = false { + public var inProgress: Bool = false { didSet { self.updateNavigationItems() self.controllerNode.inProgress = self.inProgress self.confirmationController?.inProgress = self.inProgress } } - var loginWithNumber: ((String, Bool) -> Void)? + public var loginWithNumber: ((String, Bool) -> Void)? var accountUpdated: ((UnauthorizedAccount) -> Void)? weak var confirmationController: PhoneConfirmationController? @@ -59,7 +60,7 @@ final class AuthorizationSequencePhoneEntryController: ViewController { 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) { + public init(sharedContext: SharedAccountContext, account: UnauthorizedAccount?, countriesConfiguration: CountriesConfiguration? = nil, 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 @@ -86,6 +87,10 @@ final class AuthorizationSequencePhoneEntryController: ViewController { if !otherAccountPhoneNumbers.1.isEmpty { self.navigationItem.leftBarButtonItem = UIBarButtonItem(title: presentationData.strings.Common_Cancel, style: .plain, target: self, action: #selector(self.cancelPressed)) } + + if let countriesConfiguration { + AuthorizationSequenceCountrySelectionController.setupCountryCodes(countries: countriesConfiguration.countries, codesByPrefix: countriesConfiguration.countriesByPrefix) + } } required init(coder aDecoder: NSCoder) { @@ -113,7 +118,7 @@ final class AuthorizationSequencePhoneEntryController: ViewController { } } - func updateData(countryCode: Int32, countryName: String?, number: String) { + public func updateData(countryCode: Int32, countryName: String?, number: String) { self.currentData = (countryCode, countryName, number) if self.isNodeLoaded { self.controllerNode.codeAndNumber = (countryCode, countryName, number) @@ -173,15 +178,23 @@ final class AuthorizationSequencePhoneEntryController: ViewController { self?.nextPressed() } - loadServerCountryCodes(accountManager: sharedContext.accountManager, engine: TelegramEngineUnauthorized(account: self.account), completion: { [weak self] in - if let strongSelf = self { - strongSelf.controllerNode.updateCountryCode() - } - }) + if let account = self.account { + loadServerCountryCodes(accountManager: sharedContext.accountManager, engine: TelegramEngineUnauthorized(account: account), completion: { [weak self] in + if let strongSelf = self { + strongSelf.controllerNode.updateCountryCode() + } + }) + } else { + self.controllerNode.updateCountryCode() + } + } + + public func updateCountryCode() { + self.controllerNode.updateCountryCode() } private var animatingIn = false - override func viewWillAppear(_ animated: Bool) { + override public func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) if self.shouldAnimateIn { @@ -197,7 +210,7 @@ final class AuthorizationSequencePhoneEntryController: ViewController { } } - override func viewDidAppear(_ animated: Bool) { + override public func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) if !self.animatingIn { @@ -205,7 +218,7 @@ final class AuthorizationSequencePhoneEntryController: ViewController { } } - override func viewWillDisappear(_ animated: Bool) { + override public func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) if let confirmationController = self.confirmationController { @@ -213,7 +226,7 @@ final class AuthorizationSequencePhoneEntryController: ViewController { } } - override func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) { + override public func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) { super.containerLayoutUpdated(layout, transition: transition) let hadLayout = self.validLayout != nil @@ -287,4 +300,8 @@ final class AuthorizationSequencePhoneEntryController: ViewController { self.controllerNode.animateError() } } + + public func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) { + controller.dismiss(animated: true, completion: nil) + } } diff --git a/submodules/AuthorizationUI/Sources/AuthorizationSequencePhoneEntryControllerNode.swift b/submodules/AuthorizationUI/Sources/AuthorizationSequencePhoneEntryControllerNode.swift index f224bf656c..511edeeeb7 100644 --- a/submodules/AuthorizationUI/Sources/AuthorizationSequencePhoneEntryControllerNode.swift +++ b/submodules/AuthorizationUI/Sources/AuthorizationSequencePhoneEntryControllerNode.swift @@ -18,6 +18,8 @@ import ManagedAnimationNode private final class PhoneAndCountryNode: ASDisplayNode { let strings: PresentationStrings + let theme: PresentationTheme + let countryButton: ASButtonNode let phoneBackground: ASImageNode let phoneInputNode: PhoneInputNode @@ -33,6 +35,7 @@ private final class PhoneAndCountryNode: ASDisplayNode { init(strings: PresentationStrings, theme: PresentationTheme) { self.strings = strings + self.theme = theme let inset: CGFloat = 24.0 @@ -118,37 +121,10 @@ private final class PhoneAndCountryNode: ASDisplayNode { self.countryButton.contentHorizontalAlignment = .left self.countryButton.addTarget(self, action: #selector(self.countryPressed), forControlEvents: .touchUpInside) - - let processNumberChange: (String) -> Bool = { [weak self] number in - guard let strongSelf = self else { - return false - } - if let (country, _) = AuthorizationSequenceCountrySelectionController.lookupCountryIdByNumber(number, preferredCountries: strongSelf.preferredCountryIdForCode) { - let flagString = emojiFlagForISOCountryCode(country.id) - var localizedName: String = AuthorizationSequenceCountrySelectionController.lookupCountryNameById(country.id, strings: strongSelf.strings) ?? country.name - if country.id == "FT" { - localizedName = strongSelf.strings.Login_AnonymousNumbers - } - strongSelf.countryButton.setTitle("\(flagString) \(localizedName)", with: Font.regular(20.0), with: theme.list.itemAccentColor, for: []) - strongSelf.hasCountry = true - let maskFont = Font.with(size: 20.0, design: .regular, traits: [.monospacedNumbers]) - if let mask = AuthorizationSequenceCountrySelectionController.lookupPatternByNumber(number, preferredCountries: strongSelf.preferredCountryIdForCode).flatMap({ NSAttributedString(string: $0, font: maskFont, textColor: theme.list.itemPlaceholderTextColor) }) { - strongSelf.phoneInputNode.numberField.textField.attributedPlaceholder = nil - strongSelf.phoneInputNode.mask = mask - } else { - strongSelf.phoneInputNode.mask = nil - strongSelf.phoneInputNode.numberField.textField.attributedPlaceholder = NSAttributedString(string: strings.Login_PhonePlaceholder, font: Font.regular(20.0), textColor: theme.list.itemPlaceholderTextColor) - } - return true - } else { - return false - } - } - self.phoneInputNode.numberTextUpdated = { [weak self] number in if let strongSelf = self { - let _ = processNumberChange(strongSelf.phoneInputNode.number) + let _ = strongSelf.processNumberChange(number: strongSelf.phoneInputNode.number) if strongSelf.hasCountry { strongSelf.hasNumberUpdated?(!strongSelf.phoneInputNode.codeAndNumber.2.isEmpty) @@ -164,7 +140,7 @@ private final class PhoneAndCountryNode: ASDisplayNode { strongSelf.preferredCountryIdForCode[code] = name } - if processNumberChange(strongSelf.phoneInputNode.number) { + if strongSelf.processNumberChange(number: strongSelf.phoneInputNode.number) { } else if let code = Int(code), let name = name, let countryName = countryCodeAndIdToName[CountryCodeAndId(code: code, id: name)] { let flagString = emojiFlagForISOCountryCode(name) var localizedName: String = AuthorizationSequenceCountrySelectionController.lookupCountryNameById(name, strings: strongSelf.strings) ?? countryName @@ -222,6 +198,30 @@ private final class PhoneAndCountryNode: ASDisplayNode { } } + func processNumberChange(number: String) -> Bool { + if let (country, _) = AuthorizationSequenceCountrySelectionController.lookupCountryIdByNumber(number, preferredCountries: self.preferredCountryIdForCode) { + let flagString = emojiFlagForISOCountryCode(country.id) + var localizedName: String = AuthorizationSequenceCountrySelectionController.lookupCountryNameById(country.id, strings: self.strings) ?? country.name + if country.id == "FT" { + localizedName = self.strings.Login_AnonymousNumbers + } + self.countryButton.setTitle("\(flagString) \(localizedName)", with: Font.regular(20.0), with: self.theme.list.itemAccentColor, for: []) + self.hasCountry = true + + let maskFont = Font.with(size: 20.0, design: .regular, traits: [.monospacedNumbers]) + if let mask = AuthorizationSequenceCountrySelectionController.lookupPatternByNumber(number, preferredCountries: self.preferredCountryIdForCode).flatMap({ NSAttributedString(string: $0, font: maskFont, textColor: self.theme.list.itemPlaceholderTextColor) }) { + self.phoneInputNode.numberField.textField.attributedPlaceholder = nil + self.phoneInputNode.mask = mask + } else { + self.phoneInputNode.mask = nil + self.phoneInputNode.numberField.textField.attributedPlaceholder = NSAttributedString(string: strings.Login_PhonePlaceholder, font: Font.regular(20.0), textColor: self.theme.list.itemPlaceholderTextColor) + } + return true + } else { + return false + } + } + @objc func countryPressed() { self.selectCountryCode?() } @@ -281,7 +281,7 @@ private final class ContactSyncNode: ASDisplayNode { final class AuthorizationSequencePhoneEntryControllerNode: ASDisplayNode { private let sharedContext: SharedAccountContext - private var account: UnauthorizedAccount + private var account: UnauthorizedAccount? private let strings: PresentationStrings private let theme: PresentationTheme private let hasOtherAccounts: Bool @@ -358,7 +358,7 @@ final class AuthorizationSequencePhoneEntryControllerNode: ASDisplayNode { return self.proceedNode } - init(sharedContext: SharedAccountContext, account: UnauthorizedAccount, strings: PresentationStrings, theme: PresentationTheme, debugAction: @escaping () -> Void, hasOtherAccounts: Bool) { + init(sharedContext: SharedAccountContext, account: UnauthorizedAccount?, strings: PresentationStrings, theme: PresentationTheme, debugAction: @escaping () -> Void, hasOtherAccounts: Bool) { self.sharedContext = sharedContext self.account = account @@ -376,14 +376,15 @@ final class AuthorizationSequencePhoneEntryControllerNode: ASDisplayNode { self.titleNode = ASTextNode() self.titleNode.isUserInteractionEnabled = true self.titleNode.displaysAsynchronously = false - self.titleNode.attributedText = NSAttributedString(string: strings.Login_PhoneTitle, font: Font.light(30.0), textColor: theme.list.itemPrimaryTextColor) + self.titleNode.attributedText = NSAttributedString(string: account == nil ? strings.Login_NewNumber : strings.Login_PhoneTitle, font: Font.light(30.0), textColor: theme.list.itemPrimaryTextColor) self.noticeNode = ASTextNode() self.noticeNode.maximumNumberOfLines = 0 self.noticeNode.isUserInteractionEnabled = true self.noticeNode.displaysAsynchronously = false self.noticeNode.lineSpacing = 0.1 - self.noticeNode.attributedText = NSAttributedString(string: strings.Login_PhoneAndCountryHelp, font: Font.regular(17.0), textColor: theme.list.itemPrimaryTextColor, paragraphAlignment: .center) + + self.noticeNode.attributedText = NSAttributedString(string: account == nil ? strings.ChangePhoneNumberNumber_Help : strings.Login_PhoneAndCountryHelp, font: Font.regular(17.0), textColor: theme.list.itemPrimaryTextColor, paragraphAlignment: .center) self.contactSyncNode = ContactSyncNode(theme: theme, strings: strings) @@ -425,10 +426,12 @@ final class AuthorizationSequencePhoneEntryControllerNode: ASDisplayNode { } } - self.tokenEventsDisposable.set((account.updateLoginTokenEvents - |> deliverOnMainQueue).start(next: { [weak self] _ in - self?.refreshQrToken() - })) + if let account = account { + self.tokenEventsDisposable.set((account.updateLoginTokenEvents + |> deliverOnMainQueue).start(next: { [weak self] _ in + self?.refreshQrToken() + })) + } self.proceedNode.pressed = { [weak self] in self?.checkPhone?() @@ -517,6 +520,7 @@ final class AuthorizationSequencePhoneEntryControllerNode: ASDisplayNode { func updateCountryCode() { self.phoneAndCountryNode.phoneInputNode.codeAndNumber = self.codeAndNumber + let _ = self.phoneAndCountryNode.processNumberChange(number: self.phoneAndCountryNode.phoneInputNode.number) } func containerLayoutUpdated(_ layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition: ContainedViewLayoutTransition) { @@ -536,7 +540,10 @@ final class AuthorizationSequencePhoneEntryControllerNode: ASDisplayNode { let animationSize = CGSize(width: 100.0, height: 100.0) let titleSize = self.titleNode.measure(CGSize(width: maximumWidth, height: CGFloat.greatestFiniteMagnitude)) - let noticeSize = self.noticeNode.measure(CGSize(width: min(274.0, maximumWidth - 28.0), height: CGFloat.greatestFiniteMagnitude)) + + let noticeInset: CGFloat = self.account == nil ? 32.0 : 0.0 + + let noticeSize = self.noticeNode.measure(CGSize(width: min(274.0 + noticeInset, maximumWidth - 28.0), height: CGFloat.greatestFiniteMagnitude)) let proceedHeight = self.proceedNode.updateLayout(width: maximumWidth - inset * 2.0, transition: transition) let proceedSize = CGSize(width: maximumWidth - inset * 2.0, height: proceedHeight) @@ -625,8 +632,10 @@ final class AuthorizationSequencePhoneEntryControllerNode: ASDisplayNode { } private func refreshQrToken() { + guard let account = self.account else { + return + } let sharedContext = self.sharedContext - let account = self.account let tokenSignal = sharedContext.activeAccountContexts |> castError(ExportAuthTransferTokenError.self) |> take(1) diff --git a/submodules/CountrySelectionUI/Sources/AuthorizationSequenceCountrySelectionController.swift b/submodules/CountrySelectionUI/Sources/AuthorizationSequenceCountrySelectionController.swift index 24bd975fd7..b29c7353aa 100644 --- a/submodules/CountrySelectionUI/Sources/AuthorizationSequenceCountrySelectionController.swift +++ b/submodules/CountrySelectionUI/Sources/AuthorizationSequenceCountrySelectionController.swift @@ -198,8 +198,13 @@ public final class AuthorizationSequenceCountrySelectionController: ViewControll return countryCodes } + public static func setupCountryCodes(countries: [Country], codesByPrefix: [String: (Country, Country.CountryCode)]) { + countryCodes = countries + countryCodesByPrefix = codesByPrefix + } + public static func lookupCountryNameById(_ id: String, strings: PresentationStrings) -> String? { - for country in self.countries() { + for country in countryCodes { if id == country.id { let locale = localeWithStrings(strings) if let countryName = locale.localizedString(forRegionCode: id) { @@ -254,7 +259,7 @@ public final class AuthorizationSequenceCountrySelectionController: ViewControll } public static func lookupCountryIdByCode(_ code: Int) -> String? { - for country in self.countries() { + for country in countryCodes { for countryCode in country.countryCodes { if countryCode.code == "\(code)" { return country.id diff --git a/submodules/PhoneInputNode/Sources/PhoneInputNode.swift b/submodules/PhoneInputNode/Sources/PhoneInputNode.swift index 6a51577401..2b5283a3e4 100644 --- a/submodules/PhoneInputNode/Sources/PhoneInputNode.swift +++ b/submodules/PhoneInputNode/Sources/PhoneInputNode.swift @@ -165,6 +165,7 @@ public final class PhoneInputNode: ASDisplayNode, UITextFieldDelegate { } } + private var didSetupPlaceholder = false private func updatePlaceholder() { if let mask = self.mask { let mutableMask = NSMutableAttributedString(attributedString: mask) @@ -178,7 +179,10 @@ public final class PhoneInputNode: ASDisplayNode, UITextFieldDelegate { } else { self.placeholderNode.attributedText = NSAttributedString(string: "") } - let _ = self.placeholderNode.updateLayout(CGSize(width: self.frame.size.width, height: CGFloat.greatestFiniteMagnitude)) + if !self.frame.size.width.isZero { + self.didSetupPlaceholder = true + let _ = self.placeholderNode.updateLayout(CGSize(width: self.frame.size.width, height: CGFloat.greatestFiniteMagnitude)) + } } private let fontSize: CGFloat @@ -352,4 +356,12 @@ public final class PhoneInputNode: ASDisplayNode, UITextFieldDelegate { self.updatePlaceholder() } + + public override func layout() { + super.layout() + + if !self.didSetupPlaceholder, self.frame.width > 0.0 { + self.updatePlaceholder() + } + } } diff --git a/submodules/SettingsUI/Sources/ChangePhoneNumberCodeController.swift b/submodules/SettingsUI/Sources/ChangePhoneNumberCodeController.swift index 9a31cad360..203a896bf7 100644 --- a/submodules/SettingsUI/Sources/ChangePhoneNumberCodeController.swift +++ b/submodules/SettingsUI/Sources/ChangePhoneNumberCodeController.swift @@ -322,7 +322,7 @@ func changePhoneNumberCodeController(context: AccountContext, phoneNumber: Strin } |> afterDisposed { actionsDisposable.dispose() } - + let controller = ChangePhoneNumberCodeControllerImpl(context: context, state: signal, applyCodeImpl: { code in updateState { state in return state.withUpdatedCodeText("\(code)") diff --git a/submodules/SettingsUI/Sources/ChangePhoneNumberController.swift b/submodules/SettingsUI/Sources/ChangePhoneNumberController.swift index d2317bdb4b..83c822d9da 100644 --- a/submodules/SettingsUI/Sources/ChangePhoneNumberController.swift +++ b/submodules/SettingsUI/Sources/ChangePhoneNumberController.swift @@ -13,185 +13,324 @@ import CountrySelectionUI import PhoneNumberFormat import CoreTelephony import MessageUI +import AuthorizationUI -public final class ChangePhoneNumberController: ViewController, MFMailComposeViewControllerDelegate { - private var controllerNode: ChangePhoneNumberControllerNode { - return self.displayNode as! ChangePhoneNumberControllerNode - } +public func ChangePhoneNumberController(context: AccountContext) -> ViewController { + var dismissImpl: (() -> Void)? + let presentationData = context.sharedContext.currentPresentationData.with { $0 } - private let context: AccountContext + let requestDisposable = MetaDisposable() + let changePhoneDisposable = MetaDisposable() - private var currentData: (Int32, String?, String)? - private let requestDisposable = MetaDisposable() - - 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) -> Void)? - - private let hapticFeedback = HapticFeedback() - - private var presentationData: PresentationData - - public init(context: AccountContext) { - self.context = context - self.presentationData = context.sharedContext.currentPresentationData.with { $0 } + let controller = AuthorizationSequencePhoneEntryController(sharedContext: context.sharedContext, account: nil, countriesConfiguration: context.currentCountriesConfiguration.with { $0 }, isTestingEnvironment: false, otherAccountPhoneNumbers: (nil, []), network: context.account.network, presentationData: presentationData, openUrl: { _ in }, back: { + dismissImpl?() + }) + controller.loginWithNumber = { [weak controller] phoneNumber, _ in + controller?.inProgress = true - super.init(navigationBarPresentationData: NavigationBarPresentationData(presentationData: self.presentationData)) - - self.supportedOrientations = ViewControllerSupportedOrientations(regularSize: .all, compactSize: .portrait) - self.statusBar.statusBarStyle = self.presentationData.theme.rootController.statusBarStyle.style - - self.title = self.presentationData.strings.ChangePhoneNumberNumber_Title - self.navigationItem.rightBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Common_Next, style: .done, target: self, action: #selector(self.nextPressed)) - self.navigationItem.backBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Common_Back, style: .plain, target: nil, action: nil) - } - - required init(coder aDecoder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - deinit { - self.requestDisposable.dispose() - } - - func updateData(countryCode: Int32, countryName: String, number: String) { - if self.currentData == nil || self.currentData! != (countryCode, countryName, number) { - self.currentData = (countryCode, countryName, number) - if self.isNodeLoaded { - self.controllerNode.codeAndNumber = (countryCode, countryName, number) - } - } - } - - override public func loadDisplayNode() { - self.displayNode = ChangePhoneNumberControllerNode(presentationData: self.presentationData) - self.displayNodeDidLoad() - 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 { - strongSelf.updateData(countryCode: Int32(code), countryName: name, number: strongSelf.controllerNode.codeAndNumber.2) - strongSelf.controllerNode.activateInput() - } - } - strongSelf.controllerNode.view.endEditing(true) - strongSelf.push(controller) - } - } - - loadServerCountryCodes(accountManager: self.context.sharedContext.accountManager, engine: self.context.engine, completion: { [weak self] in - if let strongSelf = self { - strongSelf.controllerNode.updateCountryCode() - } - }) - - self.navigationBar?.updateBackgroundAlpha(0.0, transition: .immediate) - } - - override public func viewWillAppear(_ animated: Bool) { - super.viewWillAppear(animated) - - self.controllerNode.activateInput() - } - - override public func viewDidAppear(_ animated: Bool) { - super.viewDidAppear(animated) - - self.controllerNode.activateInput() - } - - override public func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) { - super.containerLayoutUpdated(layout, transition: transition) - - self.controllerNode.containerLayoutUpdated(layout, navigationBarHeight: 0.0, transition: transition) - } - - @objc func nextPressed() { - let (code, _, number) = self.controllerNode.codeAndNumber - var phoneNumber = number - if let code = code { - phoneNumber = "\(code)\(phoneNumber)" - } - if !number.isEmpty { - self.inProgress = true - self.requestDisposable.set((self.context.engine.accountData.requestChangeAccountPhoneNumberVerification(phoneNumber: self.controllerNode.currentNumber) |> deliverOnMainQueue).start(next: { [weak self] next in - if let strongSelf = self { - strongSelf.inProgress = false - (strongSelf.navigationController as? NavigationController)?.pushViewController(changePhoneNumberCodeController(context: strongSelf.context, phoneNumber: strongSelf.controllerNode.currentNumber, codeData: next)) - } - }, error: { [weak self] error in - if let strongSelf = self { - strongSelf.inProgress = false - - let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 } - - let text: String - var actions: [TextAlertAction] = [] - switch error { - case .limitExceeded: - text = presentationData.strings.Login_CodeFloodError - actions.append(TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})) - case .invalidPhoneNumber: - text = presentationData.strings.Login_InvalidPhoneError - actions.append(TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})) - case .phoneNumberOccupied: - text = presentationData.strings.ChangePhone_ErrorOccupied(formatPhoneNumber(context: strongSelf.context, number: phoneNumber)).string - actions.append(TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})) - case .phoneBanned: - text = presentationData.strings.Login_PhoneBannedError - actions.append(TextAlertAction(type: .genericAction, title: strongSelf.presentationData.strings.Common_OK, action: {})) - actions.append(TextAlertAction(type: .genericAction, title: presentationData.strings.Login_PhoneNumberHelp, action: { [weak self] in - guard let strongSelf = self else { - return - } - let formattedNumber = formatPhoneNumber(context: strongSelf.context, number: number) - let appVersion = (Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String) ?? "unknown" - let systemVersion = UIDevice.current.systemVersion - let locale = Locale.current.identifier - let carrier = CTCarrier() - let mnc = carrier.mobileNetworkCode ?? "none" - - strongSelf.presentEmailComposeController(address: "login@stel.com", subject: presentationData.strings.Login_PhoneBannedEmailSubject(formattedNumber).string, body: presentationData.strings.Login_PhoneBannedEmailBody(formattedNumber, appVersion, systemVersion, locale, mnc).string) - })) - case .generic: - text = presentationData.strings.Login_UnknownError - actions.append(TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})) - } - - strongSelf.present(textAlertController(context: strongSelf.context, title: nil, text: text, actions: actions), in: .window(.root)) - } - })) - } else { - self.hapticFeedback.error() - self.controllerNode.animateError() - } - } - - private func presentEmailComposeController(address: String, subject: String, body: String) { - if MFMailComposeViewController.canSendMail() { - let composeController = MFMailComposeViewController() - composeController.setToRecipients([address]) - composeController.setSubject(subject) - composeController.setMessageBody(body, isHTML: false) - composeController.mailComposeDelegate = self + requestDisposable.set((context.engine.accountData.requestChangeAccountPhoneNumberVerification(phoneNumber: phoneNumber) + |> deliverOnMainQueue).start(next: { [weak controller] next in + controller?.inProgress = false - self.view.window?.rootViewController?.present(composeController, animated: true, completion: nil) - } else { - self.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: self.presentationData), title: nil, text: self.presentationData.strings.Login_EmailNotConfiguredError, actions: [TextAlertAction(type: .defaultAction, title: self.presentationData.strings.Common_OK, action: {})]), in: .window(.root)) - } + var dismissImpl: (() -> Void)? + let codeController = AuthorizationSequenceCodeEntryController(presentationData: presentationData, back: { + dismissImpl?() + }) + codeController.loginWithCode = { [weak codeController] code in + codeController?.inProgress = true + + changePhoneDisposable.set((context.engine.accountData.requestChangeAccountPhoneNumber(phoneNumber: phoneNumber, phoneCodeHash: next.hash, phoneCode: code) + |> deliverOnMainQueue).start(error: { [weak codeController] error in + if case .invalidCode = error { + codeController?.animateError(text: presentationData.strings.Login_WrongCodeError) + } else { + var resetCode = false + let text: String + switch error { + case .generic: + text = presentationData.strings.Login_UnknownError + case .invalidCode: + resetCode = true + text = presentationData.strings.Login_InvalidCodeError + case .codeExpired: + resetCode = true + text = presentationData.strings.Login_CodeExpiredError + case .limitExceeded: + resetCode = true + text = presentationData.strings.Login_CodeFloodError + } + + if resetCode { + codeController?.resetCode() + } + + codeController?.present(textAlertController(context: context, title: nil, text: text, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), in: .window(.root)) + } + }, completed: { [weak codeController] in + codeController?.present(OverlayStatusController(theme: presentationData.theme, type: .success), in: .window(.root)) + + let _ = dismissServerProvidedSuggestion(account: context.account, suggestion: .validatePhoneNumber).start() + + if let navigationController = codeController?.navigationController as? NavigationController { + var viewControllers = navigationController.viewControllers + viewControllers.removeAll(where: { c in + if c is AuthorizationSequencePhoneEntryController { + return true + } else if c is AuthorizationSequenceCodeEntryController { + return true + } else { + return false + } + }) + navigationController.setViewControllers(viewControllers, animated: true) + } + })) + } + codeController.openFragment = { url in + context.sharedContext.applicationBindings.openUrl(url) + } + codeController.updateData(number: formatPhoneNumber(context: context, number: phoneNumber), email: nil, codeType: next.type, nextType: nil, timeout: next.timeout, termsOfService: nil) + dismissImpl = { [weak codeController] in + codeController?.dismiss() + } + controller?.push(codeController) + }, error: { [weak controller] error in + controller?.inProgress = false + + let text: String + var actions: [TextAlertAction] = [] + switch error { + case .limitExceeded: + text = presentationData.strings.Login_CodeFloodError + actions.append(TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})) + case .invalidPhoneNumber: + text = presentationData.strings.Login_InvalidPhoneError + actions.append(TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})) + case .phoneNumberOccupied: + text = presentationData.strings.ChangePhone_ErrorOccupied(formatPhoneNumber(context: context, number: phoneNumber)).string + actions.append(TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})) + case .phoneBanned: + text = presentationData.strings.Login_PhoneBannedError + actions.append(TextAlertAction(type: .genericAction, title: presentationData.strings.Common_OK, action: {})) + actions.append(TextAlertAction(type: .genericAction, title: presentationData.strings.Login_PhoneNumberHelp, action: { [weak controller] in + let formattedNumber = formatPhoneNumber(context: context, number: phoneNumber) + let appVersion = (Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String) ?? "unknown" + let systemVersion = UIDevice.current.systemVersion + let locale = Locale.current.identifier + let carrier = CTCarrier() + let mnc = carrier.mobileNetworkCode ?? "none" + + if MFMailComposeViewController.canSendMail() { + let composeController = MFMailComposeViewController() + composeController.setToRecipients(["login@stel.com"]) + composeController.setSubject(presentationData.strings.Login_PhoneBannedEmailSubject(formattedNumber).string) + composeController.setMessageBody(presentationData.strings.Login_PhoneBannedEmailBody(formattedNumber, appVersion, systemVersion, locale, mnc).string, isHTML: false) + composeController.mailComposeDelegate = controller + + controller?.view.window?.rootViewController?.present(composeController, animated: true, completion: nil) + } else { + controller?.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: presentationData), title: nil, text: presentationData.strings.Login_EmailNotConfiguredError, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), in: .window(.root)) + } + })) + case .generic: + text = presentationData.strings.Login_UnknownError + actions.append(TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})) + } + + controller?.present(textAlertController(context: context, title: nil, text: text, actions: actions), in: .window(.root)) + })) } - public func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) { - controller.dismiss(animated: true, completion: nil) + dismissImpl = { [weak controller] in + controller?.dismiss() } + + Queue.mainQueue().justDispatch { + controller.updateData(countryCode: AuthorizationSequenceController.defaultCountryCode(), countryName: nil, number: "") + controller.updateCountryCode() + } + + return controller } + +//public final class ChangePhoneNumberController: ViewController, MFMailComposeViewControllerDelegate { +// private var controllerNode: ChangePhoneNumberControllerNode { +// return self.displayNode as! ChangePhoneNumberControllerNode +// } +// +// private let context: AccountContext +// +// private var currentData: (Int32, String?, String)? +// private let requestDisposable = MetaDisposable() +// +// 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) -> Void)? +// +// private let hapticFeedback = HapticFeedback() +// +// private var presentationData: PresentationData +// +// public init(context: AccountContext) { +// self.context = context +// self.presentationData = context.sharedContext.currentPresentationData.with { $0 } +// +// super.init(navigationBarPresentationData: NavigationBarPresentationData(presentationData: self.presentationData)) +// +// self.supportedOrientations = ViewControllerSupportedOrientations(regularSize: .all, compactSize: .portrait) +// self.statusBar.statusBarStyle = self.presentationData.theme.rootController.statusBarStyle.style +// +// self.title = self.presentationData.strings.ChangePhoneNumberNumber_Title +// self.navigationItem.rightBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Common_Next, style: .done, target: self, action: #selector(self.nextPressed)) +// self.navigationItem.backBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Common_Back, style: .plain, target: nil, action: nil) +// } +// +// required init(coder aDecoder: NSCoder) { +// fatalError("init(coder:) has not been implemented") +// } +// +// deinit { +// self.requestDisposable.dispose() +// } +// +// func updateData(countryCode: Int32, countryName: String, number: String) { +// if self.currentData == nil || self.currentData! != (countryCode, countryName, number) { +// self.currentData = (countryCode, countryName, number) +// if self.isNodeLoaded { +// self.controllerNode.codeAndNumber = (countryCode, countryName, number) +// } +// } +// } +// +// override public func loadDisplayNode() { +// self.displayNode = ChangePhoneNumberControllerNode(presentationData: self.presentationData) +// self.displayNodeDidLoad() +// 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 { +// strongSelf.updateData(countryCode: Int32(code), countryName: name, number: strongSelf.controllerNode.codeAndNumber.2) +// strongSelf.controllerNode.activateInput() +// } +// } +// strongSelf.controllerNode.view.endEditing(true) +// strongSelf.push(controller) +// } +// } +// +// loadServerCountryCodes(accountManager: self.context.sharedContext.accountManager, engine: self.context.engine, completion: { [weak self] in +// if let strongSelf = self { +// strongSelf.controllerNode.updateCountryCode() +// } +// }) +// +// self.navigationBar?.updateBackgroundAlpha(0.0, transition: .immediate) +// } +// +// override public func viewWillAppear(_ animated: Bool) { +// super.viewWillAppear(animated) +// +// self.controllerNode.activateInput() +// } +// +// override public func viewDidAppear(_ animated: Bool) { +// super.viewDidAppear(animated) +// +// self.controllerNode.activateInput() +// } +// +// override public func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) { +// super.containerLayoutUpdated(layout, transition: transition) +// +// self.controllerNode.containerLayoutUpdated(layout, navigationBarHeight: 0.0, transition: transition) +// } +// +// @objc func nextPressed() { +// let (code, _, number) = self.controllerNode.codeAndNumber +// var phoneNumber = number +// if let code = code { +// phoneNumber = "\(code)\(phoneNumber)" +// } +// if !number.isEmpty { +// self.inProgress = true +// self.requestDisposable.set((self.context.engine.accountData.requestChangeAccountPhoneNumberVerification(phoneNumber: self.controllerNode.currentNumber) |> deliverOnMainQueue).start(next: { [weak self] next in +// if let strongSelf = self { +// strongSelf.inProgress = false +// (strongSelf.navigationController as? NavigationController)?.pushViewController(changePhoneNumberCodeController(context: strongSelf.context, phoneNumber: strongSelf.controllerNode.currentNumber, codeData: next)) +// } +// }, error: { [weak self] error in +// if let strongSelf = self { +// strongSelf.inProgress = false +// +// let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 } +// +// let text: String +// var actions: [TextAlertAction] = [] +// switch error { +// case .limitExceeded: +// text = presentationData.strings.Login_CodeFloodError +// actions.append(TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})) +// case .invalidPhoneNumber: +// text = presentationData.strings.Login_InvalidPhoneError +// actions.append(TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})) +// case .phoneNumberOccupied: +// text = presentationData.strings.ChangePhone_ErrorOccupied(formatPhoneNumber(context: strongSelf.context, number: phoneNumber)).string +// actions.append(TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})) +// case .phoneBanned: +// text = presentationData.strings.Login_PhoneBannedError +// actions.append(TextAlertAction(type: .genericAction, title: strongSelf.presentationData.strings.Common_OK, action: {})) +// actions.append(TextAlertAction(type: .genericAction, title: presentationData.strings.Login_PhoneNumberHelp, action: { [weak self] in +// guard let strongSelf = self else { +// return +// } +// let formattedNumber = formatPhoneNumber(context: strongSelf.context, number: number) +// let appVersion = (Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String) ?? "unknown" +// let systemVersion = UIDevice.current.systemVersion +// let locale = Locale.current.identifier +// let carrier = CTCarrier() +// let mnc = carrier.mobileNetworkCode ?? "none" +// +// strongSelf.presentEmailComposeController(address: "login@stel.com", subject: presentationData.strings.Login_PhoneBannedEmailSubject(formattedNumber).string, body: presentationData.strings.Login_PhoneBannedEmailBody(formattedNumber, appVersion, systemVersion, locale, mnc).string) +// })) +// case .generic: +// text = presentationData.strings.Login_UnknownError +// actions.append(TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})) +// } +// +// strongSelf.present(textAlertController(context: strongSelf.context, title: nil, text: text, actions: actions), in: .window(.root)) +// } +// })) +// } else { +// self.hapticFeedback.error() +// self.controllerNode.animateError() +// } +// } +// +// private func presentEmailComposeController(address: String, subject: String, body: String) { +// if MFMailComposeViewController.canSendMail() { +// let composeController = MFMailComposeViewController() +// composeController.setToRecipients([address]) +// composeController.setSubject(subject) +// composeController.setMessageBody(body, isHTML: false) +// composeController.mailComposeDelegate = self +// +// self.view.window?.rootViewController?.present(composeController, animated: true, completion: nil) +// } else { +// self.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: self.presentationData), title: nil, text: self.presentationData.strings.Login_EmailNotConfiguredError, actions: [TextAlertAction(type: .defaultAction, title: self.presentationData.strings.Common_OK, action: {})]), in: .window(.root)) +// } +// } +// +// public func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) { +// controller.dismiss(animated: true, completion: nil) +// } +//} diff --git a/submodules/SettingsUI/Sources/ChangePhoneNumberIntroController.swift b/submodules/SettingsUI/Sources/ChangePhoneNumberIntroController.swift deleted file mode 100644 index 634fd16595..0000000000 --- a/submodules/SettingsUI/Sources/ChangePhoneNumberIntroController.swift +++ /dev/null @@ -1,153 +0,0 @@ -import Foundation -import UIKit -import Display -import AsyncDisplayKit -import TelegramCore -import TelegramPresentationData -import TextFormat -import AccountContext -import AlertUI -import PresentationDataUtils -import AppBundle -import Markdown -import PhoneNumberFormat - -private final class ChangePhoneNumberIntroControllerNode: ASDisplayNode { - var presentationData: PresentationData - - let iconNode: ASImageNode - let labelNode: ASTextNode - let buttonNode: HighlightableButtonNode - - var dismiss: (() -> Void)? - var action: (() -> Void)? - - init(presentationData: PresentationData) { - self.presentationData = presentationData - - self.iconNode = ASImageNode() - self.labelNode = ASTextNode() - self.buttonNode = HighlightableButtonNode() - - super.init() - - self.setViewBlock({ - return UITracingLayerView() - }) - - self.iconNode.image = generateTintedImage(image: UIImage(bundleImageName: "Settings/ChangePhoneIntroIcon"), color: presentationData.theme.list.freeMonoIconColor) - let textColor = self.presentationData.theme.list.freeTextColor - self.labelNode.attributedText = parseMarkdownIntoAttributedString(self.presentationData.strings.PhoneNumberHelp_Help, attributes: MarkdownAttributes(body: MarkdownAttributeSet(font: Font.regular(14.0), textColor: textColor), bold: MarkdownAttributeSet(font: Font.semibold(14.0), textColor: textColor), link: MarkdownAttributeSet(font: Font.regular(14.0), textColor: textColor), linkAttribute: { _ in return nil }), textAlignment: .center) - self.buttonNode.setTitle(self.presentationData.strings.PhoneNumberHelp_ChangeNumber, with: Font.regular(19.0), with: self.presentationData.theme.list.itemAccentColor, for: .normal) - self.buttonNode.addTarget(self, action: #selector(self.buttonPressed), forControlEvents: .touchUpInside) - - self.addSubnode(self.iconNode) - self.addSubnode(self.labelNode) - self.addSubnode(self.buttonNode) - - self.backgroundColor = self.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() { - 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: CAMediaTimingFunctionName.easeInEaseOut.rawValue, removeOnCompletion: false, completion: { [weak self] _ in - if let strongSelf = self { - strongSelf.dismiss?() - } - }) - } - - func containerLayoutUpdated(_ layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition: ContainedViewLayoutTransition) { - var insets = layout.insets(options: [.statusBar]) - insets.top += navigationBarHeight - let availableHeight = layout.size.height - insets.top - insets.bottom - - let largeScreen = availableHeight >= 420.0 - let contentHeight: CGFloat = largeScreen ? 420.0 : 400.0 - - let iconSize = self.iconNode.measure(CGSize(width: 400.0, height: 400.0)) - let labelSize = self.labelNode.updateLayout(CGSize(width: 295.0, height: CGFloat.greatestFiniteMagnitude)) - let buttonSize = self.buttonNode.measure(CGSize(width: 295.0, height: CGFloat.greatestFiniteMagnitude)) - - transition.updateFrame(node: self.iconNode, frame: CGRect(origin: CGPoint(x: floor((layout.size.width - iconSize.width) / 2.0), y: insets.top + floor((availableHeight - contentHeight) / 2.0) + floor(iconSize.height * (largeScreen ? CGFloat(0.2) : CGFloat(0.5)))), size: iconSize)) - - transition.updateFrame(node: self.labelNode, frame: CGRect(origin: CGPoint(x: floor((layout.size.width - labelSize.width) / 2.0), y: insets.top + floor((availableHeight - contentHeight) / 2.0) + floor((contentHeight - labelSize.height) / 2.0) + floor((contentHeight - iconSize.height - buttonSize.height) * 0.11)), size: labelSize)) - - transition.updateFrame(node: self.buttonNode, frame: CGRect(origin: CGPoint(x: floor((layout.size.width - buttonSize.width) / 2.0), y: insets.top + floor((availableHeight - contentHeight) / 2.0) + contentHeight - buttonSize.height), size: buttonSize)) - } - - @objc func buttonPressed() { - self.action?() - } -} - -public final class ChangePhoneNumberIntroController: ViewController { - private let context: AccountContext - private var didPlayPresentationAnimation = false - - private var presentationData: PresentationData - - public init(context: AccountContext, phoneNumber: String) { - self.context = context - - self.presentationData = context.sharedContext.currentPresentationData.with { $0 } - - super.init(navigationBarPresentationData: NavigationBarPresentationData(presentationData: self.presentationData)) - - self.supportedOrientations = ViewControllerSupportedOrientations(regularSize: .all, compactSize: .portrait) - - self.statusBar.statusBarStyle = self.presentationData.theme.rootController.statusBarStyle.style - - let formattedPhone = formatPhoneNumber(context: context, number: phoneNumber) - self.title = formattedPhone - self.navigationItem.backBarButtonItem = UIBarButtonItem(title: presentationData.strings.Common_Back, style: .plain, target: nil, action: nil) - //self.navigationItem.leftBarButtonItem = UIBarButtonItem(title: "Cancel", style: .plain, target: self, action: #selector(self.cancelPressed)) - } - - required init(coder aDecoder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - public override func loadDisplayNode() { - self.displayNode = ChangePhoneNumberIntroControllerNode(presentationData: self.presentationData) - (self.displayNode as! ChangePhoneNumberIntroControllerNode).dismiss = { [weak self] in - self?.presentingViewController?.dismiss(animated: false, completion: nil) - } - (self.displayNode as! ChangePhoneNumberIntroControllerNode).action = { [weak self] in - self?.proceed() - } - self.displayNodeDidLoad() - - self.navigationBar?.updateBackgroundAlpha(0.0, transition: .immediate) - } - - public override func viewDidAppear(_ animated: Bool) { - super.viewDidAppear(animated) - - /*if !self.didPlayPresentationAnimation { - self.didPlayPresentationAnimation = true - (self.displayNode as! ChangePhoneNumberIntroControllerNode).animateIn() - }*/ - } - - override public func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) { - super.containerLayoutUpdated(layout, transition: transition) - - (self.displayNode as! ChangePhoneNumberIntroControllerNode).containerLayoutUpdated(layout, navigationBarHeight: self.navigationLayout(layout: layout).navigationFrame.maxY, transition: transition) - } - - @objc func cancelPressed() { - (self.displayNode as! ChangePhoneNumberIntroControllerNode).animateOut() - } - - func proceed() { - self.present(textAlertController(context: self.context, title: nil, text: self.presentationData.strings.PhoneNumberHelp_Alert, actions: [TextAlertAction(type: .defaultAction, title: self.presentationData.strings.Common_Cancel, action: {}), TextAlertAction(type: .genericAction, title: self.presentationData.strings.TwoFactorSetup_Email_Action, action: { [weak self] in - if let strongSelf = self { - (strongSelf.navigationController as? NavigationController)?.replaceTopController(ChangePhoneNumberController(context: strongSelf.context), animated: true) - } - })]), in: .window(.root), with: ViewControllerPresentationArguments(presentationAnimation: .modalSheet)) - } -} diff --git a/submodules/SettingsUI/Sources/Privacy and Security/PrivacyAndSecurityController.swift b/submodules/SettingsUI/Sources/Privacy and Security/PrivacyAndSecurityController.swift index e451690eb8..4f6b695dde 100644 --- a/submodules/SettingsUI/Sources/Privacy and Security/PrivacyAndSecurityController.swift +++ b/submodules/SettingsUI/Sources/Privacy and Security/PrivacyAndSecurityController.swift @@ -1203,7 +1203,7 @@ public func privacyAndSecurityController(context: AccountContext, initialSetting var dismissCodeControllerImpl: (() -> Void)? var presentControllerImpl: ((ViewController) -> Void)? - let codeController = AuthorizationSequenceCodeEntryController(presentationData: presentationData, openUrl: { _ in }, back: { + let codeController = AuthorizationSequenceCodeEntryController(presentationData: presentationData, back: { dismissCodeControllerImpl?() }) diff --git a/submodules/TelegramUI/Sources/OpenResolvedUrl.swift b/submodules/TelegramUI/Sources/OpenResolvedUrl.swift index 0c4dacf69f..13b52b291b 100644 --- a/submodules/TelegramUI/Sources/OpenResolvedUrl.swift +++ b/submodules/TelegramUI/Sources/OpenResolvedUrl.swift @@ -28,6 +28,7 @@ import Markdown import WebUI import BotPaymentsUI import PremiumUI +import AuthorizationUI private func defaultNavigationForPeerId(_ peerId: PeerId?, navigation: ChatControllerInteractionNavigateToPeer) -> ChatControllerInteractionNavigateToPeer { if case .default = navigation { @@ -223,7 +224,9 @@ func openResolvedUrlImpl(_ resolvedUrl: ResolvedUrl, context: AccountContext, ur dismissInput() present(ProxyServerActionSheetController(context: context, server: server), nil) case let .confirmationCode(code): - if let topController = navigationController?.topViewController as? ChangePhoneNumberCodeController { + if let topController = navigationController?.topViewController as? AuthorizationSequenceCodeEntryController { + topController.applyConfirmationCode(code) + } else if let topController = navigationController?.topViewController as? ChangePhoneNumberCodeController { topController.applyCode(code) } else { var found = false From b8a7ca4de1ace9e5f1d097349aa9c8fba2b136e3 Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Sun, 27 Nov 2022 21:51:30 +0400 Subject: [PATCH 2/2] Fix build --- .../Sources/AuthorizationSequenceCodeEntryController.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/AuthorizationUI/Sources/AuthorizationSequenceCodeEntryController.swift b/submodules/AuthorizationUI/Sources/AuthorizationSequenceCodeEntryController.swift index 25fa5f7bf7..c791af5863 100644 --- a/submodules/AuthorizationUI/Sources/AuthorizationSequenceCodeEntryController.swift +++ b/submodules/AuthorizationUI/Sources/AuthorizationSequenceCodeEntryController.swift @@ -215,7 +215,7 @@ public final class AuthorizationSequenceCodeEntryController: ViewController { self.loginWithCode?(code) } - func applyConfirmationCode(_ code: Int) { + public func applyConfirmationCode(_ code: Int) { self.controllerNode.updateCode("\(code)") } }