mirror of
https://github.com/oxen-io/session-ios.git
synced 2023-12-13 21:30:14 +01:00
Sketch out the 'onboarding 2FA' view.
This commit is contained in:
parent
9d0813d7b9
commit
0b55ecc682
|
@ -165,6 +165,7 @@
|
||||||
3496957321A301A100DCFE74 /* OWSBackupJob.m in Sources */ = {isa = PBXBuildFile; fileRef = 3496956A21A301A100DCFE74 /* OWSBackupJob.m */; };
|
3496957321A301A100DCFE74 /* OWSBackupJob.m in Sources */ = {isa = PBXBuildFile; fileRef = 3496956A21A301A100DCFE74 /* OWSBackupJob.m */; };
|
||||||
3496957421A301A100DCFE74 /* OWSBackupAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3496956B21A301A100DCFE74 /* OWSBackupAPI.swift */; };
|
3496957421A301A100DCFE74 /* OWSBackupAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3496956B21A301A100DCFE74 /* OWSBackupAPI.swift */; };
|
||||||
349EA07C2162AEA800F7B17F /* OWS111UDAttributesMigration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 349EA07B2162AEA700F7B17F /* OWS111UDAttributesMigration.swift */; };
|
349EA07C2162AEA800F7B17F /* OWS111UDAttributesMigration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 349EA07B2162AEA700F7B17F /* OWS111UDAttributesMigration.swift */; };
|
||||||
|
349ED990221B0194008045B0 /* Onboarding2FAViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 349ED98F221B0194008045B0 /* Onboarding2FAViewController.swift */; };
|
||||||
34A4C61E221613D00042EF2E /* OnboardingVerificationViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34A4C61D221613D00042EF2E /* OnboardingVerificationViewController.swift */; };
|
34A4C61E221613D00042EF2E /* OnboardingVerificationViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34A4C61D221613D00042EF2E /* OnboardingVerificationViewController.swift */; };
|
||||||
34A4C62022175C5C0042EF2E /* OnboardingProfileViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34A4C61F22175C5C0042EF2E /* OnboardingProfileViewController.swift */; };
|
34A4C62022175C5C0042EF2E /* OnboardingProfileViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34A4C61F22175C5C0042EF2E /* OnboardingProfileViewController.swift */; };
|
||||||
34A55F3720485465002CC6DE /* OWS2FARegistrationViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 34A55F3520485464002CC6DE /* OWS2FARegistrationViewController.m */; };
|
34A55F3720485465002CC6DE /* OWS2FARegistrationViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 34A55F3520485464002CC6DE /* OWS2FARegistrationViewController.m */; };
|
||||||
|
@ -848,6 +849,7 @@
|
||||||
3496956C21A301A100DCFE74 /* OWSBackupImportJob.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSBackupImportJob.h; sourceTree = "<group>"; };
|
3496956C21A301A100DCFE74 /* OWSBackupImportJob.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSBackupImportJob.h; sourceTree = "<group>"; };
|
||||||
3496956D21A301A100DCFE74 /* OWSBackupIO.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSBackupIO.h; sourceTree = "<group>"; };
|
3496956D21A301A100DCFE74 /* OWSBackupIO.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSBackupIO.h; sourceTree = "<group>"; };
|
||||||
349EA07B2162AEA700F7B17F /* OWS111UDAttributesMigration.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OWS111UDAttributesMigration.swift; sourceTree = "<group>"; };
|
349EA07B2162AEA700F7B17F /* OWS111UDAttributesMigration.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OWS111UDAttributesMigration.swift; sourceTree = "<group>"; };
|
||||||
|
349ED98F221B0194008045B0 /* Onboarding2FAViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Onboarding2FAViewController.swift; sourceTree = "<group>"; };
|
||||||
34A4C61D221613D00042EF2E /* OnboardingVerificationViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OnboardingVerificationViewController.swift; sourceTree = "<group>"; };
|
34A4C61D221613D00042EF2E /* OnboardingVerificationViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OnboardingVerificationViewController.swift; sourceTree = "<group>"; };
|
||||||
34A4C61F22175C5C0042EF2E /* OnboardingProfileViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OnboardingProfileViewController.swift; sourceTree = "<group>"; };
|
34A4C61F22175C5C0042EF2E /* OnboardingProfileViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OnboardingProfileViewController.swift; sourceTree = "<group>"; };
|
||||||
34A55F3520485464002CC6DE /* OWS2FARegistrationViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWS2FARegistrationViewController.m; sourceTree = "<group>"; };
|
34A55F3520485464002CC6DE /* OWS2FARegistrationViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWS2FARegistrationViewController.m; sourceTree = "<group>"; };
|
||||||
|
@ -1471,6 +1473,7 @@
|
||||||
3441FD9E21A3604F00BB9542 /* BackupRestoreViewController.swift */,
|
3441FD9E21A3604F00BB9542 /* BackupRestoreViewController.swift */,
|
||||||
340FC879204DAC8C007AEB0F /* CodeVerificationViewController.h */,
|
340FC879204DAC8C007AEB0F /* CodeVerificationViewController.h */,
|
||||||
340FC877204DAC8C007AEB0F /* CodeVerificationViewController.m */,
|
340FC877204DAC8C007AEB0F /* CodeVerificationViewController.m */,
|
||||||
|
349ED98F221B0194008045B0 /* Onboarding2FAViewController.swift */,
|
||||||
3448E1612213585C004B052E /* OnboardingBaseViewController.swift */,
|
3448E1612213585C004B052E /* OnboardingBaseViewController.swift */,
|
||||||
3448E1652215B313004B052E /* OnboardingCaptchaViewController.swift */,
|
3448E1652215B313004B052E /* OnboardingCaptchaViewController.swift */,
|
||||||
3448E15D221333F5004B052E /* OnboardingController.swift */,
|
3448E15D221333F5004B052E /* OnboardingController.swift */,
|
||||||
|
@ -3530,6 +3533,7 @@
|
||||||
4C4AEC4520EC343B0020E72B /* DismissableTextField.swift in Sources */,
|
4C4AEC4520EC343B0020E72B /* DismissableTextField.swift in Sources */,
|
||||||
4CB5F26720F6E1E2004D1B42 /* MenuActionsViewController.swift in Sources */,
|
4CB5F26720F6E1E2004D1B42 /* MenuActionsViewController.swift in Sources */,
|
||||||
3496955E219B605E00DCFE74 /* PhotoLibrary.swift in Sources */,
|
3496955E219B605E00DCFE74 /* PhotoLibrary.swift in Sources */,
|
||||||
|
349ED990221B0194008045B0 /* Onboarding2FAViewController.swift in Sources */,
|
||||||
45D231771DC7E8F10034FA89 /* SessionResetJob.swift in Sources */,
|
45D231771DC7E8F10034FA89 /* SessionResetJob.swift in Sources */,
|
||||||
340FC8A9204DAC8D007AEB0F /* NotificationSettingsOptionsViewController.m in Sources */,
|
340FC8A9204DAC8D007AEB0F /* NotificationSettingsOptionsViewController.m in Sources */,
|
||||||
452037D11EE84975004E4CDF /* DebugUISessionState.m in Sources */,
|
452037D11EE84975004E4CDF /* DebugUISessionState.m in Sources */,
|
||||||
|
|
|
@ -0,0 +1,176 @@
|
||||||
|
//
|
||||||
|
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
@objc
|
||||||
|
public class Onboarding2FAViewController: OnboardingBaseViewController {
|
||||||
|
|
||||||
|
private let pinTextField = UITextField()
|
||||||
|
|
||||||
|
private var pinStrokeNormal: UIView?
|
||||||
|
private var pinStrokeError: UIView?
|
||||||
|
private let validationWarningLabel = UILabel()
|
||||||
|
private var isPinInvalid = false {
|
||||||
|
didSet {
|
||||||
|
updateValidationWarnings()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override public func loadView() {
|
||||||
|
super.loadView()
|
||||||
|
|
||||||
|
view.backgroundColor = Theme.backgroundColor
|
||||||
|
view.layoutMargins = .zero
|
||||||
|
|
||||||
|
let titleLabel = self.titleLabel(text: NSLocalizedString("ONBOARDING_2FA_TITLE", comment: "Title of the 'onboarding 2FA' view."))
|
||||||
|
|
||||||
|
let explanationLabel1 = self.explanationLabel(explanationText: NSLocalizedString("ONBOARDING_2FA_EXPLANATION_1",
|
||||||
|
comment: "The first explanation in the 'onboarding 2FA' view."))
|
||||||
|
let explanationLabel2 = self.explanationLabel(explanationText: NSLocalizedString("ONBOARDING_2FA_EXPLANATION_2",
|
||||||
|
comment: "The first explanation in the 'onboarding 2FA' view."))
|
||||||
|
explanationLabel1.font = UIFont.ows_dynamicTypeCaption1
|
||||||
|
explanationLabel2.font = UIFont.ows_dynamicTypeCaption1
|
||||||
|
|
||||||
|
pinTextField.textAlignment = .center
|
||||||
|
pinTextField.delegate = self
|
||||||
|
pinTextField.keyboardType = .numberPad
|
||||||
|
pinTextField.textColor = Theme.primaryColor
|
||||||
|
pinTextField.font = UIFont.ows_dynamicTypeBodyClamped
|
||||||
|
pinTextField.setContentHuggingHorizontalLow()
|
||||||
|
pinTextField.setCompressionResistanceHorizontalLow()
|
||||||
|
pinTextField.autoSetDimension(.height, toSize: 40)
|
||||||
|
|
||||||
|
pinStrokeNormal = pinTextField.addBottomStroke()
|
||||||
|
pinStrokeError = pinTextField.addBottomStroke(color: .ows_destructiveRed, strokeWidth: 2)
|
||||||
|
|
||||||
|
validationWarningLabel.text = NSLocalizedString("ONBOARDING_PHONE_NUMBER_VALIDATION_WARNING",
|
||||||
|
comment: "Label indicating that the phone number is invalid in the 'onboarding phone number' view.")
|
||||||
|
validationWarningLabel.textColor = .ows_destructiveRed
|
||||||
|
validationWarningLabel.font = UIFont.ows_dynamicTypeSubheadlineClamped
|
||||||
|
validationWarningLabel.textAlignment = .center
|
||||||
|
|
||||||
|
let validationWarningRow = UIView()
|
||||||
|
validationWarningRow.addSubview(validationWarningLabel)
|
||||||
|
validationWarningLabel.ows_autoPinToSuperviewEdges()
|
||||||
|
validationWarningRow.autoSetDimension(.height, toSize: validationWarningLabel.font.lineHeight)
|
||||||
|
|
||||||
|
let forgotPinLink = self.linkButton(title: NSLocalizedString("ONBOARDING_2FA_FORGOT_PIN_LINK",
|
||||||
|
comment: "Label for the 'forgot 2FA PIN' link in the 'onboarding 2FA' view."),
|
||||||
|
selector: #selector(forgotPinLinkTapped))
|
||||||
|
|
||||||
|
let nextButton = self.button(title: NSLocalizedString("BUTTON_NEXT",
|
||||||
|
comment: "Label for the 'next' button."),
|
||||||
|
selector: #selector(nextPressed))
|
||||||
|
|
||||||
|
let topSpacer = UIView.vStretchingSpacer()
|
||||||
|
let bottomSpacer = UIView.vStretchingSpacer()
|
||||||
|
|
||||||
|
let stackView = UIStackView(arrangedSubviews: [
|
||||||
|
titleLabel,
|
||||||
|
UIView.spacer(withHeight: 10),
|
||||||
|
explanationLabel1,
|
||||||
|
UIView.spacer(withHeight: 10),
|
||||||
|
explanationLabel2,
|
||||||
|
|
||||||
|
topSpacer,
|
||||||
|
pinTextField,
|
||||||
|
UIView.spacer(withHeight: 10),
|
||||||
|
validationWarningRow,
|
||||||
|
bottomSpacer,
|
||||||
|
forgotPinLink,
|
||||||
|
UIView.spacer(withHeight: 10),
|
||||||
|
nextButton
|
||||||
|
])
|
||||||
|
stackView.axis = .vertical
|
||||||
|
stackView.alignment = .fill
|
||||||
|
stackView.layoutMargins = UIEdgeInsets(top: 20, left: 32, bottom: 20, right: 32)
|
||||||
|
stackView.isLayoutMarginsRelativeArrangement = true
|
||||||
|
view.addSubview(stackView)
|
||||||
|
stackView.autoPinWidthToSuperview()
|
||||||
|
stackView.autoPin(toTopLayoutGuideOf: self, withInset: 0)
|
||||||
|
autoPinView(toBottomOfViewControllerOrKeyboard: stackView, avoidNotch: true)
|
||||||
|
|
||||||
|
// Ensure whitespace is balanced, so inputs are vertically centered.
|
||||||
|
topSpacer.autoMatch(.height, to: .height, of: bottomSpacer)
|
||||||
|
|
||||||
|
updateValidationWarnings()
|
||||||
|
}
|
||||||
|
|
||||||
|
public override func viewDidAppear(_ animated: Bool) {
|
||||||
|
super.viewDidAppear(animated)
|
||||||
|
|
||||||
|
_ = pinTextField.becomeFirstResponder()
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Events
|
||||||
|
|
||||||
|
@objc func forgotPinLinkTapped() {
|
||||||
|
Logger.info("")
|
||||||
|
|
||||||
|
OWSAlerts.showAlert(title: nil, message: NSLocalizedString("REGISTER_2FA_FORGOT_PIN_ALERT_MESSAGE",
|
||||||
|
comment: "Alert message explaining what happens if you forget your 'two-factor auth pin'."))
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc func nextPressed() {
|
||||||
|
Logger.info("")
|
||||||
|
|
||||||
|
tryToVerify()
|
||||||
|
}
|
||||||
|
|
||||||
|
private func tryToVerify() {
|
||||||
|
Logger.info("")
|
||||||
|
|
||||||
|
guard let pin = pinTextField.text?.ows_stripped(),
|
||||||
|
pin.count > 0 else {
|
||||||
|
isPinInvalid = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
isPinInvalid = false
|
||||||
|
|
||||||
|
onboardingController.update(twoFAPin: pin)
|
||||||
|
|
||||||
|
onboardingController.tryToVerify(fromViewController: self, completion: { (outcome) in
|
||||||
|
if outcome == .invalid2FAPin {
|
||||||
|
self.isPinInvalid = true
|
||||||
|
} else if outcome == .invalidVerificationCode {
|
||||||
|
owsFailDebug("Invalid verification code in 2FA view.")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
private func updateValidationWarnings() {
|
||||||
|
AssertIsOnMainThread()
|
||||||
|
|
||||||
|
pinStrokeNormal?.isHidden = isPinInvalid
|
||||||
|
pinStrokeError?.isHidden = !isPinInvalid
|
||||||
|
validationWarningLabel.isHidden = !isPinInvalid
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: -
|
||||||
|
|
||||||
|
extension Onboarding2FAViewController: UITextFieldDelegate {
|
||||||
|
public func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
|
||||||
|
let newString = string.digitsOnly
|
||||||
|
var oldText = ""
|
||||||
|
if let textFieldText = textField.text {
|
||||||
|
oldText = textFieldText
|
||||||
|
}
|
||||||
|
let left = oldText.substring(to: range.location)
|
||||||
|
let right = oldText.substring(from: range.location + range.length)
|
||||||
|
textField.text = left + newString + right
|
||||||
|
|
||||||
|
isPinInvalid = false
|
||||||
|
|
||||||
|
// Inform our caller that we took care of performing the change.
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
public func textFieldShouldReturn(_ textField: UITextField) -> Bool {
|
||||||
|
tryToVerify()
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
|
@ -273,6 +273,10 @@ public class OnboardingController: NSObject {
|
||||||
|
|
||||||
public private(set) var captchaToken: String?
|
public private(set) var captchaToken: String?
|
||||||
|
|
||||||
|
public private(set) var verificationCode: String?
|
||||||
|
|
||||||
|
public private(set) var twoFAPin: String?
|
||||||
|
|
||||||
@objc
|
@objc
|
||||||
public func update(countryState: OnboardingCountryState) {
|
public func update(countryState: OnboardingCountryState) {
|
||||||
AssertIsOnMainThread()
|
AssertIsOnMainThread()
|
||||||
|
@ -294,6 +298,20 @@ public class OnboardingController: NSObject {
|
||||||
self.captchaToken = captchaToken
|
self.captchaToken = captchaToken
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@objc
|
||||||
|
public func update(verificationCode: String) {
|
||||||
|
AssertIsOnMainThread()
|
||||||
|
|
||||||
|
self.verificationCode = verificationCode
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc
|
||||||
|
public func update(twoFAPin: String) {
|
||||||
|
AssertIsOnMainThread()
|
||||||
|
|
||||||
|
self.twoFAPin = twoFAPin
|
||||||
|
}
|
||||||
|
|
||||||
// MARK: - Debug
|
// MARK: - Debug
|
||||||
|
|
||||||
private static let kKeychainService_LastRegistered = "kKeychainService_LastRegistered"
|
private static let kKeychainService_LastRegistered = "kKeychainService_LastRegistered"
|
||||||
|
@ -405,26 +423,35 @@ public class OnboardingController: NSObject {
|
||||||
|
|
||||||
// MARK: - Verification
|
// MARK: - Verification
|
||||||
|
|
||||||
|
public enum VerificationOutcome {
|
||||||
|
case success
|
||||||
|
case invalidVerificationCode
|
||||||
|
case invalid2FAPin
|
||||||
|
}
|
||||||
|
|
||||||
public func tryToVerify(fromViewController: UIViewController,
|
public func tryToVerify(fromViewController: UIViewController,
|
||||||
verificationCode: String,
|
completion : @escaping (VerificationOutcome) -> Void) {
|
||||||
pin: String?,
|
|
||||||
isInvalidCodeCallback : @escaping () -> Void) {
|
|
||||||
AssertIsOnMainThread()
|
AssertIsOnMainThread()
|
||||||
|
|
||||||
guard let phoneNumber = phoneNumber else {
|
guard let phoneNumber = phoneNumber else {
|
||||||
owsFailDebug("Missing phoneNumber.")
|
owsFailDebug("Missing phoneNumber.")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
guard let verificationCode = verificationCode else {
|
||||||
|
completion(.invalidVerificationCode)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// Ensure the account manager state is up-to-date.
|
// Ensure the account manager state is up-to-date.
|
||||||
//
|
//
|
||||||
// TODO: We could skip this in production.
|
// TODO: We could skip this in production.
|
||||||
tsAccountManager.phoneNumberAwaitingVerification = phoneNumber.e164
|
tsAccountManager.phoneNumberAwaitingVerification = phoneNumber.e164
|
||||||
|
|
||||||
|
let twoFAPin = self.twoFAPin
|
||||||
ModalActivityIndicatorViewController.present(fromViewController: fromViewController,
|
ModalActivityIndicatorViewController.present(fromViewController: fromViewController,
|
||||||
canCancel: true) { (modal) in
|
canCancel: true) { (modal) in
|
||||||
|
|
||||||
self.accountManager.register(verificationCode: verificationCode, pin: pin)
|
self.accountManager.register(verificationCode: verificationCode, pin: twoFAPin)
|
||||||
.done { (_) in
|
.done { (_) in
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
modal.dismiss(completion: {
|
modal.dismiss(completion: {
|
||||||
|
@ -438,7 +465,7 @@ public class OnboardingController: NSObject {
|
||||||
modal.dismiss(completion: {
|
modal.dismiss(completion: {
|
||||||
self.verificationFailed(fromViewController: fromViewController,
|
self.verificationFailed(fromViewController: fromViewController,
|
||||||
error: error as NSError,
|
error: error as NSError,
|
||||||
isInvalidCodeCallback: isInvalidCodeCallback)
|
completion: completion)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}).retainUntilComplete()
|
}).retainUntilComplete()
|
||||||
|
@ -446,7 +473,7 @@ public class OnboardingController: NSObject {
|
||||||
}
|
}
|
||||||
|
|
||||||
private func verificationFailed(fromViewController: UIViewController, error: NSError,
|
private func verificationFailed(fromViewController: UIViewController, error: NSError,
|
||||||
isInvalidCodeCallback : @escaping () -> Void) {
|
completion : @escaping (VerificationOutcome) -> Void) {
|
||||||
AssertIsOnMainThread()
|
AssertIsOnMainThread()
|
||||||
|
|
||||||
if error.domain == OWSSignalServiceKitErrorDomain &&
|
if error.domain == OWSSignalServiceKitErrorDomain &&
|
||||||
|
@ -454,11 +481,13 @@ public class OnboardingController: NSObject {
|
||||||
|
|
||||||
Logger.info("Missing 2FA PIN.")
|
Logger.info("Missing 2FA PIN.")
|
||||||
|
|
||||||
|
completion(.invalid2FAPin)
|
||||||
|
|
||||||
onboardingDidRequire2FAPin(viewController: fromViewController)
|
onboardingDidRequire2FAPin(viewController: fromViewController)
|
||||||
} else {
|
} else {
|
||||||
if error.domain == OWSSignalServiceKitErrorDomain &&
|
if error.domain == OWSSignalServiceKitErrorDomain &&
|
||||||
error.code == OWSErrorCode.userError.rawValue {
|
error.code == OWSErrorCode.userError.rawValue {
|
||||||
isInvalidCodeCallback()
|
completion(.invalidVerificationCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger.verbose("error: \(error.domain) \(error.code)")
|
Logger.verbose("error: \(error.domain) \(error.code)")
|
||||||
|
|
|
@ -103,7 +103,7 @@ public class OnboardingPhoneNumberViewController: OnboardingBaseViewController {
|
||||||
let validationWarningRow = UIView()
|
let validationWarningRow = UIView()
|
||||||
validationWarningRow.addSubview(validationWarningLabel)
|
validationWarningRow.addSubview(validationWarningLabel)
|
||||||
validationWarningLabel.autoPinHeightToSuperview()
|
validationWarningLabel.autoPinHeightToSuperview()
|
||||||
validationWarningLabel.autoPinEdge(toSuperviewEdge: .trailing)
|
validationWarningLabel.autoPinEdge(toSuperviewEdge: .leading)
|
||||||
|
|
||||||
// TODO: Finalize copy.
|
// TODO: Finalize copy.
|
||||||
|
|
||||||
|
|
|
@ -251,7 +251,6 @@ public class OnboardingVerificationViewController: OnboardingBaseViewController
|
||||||
private var codeState = CodeState.sent
|
private var codeState = CodeState.sent
|
||||||
|
|
||||||
private var titleLabel: UILabel?
|
private var titleLabel: UILabel?
|
||||||
private let phoneNumberTextField = UITextField()
|
|
||||||
private let onboardingCodeView = OnboardingCodeView()
|
private let onboardingCodeView = OnboardingCodeView()
|
||||||
private var codeStateLink: OWSFlatButton?
|
private var codeStateLink: OWSFlatButton?
|
||||||
private let errorLabel = UILabel()
|
private let errorLabel = UILabel()
|
||||||
|
@ -477,13 +476,18 @@ public class OnboardingVerificationViewController: OnboardingBaseViewController
|
||||||
Logger.info("")
|
Logger.info("")
|
||||||
|
|
||||||
guard onboardingCodeView.isComplete else {
|
guard onboardingCodeView.isComplete else {
|
||||||
|
self.setHasInvalidCode(true)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
setHasInvalidCode(false)
|
setHasInvalidCode(false)
|
||||||
|
|
||||||
onboardingController.tryToVerify(fromViewController: self, verificationCode: onboardingCodeView.verificationCode, pin: nil, isInvalidCodeCallback: {
|
onboardingController.update(verificationCode: onboardingCodeView.verificationCode)
|
||||||
self.setHasInvalidCode(true)
|
|
||||||
|
onboardingController.tryToVerify(fromViewController: self, completion: { (outcome) in
|
||||||
|
if outcome == .invalidVerificationCode {
|
||||||
|
self.setHasInvalidCode(true)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1508,6 +1508,18 @@
|
||||||
/* No comment provided by engineer. */
|
/* No comment provided by engineer. */
|
||||||
"OK" = "OK";
|
"OK" = "OK";
|
||||||
|
|
||||||
|
/* The first explanation in the 'onboarding 2FA' view. */
|
||||||
|
"ONBOARDING_2FA_EXPLANATION_1" = "This phone number has Registration Lock enabled. Please enter the Registration Lock PIN.";
|
||||||
|
|
||||||
|
/* The first explanation in the 'onboarding 2FA' view. */
|
||||||
|
"ONBOARDING_2FA_EXPLANATION_2" = "Your Registration Lock PIN is separate from the automated verification code that was sent to your phone during the last step.";
|
||||||
|
|
||||||
|
/* Label for the 'forgot 2FA PIN' link in the 'onboarding 2FA' view. */
|
||||||
|
"ONBOARDING_2FA_FORGOT_PIN_LINK" = "I forgot my PIN";
|
||||||
|
|
||||||
|
/* Title of the 'onboarding 2FA' view. */
|
||||||
|
"ONBOARDING_2FA_TITLE" = "Registration Lock";
|
||||||
|
|
||||||
/* Title of the 'onboarding Captcha' view. */
|
/* Title of the 'onboarding Captcha' view. */
|
||||||
"ONBOARDING_CAPTCHA_TITLE" = "We need to verify that you're human";
|
"ONBOARDING_CAPTCHA_TITLE" = "We need to verify that you're human";
|
||||||
|
|
||||||
|
@ -1547,7 +1559,7 @@
|
||||||
/* Label for the link that lets users change their phone number in the onboarding views. */
|
/* Label for the link that lets users change their phone number in the onboarding views. */
|
||||||
"ONBOARDING_VERIFICATION_BACK_LINK" = "Wrong number?";
|
"ONBOARDING_VERIFICATION_BACK_LINK" = "Wrong number?";
|
||||||
|
|
||||||
/* Format for the label of the 'pending code' label of the 'onboarding verification' view. Embeds {{the time until the code can be resent}}. */
|
/* Format for the label of the 'sent code' label of the 'onboarding verification' view. Embeds {{the time until the code can be resent}}. */
|
||||||
"ONBOARDING_VERIFICATION_CODE_COUNTDOWN_FORMAT" = "I didn't get a code (available in %@)";
|
"ONBOARDING_VERIFICATION_CODE_COUNTDOWN_FORMAT" = "I didn't get a code (available in %@)";
|
||||||
|
|
||||||
/* Label indicating that the verification code is incorrect in the 'onboarding verification' view. */
|
/* Label indicating that the verification code is incorrect in the 'onboarding verification' view. */
|
||||||
|
|
Loading…
Reference in a new issue