From e3946e57793544aec7909b30a6a77973da23958d Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Fri, 15 Feb 2019 15:43:32 -0500 Subject: [PATCH] Sketch out the 'onboarding code verification' view. --- .../Registration/OnboardingController.swift | 18 +++++-- .../OnboardingPhoneNumberViewController.swift | 1 + ...OnboardingVerificationViewController.swift | 52 ++++++++++++++++--- .../translations/en.lproj/Localizable.strings | 5 +- .../src/Network/API/TSNetworkManager.m | 2 +- 5 files changed, 66 insertions(+), 12 deletions(-) diff --git a/Signal/src/ViewControllers/Registration/OnboardingController.swift b/Signal/src/ViewControllers/Registration/OnboardingController.swift index 000cce21f..a457b56fb 100644 --- a/Signal/src/ViewControllers/Registration/OnboardingController.swift +++ b/Signal/src/ViewControllers/Registration/OnboardingController.swift @@ -389,7 +389,8 @@ public class OnboardingController: NSObject { public func tryToVerify(fromViewController: UIViewController, verificationCode: String, - pin: String?) { + pin: String?, + isInvalidCodeCallback : @escaping () -> Void) { AssertIsOnMainThread() guard let phoneNumber = phoneNumber else { @@ -417,14 +418,19 @@ public class OnboardingController: NSObject { DispatchQueue.main.async { modal.dismiss(completion: { - self.verificationFailed(fromViewController: fromViewController, error: error as NSError) + self.verificationFailed(fromViewController: fromViewController, + error: error as NSError, + isInvalidCodeCallback: isInvalidCodeCallback) }) } }).retainUntilComplete() } } - private func verificationFailed(fromViewController: UIViewController, error: NSError) { + private func verificationFailed(fromViewController: UIViewController, error: NSError, + isInvalidCodeCallback : @escaping () -> Void) { + AssertIsOnMainThread() + if error.domain == OWSSignalServiceKitErrorDomain && error.code == OWSErrorCode.registrationMissing2FAPIN.rawValue { @@ -432,6 +438,12 @@ public class OnboardingController: NSObject { onboardingDidRequire2FAPin(viewController: fromViewController) } else { + if error.domain == OWSSignalServiceKitErrorDomain && + error.code == OWSErrorCode.userError.rawValue { + isInvalidCodeCallback() + } + + Logger.verbose("error: \(error.domain) \(error.code)") OWSAlerts.showAlert(title: NSLocalizedString("REGISTRATION_VERIFICATION_FAILED_TITLE", comment: "Alert view title"), message: error.localizedDescription, fromViewController: fromViewController) diff --git a/Signal/src/ViewControllers/Registration/OnboardingPhoneNumberViewController.swift b/Signal/src/ViewControllers/Registration/OnboardingPhoneNumberViewController.swift index 9ea1f70c6..388843b2b 100644 --- a/Signal/src/ViewControllers/Registration/OnboardingPhoneNumberViewController.swift +++ b/Signal/src/ViewControllers/Registration/OnboardingPhoneNumberViewController.swift @@ -98,6 +98,7 @@ public class OnboardingPhoneNumberViewController: OnboardingBaseViewController { 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.autoSetDimension(.height, toSize: validationWarningLabel.font.lineHeight) let validationWarningRow = UIView() validationWarningRow.addSubview(validationWarningLabel) diff --git a/Signal/src/ViewControllers/Registration/OnboardingVerificationViewController.swift b/Signal/src/ViewControllers/Registration/OnboardingVerificationViewController.swift index 751aa2d8b..a19f2227e 100644 --- a/Signal/src/ViewControllers/Registration/OnboardingVerificationViewController.swift +++ b/Signal/src/ViewControllers/Registration/OnboardingVerificationViewController.swift @@ -72,6 +72,7 @@ private class OnboardingCodeView: UIView { private let digitCount = 6 private var digitLabels = [UILabel]() + private var digitStrokes = [UIView]() // We use a single text field to edit the "current" digit. // The "current" digit is usually the "last" @@ -99,13 +100,14 @@ private class OnboardingCodeView: UIView { var digitViews = [UIView]() (0.. (UIView, UILabel) { + private func makeCellView(text: String, hasStroke: Bool) -> (UIView, UILabel, UIView) { let digitView = UIView() let digitLabel = UILabel() @@ -131,8 +133,8 @@ private class OnboardingCodeView: UIView { digitView.addSubview(digitLabel) digitLabel.autoCenterInSuperview() + let strokeView = UIView.container() if hasStroke { - let strokeView = UIView.container() strokeView.backgroundColor = Theme.primaryColor digitView.addSubview(strokeView) strokeView.autoPinWidthToSuperview() @@ -145,7 +147,7 @@ private class OnboardingCodeView: UIView { let cellWidth: CGFloat = cellHeight * 2 / 3 digitView.autoSetDimensions(to: CGSize(width: cellWidth, height: cellHeight)) - return (digitView, digitLabel) + return (digitView, digitLabel, strokeView) } private func digit(at index: Int) -> String { @@ -184,6 +186,13 @@ private class OnboardingCodeView: UIView { public override func becomeFirstResponder() -> Bool { return textfield.becomeFirstResponder() } + + func setHasError(_ hasError: Bool) { + let backgroundColor = (hasError ? UIColor.ows_destructiveRed : Theme.primaryColor) + for digitStroke in digitStrokes { + digitStroke.backgroundColor = backgroundColor + } + } } // MARK: - @@ -251,6 +260,7 @@ public class OnboardingVerificationViewController: OnboardingBaseViewController private let phoneNumberTextField = UITextField() private let onboardingCodeView = OnboardingCodeView() private var codeStateLink: OWSFlatButton? + private let errorLabel = UILabel() override public func loadView() { super.loadView() @@ -262,11 +272,23 @@ public class OnboardingVerificationViewController: OnboardingBaseViewController self.titleLabel = titleLabel let backLink = self.linkButton(title: NSLocalizedString("ONBOARDING_VERIFICATION_BACK_LINK", - comment: "Label for the link that lets users change their phone number."), + comment: "Label for the link that lets users change their phone number in the onboarding views."), selector: #selector(backLinkTapped)) onboardingCodeView.delegate = self + errorLabel.text = NSLocalizedString("ONBOARDING_VERIFICATION_INVALID_CODE", + comment: "Label indicating that the verification code is incorrect in the 'onboarding verification' view.") + errorLabel.textColor = .ows_destructiveRed + errorLabel.font = UIFont.ows_dynamicTypeBodyClamped.ows_mediumWeight() + errorLabel.textAlignment = .center + errorLabel.autoSetDimension(.height, toSize: errorLabel.font.lineHeight) + + // Wrap the error label in a row so that we can show/hide it without affecting view layout. + let errorRow = UIView() + errorRow.addSubview(errorLabel) + errorLabel.autoPinEdgesToSuperviewEdges() + let codeStateLink = self.linkButton(title: "", selector: #selector(resendCodeLinkTapped)) codeStateLink.enableMultilineLabel() @@ -281,6 +303,8 @@ public class OnboardingVerificationViewController: OnboardingBaseViewController backLink, topSpacer, onboardingCodeView, + UIView.spacer(withHeight: 12), + errorRow, bottomSpacer, codeStateLink ]) @@ -299,6 +323,8 @@ public class OnboardingVerificationViewController: OnboardingBaseViewController startCodeCountdown() updateCodeState() + + setHasInvalidCode(false) } // MARK: - Code State @@ -459,7 +485,17 @@ public class OnboardingVerificationViewController: OnboardingBaseViewController guard onboardingCodeView.isComplete else { return } - onboardingController.tryToVerify(fromViewController: self, verificationCode: onboardingCodeView.verificationCode, pin: nil) + + setHasInvalidCode(false) + + onboardingController.tryToVerify(fromViewController: self, verificationCode: onboardingCodeView.verificationCode, pin: nil, isInvalidCodeCallback: { + self.setHasInvalidCode(true) + }) + } + + private func setHasInvalidCode(_ value: Bool) { + onboardingCodeView.setHasError(value) + errorLabel.isHidden = !value } } @@ -469,6 +505,8 @@ extension OnboardingVerificationViewController: OnboardingCodeViewDelegate { public func codeViewDidChange() { AssertIsOnMainThread() + setHasInvalidCode(false) + tryToVerify() } } diff --git a/Signal/translations/en.lproj/Localizable.strings b/Signal/translations/en.lproj/Localizable.strings index a8bce1482..5bd79ce6d 100644 --- a/Signal/translations/en.lproj/Localizable.strings +++ b/Signal/translations/en.lproj/Localizable.strings @@ -1535,12 +1535,15 @@ /* Title of the 'onboarding splash' view. */ "ONBOARDING_SPLASH_TITLE" = "Signal is the private messenger for everybody"; -/* Label for the link that lets users change their phone number. */ +/* Label for the link that lets users change their phone number in the onboarding views. */ "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}}. */ "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. */ +"ONBOARDING_VERIFICATION_INVALID_CODE" = "This code is incorrect"; + /* Label for link that can be used when the original code did not arrive. */ "ONBOARDING_VERIFICATION_ORIGINAL_CODE_MISSING_LINK" = "I didn't get a code"; diff --git a/SignalServiceKit/src/Network/API/TSNetworkManager.m b/SignalServiceKit/src/Network/API/TSNetworkManager.m index 677b95473..bb0d4af62 100644 --- a/SignalServiceKit/src/Network/API/TSNetworkManager.m +++ b/SignalServiceKit/src/Network/API/TSNetworkManager.m @@ -517,7 +517,7 @@ dispatch_queue_t NetworkManagerQueue() if (self.tsAccountManager.isRegisteredAndReady) { [self.tsAccountManager setIsDeregistered:YES]; } else { - OWSFailDebug( + OWSLogWarn( @"Ignoring auth failure; not registered and ready: %@.", task.originalRequest.URL.absoluteString); } });