Sketch out the 'onboarding code verification' view.

This commit is contained in:
Matthew Chen 2019-02-15 10:21:19 -05:00
parent 0e62514541
commit d193eec371
6 changed files with 422 additions and 16 deletions

View File

@ -165,6 +165,7 @@
3496957321A301A100DCFE74 /* OWSBackupJob.m in Sources */ = {isa = PBXBuildFile; fileRef = 3496956A21A301A100DCFE74 /* OWSBackupJob.m */; };
3496957421A301A100DCFE74 /* OWSBackupAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3496956B21A301A100DCFE74 /* OWSBackupAPI.swift */; };
349EA07C2162AEA800F7B17F /* OWS111UDAttributesMigration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 349EA07B2162AEA700F7B17F /* OWS111UDAttributesMigration.swift */; };
34A4C61E221613D00042EF2E /* OnboardingVerificationViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34A4C61D221613D00042EF2E /* OnboardingVerificationViewController.swift */; };
34A55F3720485465002CC6DE /* OWS2FARegistrationViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 34A55F3520485464002CC6DE /* OWS2FARegistrationViewController.m */; };
34A6C28021E503E700B5B12E /* OWSImagePickerController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34A6C27F21E503E600B5B12E /* OWSImagePickerController.swift */; };
34A8B3512190A40E00218A25 /* MediaAlbumCellView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34A8B3502190A40E00218A25 /* MediaAlbumCellView.swift */; };
@ -846,6 +847,7 @@
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>"; };
349EA07B2162AEA700F7B17F /* OWS111UDAttributesMigration.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OWS111UDAttributesMigration.swift; sourceTree = "<group>"; };
34A4C61D221613D00042EF2E /* OnboardingVerificationViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OnboardingVerificationViewController.swift; sourceTree = "<group>"; };
34A55F3520485464002CC6DE /* OWS2FARegistrationViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWS2FARegistrationViewController.m; sourceTree = "<group>"; };
34A55F3620485464002CC6DE /* OWS2FARegistrationViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWS2FARegistrationViewController.h; sourceTree = "<group>"; };
34A6C27F21E503E600B5B12E /* OWSImagePickerController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OWSImagePickerController.swift; sourceTree = "<group>"; };
@ -1473,6 +1475,7 @@
3448E15B22133274004B052E /* OnboardingPermissionsViewController.swift */,
3448E16322135FFA004B052E /* OnboardingPhoneNumberViewController.swift */,
3448E15F22134C88004B052E /* OnboardingSplashViewController.swift */,
34A4C61D221613D00042EF2E /* OnboardingVerificationViewController.swift */,
346E9D5321B040B600562252 /* RegistrationController.swift */,
340FC878204DAC8C007AEB0F /* RegistrationViewController.h */,
340FC876204DAC8C007AEB0F /* RegistrationViewController.m */,
@ -3537,6 +3540,7 @@
34D1F0521F7E8EA30066283D /* GiphyDownloader.swift in Sources */,
340FC8BC204DAC8D007AEB0F /* FingerprintViewController.m in Sources */,
450DF2051E0D74AC003D14BE /* Platform.swift in Sources */,
34A4C61E221613D00042EF2E /* OnboardingVerificationViewController.swift in Sources */,
340FC8B2204DAC8D007AEB0F /* AdvancedSettingsTableViewController.m in Sources */,
452B999020A34B6B006F2F9E /* AddContactShareToExistingContactViewController.swift in Sources */,
346129991FD1E4DA00532771 /* SignalApp.m in Sources */,

View File

@ -482,6 +482,19 @@ NSString *const kArchivedConversationsReuseIdentifier = @"kArchivedConversations
[self.searchResultsController viewDidAppear:animated];
self.hasEverAppeared = YES;
dispatch_async(dispatch_get_main_queue(), ^{
OnboardingController *onboardingController = [OnboardingController new];
[onboardingController
updateWithPhoneNumber:[[OnboardingPhoneNumber alloc] initWithE164:@"+13213214321" userInput:@"3213214321"]];
// UIViewController *view = [onboardingController initialViewController];
UIViewController *view =
[[OnboardingVerificationViewController alloc] initWithOnboardingController:onboardingController];
OWSNavigationController *navigationController =
[[OWSNavigationController alloc] initWithRootViewController:view];
[self presentViewController:navigationController animated:YES completion:nil];
});
}
- (void)viewDidDisappear:(BOOL)animated

View File

@ -50,29 +50,26 @@ public class OnboardingBaseViewController: OWSViewController {
}
func button(title: String, selector: Selector) -> OWSFlatButton {
// TODO: Make sure this all fits if dynamic font sizes are maxed out.
let font = UIFont.ows_dynamicTypeBodyClamped.ows_mediumWeight()
// Button height should be 48pt if the font is 17pt.
let buttonHeight = font.pointSize * 48 / 17
let button = OWSFlatButton.button(title: title,
font: font,
titleColor: .white,
backgroundColor: .ows_materialBlue,
target: self,
selector: selector)
button.autoSetDimension(.height, toSize: buttonHeight)
return button
return button(title: title, selector: selector, titleColor: .white, backgroundColor: .ows_materialBlue)
}
func linkButton(title: String, selector: Selector) -> OWSFlatButton {
return button(title: title, selector: selector, titleColor: .ows_materialBlue, backgroundColor: .white)
}
func disabledLinkButton(title: String, selector: Selector) -> OWSFlatButton {
return self.button(title: title, selector: selector, titleColor: Theme.secondaryColor, backgroundColor: .white)
}
private func button(title: String, selector: Selector, titleColor: UIColor, backgroundColor: UIColor) -> OWSFlatButton {
// TODO: Make sure this all fits if dynamic font sizes are maxed out.
let font = UIFont.ows_dynamicTypeBodyClamped.ows_mediumWeight()
// Button height should be 48pt if the font is 17pt.
let buttonHeight = font.pointSize * 48 / 17
let button = OWSFlatButton.button(title: title,
font: font,
titleColor: .ows_materialBlue,
backgroundColor: .white,
titleColor: titleColor,
backgroundColor: backgroundColor,
target: self,
selector: selector)
button.autoSetDimension(.height, toSize: buttonHeight)

View File

@ -122,8 +122,8 @@ public class OnboardingController: NSObject {
Logger.info("")
// CodeVerificationViewController *vc = [CodeVerificationViewController new];
// [weakSelf.navigationController pushViewController:vc animated:YES];
let view = OnboardingVerificationViewController(onboardingController: self)
viewController.navigationController?.pushViewController(view, animated: true)
}
public func onboardingDidRequireCaptcha(viewController: UIViewController) {

View File

@ -0,0 +1,374 @@
//
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
//
import UIKit
import PromiseKit
private class OnboardingCodeView: UIView {
}
@objc
public class OnboardingVerificationViewController: OnboardingBaseViewController {
// // MARK: - Dependencies
//
// private var tsAccountManager: TSAccountManager {
// return TSAccountManager.sharedInstance()
// }
// MARK: -
private let phoneNumberTextField = UITextField()
// private var nextButton: OWSFlatButton?
private var resendCodeLabel: OWSFlatButton?
private var resendCodeLink: OWSFlatButton?
override public func loadView() {
super.loadView()
// populateDefaults()
view.backgroundColor = Theme.backgroundColor
view.layoutMargins = .zero
var e164PhoneNumber = ""
if let phoneNumber = onboardingController.phoneNumber {
e164PhoneNumber = phoneNumber.e164
}
let formattedPhoneNumber = PhoneNumber.bestEffortLocalizedPhoneNumber(withE164: e164PhoneNumber)
let titleText = String(format: NSLocalizedString("ONBOARDING_VERIFICATION_TITLE_FORMAT",
comment: "Format for the title of the 'onboarding verification' view. Embeds {{the user's phone number}}."),
formattedPhoneNumber)
let titleLabel = self.titleLabel(text: titleText)
let backLink = self.linkButton(title: NSLocalizedString("ONBOARDING_VERIFICATION_BACK_LINK",
comment: "Label for the link that lets users change their phone number."),
selector: #selector(backLinkTapped))
let onboardingCodeView = OnboardingCodeView()
onboardingCodeView.addRedBorder()
// resendCodeLabel.text = NSLocalizedString("ONBOARDING_VERIFICATION_BACK_LINK",
// comment: "Label for the link that lets users change their phone number."),
// resendCodeLabel.text = "TODO"
// resendCodeLabel.textColor = Theme.secondaryColor
// resendCodeLabel.font = UIFont.ows_dynamicTypeBodyClamped
// TODO: Copy.
let resendCodeLabel = disabledLinkButton(title: NSLocalizedString("ONBOARDING_VERIFICATION_RESEND_CODE_LINK",
comment: "Label for the link that lets users request another verification code."),
selector: #selector(ignoreEvent))
self.resendCodeLabel = resendCodeLabel
let resendCodeLink = self.linkButton(title: NSLocalizedString("ONBOARDING_VERIFICATION_RESEND_CODE_LINK",
comment: "Label for the link that lets users request another verification code."),
selector: #selector(resendCodeLinkTapped))
self.resendCodeLink = resendCodeLink
let resentCodeWrapper = UIView.container()
resentCodeWrapper.addSubview(resendCodeLabel)
resentCodeWrapper.addSubview(resendCodeLink)
resendCodeLabel.autoPinEdgesToSuperviewEdges()
resendCodeLink.autoPinEdgesToSuperviewEdges()
// TODO: Finalize copy.
// let nextButton = self.button(title: NSLocalizedString("BUTTON_NEXT",
// comment: "Label for the 'next' button."),
// selector: #selector(nextPressed))
// self.nextButton = nextButton
let topSpacer = UIView.vStretchingSpacer()
let bottomSpacer = UIView.vStretchingSpacer()
let stackView = UIStackView(arrangedSubviews: [
titleLabel,
UIView.spacer(withHeight: 21),
backLink,
topSpacer,
onboardingCodeView,
// countryRow,
// UIView.spacer(withHeight: 8),
// phoneNumberRow,
bottomSpacer,
resentCodeWrapper
])
stackView.axis = .vertical
stackView.alignment = .fill
stackView.layoutMargins = UIEdgeInsets(top: 32, left: 32, bottom: 32, 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)
}
// private func addBottomStroke(_ view: UIView) {
// let strokeView = UIView()
// strokeView.backgroundColor = Theme.middleGrayColor
// view.addSubview(strokeView)
// strokeView.autoSetDimension(.height, toSize: CGHairlineWidth())
// strokeView.autoPinWidthToSuperview()
// strokeView.autoPinEdge(toSuperviewEdge: .bottom)
// }
//
// public override func viewDidAppear(_ animated: Bool) {
// super.viewDidAppear(animated)
//
// phoneNumberTextField.becomeFirstResponder()
//
// if tsAccountManager.isReregistering() {
// // If re-registering, pre-populate the country (country code, calling code, country name)
// // and phone number state.
// guard let phoneNumberE164 = tsAccountManager.reregisterationPhoneNumber() else {
// owsFailDebug("Could not resume re-registration; missing phone number.")
// return
// }
// tryToReregister(phoneNumberE164: phoneNumberE164)
// }
// }
//
// private func tryToReregister(phoneNumberE164: String) {
// guard phoneNumberE164.count > 0 else {
// owsFailDebug("Could not resume re-registration; invalid phoneNumberE164.")
// return
// }
// guard let parsedPhoneNumber = PhoneNumber(fromE164: phoneNumberE164) else {
// owsFailDebug("Could not resume re-registration; couldn't parse phoneNumberE164.")
// return
// }
// guard let callingCodeNumeric = parsedPhoneNumber.getCountryCode() else {
// owsFailDebug("Could not resume re-registration; missing callingCode.")
// return
// }
// let callingCode = "\(COUNTRY_CODE_PREFIX)\(callingCodeNumeric)"
// let countryCodes: [String] =
// PhoneNumberUtil.sharedThreadLocal().countryCodes(fromCallingCode: callingCode)
// guard let countryCode = countryCodes.first else {
// owsFailDebug("Could not resume re-registration; unknown countryCode.")
// return
// }
// guard let countryName = PhoneNumberUtil.countryName(fromCountryCode: countryCode) else {
// owsFailDebug("Could not resume re-registration; unknown countryName.")
// return
// }
// if !phoneNumberE164.hasPrefix(callingCode) {
// owsFailDebug("Could not resume re-registration; non-matching calling code.")
// return
// }
// let phoneNumberWithoutCallingCode = phoneNumberE164.substring(from: callingCode.count)
//
// guard countryCode.count > 0 else {
// owsFailDebug("Invalid country code.")
// return
// }
// guard countryName.count > 0 else {
// owsFailDebug("Invalid country name.")
// return
// }
// guard callingCode.count > 0 else {
// owsFailDebug("Invalid calling code.")
// return
// }
//
// let countryState = OnboardingCountryState(countryName: countryName, callingCode: callingCode, countryCode: countryCode)
// onboardingController.update(countryState: countryState)
//
// updateState()
//
// phoneNumberTextField.text = phoneNumberWithoutCallingCode
// // Don't let user edit their phone number while re-registering.
// phoneNumberTextField.isEnabled = false
// }
//
// // MARK: -
//
// private var countryName: String {
// get {
// return onboardingController.countryState.countryName
// }
// }
// private var callingCode: String {
// get {
// AssertIsOnMainThread()
//
// return onboardingController.countryState.callingCode
// }
// }
// private var countryCode: String {
// get {
// AssertIsOnMainThread()
//
// return onboardingController.countryState.countryCode
// }
// }
//
// private func populateDefaults() {
// if let lastRegisteredPhoneNumber = OnboardingController.lastRegisteredPhoneNumber(),
// lastRegisteredPhoneNumber.count > 0,
// lastRegisteredPhoneNumber.hasPrefix(callingCode) {
// phoneNumberTextField.text = lastRegisteredPhoneNumber.substring(from: callingCode.count)
// } else if let phoneNumber = onboardingController.phoneNumber {
// phoneNumberTextField.text = phoneNumber.userInput
// }
//
// updateState()
// }
//
// private func updateState() {
// AssertIsOnMainThread()
//
// countryNameLabel.text = countryName
// callingCodeLabel.text = callingCode
//
// self.phoneNumberTextField.placeholder = ViewControllerUtils.examplePhoneNumber(forCountryCode: countryCode, callingCode: callingCode)
// }
//
// // MARK: - Events
//
// @objc func countryRowTapped(sender: UIGestureRecognizer) {
// guard sender.state == .recognized else {
// return
// }
// showCountryPicker()
// }
//
// @objc func countryCodeTapped(sender: UIGestureRecognizer) {
// guard sender.state == .recognized else {
// return
// }
// showCountryPicker()
// }
//
// @objc func nextPressed() {
// Logger.info("")
//
// parseAndTryToRegister()
// }
//
// // MARK: - Country Picker
//
// private func showCountryPicker() {
// guard !tsAccountManager.isReregistering() else {
// return
// }
//
// let countryCodeController = CountryCodeViewController()
// countryCodeController.countryCodeDelegate = self
// countryCodeController.interfaceOrientationMask = .portrait
// let navigationController = OWSNavigationController(rootViewController: countryCodeController)
// self.present(navigationController, animated: true, completion: nil)
// }
//
// // MARK: - Register
//
// private func parseAndTryToRegister() {
// guard let phoneNumberText = phoneNumberTextField.text?.ows_stripped(),
// phoneNumberText.count > 0 else {
// OWSAlerts.showAlert(title:
// NSLocalizedString("REGISTRATION_VIEW_NO_VERIFICATION_ALERT_TITLE",
// comment: "Title of alert indicating that users needs to enter a phone number to register."),
// message:
// NSLocalizedString("REGISTRATION_VIEW_NO_VERIFICATION_ALERT_MESSAGE",
// comment: "Message of alert indicating that users needs to enter a phone number to register."))
// return
// }
//
// let phoneNumber = "\(callingCode)\(phoneNumberText)"
// guard let localNumber = PhoneNumber.tryParsePhoneNumber(fromUserSpecifiedText: phoneNumber),
// localNumber.toE164().count > 0,
// PhoneNumberValidator().isValidForRegistration(phoneNumber: localNumber) else {
// OWSAlerts.showAlert(title:
// NSLocalizedString("REGISTRATION_VIEW_INVALID_VERIFICATION_ALERT_TITLE",
// comment: "Title of alert indicating that users needs to enter a valid phone number to register."),
// message:
// NSLocalizedString("REGISTRATION_VIEW_INVALID_VERIFICATION_ALERT_MESSAGE",
// comment: "Message of alert indicating that users needs to enter a valid phone number to register."))
// return
// }
// let e164PhoneNumber = localNumber.toE164()
//
// onboardingController.update(phoneNumber: OnboardingPhoneNumber(e164: e164PhoneNumber, userInput: phoneNumberText))
//
// if UIDevice.current.isIPad {
// OWSAlerts.showConfirmationAlert(title: NSLocalizedString("REGISTRATION_IPAD_CONFIRM_TITLE",
// comment: "alert title when registering an iPad"),
// message: NSLocalizedString("REGISTRATION_IPAD_CONFIRM_BODY",
// comment: "alert body when registering an iPad"),
// proceedTitle: NSLocalizedString("REGISTRATION_IPAD_CONFIRM_BUTTON",
// comment: "button text to proceed with registration when on an iPad"),
// proceedAction: { (_) in
// self.onboardingController.tryToRegister(fromViewController: self, smsVerification: false)
// })
// } else {
// onboardingController.tryToRegister(fromViewController: self, smsVerification: false)
// }
// }
// MARK: - Events
@objc func backLinkTapped() {
Logger.info("")
self.navigationController?.popViewController(animated: true)
}
@objc func ignoreEvent() {
Logger.info("")
}
@objc func resendCodeLinkTapped() {
Logger.info("")
// TODO:
// self.navigationController?.popViewController(animated: true)
}
}
//// MARK: -
//
//extension OnboardingVerificationViewController: UITextFieldDelegate {
// public func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
// // TODO: Fix auto-format of phone numbers.
// ViewControllerUtils.phoneNumber(textField, shouldChangeCharactersIn: range, replacementString: string, countryCode: countryCode)
//
// // Inform our caller that we took care of performing the change.
// return false
// }
//
// public func textFieldShouldReturn(_ textField: UITextField) -> Bool {
// parseAndTryToRegister()
// return false
// }
//}
//
//// MARK: -
//
//extension OnboardingVerificationViewController: CountryCodeViewControllerDelegate {
// public func countryCodeViewController(_ vc: CountryCodeViewController, didSelectCountryCode countryCode: String, countryName: String, callingCode: String) {
// guard countryCode.count > 0 else {
// owsFailDebug("Invalid country code.")
// return
// }
// guard countryName.count > 0 else {
// owsFailDebug("Invalid country name.")
// return
// }
// guard callingCode.count > 0 else {
// owsFailDebug("Invalid calling code.")
// return
// }
//
// let countryState = OnboardingCountryState(countryName: countryName, callingCode: callingCode, countryCode: countryCode)
//
// onboardingController.update(countryState: countryState)
//
// updateState()
//
// // Trigger the formatting logic with a no-op edit.
// _ = textField(phoneNumberTextField, shouldChangeCharactersIn: NSRange(location: 0, length: 0), replacementString: "")
// }
//}

View File

@ -1535,6 +1535,12 @@
/* 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. */
"ONBOARDING_VERIFICATION_BACK_LINK" = "Wrong number?";
/* Format for the title of the 'onboarding verification' view. Embeds {{the user's phone number}}. */
"ONBOARDING_VERIFICATION_TITLE_FORMAT" = "Enter the code we sent to %@";
/* Button text which opens the settings app */
"OPEN_SETTINGS_BUTTON" = "Settings";
@ -1835,12 +1841,24 @@
/* Title of alert indicating that users needs to enter a valid phone number to register. */
"REGISTRATION_VIEW_INVALID_PHONE_NUMBER_ALERT_TITLE" = "Invalid Phone Number";
/* Message of alert indicating that users needs to enter a valid phone number to register. */
"REGISTRATION_VIEW_INVALID_VERIFICATION_ALERT_MESSAGE" = "REGISTRATION_VIEW_INVALID_VERIFICATION_ALERT_MESSAGE";
/* Title of alert indicating that users needs to enter a valid phone number to register. */
"REGISTRATION_VIEW_INVALID_VERIFICATION_ALERT_TITLE" = "REGISTRATION_VIEW_INVALID_VERIFICATION_ALERT_TITLE";
/* Message of alert indicating that users needs to enter a phone number to register. */
"REGISTRATION_VIEW_NO_PHONE_NUMBER_ALERT_MESSAGE" = "Please enter a phone number to register.";
/* Title of alert indicating that users needs to enter a phone number to register. */
"REGISTRATION_VIEW_NO_PHONE_NUMBER_ALERT_TITLE" = "No Phone Number";
/* Message of alert indicating that users needs to enter a phone number to register. */
"REGISTRATION_VIEW_NO_VERIFICATION_ALERT_MESSAGE" = "REGISTRATION_VIEW_NO_VERIFICATION_ALERT_MESSAGE";
/* Title of alert indicating that users needs to enter a phone number to register. */
"REGISTRATION_VIEW_NO_VERIFICATION_ALERT_TITLE" = "REGISTRATION_VIEW_NO_VERIFICATION_ALERT_TITLE";
/* notification action */
"REJECT_CALL_BUTTON_TITLE" = "Reject";