diff --git a/Signal/Images.xcassets/onboarding_splash_hero.imageset/Contents.json b/Signal/Images.xcassets/onboarding_splash_hero.imageset/Contents.json index 2eb68d3be..e4663220c 100644 --- a/Signal/Images.xcassets/onboarding_splash_hero.imageset/Contents.json +++ b/Signal/Images.xcassets/onboarding_splash_hero.imageset/Contents.json @@ -2,7 +2,7 @@ "images" : [ { "idiom" : "universal", - "filename" : "Screen Shot 2019-02-12 at 2.22.35 PM.png", + "filename" : "onboarding_splash.png", "scale" : "1x" }, { diff --git a/Signal/Images.xcassets/onboarding_splash_hero.imageset/Screen Shot 2019-02-12 at 2.22.35 PM.png b/Signal/Images.xcassets/onboarding_splash_hero.imageset/Screen Shot 2019-02-12 at 2.22.35 PM.png deleted file mode 100644 index 6ef277fb8..000000000 Binary files a/Signal/Images.xcassets/onboarding_splash_hero.imageset/Screen Shot 2019-02-12 at 2.22.35 PM.png and /dev/null differ diff --git a/Signal/Images.xcassets/onboarding_splash_hero.imageset/onboarding_splash.png b/Signal/Images.xcassets/onboarding_splash_hero.imageset/onboarding_splash.png new file mode 100644 index 000000000..b99099af2 Binary files /dev/null and b/Signal/Images.xcassets/onboarding_splash_hero.imageset/onboarding_splash.png differ diff --git a/Signal/src/ViewControllers/Registration/OnboardingBaseViewController.swift b/Signal/src/ViewControllers/Registration/OnboardingBaseViewController.swift index d242b81e2..bd76bdb98 100644 --- a/Signal/src/ViewControllers/Registration/OnboardingBaseViewController.swift +++ b/Signal/src/ViewControllers/Registration/OnboardingBaseViewController.swift @@ -31,37 +31,31 @@ public class OnboardingBaseViewController: OWSViewController { let titleLabel = UILabel() titleLabel.text = text titleLabel.textColor = Theme.primaryColor - titleLabel.font = UIFont.ows_dynamicTypeTitle2.ows_mediumWeight() + titleLabel.font = UIFont.ows_dynamicTypeTitle1Clamped.ows_mediumWeight() titleLabel.numberOfLines = 0 titleLabel.lineBreakMode = .byWordWrapping titleLabel.textAlignment = .center return titleLabel } - func explanationLabel(explanationText: String, linkText: String, selector: Selector) -> UILabel { - let explanationText = NSAttributedString(string: explanationText) - .rtlSafeAppend(NSAttributedString(string: " ")) - .rtlSafeAppend(linkText, - attributes: [ - NSAttributedStringKey.foregroundColor: UIColor.ows_materialBlue - ]) + func explanationLabel(explanationText: String) -> UILabel { let explanationLabel = UILabel() explanationLabel.textColor = Theme.secondaryColor - explanationLabel.font = UIFont.ows_dynamicTypeCaption1 - explanationLabel.attributedText = explanationText + explanationLabel.font = UIFont.ows_dynamicTypeSubheadlineClamped + explanationLabel.text = explanationText explanationLabel.numberOfLines = 0 explanationLabel.textAlignment = .center explanationLabel.lineBreakMode = .byWordWrapping - explanationLabel.isUserInteractionEnabled = true - explanationLabel.addGestureRecognizer(UITapGestureRecognizer(target: self, action: selector)) return explanationLabel } func button(title: String, selector: Selector) -> OWSFlatButton { // TODO: Make sure this all fits if dynamic font sizes are maxed out. - let buttonHeight: CGFloat = 48 + 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: OWSFlatButton.fontForHeight(buttonHeight), + font: font, titleColor: .white, backgroundColor: .ows_materialBlue, target: self, @@ -70,11 +64,28 @@ public class OnboardingBaseViewController: OWSViewController { return button } + func linkButton(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: .ows_materialBlue, + backgroundColor: .white, + target: self, + selector: selector) + button.autoSetDimension(.height, toSize: buttonHeight) + return button + } + // MARK: - View Lifecycle public override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) + self.navigationController?.isNavigationBarHidden = true + // TODO: Is there a better way to do this? if let navigationController = self.navigationController as? OWSNavigationController { SignalApp.shared().signUpFlowNavigationController = navigationController @@ -83,6 +94,12 @@ public class OnboardingBaseViewController: OWSViewController { } } + public override func viewDidAppear(_ animated: Bool) { + super.viewDidAppear(animated) + + self.navigationController?.isNavigationBarHidden = true + } + // MARK: - Orientation public override var supportedInterfaceOrientations: UIInterfaceOrientationMask { diff --git a/Signal/src/ViewControllers/Registration/OnboardingCaptchaViewController.swift b/Signal/src/ViewControllers/Registration/OnboardingCaptchaViewController.swift index d9e152a8b..9f1f60103 100644 --- a/Signal/src/ViewControllers/Registration/OnboardingCaptchaViewController.swift +++ b/Signal/src/ViewControllers/Registration/OnboardingCaptchaViewController.swift @@ -73,8 +73,6 @@ public class OnboardingCaptchaViewController: OnboardingBaseViewController { public override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) - self.navigationController?.isNavigationBarHidden = false - loadContent() } @@ -93,12 +91,6 @@ public class OnboardingCaptchaViewController: OnboardingBaseViewController { webView.scrollView.contentOffset = .zero } - public override func viewDidAppear(_ animated: Bool) { - super.viewDidAppear(animated) - - self.navigationController?.isNavigationBarHidden = false - } - // MARK: - Notifications @objc func didBecomeActive() { diff --git a/Signal/src/ViewControllers/Registration/OnboardingPermissionsViewController.swift b/Signal/src/ViewControllers/Registration/OnboardingPermissionsViewController.swift index c19dd160d..9d39883eb 100644 --- a/Signal/src/ViewControllers/Registration/OnboardingPermissionsViewController.swift +++ b/Signal/src/ViewControllers/Registration/OnboardingPermissionsViewController.swift @@ -12,10 +12,7 @@ public class OnboardingPermissionsViewController: OnboardingBaseViewController { super.loadView() view.backgroundColor = Theme.backgroundColor - view.layoutMargins = UIEdgeInsets(top: 32, left: 32, bottom: 32, right: 32) - - // TODO: -// navigationItem.title = NSLocalizedString("SETTINGS_BACKUP", comment: "Label for the backup view in app settings.") + view.layoutMargins = .zero navigationItem.rightBarButtonItem = UIBarButtonItem(title: NSLocalizedString("NAVIGATION_ITEM_SKIP_BUTTON", comment: "A button to skip a view."), style: .plain, @@ -23,58 +20,42 @@ public class OnboardingPermissionsViewController: OnboardingBaseViewController { action: #selector(skipWasPressed)) let titleLabel = self.titleLabel(text: NSLocalizedString("ONBOARDING_PERMISSIONS_TITLE", comment: "Title of the 'onboarding permissions' view.")) - view.addSubview(titleLabel) - titleLabel.autoPinEdges(toSuperviewMarginsExcludingEdge: .bottom) - // TODO: Finalize copy. let explanationLabel = self.explanationLabel(explanationText: NSLocalizedString("ONBOARDING_PERMISSIONS_EXPLANATION", - comment: "Explanation in the 'onboarding permissions' view."), - linkText: NSLocalizedString("ONBOARDING_PERMISSIONS_LEARN_MORE_LINK", - comment: "Link to the 'learn more' in the 'onboarding permissions' view."), - selector: #selector(explanationLabelTapped)) + comment: "Explanation in the 'onboarding permissions' view.")) // TODO: Make sure this all fits if dynamic font sizes are maxed out. - let giveAccessButton = self.button(title: NSLocalizedString("ONBOARDING_PERMISSIONS_GIVE_ACCESS_BUTTON", + let giveAccessButton = self.button(title: NSLocalizedString("ONBOARDING_PERMISSIONS_ENABLE_PERMISSIONS_BUTTON", comment: "Label for the 'give access' button in the 'onboarding permissions' view."), selector: #selector(giveAccessPressed)) - let notNowButton = self.button(title: NSLocalizedString("ONBOARDING_PERMISSIONS_NOT_NOW_BUTTON", - comment: "Label for the 'not now' button in the 'onboarding permissions' view."), + let notNowButton = self.linkButton(title: NSLocalizedString("ONBOARDING_PERMISSIONS_NOT_NOW_BUTTON", + comment: "Label for the 'not now' button in the 'onboarding permissions' view."), selector: #selector(notNowPressed)) - let buttonStack = UIStackView(arrangedSubviews: [ - giveAccessButton, - notNowButton - ]) - buttonStack.axis = .vertical - buttonStack.alignment = .fill - buttonStack.spacing = 12 - + let topSpacer = UIView.vStretchingSpacer() + let bottomSpacer = UIView.vStretchingSpacer() let stackView = UIStackView(arrangedSubviews: [ + titleLabel, + UIView.spacer(withHeight: 20), explanationLabel, - buttonStack + topSpacer, + giveAccessButton, + UIView.spacer(withHeight: 12), + notNowButton, + bottomSpacer ]) stackView.axis = .vertical stackView.alignment = .fill - stackView.spacing = 40 + stackView.layoutMargins = UIEdgeInsets(top: 32, left: 32, bottom: 32, right: 32) + stackView.isLayoutMarginsRelativeArrangement = true view.addSubview(stackView) - stackView.autoPinWidthToSuperviewMargins() - stackView.autoPinEdge(.top, to: .bottom, of: titleLabel, withOffset: 20, relation: .greaterThanOrEqual) - NSLayoutConstraint.autoSetPriority(.defaultHigh) { - stackView.autoVCenterInSuperview() - } - } + stackView.autoPinWidthToSuperview() + stackView.autoPin(toTopLayoutGuideOf: self, withInset: 0) + stackView.autoPin(toBottomLayoutGuideOf: self, withInset: 0) - public override func viewWillAppear(_ animated: Bool) { - super.viewWillAppear(animated) - - self.navigationController?.isNavigationBarHidden = false - } - - public override func viewDidAppear(_ animated: Bool) { - super.viewDidAppear(animated) - - self.navigationController?.isNavigationBarHidden = false + // Ensure whitespace is balanced, so inputs are vertically centered. + topSpacer.autoMatch(.height, to: .height, of: bottomSpacer) } // MARK: Request Access @@ -117,13 +98,6 @@ public class OnboardingPermissionsViewController: OnboardingBaseViewController { onboardingController.onboardingPermissionsWasSkipped(viewController: self) } - @objc func explanationLabelTapped(sender: UIGestureRecognizer) { - guard sender.state == .recognized else { - return - } - // TODO: - } - @objc func giveAccessPressed() { Logger.info("") diff --git a/Signal/src/ViewControllers/Registration/OnboardingPhoneNumberViewController.swift b/Signal/src/ViewControllers/Registration/OnboardingPhoneNumberViewController.swift index 8846ae7f2..b3820df34 100644 --- a/Signal/src/ViewControllers/Registration/OnboardingPhoneNumberViewController.swift +++ b/Signal/src/ViewControllers/Registration/OnboardingPhoneNumberViewController.swift @@ -20,6 +20,10 @@ public class OnboardingPhoneNumberViewController: OnboardingBaseViewController { private let callingCodeLabel = UILabel() private let phoneNumberTextField = UITextField() private var nextButton: OWSFlatButton? + private var phoneStrokeNormal: UIView? + private var phoneStrokeError: UIView? + private let validationWarningLabel = UILabel() + private var isPhoneNumberInvalid = false override public func loadView() { super.loadView() @@ -29,9 +33,6 @@ public class OnboardingPhoneNumberViewController: OnboardingBaseViewController { view.backgroundColor = Theme.backgroundColor view.layoutMargins = .zero - // TODO: -// navigationItem.title = NSLocalizedString("SETTINGS_BACKUP", comment: "Label for the backup view in app settings.") - let titleLabel = self.titleLabel(text: NSLocalizedString("ONBOARDING_PHONE_NUMBER_TITLE", comment: "Title of the 'onboarding phone number' view.")) // Country @@ -39,7 +40,7 @@ public class OnboardingPhoneNumberViewController: OnboardingBaseViewController { let rowHeight: CGFloat = 40 countryNameLabel.textColor = Theme.primaryColor - countryNameLabel.font = UIFont.ows_dynamicTypeBody + countryNameLabel.font = UIFont.ows_dynamicTypeBodyClamped countryNameLabel.setContentHuggingHorizontalLow() countryNameLabel.setCompressionResistanceHorizontalLow() @@ -61,26 +62,27 @@ public class OnboardingPhoneNumberViewController: OnboardingBaseViewController { countryRow.isUserInteractionEnabled = true countryRow.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(countryRowTapped))) countryRow.autoSetDimension(.height, toSize: rowHeight) - addBottomStroke(countryRow) + _ = addBottomStroke(countryRow) callingCodeLabel.textColor = Theme.primaryColor - callingCodeLabel.font = UIFont.ows_dynamicTypeBody + callingCodeLabel.font = UIFont.ows_dynamicTypeBodyClamped callingCodeLabel.setContentHuggingHorizontalHigh() callingCodeLabel.setCompressionResistanceHorizontalHigh() callingCodeLabel.isUserInteractionEnabled = true callingCodeLabel.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(countryCodeTapped))) - addBottomStroke(callingCodeLabel) + _ = addBottomStroke(callingCodeLabel) callingCodeLabel.autoSetDimension(.width, toSize: rowHeight, relation: .greaterThanOrEqual) phoneNumberTextField.textAlignment = .left phoneNumberTextField.delegate = self phoneNumberTextField.keyboardType = .numberPad phoneNumberTextField.textColor = Theme.primaryColor - phoneNumberTextField.font = UIFont.ows_dynamicTypeBody + phoneNumberTextField.font = UIFont.ows_dynamicTypeBodyClamped phoneNumberTextField.setContentHuggingHorizontalLow() phoneNumberTextField.setCompressionResistanceHorizontalLow() - addBottomStroke(phoneNumberTextField) + phoneStrokeNormal = addBottomStroke(phoneNumberTextField) + phoneStrokeError = addBottomStroke(phoneNumberTextField, color: .ows_destructiveRed, strokeWidth: 2) let phoneNumberRow = UIStackView(arrangedSubviews: [ callingCodeLabel, @@ -92,6 +94,16 @@ public class OnboardingPhoneNumberViewController: OnboardingBaseViewController { phoneNumberRow.autoSetDimension(.height, toSize: rowHeight) callingCodeLabel.autoMatch(.height, to: .height, of: phoneNumberTextField) + 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 + + let validationWarningRow = UIView() + validationWarningRow.addSubview(validationWarningLabel) + validationWarningLabel.autoPinHeightToSuperview() + validationWarningLabel.autoPinEdge(toSuperviewEdge: .trailing) + // TODO: Finalize copy. let nextButton = self.button(title: NSLocalizedString("BUTTON_NEXT", @@ -107,6 +119,8 @@ public class OnboardingPhoneNumberViewController: OnboardingBaseViewController { countryRow, UIView.spacer(withHeight: 8), phoneNumberRow, + UIView.spacer(withHeight: 8), + validationWarningRow, bottomSpacer, nextButton ]) @@ -115,34 +129,43 @@ public class OnboardingPhoneNumberViewController: OnboardingBaseViewController { stackView.layoutMargins = UIEdgeInsets(top: 32, left: 32, bottom: 32, right: 32) stackView.isLayoutMarginsRelativeArrangement = true view.addSubview(stackView) - stackView.autoPinWidthToSuperviewMargins() + 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) + + validationWarningLabel.autoPinEdge(.leading, to: .leading, of: phoneNumberTextField) + } + + private func addBottomStroke(_ view: UIView) -> UIView { + return addBottomStroke(view, color: Theme.middleGrayColor, strokeWidth: CGHairlineWidth()) } - private func addBottomStroke(_ view: UIView) { + private func addBottomStroke(_ view: UIView, color: UIColor, strokeWidth: CGFloat) -> UIView { let strokeView = UIView() - strokeView.backgroundColor = Theme.middleGrayColor + strokeView.backgroundColor = color view.addSubview(strokeView) - strokeView.autoSetDimension(.height, toSize: CGHairlineWidth()) + strokeView.autoSetDimension(.height, toSize: strokeWidth) strokeView.autoPinWidthToSuperview() strokeView.autoPinEdge(toSuperviewEdge: .bottom) + return strokeView } + // MARK: - View Lifecycle + public override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) - self.navigationController?.isNavigationBarHidden = false + isPhoneNumberInvalid = false + + updateViewState() } public override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) - self.navigationController?.isNavigationBarHidden = false - phoneNumberTextField.becomeFirstResponder() if tsAccountManager.isReregistering() { @@ -202,11 +225,12 @@ public class OnboardingPhoneNumberViewController: OnboardingBaseViewController { 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 + + updateViewState() } // MARK: - @@ -236,18 +260,30 @@ public class OnboardingPhoneNumberViewController: OnboardingBaseViewController { lastRegisteredPhoneNumber.count > 0, lastRegisteredPhoneNumber.hasPrefix(callingCode) { phoneNumberTextField.text = lastRegisteredPhoneNumber.substring(from: callingCode.count) + } else if let phoneNumber = onboardingController.phoneNumber { + phoneNumberTextField.text = phoneNumber.userInput } - updateState() + updateViewState() } - private func updateState() { + private func updateViewState() { AssertIsOnMainThread() countryNameLabel.text = countryName callingCodeLabel.text = callingCode self.phoneNumberTextField.placeholder = ViewControllerUtils.examplePhoneNumber(forCountryCode: countryCode, callingCode: callingCode) + + updateValidationWarnings() + } + + private func updateValidationWarnings() { + AssertIsOnMainThread() + + phoneStrokeNormal?.isHidden = isPhoneNumberInvalid + phoneStrokeError?.isHidden = !isPhoneNumberInvalid + validationWarningLabel.isHidden = !isPhoneNumberInvalid } // MARK: - Events @@ -291,6 +327,10 @@ public class OnboardingPhoneNumberViewController: OnboardingBaseViewController { private func parseAndTryToRegister() { guard let phoneNumberText = phoneNumberTextField.text?.ows_stripped(), phoneNumberText.count > 0 else { + + isPhoneNumberInvalid = false + updateValidationWarnings() + OWSAlerts.showAlert(title: NSLocalizedString("REGISTRATION_VIEW_NO_PHONE_NUMBER_ALERT_TITLE", comment: "Title of alert indicating that users needs to enter a phone number to register."), @@ -304,6 +344,10 @@ public class OnboardingPhoneNumberViewController: OnboardingBaseViewController { guard let localNumber = PhoneNumber.tryParsePhoneNumber(fromUserSpecifiedText: phoneNumber), localNumber.toE164().count > 0, PhoneNumberValidator().isValidForRegistration(phoneNumber: localNumber) else { + + isPhoneNumberInvalid = false + updateValidationWarnings() + OWSAlerts.showAlert(title: NSLocalizedString("REGISTRATION_VIEW_INVALID_PHONE_NUMBER_ALERT_TITLE", comment: "Title of alert indicating that users needs to enter a valid phone number to register."), @@ -339,6 +383,9 @@ extension OnboardingPhoneNumberViewController: UITextFieldDelegate { // TODO: Fix auto-format of phone numbers. ViewControllerUtils.phoneNumber(textField, shouldChangeCharactersIn: range, replacementString: string, countryCode: countryCode) + isPhoneNumberInvalid = false + updateValidationWarnings() + // Inform our caller that we took care of performing the change. return false } @@ -370,7 +417,7 @@ extension OnboardingPhoneNumberViewController: CountryCodeViewControllerDelegate onboardingController.update(countryState: countryState) - updateState() + updateViewState() // Trigger the formatting logic with a no-op edit. _ = textField(phoneNumberTextField, shouldChangeCharactersIn: NSRange(location: 0, length: 0), replacementString: "") diff --git a/Signal/src/ViewControllers/Registration/OnboardingSplashViewController.swift b/Signal/src/ViewControllers/Registration/OnboardingSplashViewController.swift index 14353ad1f..195e6dfa2 100644 --- a/Signal/src/ViewControllers/Registration/OnboardingSplashViewController.swift +++ b/Signal/src/ViewControllers/Registration/OnboardingSplashViewController.swift @@ -14,9 +14,6 @@ public class OnboardingSplashViewController: OnboardingBaseViewController { view.backgroundColor = Theme.backgroundColor view.layoutMargins = .zero - // TODO: - // navigationItem.title = NSLocalizedString("SETTINGS_BACKUP", comment: "Label for the backup view in app settings.") - let heroImage = UIImage(named: "onboarding_splash_hero") let heroImageView = UIImageView(image: heroImage) heroImageView.contentMode = .scaleAspectFit @@ -29,12 +26,16 @@ public class OnboardingSplashViewController: OnboardingBaseViewController { view.addSubview(titleLabel) titleLabel.autoPinEdges(toSuperviewMarginsExcludingEdge: .bottom) - // TODO: Finalize copy. - let explanationLabel = self.explanationLabel(explanationText: NSLocalizedString("ONBOARDING_SPLASH_EXPLANATION", - comment: "Explanation in the 'onboarding splash' view."), - linkText: NSLocalizedString("ONBOARDING_SPLASH_TERM_AND_PRIVACY_POLICY", - comment: "Link to the 'terms and privacy policy' in the 'onboarding splash' view."), - selector: #selector(explanationLabelTapped)) + let explanationLabel = UILabel() + explanationLabel.text = NSLocalizedString("ONBOARDING_SPLASH_TERM_AND_PRIVACY_POLICY", + comment: "Link to the 'terms and privacy policy' in the 'onboarding splash' view.") + explanationLabel.textColor = .ows_materialBlue + explanationLabel.font = UIFont.ows_dynamicTypeSubheadlineClamped + explanationLabel.numberOfLines = 0 + explanationLabel.textAlignment = .center + explanationLabel.lineBreakMode = .byWordWrapping + explanationLabel.isUserInteractionEnabled = true + explanationLabel.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(explanationLabelTapped))) // TODO: Make sure this all fits if dynamic font sizes are maxed out. let continueButton = self.button(title: NSLocalizedString("BUTTON_CONTINUE", @@ -46,9 +47,9 @@ public class OnboardingSplashViewController: OnboardingBaseViewController { heroImageView, UIView.spacer(withHeight: 22), titleLabel, - UIView.spacer(withHeight: 56), + UIView.spacer(withHeight: 92), explanationLabel, - UIView.spacer(withHeight: 40), + UIView.spacer(withHeight: 24), continueButton ]) stackView.axis = .vertical @@ -56,23 +57,11 @@ public class OnboardingSplashViewController: OnboardingBaseViewController { stackView.layoutMargins = UIEdgeInsets(top: 32, left: 32, bottom: 32, right: 32) stackView.isLayoutMarginsRelativeArrangement = true view.addSubview(stackView) - stackView.autoPinWidthToSuperviewMargins() + stackView.autoPinWidthToSuperview() stackView.autoPin(toTopLayoutGuideOf: self, withInset: 0) stackView.autoPin(toBottomLayoutGuideOf: self, withInset: 0) } - public override func viewWillAppear(_ animated: Bool) { - super.viewWillAppear(animated) - - self.navigationController?.isNavigationBarHidden = true - } - - public override func viewDidAppear(_ animated: Bool) { - super.viewDidAppear(animated) - - self.navigationController?.isNavigationBarHidden = true - } - // MARK: - Events @objc func explanationLabelTapped(sender: UIGestureRecognizer) { diff --git a/Signal/translations/en.lproj/Localizable.strings b/Signal/translations/en.lproj/Localizable.strings index 6de276e74..9c80faccb 100644 --- a/Signal/translations/en.lproj/Localizable.strings +++ b/Signal/translations/en.lproj/Localizable.strings @@ -1511,29 +1511,26 @@ /* Title of the 'onboarding Captcha' view. */ "ONBOARDING_CAPTCHA_TITLE" = "We need to verify that you're human"; -/* Explanation in the 'onboarding permissions' view. */ -"ONBOARDING_PERMISSIONS_EXPLANATION" = "ONBOARDING_PERMISSIONS_EXPLANATION"; - /* Label for the 'give access' button in the 'onboarding permissions' view. */ -"ONBOARDING_PERMISSIONS_GIVE_ACCESS_BUTTON" = "Give Access"; +"ONBOARDING_PERMISSIONS_ENABLE_PERMISSIONS_BUTTON" = "Enable Permissions"; -/* Link to the 'learn more' in the 'onboarding permissions' view. */ -"ONBOARDING_PERMISSIONS_LEARN_MORE_LINK" = "Learn More"; +/* Explanation in the 'onboarding permissions' view. */ +"ONBOARDING_PERMISSIONS_EXPLANATION" = "Your contact information is always transmitted securely."; /* Label for the 'not now' button in the 'onboarding permissions' view. */ "ONBOARDING_PERMISSIONS_NOT_NOW_BUTTON" = "Not Now"; /* Title of the 'onboarding permissions' view. */ -"ONBOARDING_PERMISSIONS_TITLE" = "We need access to your contacts and notifications"; +"ONBOARDING_PERMISSIONS_TITLE" = "Signal can let you know when you get a message (and who it is from)"; /* Title of the 'onboarding phone number' view. */ "ONBOARDING_PHONE_NUMBER_TITLE" = "Enter your phone number to get started"; -/* Explanation in the 'onboarding splash' view. */ -"ONBOARDING_SPLASH_EXPLANATION" = "By continuing, you agree to Signal's terms."; +/* Label indicating that the phone number is invalid in the 'onboarding phone number' view. */ +"ONBOARDING_PHONE_NUMBER_VALIDATION_WARNING" = "Invalid number"; /* Link to the 'terms and privacy policy' in the 'onboarding splash' view. */ -"ONBOARDING_SPLASH_TERM_AND_PRIVACY_POLICY" = "Terms and Privacy Policy"; +"ONBOARDING_SPLASH_TERM_AND_PRIVACY_POLICY" = "Terms & Privacy Policy"; /* Title of the 'onboarding splash' view. */ "ONBOARDING_SPLASH_TITLE" = "Signal is the private messenger for everybody"; diff --git a/SignalMessaging/categories/UIFont+OWS.h b/SignalMessaging/categories/UIFont+OWS.h index e719dddcb..b0bcda463 100644 --- a/SignalMessaging/categories/UIFont+OWS.h +++ b/SignalMessaging/categories/UIFont+OWS.h @@ -1,5 +1,5 @@ // -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. +// Copyright (c) 2019 Open Whisper Systems. All rights reserved. // #import @@ -36,6 +36,18 @@ NS_ASSUME_NONNULL_BEGIN @property (class, readonly, nonatomic) UIFont *ows_dynamicTypeCaption1Font; @property (class, readonly, nonatomic) UIFont *ows_dynamicTypeCaption2Font; +#pragma mark - Dynamic Type Clamped + +@property (class, readonly, nonatomic) UIFont *ows_dynamicTypeTitle1ClampedFont; +@property (class, readonly, nonatomic) UIFont *ows_dynamicTypeTitle2ClampedFont; +@property (class, readonly, nonatomic) UIFont *ows_dynamicTypeTitle3ClampedFont; +@property (class, readonly, nonatomic) UIFont *ows_dynamicTypeHeadlineClampedFont; +@property (class, readonly, nonatomic) UIFont *ows_dynamicTypeBodyClampedFont; +@property (class, readonly, nonatomic) UIFont *ows_dynamicTypeSubheadlineClampedFont; +@property (class, readonly, nonatomic) UIFont *ows_dynamicTypeFootnoteClampedFont; +@property (class, readonly, nonatomic) UIFont *ows_dynamicTypeCaption1ClampedFont; +@property (class, readonly, nonatomic) UIFont *ows_dynamicTypeCaption2ClampedFont; + #pragma mark - Styles - (UIFont *)ows_italic; diff --git a/SignalMessaging/categories/UIFont+OWS.m b/SignalMessaging/categories/UIFont+OWS.m index 2cd08f628..a7a1a4451 100644 --- a/SignalMessaging/categories/UIFont+OWS.m +++ b/SignalMessaging/categories/UIFont+OWS.m @@ -1,5 +1,5 @@ // -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. +// Copyright (c) 2019 Open Whisper Systems. All rights reserved. // #import "UIFont+OWS.h" @@ -97,6 +97,86 @@ NS_ASSUME_NONNULL_BEGIN return [UIFont preferredFontForTextStyle:UIFontTextStyleCaption2]; } +#pragma mark - Dynamic Type Clamped + ++ (UIFont *)preferredFontForTextStyleClamped:(UIFontTextStyle)fontTextStyle +{ + // We clamp the dynamic type sizes at the max size available + // without "larger accessibility sizes" enabled. + static NSDictionary *maxPointSizeMap = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + maxPointSizeMap = @{ + UIFontTextStyleTitle1 : @(34.0), + UIFontTextStyleTitle2 : @(28.0), + UIFontTextStyleTitle3 : @(26.0), + UIFontTextStyleHeadline : @(23.0), + UIFontTextStyleBody : @(23.0), + UIFontTextStyleSubheadline : @(21.0), + UIFontTextStyleFootnote : @(19.0), + UIFontTextStyleCaption1 : @(18.0), + UIFontTextStyleCaption2 : @(17.0), + }; + }); + + UIFont *font = [UIFont preferredFontForTextStyle:fontTextStyle]; + NSNumber *_Nullable maxPointSize = maxPointSizeMap[fontTextStyle]; + if (maxPointSize) { + if (maxPointSize.floatValue < font.pointSize) { + return [font fontWithSize:maxPointSize.floatValue]; + } + } else { + OWSFailDebug(@"Missing max point size for style: %@", fontTextStyle); + } + + return font; +} + ++ (UIFont *)ows_dynamicTypeTitle1ClampedFont +{ + return [UIFont preferredFontForTextStyleClamped:UIFontTextStyleTitle1]; +} + ++ (UIFont *)ows_dynamicTypeTitle2ClampedFont +{ + return [UIFont preferredFontForTextStyleClamped:UIFontTextStyleTitle2]; +} + ++ (UIFont *)ows_dynamicTypeTitle3ClampedFont +{ + return [UIFont preferredFontForTextStyleClamped:UIFontTextStyleTitle3]; +} + ++ (UIFont *)ows_dynamicTypeHeadlineClampedFont +{ + return [UIFont preferredFontForTextStyleClamped:UIFontTextStyleHeadline]; +} + ++ (UIFont *)ows_dynamicTypeBodyClampedFont +{ + return [UIFont preferredFontForTextStyleClamped:UIFontTextStyleBody]; +} + ++ (UIFont *)ows_dynamicTypeSubheadlineClampedFont +{ + return [UIFont preferredFontForTextStyleClamped:UIFontTextStyleSubheadline]; +} + ++ (UIFont *)ows_dynamicTypeFootnoteClampedFont +{ + return [UIFont preferredFontForTextStyleClamped:UIFontTextStyleFootnote]; +} + ++ (UIFont *)ows_dynamicTypeCaption1ClampedFont +{ + return [UIFont preferredFontForTextStyleClamped:UIFontTextStyleCaption1]; +} + ++ (UIFont *)ows_dynamicTypeCaption2ClampedFont +{ + return [UIFont preferredFontForTextStyleClamped:UIFontTextStyleCaption2]; +} + #pragma mark - Styles - (UIFont *)ows_italic