mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-22 22:25:57 +00:00
Password reset fixes
This commit is contained in:
@@ -14,18 +14,27 @@ import AnimatedStickerNode
|
||||
|
||||
public enum TwoFactorDataInputMode {
|
||||
public struct Recovery {
|
||||
public var code: String
|
||||
public var syncContacts: Bool
|
||||
public var account: UnauthorizedAccount
|
||||
public enum Mode {
|
||||
case notAuthorized(syncContacts: Bool)
|
||||
case authorized
|
||||
}
|
||||
|
||||
public init(code: String, syncContacts: Bool, account: UnauthorizedAccount) {
|
||||
public var code: String
|
||||
public var mode: Mode
|
||||
|
||||
public init(code: String, mode: Mode) {
|
||||
self.code = code
|
||||
self.syncContacts = syncContacts
|
||||
self.account = account
|
||||
self.mode = mode
|
||||
}
|
||||
}
|
||||
|
||||
public enum PasswordRecoveryEmailMode {
|
||||
case notAuthorized(syncContacts: Bool)
|
||||
case authorized
|
||||
}
|
||||
|
||||
case password
|
||||
case passwordRecoveryEmail(emailPattern: String, mode: PasswordRecoveryEmailMode)
|
||||
case passwordRecovery(Recovery)
|
||||
case emailAddress(password: String, hint: String)
|
||||
case updateEmailAddress(password: String)
|
||||
@@ -39,8 +48,9 @@ public final class TwoFactorDataInputScreen: ViewController {
|
||||
private var presentationData: PresentationData
|
||||
private let mode: TwoFactorDataInputMode
|
||||
private let stateUpdated: (SetupTwoStepVerificationStateUpdate) -> Void
|
||||
private let actionDisposable = MetaDisposable()
|
||||
|
||||
public init(sharedContext: SharedAccountContext, engine: SomeTelegramEngine, mode: TwoFactorDataInputMode, stateUpdated: @escaping (SetupTwoStepVerificationStateUpdate) -> Void) {
|
||||
public init(sharedContext: SharedAccountContext, engine: SomeTelegramEngine, mode: TwoFactorDataInputMode, stateUpdated: @escaping (SetupTwoStepVerificationStateUpdate) -> Void, presentation: ViewControllerNavigationPresentation = .modalInLargeLayout) {
|
||||
self.sharedContext = sharedContext
|
||||
self.engine = engine
|
||||
self.mode = mode
|
||||
@@ -54,7 +64,7 @@ public final class TwoFactorDataInputScreen: ViewController {
|
||||
super.init(navigationBarPresentationData: NavigationBarPresentationData(theme: navigationBarTheme, strings: NavigationBarStrings(back: self.presentationData.strings.Common_Back, close: self.presentationData.strings.Common_Close)))
|
||||
|
||||
self.statusBar.statusBarStyle = self.presentationData.theme.rootController.statusBarStyle.style
|
||||
self.navigationPresentation = .modalInLargeLayout
|
||||
self.navigationPresentation = presentation
|
||||
self.supportedOrientations = ViewControllerSupportedOrientations(regularSize: .all, compactSize: .portrait)
|
||||
self.navigationBar?.intrinsicCanTransitionInline = false
|
||||
|
||||
@@ -64,6 +74,10 @@ public final class TwoFactorDataInputScreen: ViewController {
|
||||
required init(coder aDecoder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
deinit {
|
||||
self.actionDisposable.dispose()
|
||||
}
|
||||
|
||||
@objc private func backPressed() {
|
||||
self.dismiss()
|
||||
@@ -101,8 +115,57 @@ public final class TwoFactorDataInputScreen: ViewController {
|
||||
}
|
||||
return true
|
||||
}
|
||||
controllers.append(TwoFactorDataInputScreen(sharedContext: strongSelf.sharedContext, engine: strongSelf.engine, mode: .passwordHint(recovery: nil, password: values[0]), stateUpdated: strongSelf.stateUpdated))
|
||||
controllers.append(TwoFactorDataInputScreen(sharedContext: strongSelf.sharedContext, engine: strongSelf.engine, mode: .passwordHint(recovery: nil, password: values[0]), stateUpdated: strongSelf.stateUpdated, presentation: strongSelf.navigationPresentation))
|
||||
navigationController.setViewControllers(controllers, animated: true)
|
||||
case let .passwordRecoveryEmail(_, mode):
|
||||
guard let text = (strongSelf.displayNode as! TwoFactorDataInputScreenNode).inputText.first, !text.isEmpty else {
|
||||
return
|
||||
}
|
||||
let statusController = OverlayStatusController(theme: strongSelf.presentationData.theme, type: .loading(cancelled: nil))
|
||||
strongSelf.present(statusController, in: .window(.root))
|
||||
|
||||
strongSelf.actionDisposable.set((strongSelf.engine.auth.checkPasswordRecoveryCode(code: text)
|
||||
|> deliverOnMainQueue).start(error: { [weak statusController] error in
|
||||
statusController?.dismiss()
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
|
||||
let text: String
|
||||
switch error {
|
||||
case .limitExceeded:
|
||||
text = strongSelf.presentationData.strings.LoginPassword_FloodError
|
||||
case .invalidCode:
|
||||
text = strongSelf.presentationData.strings.Login_InvalidCodeError
|
||||
case .expired:
|
||||
text = strongSelf.presentationData.strings.Login_CodeExpiredError
|
||||
case .generic:
|
||||
text = strongSelf.presentationData.strings.Login_UnknownError
|
||||
}
|
||||
|
||||
strongSelf.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: strongSelf.presentationData), title: nil, text: text, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})]), in: .window(.root))
|
||||
}, completed: { [weak statusController] in
|
||||
statusController?.dismiss()
|
||||
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
|
||||
let mappedMode: TwoFactorDataInputMode.Recovery.Mode
|
||||
switch mode {
|
||||
case .authorized:
|
||||
mappedMode = .authorized
|
||||
case let .notAuthorized(syncContacts):
|
||||
mappedMode = .notAuthorized(syncContacts: syncContacts)
|
||||
}
|
||||
|
||||
let setupController = TwoFactorDataInputScreen(sharedContext: strongSelf.sharedContext, engine: strongSelf.engine, mode: .passwordRecovery(TwoFactorDataInputMode.Recovery(code: text, mode: mappedMode)), stateUpdated: strongSelf.stateUpdated, presentation: strongSelf.navigationPresentation)
|
||||
|
||||
guard let navigationController = strongSelf.navigationController as? NavigationController else {
|
||||
return
|
||||
}
|
||||
navigationController.replaceController(strongSelf, with: setupController, animated: true)
|
||||
}))
|
||||
case let .passwordRecovery(recovery):
|
||||
let values = (strongSelf.displayNode as! TwoFactorDataInputScreenNode).inputText
|
||||
if values.count != 2 {
|
||||
@@ -120,17 +183,7 @@ public final class TwoFactorDataInputScreen: ViewController {
|
||||
guard let navigationController = strongSelf.navigationController as? NavigationController else {
|
||||
return
|
||||
}
|
||||
var controllers = navigationController.viewControllers.filter { controller in
|
||||
if controller is TwoFactorAuthSplashScreen {
|
||||
return false
|
||||
}
|
||||
if controller is TwoFactorDataInputScreen && controller !== strongSelf {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
controllers.append(TwoFactorDataInputScreen(sharedContext: strongSelf.sharedContext, engine: strongSelf.engine, mode: .passwordHint(recovery: recovery, password: values[0]), stateUpdated: strongSelf.stateUpdated))
|
||||
navigationController.setViewControllers(controllers, animated: true)
|
||||
navigationController.replaceController(strongSelf, with: TwoFactorDataInputScreen(sharedContext: strongSelf.sharedContext, engine: strongSelf.engine, mode: .passwordHint(recovery: recovery, password: values[0]), stateUpdated: strongSelf.stateUpdated, presentation: strongSelf.navigationPresentation), animated: true)
|
||||
case let .emailAddress(password, hint):
|
||||
guard let text = (strongSelf.displayNode as! TwoFactorDataInputScreenNode).inputText.first, !text.isEmpty else {
|
||||
return
|
||||
@@ -163,7 +216,7 @@ public final class TwoFactorDataInputScreen: ViewController {
|
||||
}
|
||||
return true
|
||||
}
|
||||
controllers.append(TwoFactorDataInputScreen(sharedContext: strongSelf.sharedContext, engine: strongSelf.engine, mode: .emailConfirmation(passwordAndHint: (password, hint), emailPattern: text, codeLength: pendingEmail.codeLength.flatMap(Int.init)), stateUpdated: strongSelf.stateUpdated))
|
||||
controllers.append(TwoFactorDataInputScreen(sharedContext: strongSelf.sharedContext, engine: strongSelf.engine, mode: .emailConfirmation(passwordAndHint: (password, hint), emailPattern: text, codeLength: pendingEmail.codeLength.flatMap(Int.init)), stateUpdated: strongSelf.stateUpdated, presentation: strongSelf.navigationPresentation))
|
||||
navigationController.setViewControllers(controllers, animated: true)
|
||||
} else {
|
||||
guard let navigationController = strongSelf.navigationController as? NavigationController else {
|
||||
@@ -337,7 +390,7 @@ public final class TwoFactorDataInputScreen: ViewController {
|
||||
if let recovery = recovery {
|
||||
strongSelf.performRecovery(recovery: recovery, password: password, hint: value)
|
||||
} else {
|
||||
strongSelf.push(TwoFactorDataInputScreen(sharedContext: strongSelf.sharedContext, engine: strongSelf.engine, mode: .emailAddress(password: password, hint: value), stateUpdated: strongSelf.stateUpdated))
|
||||
strongSelf.push(TwoFactorDataInputScreen(sharedContext: strongSelf.sharedContext, engine: strongSelf.engine, mode: .emailAddress(password: password, hint: value), stateUpdated: strongSelf.stateUpdated, presentation: strongSelf.navigationPresentation))
|
||||
}
|
||||
}
|
||||
}, skipAction: { [weak self] in
|
||||
@@ -405,7 +458,7 @@ public final class TwoFactorDataInputScreen: ViewController {
|
||||
if let recovery = recovery {
|
||||
strongSelf.performRecovery(recovery: recovery, password: password, hint: "")
|
||||
} else {
|
||||
strongSelf.push(TwoFactorDataInputScreen(sharedContext: strongSelf.sharedContext, engine: strongSelf.engine, mode: .emailAddress(password: password, hint: ""), stateUpdated: strongSelf.stateUpdated))
|
||||
strongSelf.push(TwoFactorDataInputScreen(sharedContext: strongSelf.sharedContext, engine: strongSelf.engine, mode: .emailAddress(password: password, hint: ""), stateUpdated: strongSelf.stateUpdated, presentation: strongSelf.navigationPresentation))
|
||||
}
|
||||
case let .passwordRecovery(recovery):
|
||||
strongSelf.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: strongSelf.presentationData), title: strongSelf.presentationData.strings.TwoFactorSetup_PasswordRecovery_SkipAlertTitle, text: strongSelf.presentationData.strings.TwoFactorSetup_PasswordRecovery_SkipAlertText, actions: [
|
||||
@@ -439,10 +492,32 @@ public final class TwoFactorDataInputScreen: ViewController {
|
||||
}
|
||||
return true
|
||||
}
|
||||
controllers.append(TwoFactorDataInputScreen(sharedContext: strongSelf.sharedContext, engine: strongSelf.engine, mode: .emailAddress(password: password, hint: hint), stateUpdated: strongSelf.stateUpdated))
|
||||
controllers.append(TwoFactorDataInputScreen(sharedContext: strongSelf.sharedContext, engine: strongSelf.engine, mode: .emailAddress(password: password, hint: hint), stateUpdated: strongSelf.stateUpdated, presentation: strongSelf.navigationPresentation))
|
||||
navigationController.setViewControllers(controllers, animated: true)
|
||||
} else {
|
||||
}
|
||||
case .passwordRecoveryEmail:
|
||||
switch strongSelf.engine {
|
||||
case let .authorized(engine):
|
||||
strongSelf.present(textAlertController(sharedContext: strongSelf.sharedContext, title: strongSelf.presentationData.strings.TwoStepAuth_RecoveryUnavailableResetTitle, text: strongSelf.presentationData.strings.TwoStepAuth_RecoveryEmailResetText, actions: [TextAlertAction(type: .genericAction, title: strongSelf.presentationData.strings.Common_Cancel, action: {}), TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.TwoStepAuth_RecoveryUnavailableResetAction, action: {
|
||||
let _ = (engine.auth.requestTwoStepPasswordReset()
|
||||
|> deliverOnMainQueue).start(next: { result in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
switch result {
|
||||
case .done, .waitingForReset:
|
||||
strongSelf.stateUpdated(.pendingPasswordReset)
|
||||
case .declined:
|
||||
break
|
||||
case let .error(reason):
|
||||
break
|
||||
}
|
||||
})
|
||||
})]), in: .window(.root))
|
||||
case .unauthorized:
|
||||
strongSelf.present(textAlertController(sharedContext: strongSelf.sharedContext, title: nil, text: strongSelf.presentationData.strings.TwoStepAuth_RecoveryFailed, actions: [TextAlertAction(type: .genericAction, title: strongSelf.presentationData.strings.Common_OK, action: {})]), in: .window(.root))
|
||||
}
|
||||
default:
|
||||
break
|
||||
}
|
||||
@@ -450,29 +525,57 @@ public final class TwoFactorDataInputScreen: ViewController {
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
|
||||
let statusController = OverlayStatusController(theme: strongSelf.presentationData.theme, type: .loading(cancelled: nil))
|
||||
strongSelf.present(statusController, in: .window(.root))
|
||||
switch strongSelf.mode {
|
||||
case .passwordRecoveryEmail:
|
||||
let statusController = OverlayStatusController(theme: strongSelf.presentationData.theme, type: .loading(cancelled: nil))
|
||||
strongSelf.present(statusController, in: .window(.root))
|
||||
|
||||
let _ = (strongSelf.engine.auth.resendTwoStepRecoveryEmail()
|
||||
|> deliverOnMainQueue).start(error: { [weak statusController] error in
|
||||
statusController?.dismiss()
|
||||
|
||||
guard let strongSelf = self else {
|
||||
let _ = (strongSelf.engine.auth.requestTwoStepVerificationPasswordRecoveryCode()
|
||||
|> deliverOnMainQueue).start(error: { [weak statusController] error in
|
||||
statusController?.dismiss()
|
||||
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
|
||||
let text: String
|
||||
switch error {
|
||||
case .limitExceeded:
|
||||
text = strongSelf.presentationData.strings.TwoStepAuth_FloodError
|
||||
case .generic:
|
||||
text = strongSelf.presentationData.strings.Login_UnknownError
|
||||
}
|
||||
strongSelf.present(textAlertController(sharedContext: strongSelf.sharedContext, title: nil, text: text, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})]), in: .window(.root))
|
||||
}, completed: { [weak statusController] in
|
||||
statusController?.dismiss()
|
||||
})
|
||||
default:
|
||||
guard case let .authorized(engine) = strongSelf.engine else {
|
||||
return
|
||||
}
|
||||
|
||||
let text: String
|
||||
switch error {
|
||||
case .flood:
|
||||
text = strongSelf.presentationData.strings.TwoStepAuth_FloodError
|
||||
case .generic:
|
||||
text = strongSelf.presentationData.strings.Login_UnknownError
|
||||
}
|
||||
strongSelf.present(textAlertController(sharedContext: strongSelf.sharedContext, title: nil, text: text, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})]), in: .window(.root))
|
||||
}, completed: { [weak statusController] in
|
||||
statusController?.dismiss()
|
||||
})
|
||||
let statusController = OverlayStatusController(theme: strongSelf.presentationData.theme, type: .loading(cancelled: nil))
|
||||
strongSelf.present(statusController, in: .window(.root))
|
||||
|
||||
let _ = (engine.auth.resendTwoStepRecoveryEmail()
|
||||
|> deliverOnMainQueue).start(error: { [weak statusController] error in
|
||||
statusController?.dismiss()
|
||||
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
|
||||
let text: String
|
||||
switch error {
|
||||
case .flood:
|
||||
text = strongSelf.presentationData.strings.TwoStepAuth_FloodError
|
||||
case .generic:
|
||||
text = strongSelf.presentationData.strings.Login_UnknownError
|
||||
}
|
||||
strongSelf.present(textAlertController(sharedContext: strongSelf.sharedContext, title: nil, text: text, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})]), in: .window(.root))
|
||||
}, completed: { [weak statusController] in
|
||||
statusController?.dismiss()
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
self.displayNodeDidLoad()
|
||||
@@ -485,42 +588,93 @@ public final class TwoFactorDataInputScreen: ViewController {
|
||||
}
|
||||
|
||||
private func performRecovery(recovery: TwoFactorDataInputMode.Recovery, password: String, hint: String) {
|
||||
guard case let .unauthorized(engine) = self.engine else {
|
||||
return
|
||||
}
|
||||
let statusController = OverlayStatusController(theme: self.presentationData.theme, type: .loading(cancelled: nil))
|
||||
self.present(statusController, in: .window(.root))
|
||||
|
||||
let _ = (engine.auth.performPasswordRecovery(accountManager: self.sharedContext.accountManager, code: recovery.code, syncContacts: recovery.syncContacts, updatedPassword: password.isEmpty ? .none : .password(password: password, hint: hint, email: nil))
|
||||
|> deliverOnMainQueue).start(error: { [weak self, weak statusController] error in
|
||||
statusController?.dismiss()
|
||||
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
switch self.engine {
|
||||
case let .unauthorized(engine):
|
||||
var syncContacts = false
|
||||
switch recovery.mode {
|
||||
case let .notAuthorized(syncContactsValue):
|
||||
syncContacts = syncContactsValue
|
||||
case .authorized:
|
||||
break
|
||||
}
|
||||
let _ = (engine.auth.performPasswordRecovery(code: recovery.code, updatedPassword: password.isEmpty ? .none : .password(password: password, hint: hint, email: nil))
|
||||
|> deliverOnMainQueue).start(next: { [weak self, weak statusController] recoveredAccountData in
|
||||
statusController?.dismiss()
|
||||
|
||||
let text: String
|
||||
switch error {
|
||||
case .limitExceeded:
|
||||
text = strongSelf.presentationData.strings.LoginPassword_FloodError
|
||||
case .invalidCode:
|
||||
text = strongSelf.presentationData.strings.Login_InvalidCodeError
|
||||
case .expired:
|
||||
text = strongSelf.presentationData.strings.Login_CodeExpiredError
|
||||
case .generic:
|
||||
text = strongSelf.presentationData.strings.Login_UnknownError
|
||||
}
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
|
||||
strongSelf.present(textAlertController(sharedContext: strongSelf.sharedContext, title: nil, text: text, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})]), in: .window(.root))
|
||||
}, completed: { [weak self, weak statusController] in
|
||||
statusController?.dismiss()
|
||||
if password.isEmpty {
|
||||
strongSelf.stateUpdated(.noPassword)
|
||||
} else {
|
||||
strongSelf.stateUpdated(.passwordSet(password: password, hasRecoveryEmail: true, hasSecureValues: false))
|
||||
}
|
||||
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
(strongSelf.navigationController as? NavigationController)?.replaceController(strongSelf, with: TwoFactorAuthSplashScreen(sharedContext: strongSelf.sharedContext, engine: strongSelf.engine, mode: .recoveryDone(recoveredAccountData: recoveredAccountData, syncContacts: syncContacts)), animated: true)
|
||||
}, error: { [weak self, weak statusController] error in
|
||||
statusController?.dismiss()
|
||||
|
||||
strongSelf.dismiss()
|
||||
})
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
|
||||
let text: String
|
||||
switch error {
|
||||
case .limitExceeded:
|
||||
text = strongSelf.presentationData.strings.LoginPassword_FloodError
|
||||
case .invalidCode:
|
||||
text = strongSelf.presentationData.strings.Login_InvalidCodeError
|
||||
case .expired:
|
||||
text = strongSelf.presentationData.strings.Login_CodeExpiredError
|
||||
case .generic:
|
||||
text = strongSelf.presentationData.strings.Login_UnknownError
|
||||
}
|
||||
|
||||
strongSelf.present(textAlertController(sharedContext: strongSelf.sharedContext, title: nil, text: text, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})]), in: .window(.root))
|
||||
}, completed: { [weak self, weak statusController] in
|
||||
statusController?.dismiss()
|
||||
})
|
||||
case let .authorized(engine):
|
||||
let _ = (engine.auth.performPasswordRecovery(code: recovery.code, updatedPassword: password.isEmpty ? .none : .password(password: password, hint: hint, email: nil))
|
||||
|> deliverOnMainQueue).start(error: { [weak self, weak statusController] error in
|
||||
statusController?.dismiss()
|
||||
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
|
||||
let text: String
|
||||
switch error {
|
||||
case .limitExceeded:
|
||||
text = strongSelf.presentationData.strings.LoginPassword_FloodError
|
||||
case .invalidCode:
|
||||
text = strongSelf.presentationData.strings.Login_InvalidCodeError
|
||||
case .expired:
|
||||
text = strongSelf.presentationData.strings.Login_CodeExpiredError
|
||||
case .generic:
|
||||
text = strongSelf.presentationData.strings.Login_UnknownError
|
||||
}
|
||||
|
||||
strongSelf.present(textAlertController(sharedContext: strongSelf.sharedContext, title: nil, text: text, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})]), in: .window(.root))
|
||||
}, completed: { [weak self, weak statusController] in
|
||||
statusController?.dismiss()
|
||||
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
|
||||
if password.isEmpty {
|
||||
strongSelf.stateUpdated(.noPassword)
|
||||
} else {
|
||||
strongSelf.stateUpdated(.passwordSet(password: password, hasRecoveryEmail: true, hasSecureValues: false))
|
||||
}
|
||||
strongSelf.dismiss()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -805,7 +959,7 @@ private final class TwoFactorDataInputScreenNode: ViewControllerTracingNode, UIS
|
||||
self.scrollNode.canCancelAllTouchesInViews = true
|
||||
|
||||
switch mode {
|
||||
case .password, .passwordRecovery, .emailAddress, .updateEmailAddress:
|
||||
case .password, .passwordRecovery, .passwordRecoveryEmail, .emailAddress, .updateEmailAddress:
|
||||
self.monkeyNode = ManagedMonkeyAnimationNode()
|
||||
case .emailConfirmation:
|
||||
if let path = getAppBundle().path(forResource: "TwoFactorSetupMail", ofType: "tgs") {
|
||||
@@ -909,6 +1063,33 @@ private final class TwoFactorDataInputScreenNode: ViewControllerTracingNode, UIS
|
||||
toggleTextHidden?(node)
|
||||
}),
|
||||
]
|
||||
case let .passwordRecoveryEmail(emailPattern, _):
|
||||
title = presentationData.strings.TwoFactorSetup_EmailVerification_Title
|
||||
let (rawText, ranges) = presentationData.strings.TwoFactorSetup_EmailVerification_Text(emailPattern)
|
||||
|
||||
let string = NSMutableAttributedString()
|
||||
string.append(NSAttributedString(string: rawText, font: Font.regular(16.0), textColor: presentationData.theme.list.itemPrimaryTextColor))
|
||||
for (_, range) in ranges {
|
||||
string.addAttribute(.font, value: Font.semibold(16.0), range: range)
|
||||
}
|
||||
|
||||
text = string
|
||||
|
||||
buttonText = presentationData.strings.TwoFactorSetup_EmailVerification_Action
|
||||
skipActionText = ""
|
||||
changeEmailActionText = presentationData.strings.TwoStepAuth_RecoveryEmailResetNoAccess
|
||||
resendCodeActionText = presentationData.strings.TwoFactorSetup_EmailVerification_ResendAction
|
||||
inputNodes = [
|
||||
TwoFactorDataInputTextNode(theme: presentationData.theme, mode: .code, placeholder: presentationData.strings.TwoFactorSetup_EmailVerification_Placeholder, focusUpdated: { node, focused in
|
||||
focusUpdated?(node, focused)
|
||||
}, next: { node in
|
||||
next?(node)
|
||||
}, updated: { node in
|
||||
updated?(node)
|
||||
}, toggleTextHidden: { node in
|
||||
toggleTextHidden?(node)
|
||||
}),
|
||||
]
|
||||
case let .emailConfirmation(_, emailPattern, _):
|
||||
title = presentationData.strings.TwoFactorSetup_EmailVerification_Title
|
||||
let (rawText, ranges) = presentationData.strings.TwoFactorSetup_EmailVerification_Text(emailPattern)
|
||||
@@ -985,7 +1166,6 @@ private final class TwoFactorDataInputScreenNode: ViewControllerTracingNode, UIS
|
||||
self.changeEmailActionTitleNode.attributedText = NSAttributedString(string: changeEmailActionText, font: Font.regular(16.0), textColor: self.presentationData.theme.list.itemAccentColor)
|
||||
self.changeEmailActionButtonNode = HighlightTrackingButtonNode()
|
||||
self.changeEmailActionButtonNode.isHidden = changeEmailActionText.isEmpty
|
||||
self.changeEmailActionButtonNode.isHidden = changeEmailActionText.isEmpty
|
||||
|
||||
self.resendCodeActionTitleNode = ImmediateTextNode()
|
||||
self.resendCodeActionTitleNode.isUserInteractionEnabled = false
|
||||
@@ -1129,7 +1309,7 @@ private final class TwoFactorDataInputScreenNode: ViewControllerTracingNode, UIS
|
||||
break
|
||||
}
|
||||
}
|
||||
focusUpdated = { [weak self] node, _ in
|
||||
focusUpdated = { node, _ in
|
||||
DispatchQueue.main.async {
|
||||
updateAnimations()
|
||||
}
|
||||
@@ -1156,6 +1336,18 @@ private final class TwoFactorDataInputScreenNode: ViewControllerTracingNode, UIS
|
||||
if let codeLength = codeLength, text.count == codeLength {
|
||||
action()
|
||||
}
|
||||
case .passwordRecoveryEmail:
|
||||
let text = strongSelf.inputNodes[0].text
|
||||
let hasText = !text.isEmpty
|
||||
strongSelf.buttonNode.isHidden = !hasText
|
||||
strongSelf.changeEmailActionTitleNode.isHidden = hasText
|
||||
strongSelf.changeEmailActionButtonNode.isHidden = hasText
|
||||
strongSelf.resendCodeActionTitleNode.isHidden = hasText
|
||||
strongSelf.resendCodeActionButtonNode.isHidden = hasText
|
||||
|
||||
if text.count == 6 {
|
||||
action()
|
||||
}
|
||||
case .passwordHint:
|
||||
let hasText = strongSelf.inputNodes.contains(where: { !$0.text.isEmpty })
|
||||
strongSelf.buttonNode.isHidden = !hasText
|
||||
|
||||
Reference in New Issue
Block a user