Skip to content
This repository has been archived by the owner on May 10, 2024. It is now read-only.

Commit

Permalink
Adding p3a transparent callout, logic is added
Browse files Browse the repository at this point in the history
  • Loading branch information
soner-yuksel committed Nov 2, 2022
1 parent 04a9dae commit 2f5817f
Show file tree
Hide file tree
Showing 15 changed files with 266 additions and 98 deletions.
4 changes: 2 additions & 2 deletions App/iOS/Delegates/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -269,8 +269,8 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
}

// Check if user has launched the application before and determine if it is a new retention user
if Preferences.General.isFirstLaunch.value, Preferences.General.isNewRetentionUser.value == nil {
Preferences.General.isNewRetentionUser.value = true
if Preferences.General.isFirstLaunch.value, Preferences.Onboarding.isNewRetentionUser.value == nil {
Preferences.Onboarding.isNewRetentionUser.value = true
}

if Preferences.DAU.appRetentionLaunchDate.value == nil {
Expand Down
23 changes: 12 additions & 11 deletions Client/Frontend/Browser/BrowserViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1112,21 +1112,22 @@ public class BrowserViewController: UIViewController {
}

override public func viewDidAppear(_ animated: Bool) {
// Passcode Migration has highest priority, it should be presented over everything else
presentPassCodeMigration()

// Present Onboarding to new users, existing users will not see the onboarding
presentOnboardingIntro()

// Full Screen Callout Presentation
// Priority: VPN - Default Browser - Rewards - Sync
// TODO: Remove the dispatch after with a proper fix and fix calling present functions before super.viewDidAppear
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
// // Passcode Migration has highest priority, it should be presented over everything else
// presentPassCodeMigration()
//
// // Present Onboarding to new users, existing users will not see the onboarding
// presentOnboardingIntro()
//
// // Full Screen Callout Presentation
// // Priority: P3A - VPN - Default Browser - Rewards
// // TODO: Remove the dispatch after with a proper fix and fix calling present functions before super.viewDidAppear
// DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
self.presentP3AScreenCallout()
self.presentVPNAlertCallout()
self.presentDefaultBrowserScreenCallout()
self.presentBraveRewardsScreenCallout()
self.presentCookieNotificationBlockingCalloutIfNeeded()
}
// }

screenshotHelper.viewIsVisible = true
screenshotHelper.takePendingScreenshots(tabManager.allTabs)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ extension BrowserViewController {

func showBraveRewardsPanel() {
if !Preferences.FullScreenCallout.rewardsCalloutCompleted.value,
Preferences.General.isNewRetentionUser.value == true,
Preferences.Onboarding.isNewRetentionUser.value == true,
!Preferences.Rewards.rewardsToggledOnce.value {

let controller = OnboardingRewardsAgreementViewController()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,46 @@ extension BrowserViewController {
present(controller, animated: false)
}
}

func presentP3AScreenCallout() {
// if Preferences.DebugFlag.skipNTPCallouts == true || isOnboardingOrFullScreenCalloutPresented { return }
//
// if presentedViewController != nil || !FullScreenCalloutManager.shouldShowDefaultBrowserCallout(calloutType: .p3a) {
// return
// }

// let onboardingP3ACalloutController = WelcomeViewController(p3aUtilities: braveCore.p3aUtils)

let onboardingP3ACalloutController = Welcome3PAViewController(p3aUtilities: braveCore.p3aUtils)

let state = WelcomeViewCalloutState.p3a(
info: WelcomeViewCalloutState.WelcomeViewDefaultBrowserDetails(
title: "Help make Brave better.",
toggleTitle: "Share anonymous, private product insights.",
details: "This helps us learn what Brave features are used most often. Change this at any time in Brave Settings under ‘Brave Shields and Privacy’.",
linkDescription: "Learn more about our Privacy Preserving Product Analytics (P3A).",
primaryButtonTitle: "Done",
toggleAction: { [weak self] isOn in
self?.braveCore.p3aUtils.isP3AEnabled = isOn
},
linkAction: { url in
onboardingP3ACalloutController.present(OnboardingWebViewController(url: .p3aDescription), animated: true, completion: nil)
},
primaryButtonAction: { [weak self] in
Preferences.Onboarding.p3aOnboardingShown.value = true

self?.isOnboardingOrFullScreenCalloutPresented = true
self?.dismiss(animated: false)
}
)
)

onboardingP3ACalloutController.setLayoutState(state: state)

if !isOnboardingOrFullScreenCalloutPresented {
present(onboardingP3ACalloutController, animated: true)
}
}

func presentVPNAlertCallout() {
if Preferences.DebugFlag.skipNTPCallouts == true || isOnboardingOrFullScreenCalloutPresented { return }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ extension BrowserViewController {
// 1. User is brand new
// 2. User hasn't completed onboarding
if Preferences.Onboarding.basicOnboardingCompleted.value != OnboardingState.completed.rawValue,
Preferences.General.isNewRetentionUser.value == true {
Preferences.Onboarding.isNewRetentionUser.value == true {
let onboardingController = WelcomeViewController(p3aUtilities: braveCore.p3aUtils)
onboardingController.modalPresentationStyle = .fullScreen
parentController.present(onboardingController, animated: false)
Expand All @@ -58,7 +58,7 @@ extension BrowserViewController {
Preferences.DebugFlag.skipNTPCallouts != true {

if !Preferences.FullScreenCallout.omniboxCalloutCompleted.value,
Preferences.General.isNewRetentionUser.value == true {
Preferences.Onboarding.isNewRetentionUser.value == true {
presentOmniBoxOnboarding()
addNTPTutorialPage()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ extension BrowserViewController {
!Preferences.General.onboardingAdblockPopoverShown.value,
!benchmarkNotificationPresented,
!Preferences.AppState.backgroundedCleanly.value,
Preferences.General.isNewRetentionUser.value == true,
Preferences.Onboarding.isNewRetentionUser.value == true,
!topToolbar.inOverlayMode,
!isTabTrayActive,
selectedTab.webView?.scrollView.isDragging == false,
Expand Down
39 changes: 0 additions & 39 deletions Client/Frontend/ClientPreferences.swift
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,6 @@ extension Preferences {
final public class General {
/// Whether this is the first time user has ever launched Brave after intalling. *Should never be set to `true` manually!*
public static let isFirstLaunch = Option<Bool>(key: "general.first-launch", default: true)
/// Whether this is a new user who installed the application after onboarding retention updates
public static let isNewRetentionUser = Option<Bool?>(key: "general.new-retention", default: nil)
/// Whether or not to save logins in Brave
static let saveLogins = Option<Bool>(key: "general.save-logins", default: true)
/// Whether or not to block popups from websites automaticaly
Expand Down Expand Up @@ -112,43 +110,6 @@ extension Preferences {
static let isUsingBottomBar = Option<Bool>(key: "general.bottom-bar", default: false)
}

final public class FullScreenCallout {
/// Whether the block cookie consent notices callout is shown.
static let blockCookieConsentNoticesCalloutCompleted =
Option<Bool>(key: "fullScreenCallout.full-screen-cookie-consent-notices-callout-completed", default: false)

/// Whether the vpn callout is shown.
static let vpnCalloutCompleted =
Option<Bool>(key: "fullScreenCallout.full-screen-vpn-callout-completed", default: false)

/// Whether the rewards callout is shown.
static let rewardsCalloutCompleted =
Option<Bool>(key: "fullScreenCallout.full-screen-rewards-callout-completed", default: false)

/// Whether the whats new callout should be shown.
static let whatsNewCalloutOptIn =
Option<Bool>(key: "fullScreenCallout.full-screen-whats-new-callout-completed", default: false)

/// Whether the ntp callout is shown.
static let ntpCalloutCompleted =
Option<Bool>(key: "fullScreenCallout.full-screen-ntp-callout-completed", default: false)

/// Whether the omnibox callout is shown.
static let omniboxCalloutCompleted =
Option<Bool>(key: "fullScreenCallout.full-screen-omnibox-callout-completed", default: false)
}

final public class DefaultBrowserIntro {
/// Whether the default browser onboarding completed. This can happen by opening app settings or after the user
/// dismissed the intro screen enough amount of times.
static let completed =
Option<Bool>(key: "defaultBrowserIntro.intro-completed", default: false)

/// Whether system notification showed or not
static let defaultBrowserNotificationScheduled =
Option<Bool>(key: "general.default-browser-notification-scheduled", default: false)
}

final public class Search {
/// Whether or not to show suggestions while the user types
static let showSuggestions = Option<Bool>(key: "search.show-suggestions", default: false)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,11 +107,11 @@ class RetentionPreferencesDebugMenuViewController: TableViewController {
.boolRow(
title: "Retention User",
detailText: "Flag showing if the user installed the application after new onboarding is added.",
toggleValue: Preferences.General.isNewRetentionUser.value ?? false,
toggleValue: Preferences.Onboarding.isNewRetentionUser.value ?? false,
valueChange: {
if $0 {
let status = $0
Preferences.General.isNewRetentionUser.value = status
Preferences.Onboarding.isNewRetentionUser.value = status
}
},
cellReuseId: "RetentionUserCell"),
Expand Down
63 changes: 62 additions & 1 deletion Sources/Onboarding/OnboardingPreferences.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,72 @@ extension Preferences {
public static let basicOnboardingCompleted = Option<Int>(
key: "general.basic-onboarding-completed",
default: OnboardingState.undetermined.rawValue)

/// The time until the next on-boarding shows
public static let basicOnboardingDefaultBrowserSelected = Option<Bool>(
key: "general.basic-onboarding-default-browser-selected",
default: false)

/// The progress the user has made with onboarding
public static let basicOnboardingProgress = Option<Int>(key: "general.basic-onboarding-progress", default: OnboardingProgress.none.rawValue)
public static let basicOnboardingProgress = Option<Int>(
key: "general.basic-onboarding-progress",
default: OnboardingProgress.none.rawValue)

/// The bool detemining if p3a infomartion is shown in onboarding to a user so they will not see it again as pop-over
public static let p3aOnboardingShown = Option<Bool>(
key: "onboarding.basic-onboarding-default-browser-selected",
default: false)

/// Whether this is a new user who installed the application after onboarding retention updates
public static let isNewRetentionUser = Option<Bool?>(key: "general.new-retention", default: nil)
}
}

extension Preferences {
public final class FullScreenCallout {
/// Whether the block cookie consent notices callout is shown.
static let blockCookieConsentNoticesCalloutCompleted = Option<Bool>(
key: "fullScreenCallout.full-screen-cookie-consent-notices-callout-completed",
default: false)

/// Whether the vpn callout is shown.
public static let vpnCalloutCompleted = Option<Bool>(
key: "fullScreenCallout.full-screen-vpn-callout-completed",
default: false)

/// Whether the rewards callout is shown.
public static let rewardsCalloutCompleted = Option<Bool>(
key: "fullScreenCallout.full-screen-rewards-callout-completed",
default: false)

/// Whether the whats new callout should be shown.
public static let whatsNewCalloutOptIn = Option<Bool>(
key: "fullScreenCallout.full-screen-whats-new-callout-completed",
default: false)

/// Whether the ntp callout is shown.
public static let ntpCalloutCompleted = Option<Bool>(
key: "fullScreenCallout.full-screen-ntp-callout-completed",
default: false)

/// Whether the omnibox callout is shown.
public static let omniboxCalloutCompleted = Option<Bool>(
key: "fullScreenCallout.full-screen-omnibox-callout-completed",
default: false)
}
}

extension Preferences {
public final class DefaultBrowserIntro {
/// Whether the default browser onboarding completed. This can happen by opening app settings or after the user
/// dismissed the intro screen enough amount of times.
public static let completed = Option<Bool>(
key: "defaultBrowserIntro.intro-completed",
default: false)

/// Whether system notification showed or not
public static let defaultBrowserNotificationScheduled = Option<Bool>(
key: "general.default-browser-notification-scheduled",
default: false)
}
}
14 changes: 7 additions & 7 deletions Sources/Onboarding/OnboardingWebViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ import BraveUI
import UIKit
import Storage

class OnboardingWebViewController: UIViewController, WKNavigationDelegate {
public class OnboardingWebViewController: UIViewController, WKNavigationDelegate {

enum URLType {
public enum URLType {
case termsOfService
case privacyPolicy
case p3aDescription
Expand Down Expand Up @@ -52,7 +52,7 @@ class OnboardingWebViewController: UIViewController, WKNavigationDelegate {
KVOs.forEach { webView.removeObserver(self, forKeyPath: $0.rawValue) }
}

init(url: URLType) {
public init(url: URLType) {
self.urlType = url
super.init(nibName: nil, bundle: nil)
}
Expand All @@ -61,7 +61,7 @@ class OnboardingWebViewController: UIViewController, WKNavigationDelegate {
fatalError("init(coder:) has not been implemented")
}

override func viewDidLoad() {
public override func viewDidLoad() {
super.viewDidLoad()

let stackView = UIStackView().then {
Expand Down Expand Up @@ -93,7 +93,7 @@ class OnboardingWebViewController: UIViewController, WKNavigationDelegate {
toolbar.forwardButton.addTarget(self, action: #selector(onForward), for: .touchUpInside)
}

override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey: Any]?, context: UnsafeMutableRawPointer?) {
public override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey: Any]?, context: UnsafeMutableRawPointer?) {
guard let webView = object as? WKWebView, let kp = keyPath, let path = KVOConstants(rawValue: kp) else {
return
}
Expand Down Expand Up @@ -181,7 +181,7 @@ class OnboardingWebViewController: UIViewController, WKNavigationDelegate {
toolbar.forwardButton.tintColor = webView.canGoForward ? UX.buttonEnabledColor : UX.buttonDisabledColor
}

func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) {
public func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) {
let error = error as NSError
if error.domain == "WebKitErrorDomain" && error.code == 102 {
return
Expand All @@ -197,7 +197,7 @@ class OnboardingWebViewController: UIViewController, WKNavigationDelegate {
}
}

func webView(_ webView: WKWebView, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
public func webView(_ webView: WKWebView, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
completionHandler(.performDefaultHandling, nil)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,36 +7,43 @@ import Foundation
import Shared
import BraveShared

struct FullScreenCalloutManager {
public struct FullScreenCalloutManager {

enum FullScreenCalloutType {
case vpn, rewards, defaultBrowser, blockCookieConsentNotices
public enum FullScreenCalloutType {
case p3a, vpn, rewards, defaultBrowser, blockCookieConsentNotices

/// The number of days passed to show certain type of callout
var period: Int {
switch self {
case .blockCookieConsentNotices: return 0
case .p3a: return 0
case .vpn: return 4
case .rewards: return 8
case .defaultBrowser: return 10
case .blockCookieConsentNotices: return 0
}
}

/// The preference value stored for complete state
var preferenceValue: Preferences.Option<Bool> {
public var preferenceValue: Preferences.Option<Bool> {
switch self {
case .blockCookieConsentNotices: return Preferences.FullScreenCallout.blockCookieConsentNoticesCalloutCompleted
case .vpn: return Preferences.FullScreenCallout.vpnCalloutCompleted
case .rewards: return Preferences.FullScreenCallout.rewardsCalloutCompleted
case .defaultBrowser: return Preferences.DefaultBrowserIntro.completed
case .p3a:
return Preferences.Onboarding.p3aOnboardingShown
case .vpn:
return Preferences.FullScreenCallout.vpnCalloutCompleted
case .rewards:
return Preferences.FullScreenCallout.rewardsCalloutCompleted
case .defaultBrowser:
return Preferences.DefaultBrowserIntro.completed
case .blockCookieConsentNotices:
return Preferences.FullScreenCallout.blockCookieConsentNoticesCalloutCompleted
}
}
}

/// It determines whether we should show show the designated callout or not and sets corresponding preferences accordingly.
/// Returns true if the callout should be shown.
static func shouldShowDefaultBrowserCallout(calloutType: FullScreenCalloutType) -> Bool {
guard Preferences.General.isNewRetentionUser.value == true,
public static func shouldShowDefaultBrowserCallout(calloutType: FullScreenCalloutType) -> Bool {
guard Preferences.Onboarding.isNewRetentionUser.value == true,
let appRetentionLaunchDate = Preferences.DAU.appRetentionLaunchDate.value,
!calloutType.preferenceValue.value
else {
Expand Down
Loading

0 comments on commit 2f5817f

Please sign in to comment.