diff --git a/submodules/AuthorizationUI/Sources/AuthorizationSequenceCodeEntryController.swift b/submodules/AuthorizationUI/Sources/AuthorizationSequenceCodeEntryController.swift index 8a0f4d3ba6..0da39800b4 100644 --- a/submodules/AuthorizationUI/Sources/AuthorizationSequenceCodeEntryController.swift +++ b/submodules/AuthorizationUI/Sources/AuthorizationSequenceCodeEntryController.swift @@ -22,7 +22,7 @@ public final class AuthorizationSequenceCodeEntryController: ViewController { public var openFragment: ((String) -> Void)? var reset: (() -> Void)? - var requestNextOption: (() -> Void)? + public var requestNextOption: (() -> Void)? var resetEmail: (() -> Void)? var retryResetEmail: (() -> Void)? diff --git a/submodules/AuthorizationUI/Sources/AuthorizationSequenceController.swift b/submodules/AuthorizationUI/Sources/AuthorizationSequenceController.swift index d75d334f95..9b2377772c 100644 --- a/submodules/AuthorizationUI/Sources/AuthorizationSequenceController.swift +++ b/submodules/AuthorizationUI/Sources/AuthorizationSequenceController.swift @@ -20,13 +20,16 @@ import TelegramNotices import AuthenticationServices import Markdown import AlertUI +import ObjectiveC + +private var ObjCKey_Delegate: Int? private enum InnerState: Equatable { case state(UnauthorizedAccountStateContents) case authorized } -public final class AuthorizationSequenceController: NavigationController, MFMailComposeViewControllerDelegate, ASAuthorizationControllerDelegate, ASAuthorizationControllerPresentationContextProviding { +public final class AuthorizationSequenceController: NavigationController, ASAuthorizationControllerDelegate, ASAuthorizationControllerPresentationContextProviding { static func navigationBarTheme(_ theme: PresentationTheme) -> NavigationBarTheme { return NavigationBarTheme(buttonColor: theme.intro.accentTextColor, disabledButtonColor: theme.intro.disabledTextColor, primaryTextColor: theme.intro.primaryTextColor, backgroundColor: .clear, enableBackgroundBlur: false, separatorColor: .clear, badgeBackgroundColor: theme.rootController.navigationBar.badgeBackgroundColor, badgeStrokeColor: theme.rootController.navigationBar.badgeStrokeColor, badgeTextColor: theme.rootController.navigationBar.badgeTextColor) } @@ -216,7 +219,7 @@ public final class AuthorizationSequenceController: NavigationController, MFMail let carrier = CTCarrier() let mnc = carrier.mobileNetworkCode ?? "none" - strongSelf.presentEmailComposeController(address: "login@stel.com", subject: strongSelf.presentationData.strings.Login_InvalidPhoneEmailSubject(formattedNumber).string, body: strongSelf.presentationData.strings.Login_InvalidPhoneEmailBody(formattedNumber, appVersion, systemVersion, locale, mnc).string, from: controller) + AuthorizationSequenceController.presentEmailComposeController(address: "login@stel.com", subject: strongSelf.presentationData.strings.Login_InvalidPhoneEmailSubject(formattedNumber).string, body: strongSelf.presentationData.strings.Login_InvalidPhoneEmailBody(formattedNumber, appVersion, systemVersion, locale, mnc).string, from: controller, presentationData: strongSelf.presentationData) })) case .phoneLimitExceeded: text = strongSelf.presentationData.strings.Login_PhoneFloodError @@ -242,7 +245,7 @@ public final class AuthorizationSequenceController: NavigationController, MFMail let carrier = CTCarrier() let mnc = carrier.mobileNetworkCode ?? "none" - strongSelf.presentEmailComposeController(address: "login@stel.com", subject: strongSelf.presentationData.strings.Login_PhoneBannedEmailSubject(formattedNumber).string, body: strongSelf.presentationData.strings.Login_PhoneBannedEmailBody(formattedNumber, appVersion, systemVersion, locale, mnc).string, from: controller) + AuthorizationSequenceController.presentEmailComposeController(address: "login@stel.com", subject: strongSelf.presentationData.strings.Login_PhoneBannedEmailSubject(formattedNumber).string, body: strongSelf.presentationData.strings.Login_PhoneBannedEmailBody(formattedNumber, appVersion, systemVersion, locale, mnc).string, from: controller, presentationData: strongSelf.presentationData) })) case let .generic(info): text = strongSelf.presentationData.strings.Login_UnknownError @@ -264,7 +267,7 @@ public final class AuthorizationSequenceController: NavigationController, MFMail errorString = "unknown" } - strongSelf.presentEmailComposeController(address: "login@stel.com", subject: strongSelf.presentationData.strings.Login_PhoneGenericEmailSubject(formattedNumber).string, body: strongSelf.presentationData.strings.Login_PhoneGenericEmailBody(formattedNumber, errorString, appVersion, systemVersion, locale, mnc).string, from: controller) + AuthorizationSequenceController.presentEmailComposeController(address: "login@stel.com", subject: strongSelf.presentationData.strings.Login_PhoneGenericEmailSubject(formattedNumber).string, body: strongSelf.presentationData.strings.Login_PhoneGenericEmailBody(formattedNumber, errorString, appVersion, systemVersion, locale, mnc).string, from: controller, presentationData: strongSelf.presentationData) })) case .timeout: text = strongSelf.presentationData.strings.Login_NetworkError @@ -558,26 +561,8 @@ public final class AuthorizationSequenceController: NavigationController, MFMail controller.requestNextOption = { [weak self, weak controller] in if let strongSelf = self { if nextType == nil { - if MFMailComposeViewController.canSendMail(), let controller = controller { - let formattedNumber = formatPhoneNumber(number) - - var emailBody = "" - emailBody.append(strongSelf.presentationData.strings.Login_EmailCodeBody(formattedNumber).string) - emailBody.append("\n\n") - - 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" - emailBody.append("Telegram: \(appVersion)\n") - emailBody.append("OS: \(systemVersion)\n") - emailBody.append("Locale: \(locale)\n") - emailBody.append("MNC: \(mnc)") - - strongSelf.presentEmailComposeController(address: "sms@telegram.org", subject: strongSelf.presentationData.strings.Login_EmailCodeSubject(formattedNumber).string, body: emailBody, from: controller) - } else { - controller?.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: strongSelf.presentationData), title: nil, text: strongSelf.presentationData.strings.Login_EmailNotConfiguredError, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})]), in: .window(.root)) + if let controller { + AuthorizationSequenceController.presentDidNotGetCodeUI(controller: controller, presentationData: strongSelf.presentationData, number: number) } } else { controller?.inProgress = true @@ -1250,24 +1235,29 @@ public final class AuthorizationSequenceController: NavigationController, MFMail } } - private func presentEmailComposeController(address: String, subject: String, body: String, from controller: ViewController) { + private static func presentEmailComposeController(address: String, subject: String, body: String, from controller: ViewController, presentationData: PresentationData) { if MFMailComposeViewController.canSendMail() { + final class ComposeDelegate: NSObject, MFMailComposeViewControllerDelegate { + @objc func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) { + controller.dismiss(animated: true, completion: nil) + } + } + let composeController = MFMailComposeViewController() composeController.setToRecipients([address]) composeController.setSubject(subject) composeController.setMessageBody(body, isHTML: false) - composeController.mailComposeDelegate = self + + let composeDelegate = ComposeDelegate() + objc_setAssociatedObject(composeDelegate, &ObjCKey_Delegate, composeDelegate, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) + composeController.mailComposeDelegate = composeDelegate controller.view.window?.rootViewController?.present(composeController, animated: true, completion: nil) } else { - controller.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)) + 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)) } } - public func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) { - controller.dismiss(animated: true, completion: nil) - } - private func animateIn() { if !self.otherAccountPhoneNumbers.1.isEmpty { self.view.layer.animatePosition(from: CGPoint(x: self.view.layer.position.x, y: self.view.layer.position.y + self.view.layer.bounds.size.height), to: self.view.layer.position, duration: 0.5, timingFunction: kCAMediaTimingFunctionSpring) @@ -1324,4 +1314,28 @@ public final class AuthorizationSequenceController: NavigationController, MFMail return countryCode } + + public static func presentDidNotGetCodeUI(controller: ViewController, presentationData: PresentationData, number: String) { + if MFMailComposeViewController.canSendMail() { + let formattedNumber = formatPhoneNumber(number) + + var emailBody = "" + emailBody.append(presentationData.strings.Login_EmailCodeBody(formattedNumber).string) + emailBody.append("\n\n") + + 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" + emailBody.append("Telegram: \(appVersion)\n") + emailBody.append("OS: \(systemVersion)\n") + emailBody.append("Locale: \(locale)\n") + emailBody.append("MNC: \(mnc)") + + AuthorizationSequenceController.presentEmailComposeController(address: "sms@telegram.org", subject: presentationData.strings.Login_EmailCodeSubject(formattedNumber).string, body: emailBody, from: controller, presentationData: presentationData) + } 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)) + } + } } diff --git a/submodules/SettingsUI/Sources/ChangePhoneNumberController.swift b/submodules/SettingsUI/Sources/ChangePhoneNumberController.swift index b2eef15752..d2ad53873f 100644 --- a/submodules/SettingsUI/Sources/ChangePhoneNumberController.swift +++ b/submodules/SettingsUI/Sources/ChangePhoneNumberController.swift @@ -28,7 +28,16 @@ public func ChangePhoneNumberController(context: AccountContext) -> ViewControll controller.loginWithNumber = { [weak controller] phoneNumber, _ in controller?.inProgress = true - requestDisposable.set((context.engine.accountData.requestChangeAccountPhoneNumberVerification(phoneNumber: phoneNumber) + let authorizationPushConfiguration = context.sharedContext.authorizationPushConfiguration + |> take(1) + |> timeout(2.0, queue: .mainQueue(), alternate: .single(nil)) + + requestDisposable.set(( + authorizationPushConfiguration + |> castError(RequestChangeAccountPhoneNumberVerificationError.self) + |> mapToSignal { authorizationPushConfiguration in + return context.engine.accountData.requestChangeAccountPhoneNumberVerification(phoneNumber: phoneNumber, pushNotificationConfiguration: authorizationPushConfiguration, firebaseSecretStream: context.sharedContext.firebaseSecretStream) + } |> deliverOnMainQueue).start(next: { [weak controller] next in controller?.inProgress = false @@ -86,6 +95,12 @@ public func ChangePhoneNumberController(context: AccountContext) -> ViewControll } })) } + codeController.requestNextOption = { [weak codeController] in + guard let codeController else { + return + } + AuthorizationSequenceController.presentDidNotGetCodeUI(controller: codeController, presentationData: context.sharedContext.currentPresentationData.with({ $0 }), number: phoneNumber) + } codeController.openFragment = { url in context.sharedContext.applicationBindings.openUrl(url) } diff --git a/submodules/TelegramCore/Sources/TelegramEngine/AccountData/ChangeAccountPhoneNumber.swift b/submodules/TelegramCore/Sources/TelegramEngine/AccountData/ChangeAccountPhoneNumber.swift index 44d473bfd2..778b2e986f 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/AccountData/ChangeAccountPhoneNumber.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/AccountData/ChangeAccountPhoneNumber.swift @@ -36,8 +36,21 @@ public enum RequestChangeAccountPhoneNumberVerificationError { case generic } -func _internal_requestChangeAccountPhoneNumberVerification(account: Account, phoneNumber: String) -> Signal { - return account.network.request(Api.functions.account.sendChangePhoneCode(phoneNumber: phoneNumber, settings: .codeSettings(flags: 0, logoutTokens: nil, token: nil, appSandbox: nil)), automaticFloodWait: false) +func _internal_requestChangeAccountPhoneNumberVerification(account: Account, phoneNumber: String, pushNotificationConfiguration: AuthorizationCodePushNotificationConfiguration?, firebaseSecretStream: Signal<[String: String], NoError>) -> Signal { + var flags: Int32 = 0 + + flags |= 1 << 5 //allowMissedCall + + var token: String? + var appSandbox: Api.Bool? + if let pushNotificationConfiguration = pushNotificationConfiguration { + flags |= 1 << 7 + flags |= 1 << 8 + token = pushNotificationConfiguration.token + appSandbox = pushNotificationConfiguration.isSandbox ? .boolTrue : .boolFalse + } + + return account.network.request(Api.functions.account.sendChangePhoneCode(phoneNumber: phoneNumber, settings: .codeSettings(flags: flags, logoutTokens: nil, token: token, appSandbox: appSandbox)), automaticFloodWait: false) |> mapError { error -> RequestChangeAccountPhoneNumberVerificationError in if error.errorDescription.hasPrefix("FLOOD_WAIT") { return .limitExceeded diff --git a/submodules/TelegramCore/Sources/TelegramEngine/AccountData/TelegramEngineAccountData.swift b/submodules/TelegramCore/Sources/TelegramEngine/AccountData/TelegramEngineAccountData.swift index b966accbeb..b4aebf2428 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/AccountData/TelegramEngineAccountData.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/AccountData/TelegramEngineAccountData.swift @@ -15,8 +15,8 @@ public extension TelegramEngine { return _internal_acceptTermsOfService(account: self.account, id: id) } - public func requestChangeAccountPhoneNumberVerification(phoneNumber: String) -> Signal { - return _internal_requestChangeAccountPhoneNumberVerification(account: self.account, phoneNumber: phoneNumber) + public func requestChangeAccountPhoneNumberVerification(phoneNumber: String, pushNotificationConfiguration: AuthorizationCodePushNotificationConfiguration?, firebaseSecretStream: Signal<[String: String], NoError>) -> Signal { + return _internal_requestChangeAccountPhoneNumberVerification(account: self.account, phoneNumber: phoneNumber, pushNotificationConfiguration: pushNotificationConfiguration, firebaseSecretStream: firebaseSecretStream) } public func requestNextChangeAccountPhoneNumberVerification(phoneNumber: String, phoneCodeHash: String) -> Signal {