Use PIN progress animation for verification

This commit is contained in:
Nora Trapp 2020-04-01 20:18:13 -07:00
parent a8c32a92e6
commit 5500a531b9
4 changed files with 77 additions and 43 deletions

View File

@ -429,7 +429,7 @@ public class PinSetupViewController: OWSViewController {
pinTextField.resignFirstResponder()
let progressView = ProgressView(
let progressView = PinProgressView(
loadingText: NSLocalizedString("PIN_CREATION_PIN_PROGRESS",
comment: "Indicates the work we are doing while creating the user's pin")
)
@ -520,7 +520,7 @@ extension PinSetupViewController: UITextFieldDelegate {
}
}
private class ProgressView: UIView {
class PinProgressView: UIView {
private let label = UILabel()
private let progressAnimation = AnimationView(name: "pinCreationInProgress")
private let errorAnimation = AnimationView(name: "pinCreationFail")

View File

@ -13,6 +13,8 @@ public class Onboarding2FAViewController: OnboardingBaseViewController {
private let pinTextField = UITextField()
private let pinTypeToggle = UIButton()
private lazy var nextButton = self.primaryButton(title: CommonStrings.nextButton,
selector: #selector(nextPressed))
private lazy var pinStrokeNormal = pinTextField.addBottomStroke()
private lazy var pinStrokeError = pinTextField.addBottomStroke(color: .ows_accentRed, strokeWidth: 2)
@ -121,8 +123,6 @@ public class Onboarding2FAViewController: OnboardingBaseViewController {
pinTypeToggle.addTarget(self, action: #selector(togglePinType), for: .touchUpInside)
pinTypeToggle.accessibilityIdentifier = "pinCreation.pinTypeToggle"
let nextButton = self.primaryButton(title: CommonStrings.nextButton,
selector: #selector(nextPressed))
nextButton.accessibilityIdentifier = "onboarding.2fa." + "nextButton"
let primaryButtonView = OnboardingBaseViewController.horizontallyWrap(primaryButton: nextButton)
@ -241,6 +241,30 @@ public class Onboarding2FAViewController: OnboardingBaseViewController {
return
}
let progressView = PinProgressView(
loadingText: NSLocalizedString("REGISTER_2FA_PIN_PROGRESS",
comment: "Indicates the work we are doing while verifying the user's pin")
)
view.addSubview(progressView)
progressView.autoPinWidthToSuperview()
progressView.autoVCenterInSuperview()
progressView.startLoading {
self.view.isUserInteractionEnabled = false
self.nextButton.alpha = 0.5
self.pinTypeToggle.alpha = 0.5
}
func animateProgressFail() {
progressView.loadingComplete(success: false, animateAlongside: {
self.nextButton.alpha = 1
self.pinTypeToggle.alpha = 1
}) {
self.view.isUserInteractionEnabled = true
progressView.removeFromSuperview()
}
}
// v1 pins also have a max length, but we'll rely on the server to verify that
// since we do not know if this is a v1 or a v2 pin at registration time.
@ -259,17 +283,30 @@ public class Onboarding2FAViewController: OnboardingBaseViewController {
}
self.attemptState = .invalid(remainingAttempts: nil)
animateProgressFail()
case .invalidV2RegistrationLockPin(let remainingAttempts):
self.attemptState = .invalid(remainingAttempts: remainingAttempts)
animateProgressFail()
case .exhaustedV2RegistrationLockAttempts:
self.attemptState = .exhausted
self.showAttemptsExhausted()
progressView.loadingComplete(success: false, animated: false) { [weak self] in
guard let self = self else { return }
self.showAttemptsExhausted()
}
case .success:
self.attemptState = .valid
// If we have success while pending restoration, show the next onboarding milestone.
if self.hasPendingRestoration { self.showNextMilestone(wasSuccessful: true) }
// The completion handler always dismisses this view, so we don't want to animate anything.
progressView.loadingComplete(success: true, animated: false) { [weak self] in
guard let self = self else { return }
// If we have success while pending restoration, show the next onboarding milestone.
if self.hasPendingRestoration { self.showNextMilestone(wasSuccessful: true) }
}
case .invalidVerificationCode:
owsFailDebug("Invalid verification code in 2FA view.")
animateProgressFail()
}
})
}

View File

@ -743,42 +743,36 @@ public class OnboardingController: NSObject {
return completion(.invalid2FAPin)
}
ModalActivityIndicatorViewController.present(fromViewController: fromViewController, canCancel: false) { modal in
KeyBackupService.restoreKeys(with: twoFAPin, and: self.kbsAuth).done {
// If we restored successfully clear out KBS auth, the server will give it
// to us again if we still need to do KBS operations.
self.kbsAuth = nil
KeyBackupService.restoreKeys(with: twoFAPin, and: self.kbsAuth).done {
// If we restored successfully clear out KBS auth, the server will give it
// to us again if we still need to do KBS operations.
self.kbsAuth = nil
modal.dismiss {
if self.tsAccountManager.isRegistered {
completion(.success)
} else {
// We've restored our keys, we can now re-run this method to post our registration token
self.submitVerification(fromViewController: fromViewController, completion: completion)
}
}
}.catch { error in
modal.dismiss {
guard let error = error as? KeyBackupService.KBSError else {
owsFailDebug("unexpected response from KBS")
return completion(.invalid2FAPin)
}
if self.tsAccountManager.isRegistered {
completion(.success)
} else {
// We've restored our keys, we can now re-run this method to post our registration token
self.submitVerification(fromViewController: fromViewController, completion: completion)
}
}.catch { error in
guard let error = error as? KeyBackupService.KBSError else {
owsFailDebug("unexpected response from KBS")
return completion(.invalid2FAPin)
}
switch error {
case .assertion:
owsFailDebug("unexpected response from KBS")
completion(.invalid2FAPin)
case .invalidPin(let remainingAttempts):
completion(.invalidV2RegistrationLockPin(remainingAttempts: remainingAttempts))
case .backupMissing:
// We don't have a backup for this person, it probably
// was deleted due to too many failed attempts. They'll
// have to retry after the registration lock window expires.
completion(.exhaustedV2RegistrationLockAttempts)
}
}
}.retainUntilComplete()
}
switch error {
case .assertion:
owsFailDebug("unexpected response from KBS")
completion(.invalid2FAPin)
case .invalidPin(let remainingAttempts):
completion(.invalidV2RegistrationLockPin(remainingAttempts: remainingAttempts))
case .backupMissing:
// We don't have a backup for this person, it probably
// was deleted due to too many failed attempts. They'll
// have to retry after the registration lock window expires.
completion(.exhaustedV2RegistrationLockAttempts)
}
}.retainUntilComplete()
return
}

View File

@ -2391,7 +2391,7 @@
"PIN_CREATION_PIN_CONFIRMATION_HINT" = "Re-enter PIN";
/* Indicates the work we are doing while creating the user's pin */
"PIN_CREATION_PIN_PROGRESS" = "Creating PIN...";
"PIN_CREATION_PIN_PROGRESS" = "Creating PIN";
/* The re-creation explanation in the 'pin creation' view. */
"PIN_CREATION_RECREATION_EXPLANATION" = "You can choose a new PIN because this device is registered. If you forget your PIN, you may need to wait 7 days to register again.";
@ -2711,6 +2711,9 @@
/* Alert title explaining what happens if you forget your 'two-factor auth pin'. */
"REGISTER_2FA_INVALID_PIN_ALERT_TITLE" = "Incorrect PIN";
/* Indicates the work we are doing while verifying the user's pin */
"REGISTER_2FA_PIN_PROGRESS" = "Verifying PIN…";
/* Label for 'submit' button in the 2FA registration view. */
"REGISTER_2FA_SUBMIT_BUTTON" = "Submit";
@ -2898,7 +2901,7 @@
"SECONDARY_ONBOARDING_GET_STARTED_BY_OPENING_PRIMARY" = "Launch Signal on your phone to link this iPad to your account";
/* Link explaining what to do when trying to link a device before having a primary device. */
"SECONDARY_ONBOARDING_GET_STARTED_DO_NOT_HAVE_PRIMARY" = "I don't have Signal on my phone...";
"SECONDARY_ONBOARDING_GET_STARTED_DO_NOT_HAVE_PRIMARY" = "I don't have Signal on my phone";
/* alert body */
"SECONDARY_ONBOARDING_INSTALL_PRIMARY_FIRST_BODY" = "Go to the App Store on your phone, install Signal, complete the registration process, and then you can link your iPad to the same account.";