From 0761eb5325a51e569a7d931f73b60378dabda949 Mon Sep 17 00:00:00 2001 From: Brandon-T Date: Mon, 21 Oct 2019 12:47:32 -0400 Subject: [PATCH] Fix #1695, Fix #1720, Fix #1719: Removes Onboarding agreement checkbox & Updates UI. (#1702) - Big updates to rewards where we changed the flow around and also the logic of what shows when. - Updated the progress state because when you click an ad, it never updated and so when the browser controller showed again, it would popup again to do the entire onboarding (infinitely unless you press skip). - Centers all confirmation buttons on the onboarding screen. --- BraveShared/BraveStrings.swift | 6 +- .../Browser/BrowserViewController.swift | 56 ++++++++++- .../OnboardingAdsCountdownView.swift | 4 + .../OnboardingNavigationController.swift | 16 ++-- .../OnboardingRewardsAgreementView.swift | 93 +++++++------------ ...ardingRewardsAgreementViewController.swift | 33 ++++--- .../Onboarding/OnboardingRewardsView.swift | 10 +- .../OnboardingRewardsViewController.swift | 16 ---- .../OnboardingSearchEnginesView.swift | 4 + .../Onboarding/OnboardingShieldsView.swift | 6 ++ .../OnboardingWebViewController.swift | 14 +-- 11 files changed, 148 insertions(+), 110 deletions(-) diff --git a/BraveShared/BraveStrings.swift b/BraveShared/BraveStrings.swift index 8753b5f3f13..5dc910d07a7 100644 --- a/BraveShared/BraveStrings.swift +++ b/BraveShared/BraveStrings.swift @@ -555,7 +555,7 @@ extension Strings { public static let OBFinishButton = NSLocalizedString("OBFinishButton", bundle: Bundle.braveShared, value: "Start browsing", comment: "Button to finish onboarding and start using the app.") public static let OBJoinButton = NSLocalizedString("OBJoinButton", bundle: Bundle.braveShared, value: "Join", comment: "Button to join Brave Rewards.") public static let OBTurnOnButton = NSLocalizedString("OBTurnOnButton", bundle: Bundle.braveShared, value: "Turn On", comment: "Button to show Brave Rewards.") - public static let OBAgreeButton = NSLocalizedString("OBAgreeButton", bundle: Bundle.braveShared, value: "Agree", comment: "Button to agree to Brave's Terms of Service.") + public static let OBShowMeButton = NSLocalizedString("OBShowMeButton", bundle: Bundle.braveShared, value: "Show Me", comment: "Button to show the Brave Rewards Ads.") public static let OBDidntSeeAdButton = NSLocalizedString("OBDidntSeeAdButton", bundle: Bundle.braveShared, value: "I didn't see an ad", comment: "Button to show information on how to enable ads") public static let OBSearchEngineTitle = NSLocalizedString("OBSearchEngineTitle", bundle: Bundle.braveShared, value: "Welcome to Brave Browser", comment: "Title for search engine onboarding screen") public static let OBSearchEngineDetail = NSLocalizedString("OBSearchEngineDetail", bundle: Bundle.braveShared, value: "Select your default search engine", comment: "Detail text for search engine onboarding screen") @@ -564,8 +564,8 @@ extension Strings { public static let OBRewardsTitle = NSLocalizedString("OBRewardsTitle", bundle: Bundle.braveShared, value: "Brave Rewards", comment: "Title for rewards onboarding screen") public static let OBRewardsDetailInAdRegion = NSLocalizedString("OBRewardsDetailInAdRegion", bundle: Bundle.braveShared, value: "Earn tokens for seeing privacy-respecting ads. Use them to support your favorite sites and creators.", comment: "Detail text for rewards onboarding screen") public static let OBRewardsDetailOutsideAdRegion = NSLocalizedString("OBRewardsDetailOutsideAdRegion", bundle: Bundle.braveShared, value: "Support your favorite websites and creators based on your attention.", comment: "Detail text for rewards onboarding screen") - public static let OBRewardsAgreementTitle = NSLocalizedString("OBRewardsAgreementTitle", bundle: Bundle.braveShared, value: "Agree to the Terms to use Brave Rewards", comment: "Title for rewards agreement onboarding screen") - public static let OBRewardsAgreementDetail = NSLocalizedString("OBRewardsAgreementDetail", bundle: Bundle.braveShared, value: "I agree to the Brave Rewards", comment: "Detail text for rewards agreement onboarding screen") + public static let OBRewardsAgreementTitle = NSLocalizedString("OBRewardsAgreementTitle", bundle: Bundle.braveShared, value: "Brave Rewards", comment: "Title for rewards agreement onboarding screen") + public static let OBRewardsAgreementDetail = NSLocalizedString("OBRewardsAgreementDetail", bundle: Bundle.braveShared, value: "By turning on Rewards, you agree to the", comment: "Detail text for rewards agreement onboarding screen") public static let OBRewardsAgreementDetailLink = NSLocalizedString("OBRewardsAgreementDetailLink", bundle: Bundle.braveShared, value: "Terms of Service", comment: "Detail text for rewards agreement onboarding screen") public static let OBAdsTitle = NSLocalizedString("OBAdsTitle", bundle: Bundle.braveShared, value: "Brave will show your first ad in", comment: "Title for ads onboarding screen") public static let OBCompleteTitle = NSLocalizedString("OBCompleteTitle", bundle: Bundle.braveShared, value: "Now you're ready to go.", comment: "Title for when the user completes onboarding") diff --git a/Client/Frontend/Browser/BrowserViewController.swift b/Client/Frontend/Browser/BrowserViewController.swift index 70f1d07b002..23e6e37a70b 100644 --- a/Client/Frontend/Browser/BrowserViewController.swift +++ b/Client/Frontend/Browser/BrowserViewController.swift @@ -684,6 +684,25 @@ class BrowserViewController: UIViewController { } func presentOnboardingIntro() { + // 1. Existing user. + // 2. User already completed onboarding. + if Preferences.General.basicOnboardingCompleted.value == OnboardingState.completed.rawValue { + // The user has ads in their region and they completed all onboarding. + if BraveAds.isCurrentRegionSupported() + && + Preferences.General.basicOnboardingProgress.value == OnboardingProgress.ads.rawValue { + return + } + + // The user doesn't have ads in their region and they've completed rewards. + if !BraveAds.isCurrentRegionSupported() + && + Preferences.General.basicOnboardingProgress.value == OnboardingProgress.rewards.rawValue { + return + } + } + + // The user either skipped or didn't complete onboarding. let isRewardsEnabled = rewards?.ledger.isEnabled == true // 1. Existing user. @@ -3306,12 +3325,43 @@ extension BrowserViewController { extension BrowserViewController: OnboardingControllerDelegate { func onboardingCompleted(_ onboardingController: OnboardingNavigationController) { + Preferences.General.basicOnboardingCompleted.value = OnboardingState.completed.rawValue + Preferences.General.basicOnboardingNextOnboardingPrompt.value = nil + + #if NO_REWARDS switch onboardingController.onboardingType { case .newUser: - Preferences.General.basicOnboardingCompleted.value = OnboardingState.completed.rawValue - Preferences.General.basicOnboardingNextOnboardingPrompt.value = nil - default: break + Preferences.General.basicOnboardingProgress.value = OnboardingProgress.searchEngine.rawValue + + case .existingUserRewardsOff, .existingUserRewardsOn: + break + + default: + break } + #else + switch onboardingController.onboardingType { + case .newUser: + if BraveAds.isCurrentRegionSupported() { + Preferences.General.basicOnboardingProgress.value = OnboardingProgress.ads.rawValue + } else { + Preferences.General.basicOnboardingProgress.value = OnboardingProgress.rewards.rawValue + } + + case .existingUserRewardsOff: + if BraveAds.isCurrentRegionSupported() { + Preferences.General.basicOnboardingProgress.value = OnboardingProgress.ads.rawValue + } + + case .existingUserRewardsOn: + if BraveAds.isCurrentRegionSupported() { + Preferences.General.basicOnboardingProgress.value = OnboardingProgress.ads.rawValue + } + + default: + break + } + #endif onboardingController.dismiss(animated: true) } diff --git a/Client/Frontend/Browser/Onboarding/OnboardingAdsCountdownView.swift b/Client/Frontend/Browser/Onboarding/OnboardingAdsCountdownView.swift index d5d893611bf..b9882ddd838 100644 --- a/Client/Frontend/Browser/Onboarding/OnboardingAdsCountdownView.swift +++ b/Client/Frontend/Browser/Onboarding/OnboardingAdsCountdownView.swift @@ -130,6 +130,10 @@ extension OnboardingAdsCountdownViewController { countdownView.snp.makeConstraints { $0.size.equalTo(UX.animationContentSize) } + + finishedButton.snp.makeConstraints { + $0.centerX.equalTo(self.snp.centerX) + } } func applyTheme(_ theme: Theme) { diff --git a/Client/Frontend/Browser/Onboarding/OnboardingNavigationController.swift b/Client/Frontend/Browser/Onboarding/OnboardingNavigationController.swift index 03fda8975af..526983d4619 100644 --- a/Client/Frontend/Browser/Onboarding/OnboardingNavigationController.swift +++ b/Client/Frontend/Browser/Onboarding/OnboardingNavigationController.swift @@ -55,8 +55,8 @@ class OnboardingNavigationController: UINavigationController { } #else switch self { - case .newUser: return BraveAds.isCurrentRegionSupported() ? [.searchEnginePicker, .shieldsInfo, .rewardsInfo, .rewardsAgreement, .adsCountdown] : [.searchEnginePicker, .shieldsInfo, .rewardsInfo, .rewardsAgreement] - case .existingUserRewardsOff: return BraveAds.isCurrentRegionSupported() ? [.rewardsInfo, .rewardsAgreement, .adsCountdown] : [] + case .newUser: return BraveAds.isCurrentRegionSupported() ? [.searchEnginePicker, .shieldsInfo, .rewardsAgreement, .adsCountdown] : [.searchEnginePicker, .shieldsInfo, .rewardsAgreement] + case .existingUserRewardsOff: return BraveAds.isCurrentRegionSupported() ? [.rewardsAgreement, .adsCountdown] : [] case .existingUserRewardsOn: return BraveAds.isCurrentRegionSupported() ? [.rewardsInfo, .adsCountdown] : [] } #endif @@ -66,7 +66,7 @@ class OnboardingNavigationController: UINavigationController { fileprivate enum Screens { case searchEnginePicker case shieldsInfo - case rewardsInfo + case existingRewards case rewardsAgreement case adsCountdown @@ -77,7 +77,7 @@ class OnboardingNavigationController: UINavigationController { return OnboardingSearchEnginesViewController(profile: profile, rewards: rewards, theme: theme) case .shieldsInfo: return OnboardingShieldsViewController(profile: profile, rewards: rewards, theme: theme) - case .rewardsInfo: + case .existingRewards: return OnboardingRewardsViewController(profile: profile, rewards: rewards, theme: theme) case .rewardsAgreement: return OnboardingRewardsAgreementViewController(profile: profile, rewards: rewards, theme: theme) @@ -90,7 +90,7 @@ class OnboardingNavigationController: UINavigationController { switch self { case .searchEnginePicker: return OnboardingSearchEnginesViewController.self case .shieldsInfo: return OnboardingShieldsViewController.self - case .rewardsInfo: return OnboardingRewardsViewController.self + case .existingRewards: return OnboardingRewardsViewController.self case .rewardsAgreement: return OnboardingRewardsAgreementViewController.self case .adsCountdown: return OnboardingAdsCountdownViewController.self } @@ -170,11 +170,9 @@ extension OnboardingNavigationController: UINavigationControllerDelegate { switch operation { case .push: - let shouldFade = !fromVC.isKind(of: OnboardingRewardsViewController.self) - return CustomAnimator(isPresenting: true, shouldFadeGraphics: shouldFade) + return CustomAnimator(isPresenting: true, shouldFadeGraphics: false) default: - let shouldFade = !fromVC.isKind(of: OnboardingRewardsAgreementViewController.self) - return CustomAnimator(isPresenting: false, shouldFadeGraphics: shouldFade) + return CustomAnimator(isPresenting: false, shouldFadeGraphics: false) } } } diff --git a/Client/Frontend/Browser/Onboarding/OnboardingRewardsAgreementView.swift b/Client/Frontend/Browser/Onboarding/OnboardingRewardsAgreementView.swift index 1029c706184..ca9a902f156 100644 --- a/Client/Frontend/Browser/Onboarding/OnboardingRewardsAgreementView.swift +++ b/Client/Frontend/Browser/Onboarding/OnboardingRewardsAgreementView.swift @@ -5,6 +5,7 @@ import Foundation import Shared import BraveShared +import BraveRewards import Lottie extension OnboardingRewardsAgreementViewController { @@ -22,14 +23,13 @@ extension OnboardingRewardsAgreementViewController { var onTermsOfServicePressed: (() -> Void)? - let agreeButton = CommonViews.primaryButton(text: Strings.OBAgreeButton).then { - $0.accessibilityIdentifier = "OnboardingRewardsAgreementViewController.AgreeButton" - $0.backgroundColor = BraveUX.BraveOrange.withAlphaComponent(0.7) - $0.isEnabled = false + let turnOnButton = CommonViews.primaryButton(text: Strings.OBTurnOnButton).then { + $0.accessibilityIdentifier = "OnboardingRewardsAgreementViewController.OBTurnOnButton" + $0.backgroundColor = BraveUX.BraveOrange } - let cancelButton = CommonViews.secondaryButton(text: Strings.CancelButtonTitle).then { - $0.accessibilityIdentifier = "OnboardingRewardsAgreementViewController.CancelButton" + let skipButton = CommonViews.secondaryButton(text: Strings.OBSkipButton).then { + $0.accessibilityIdentifier = "OnboardingRewardsAgreementViewController.OBSkipButton" } private let mainStackView = UIStackView().then { @@ -55,21 +55,14 @@ extension OnboardingRewardsAgreementViewController { $0.spacing = 32 } - private let descriptionCheckbox = UIButton().then { - $0.setImage(#imageLiteral(resourceName: "checkbox_off"), for: .normal) - $0.setImage(#imageLiteral(resourceName: "checkbox_on"), for: .selected) - $0.setImage(#imageLiteral(resourceName: "checkbox_on"), for: .highlighted) - $0.adjustsImageWhenHighlighted = true - - $0.contentMode = .scaleAspectFit - $0.setContentHuggingPriority(.required, for: .horizontal) - $0.setContentCompressionResistancePriority(.required, for: .horizontal) - } - private let titleLabel = CommonViews.primaryText(Strings.OBRewardsAgreementTitle).then { $0.numberOfLines = 0 } + private let subtitleLabel = CommonViews.secondaryText("").then { + $0.attributedText = BraveAds.isCurrentRegionSupported() ? Strings.OBRewardsDetailInAdRegion.boldWords(with: $0.font, amount: 2) : Strings.OBRewardsDetailOutsideAdRegion.boldWords(with: $0.font, amount: 1) + } + private lazy var descriptionLabel = UITextView().then { $0.delaysContentTouches = false $0.isEditable = false @@ -93,12 +86,12 @@ extension OnboardingRewardsAgreementViewController { private lazy var textStackView = UIStackView().then { stackView in stackView.axis = .vertical stackView.spacing = 8 - let descriptionStackView = UIStackView(arrangedSubviews: [descriptionLabel, descriptionCheckbox]).then { - $0.alignment = .center - $0.spacing = 65.0 + stackView.layoutMargins = UIEdgeInsets(top: 0.0, left: 20.0, bottom: 0.0, right: 20.0) + stackView.isLayoutMarginsRelativeArrangement = true + + [titleLabel, subtitleLabel, descriptionLabel].forEach { + stackView.addArrangedSubview($0) } - - [titleLabel, descriptionStackView].forEach(stackView.addArrangedSubview(_:)) } private let buttonsStackView = UIStackView().then { @@ -107,31 +100,33 @@ extension OnboardingRewardsAgreementViewController { private func updateDescriptionLabel() { descriptionLabel.attributedText = { + let fontSize: CGFloat = 14.0 let titleLabelColor = titleLabel.textColor ?? .black let text = NSMutableAttributedString(string: Strings.OBRewardsAgreementDetail, attributes: [ - .font: UIFont.systemFont(ofSize: 16, weight: UIFont.Weight.regular), + .font: UIFont.systemFont(ofSize: fontSize, weight: UIFont.Weight.regular), .foregroundColor: titleLabelColor ]) text.append(NSAttributedString(string: " ", attributes: [ - .font: UIFont.systemFont(ofSize: 16, weight: UIFont.Weight.regular), + .font: UIFont.systemFont(ofSize: fontSize, weight: UIFont.Weight.regular), .foregroundColor: titleLabelColor ])) text.append(NSAttributedString(string: Strings.OBRewardsAgreementDetailLink, attributes: [ - .font: UIFont.systemFont(ofSize: 16, weight: UIFont.Weight.regular), + .font: UIFont.systemFont(ofSize: fontSize, weight: UIFont.Weight.regular), .foregroundColor: UX.linkColor, .link: "brave_terms_of_service" ])) text.append(NSAttributedString(string: ".", attributes: [ - .font: UIFont.systemFont(ofSize: 16, weight: UIFont.Weight.regular), + .font: UIFont.systemFont(ofSize: fontSize, weight: UIFont.Weight.regular), .foregroundColor: titleLabelColor ])) let paragraphStyle = NSMutableParagraphStyle() paragraphStyle.lineBreakMode = .byWordWrapping + paragraphStyle.alignment = .center text.addAttribute(.paragraphStyle, value: paragraphStyle, range: NSRange(location: 0, length: text.length)) @@ -144,6 +139,10 @@ extension OnboardingRewardsAgreementViewController { descriptionLabel.isAccessibilityElement = true } + func updateSubtitleText(_ text: String, boldWords: Int) { + self.subtitleLabel.attributedText = text.boldWords(with: self.subtitleLabel.font, amount: boldWords) + } + init(theme: Theme) { super.init(frame: .zero) @@ -165,19 +164,20 @@ extension OnboardingRewardsAgreementViewController { mainStackView.addArrangedSubview(descriptionView) - [cancelButton, agreeButton, UIView.spacer(.horizontal, amount: 0)] + [skipButton, turnOnButton, UIView.spacer(.horizontal, amount: 0)] .forEach(buttonsStackView.addArrangedSubview(_:)) [textStackView, buttonsStackView].forEach(descriptionStackView.addArrangedSubview(_:)) - descriptionCheckbox.addTarget(self, action: #selector(onTermsAccepted(_:)), for: .touchUpInside) + turnOnButton.snp.makeConstraints { + $0.centerX.equalTo(self.snp.centerX) + } } func applyTheme(_ theme: Theme) { descriptionView.backgroundColor = OnboardingViewController.colorForTheme(theme) titleLabel.appearanceTextColor = theme.colors.tints.home updateDescriptionLabel() - descriptionCheckbox.setImage(theme.isDark ? #imageLiteral(resourceName: "checkbox_off_dark") : #imageLiteral(resourceName: "checkbox_off"), for: .normal) } override func layoutSubviews() { @@ -191,31 +191,8 @@ extension OnboardingRewardsAgreementViewController { } @available(*, unavailable) - required init(coder: NSCoder) { fatalError() } - - @objc - private func onTermsAccepted(_ button: UIButton) { - button.isSelected.toggle() - - agreeButton.backgroundColor = button.isSelected ? BraveUX.BraveOrange : BraveUX.BraveOrange.withAlphaComponent(0.7) - agreeButton.isEnabled = button.isSelected - } - - override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { - if !descriptionCheckbox.isHidden && - descriptionCheckbox.isUserInteractionEnabled && - descriptionCheckbox.alpha >= 0.01, - let frame = descriptionCheckbox.superview?.convert( - descriptionCheckbox.frame, - to: self - ) { - - if frame.inset(by: UIEdgeInsets(equalInset: UX.checkboxInsets)).contains(point) { - return descriptionCheckbox - } - } - - return super.hitTest(point, with: event) + required init(coder: NSCoder) { + fatalError() } } } @@ -230,11 +207,12 @@ extension OnboardingRewardsAgreementViewController.View: UITextViewDelegate { } private extension String { - func boldFirstWord(with font: UIFont) -> NSMutableAttributedString { + func boldWords(with font: UIFont, amount: Int) -> NSMutableAttributedString { let mutableDescriptionText = NSMutableAttributedString(string: self) - if let firstWord = self.components(separatedBy: " ").first { - if let range = self.range(of: firstWord) { + let components = self.components(separatedBy: " ") + for i in 0..