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

Fix #1938: Implement P3A on iOS #6308

Merged
merged 13 commits into from
Nov 16, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions App/iOS/Delegates/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -270,8 +270,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 Expand Up @@ -339,6 +339,15 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
.didFinishLaunching(options: launchOptions ?? [:])
)

// DAU may not have pinged on the first launch so weekOfInstallation pref may not be set yet
if let weekOfInstall = Preferences.DAU.weekOfInstallation.value ??
Preferences.DAU.installationDate.value?.mondayOfCurrentWeekFormatted {
braveCore.initializeP3AService(
forChannel: AppConstants.buildChannel.serverChannelParam,
weekOfInstall: weekOfInstall
)
}

return shouldPerformAdditionalDelegateHandling
}

Expand Down
3 changes: 2 additions & 1 deletion Client/Frontend/Browser/BrowserViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1120,9 +1120,10 @@ public class BrowserViewController: UIViewController {
presentOnboardingIntro()

// Full Screen Callout Presentation
// Priority: VPN - Default Browser - Rewards - Sync
// 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()
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 @@ -11,6 +11,7 @@ import SwiftKeychainWrapper
import SwiftUI
import BraveVPN
import Onboarding
import SafariServices

// MARK: - Callouts

Expand All @@ -29,6 +30,51 @@ 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 = Welcome3PAViewController().then {
$0.isModalInPresentation = true
$0.modalPresentationStyle = .overFullScreen
}

let state = WelcomeViewCalloutState.p3a(
info: WelcomeViewCalloutState.WelcomeViewDefaultBrowserDetails(
title: Strings.Callout.p3aCalloutTitle,
toggleTitle: Strings.Callout.p3aCalloutToggleTitle,
details: Strings.Callout.p3aCalloutDescription,
linkDescription: Strings.Callout.p3aCalloutLinkTitle,
primaryButtonTitle: Strings.done,
toggleAction: { [weak self] isOn in
self?.braveCore.p3aUtils.isP3AEnabled = isOn
},
linkAction: { url in
let p3aLearnMoreController = SFSafariViewController(url: BraveUX.braveP3ALearnMoreURL, configuration: .init())
p3aLearnMoreController.modalPresentationStyle = .currentContext

onboardingP3ACalloutController.present(p3aLearnMoreController, animated: true)
},
primaryButtonAction: { [weak self] in
Preferences.Onboarding.p3aOnboardingShown.value = true

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

onboardingP3ACalloutController.setLayoutState(state: state)

if !isOnboardingOrFullScreenCalloutPresented {
braveCore.p3aUtils.isNoticeAcknowledged = true
present(onboardingP3ACalloutController, animated: false)
}
}

func presentVPNAlertCallout() {
if Preferences.DebugFlag.skipNTPCallouts == true || isOnboardingOrFullScreenCalloutPresented { return }
Expand Down Expand Up @@ -77,7 +123,7 @@ extension BrowserViewController {
details: Strings.Callout.defaultBrowserCalloutDescription,
primaryButtonTitle: Strings.Callout.defaultBrowserCalloutPrimaryButtonTitle,
secondaryButtonTitle: Strings.Callout.defaultBrowserCalloutSecondaryButtonTitle,
primaryAction: { [weak self] in
primaryButtonAction: { [weak self] in
guard let settingsUrl = URL(string: UIApplication.openSettingsURLString) else {
return
}
Expand All @@ -88,13 +134,13 @@ extension BrowserViewController {
UIApplication.shared.open(settingsUrl)
self?.dismiss(animated: false)
},
secondaryAction: { [weak self] in
secondaryButtonAction: { [weak self] in
self?.isOnboardingOrFullScreenCalloutPresented = true

self?.dismiss(animated: false)
}
)
)
), p3aUtilities: braveCore.p3aUtils
)

if !isOnboardingOrFullScreenCalloutPresented {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import SwiftUI
import BraveUI
import BraveShared
import Data
import Onboarding

extension BrowserViewController {
func presentCookieNotificationBlockingCalloutIfNeeded() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ 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 {
let onboardingController = WelcomeViewController()
Preferences.Onboarding.isNewRetentionUser.value == true {
let onboardingController = WelcomeViewController(p3aUtilities: braveCore.p3aUtils)
onboardingController.modalPresentationStyle = .fullScreen
parentController.present(onboardingController, animated: false)
isOnboardingOrFullScreenCalloutPresented = true
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
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,8 @@ extension BrowserViewController: TopToolbarDelegate {
profile: self.profile,
tabManager: self.tabManager,
feedDataSource: self.feedDataSource,
historyAPI: self.braveCore.historyAPI
historyAPI: self.braveCore.historyAPI,
p3aUtilities: self.braveCore.p3aUtils
)
let container = SettingsNavigationController(rootViewController: shieldsAndPrivacy)
container.isModalInPresentation = true
Expand Down
39 changes: 0 additions & 39 deletions Client/Frontend/ClientPreferences.swift
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,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 @@ -95,43 +93,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 @@ -21,16 +21,25 @@ class BraveShieldsAndPrivacySettingsController: TableViewController {
let tabManager: TabManager
let feedDataSource: FeedDataSource
let historyAPI: BraveHistoryAPI
let p3aUtilities: BraveP3AUtils

private let cookieConsentNoticesRowUUID = UUID()
private var filterListsSubscription: AnyCancellable?
private var currentCookieConsentNoticeBlockingState: Bool

init(profile: Profile, tabManager: TabManager, feedDataSource: FeedDataSource, historyAPI: BraveHistoryAPI) {
init(
profile: Profile,
tabManager: TabManager,
feedDataSource: FeedDataSource,
historyAPI: BraveHistoryAPI,
p3aUtilities: BraveP3AUtils
) {
self.profile = profile
self.tabManager = tabManager
self.feedDataSource = feedDataSource
self.historyAPI = historyAPI

self.p3aUtilities = p3aUtilities

self.currentCookieConsentNoticeBlockingState = FilterListResourceDownloader.shared.isEnabled(
for: FilterList.cookieConsentNoticesComponentID
)
Expand Down Expand Up @@ -264,6 +273,16 @@ class BraveShieldsAndPrivacySettingsController: TableViewController {
}()

private lazy var otherSettingsSection: Section = {
let p3aRow = Row.boolRow(
title: Strings.P3A.settingTitle,
detailText: Strings.P3A.settingSubtitle,
toggleValue: p3aUtilities.isP3AEnabled,
valueChange: { [unowned self] isOn in
soner-yuksel marked this conversation as resolved.
Show resolved Hide resolved
p3aUtilities.isP3AEnabled = isOn
},
cellReuseId: "p3a"
)

var section = Section(
header: .title(Strings.otherPrivacySettingsSection),
rows: [
Expand All @@ -289,6 +308,7 @@ class BraveShieldsAndPrivacySettingsController: TableViewController {
)
)
}
section.rows.append(p3aRow)

return section
}()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,13 @@ import BraveShared
import UIKit
import BraveUI
import Onboarding
import BraveCore

class RetentionPreferencesDebugMenuViewController: TableViewController {
private let p3aUtilities: BraveP3AUtils

init() {
init(p3aUtilities: BraveP3AUtils) {
self.p3aUtilities = p3aUtilities
super.init(style: .insetGrouped)
}

Expand Down Expand Up @@ -52,7 +55,7 @@ class RetentionPreferencesDebugMenuViewController: TableViewController {
.init(
text: "Start Onboarding",
selection: { [unowned self] in
let onboardingController = WelcomeViewController()
let onboardingController = WelcomeViewController(state: .loading, p3aUtilities: self.p3aUtilities)
onboardingController.modalPresentationStyle = .fullScreen

present(onboardingController, animated: false)
Expand Down Expand Up @@ -104,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
16 changes: 14 additions & 2 deletions Client/Frontend/Settings/SettingsViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ class SettingsViewController: TableViewController {
private let passwordAPI: BravePasswordAPI
private let syncAPI: BraveSyncAPI
private let syncProfileServices: BraveSyncProfileServiceIOS
private let p3aUtilities: BraveP3AUtils
private let keyringStore: KeyringStore?
private let cryptoStore: CryptoStore?
private let windowProtection: WindowProtection?
Expand Down Expand Up @@ -74,6 +75,7 @@ class SettingsViewController: TableViewController {
self.passwordAPI = braveCore.passwordAPI
self.syncAPI = braveCore.syncAPI
self.syncProfileServices = braveCore.syncProfileService
self.p3aUtilities = braveCore.p3aUtils
self.keyringStore = keyringStore
self.cryptoStore = cryptoStore

Expand Down Expand Up @@ -205,7 +207,9 @@ class SettingsViewController: TableViewController {
profile: self.profile,
tabManager: self.tabManager,
feedDataSource: self.feedDataSource,
historyAPI: self.historyAPI)
historyAPI: self.historyAPI,
p3aUtilities: self.p3aUtilities
)
self.navigationController?.pushViewController(controller, animated: true)
}, image: UIImage(named: "settings-shields", in: .module, compatibleWith: nil)!, accessory: .disclosureIndicator)
],
Expand Down Expand Up @@ -659,6 +663,14 @@ class SettingsViewController: TableViewController {
selection: { [unowned self] in
self.displayBraveSearchDebugMenu()
}, accessory: .disclosureIndicator, cellClass: MultilineValue1Cell.self),
Row(
text: "View Brave Histogram (p3a) Logs",
selection: { [unowned self] in
let histogramsController = self.p3aUtilities.histogramsController().then {
$0.title = "Histograms (p3a)"
}
self.navigationController?.pushViewController(histogramsController, animated: true)
}, accessory: .disclosureIndicator, cellClass: MultilineValue1Cell.self),
Row(
text: "VPN Logs",
selection: { [unowned self] in
Expand All @@ -667,7 +679,7 @@ class SettingsViewController: TableViewController {
Row(
text: "Retention Preferences Debug Menu",
selection: { [unowned self] in
self.navigationController?.pushViewController(RetentionPreferencesDebugMenuViewController(), animated: true)
self.navigationController?.pushViewController(RetentionPreferencesDebugMenuViewController(p3aUtilities: p3aUtilities), animated: true)
}, accessory: .disclosureIndicator, cellClass: MultilineValue1Cell.self),
Row(
text: "Load all QA Links",
Expand Down
3 changes: 2 additions & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -352,14 +352,15 @@ let package = Package(
"BraveCore",
"Fuzi",
"Storage",
"Growth",
.product(name: "Lottie", package: "lottie-ios")
],
resources: [
.copy("LottieAssets/onboarding-ads.json"),
.copy("LottieAssets/onboarding-rewards.json"),
.copy("LottieAssets/onboarding-shields.json"),
.copy("Welcome/Resources/disconnect-entitylist.json"),
.copy("ProductNotifications/blocking-summary.json")
.copy("ProductNotifications/Resources/blocking-summary.json")
],
plugins: ["LoggerPlugin"]
),
Expand Down
Loading