From eb5a7598a7504567a12052a83191da69ceba5853 Mon Sep 17 00:00:00 2001
From: Sabrina Tardio <44158575+SabrinaTardio@users.noreply.github.com>
Date: Thu, 14 Mar 2024 12:32:55 +0100
Subject: [PATCH] Sabrina/surveys (#2380)
Task/Issue URL:
https://app.asana.com/0/1199230911884351/1206807075858541/f
**Description**: We want to invite app users to research interviews
[Invite design](https://app.asana.com/0/72649045549333/1206743222316770)
[Invite copy](https://app.asana.com/0/38424471409662/1206743222316766)
Survey links:
Day0
https://selfserve.decipherinc.com/survey/selfserve/32ab/240300?list=1
Day14
https://selfserve.decipherinc.com/survey/selfserve/32ab/240300?list=2
The invite needs to be shown to a very limited share of users at
different points of their usage journey, 10% of day-0 users, and 10%
day-14 users
Flow:
Users receive an invitation to participate in the survey. This invite
automatically disappears if it is dismissed, after 24 h, or if the user
clicks the participation button
Users who choose to participate are then redirected to our designated
survey platforms,
On the survey platform, committed participants have the option to share
their email addresses for further communication or updates
Users see 1 invite max
---
.../Images/QandA-128.imageset/Contents.json | 12 ++
.../Images/QandA-128.imageset/QandA-128.svg | 9 ++
DuckDuckGo/Common/Localizables/UserText.swift | 12 +-
.../Utilities/UserDefaultsWrapper.swift | 4 +-
.../Model/HomePageContinueSetUpModel.swift | 116 +++++++++-----
DuckDuckGo/Localizable.xcstrings | 102 ++++++++----
DuckDuckGo/Menus/MainMenu.swift | 9 +-
DuckDuckGo/Menus/MainMenuActions.swift | 33 ++--
.../Model/AppearancePreferences.swift | 4 +-
.../HomePage/ContinueSetUpModelTests.swift | 147 +++++++++++++-----
10 files changed, 319 insertions(+), 129 deletions(-)
create mode 100644 DuckDuckGo/Assets.xcassets/Images/QandA-128.imageset/Contents.json
create mode 100644 DuckDuckGo/Assets.xcassets/Images/QandA-128.imageset/QandA-128.svg
diff --git a/DuckDuckGo/Assets.xcassets/Images/QandA-128.imageset/Contents.json b/DuckDuckGo/Assets.xcassets/Images/QandA-128.imageset/Contents.json
new file mode 100644
index 0000000000..e708cce2ed
--- /dev/null
+++ b/DuckDuckGo/Assets.xcassets/Images/QandA-128.imageset/Contents.json
@@ -0,0 +1,12 @@
+{
+ "images" : [
+ {
+ "filename" : "QandA-128.svg",
+ "idiom" : "universal"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/DuckDuckGo/Assets.xcassets/Images/QandA-128.imageset/QandA-128.svg b/DuckDuckGo/Assets.xcassets/Images/QandA-128.imageset/QandA-128.svg
new file mode 100644
index 0000000000..4e2ca57aaf
--- /dev/null
+++ b/DuckDuckGo/Assets.xcassets/Images/QandA-128.imageset/QandA-128.svg
@@ -0,0 +1,9 @@
+
diff --git a/DuckDuckGo/Common/Localizables/UserText.swift b/DuckDuckGo/Common/Localizables/UserText.swift
index 8fad1dff04..a5149fcee7 100644
--- a/DuckDuckGo/Common/Localizables/UserText.swift
+++ b/DuckDuckGo/Common/Localizables/UserText.swift
@@ -974,23 +974,23 @@ struct UserText {
static let newTabSetUpImportCardTitle = NSLocalizedString("newTab.setup.import.title", value: "Bring Your Stuff", comment: "Title of the Import card of the Set Up section in the home page")
static let newTabSetUpDuckPlayerCardTitle = NSLocalizedString("newTab.setup.duck.player.title", value: "Clean Up YouTube", comment: "Title of the Duck Player card of the Set Up section in the home page")
static let newTabSetUpEmailProtectionCardTitle = NSLocalizedString("newTab.setup.email.protection.title", value: "Protect Your Inbox", comment: "Title of the Email Protection card of the Set Up section in the home page")
- static let newTabSetUpSurveyDay0CardTitle = NSLocalizedString("newTab.setup.survey.day.0.title", value: "Tell Us What Brought You Here", comment: "Title of the Day 0 durvey of the Set Up section in the home page")
- static let newTabSetUpSurveyDay7CardTitle = NSLocalizedString("newTab.setup.survey.day.7.title", value: "Help Us Improve", comment: "Title of the Day 7 durvey of the Set Up section in the home page")
+ static let newTabSetUpSurveyDay0CardTitle = NSLocalizedString("newTab.setup.survey.day.0.title", value: "Share Your Thoughts With Us", comment: "Title of the Day 0 durvey of the Set Up section in the home page")
+ static let newTabSetUpSurveyDay14CardTitle = NSLocalizedString("newTab.setup.survey.day.14.title", value: "Share Your Thoughts With Us", comment: "Title of the Day 14 durvey of the Set Up section in the home page")
static let newTabSetUpDefaultBrowserAction = NSLocalizedString("newTab.setup.default.browser.action", value: "Make Default Browser", comment: "Action title on the action menu of the Default Browser card")
static let newTabSetUpImportAction = NSLocalizedString("newTab.setup.Import.action", value: "Import Now", comment: "Action title on the action menu of the Import card of the Set Up section in the home page")
static let newTabSetUpDuckPlayerAction = NSLocalizedString("newTab.setup.duck.player.action", value: "Try Duck Player", comment: "Action title on the action menu of the Duck Player card of the Set Up section in the home page")
static let newTabSetUpEmailProtectionAction = NSLocalizedString("newTab.setup.email.protection.action", value: "Get a Duck Address", comment: "Action title on the action menu of the Email Protection card of the Set Up section in the home page")
static let newTabSetUpRemoveItemAction = NSLocalizedString("newTab.setup.remove.item", value: "Dismiss", comment: "Action title on the action menu of the set up cards card of the SetUp section in the home page to remove the item")
- static let newTabSetUpSurveyDay0Action = NSLocalizedString("newTab.setup.survey.day.0.action", value: "Share Your Thoughts", comment: "Action title of the Day 0 durvey of the Set Up section in the home page")
- static let newTabSetUpSurveyDay7Action = NSLocalizedString("newTab.setup.survey.day.7.action", value: "Share Your Thoughts", comment: "Action title of the Day 7 durvey of the Set Up section in the home page")
+ static let newTabSetUpSurveyDay0Action = NSLocalizedString("newTab.setup.survey.day.0.action", value: "Sign Up To Participate", comment: "Action title of the Day 0 survey of the Set Up section in the home page")
+ static let newTabSetUpSurveyDay14Action = NSLocalizedString("newTab.setup.survey.day.14.action", value: "Sign Up To Participate", comment: "Action title of the Day 14 survey of the Set Up section in the home page")
static let newTabSetUpDefaultBrowserSummary = NSLocalizedString("newTab.setup.default.browser.summary", value: "We automatically block trackers as you browse. It's privacy, simplified.", comment: "Summary of the Default Browser card")
static let newTabSetUpImportSummary = NSLocalizedString("newTab.setup.import.summary", value: "Import bookmarks, favorites, and passwords from your old browser.", comment: "Summary of the Import card of the Set Up section in the home page")
static let newTabSetUpDuckPlayerSummary = NSLocalizedString("newTab.setup.duck.player.summary", value: "Enjoy a clean viewing experience without personalized ads.", comment: "Summary of the Duck Player card of the Set Up section in the home page")
static let newTabSetUpEmailProtectionSummary = NSLocalizedString("newTab.setup.email.protection.summary", value: "Generate custom @duck.com addresses that clean trackers from incoming email.", comment: "Summary of the Email Protection card of the Set Up section in the home page")
- static let newTabSetUpSurveyDay0Summary = NSLocalizedString("newTab.setup.survey.day.0.summary", value: "Take our short survey and help us build the best browser.", comment: "Summary of the Day 0 durvey of the Set Up section in the home page")
- static let newTabSetUpSurveyDay7Summary = NSLocalizedString("newTab.setup.survey.day.7.summary", value: "Take our short survey and help us build the best browser.", comment: "Summary of the Day 7 durvey of the Set Up section in the home page")
+ static let newTabSetUpSurveyDay0Summary = NSLocalizedString("newTab.setup.survey.day.0.summary", value: "Join an interview with a member of our research team to help us build the best browser.", comment: "Summary of the card on the new tab page that invites users to partecipate to a survey")
+ static let newTabSetUpSurveyDay14Summary = NSLocalizedString("newTab.setup.survey.day.14.summary", value: "Join an interview with a member of our research team to help us build the best browser.", comment: "Summary of the card on the new tab page that invites users to partecipate to a survey")
// Recent Activity
static let newTabRecentActivitySectionTitle = NSLocalizedString("newTab.recent.activity.section.title", value: "Recent Activity", comment: "Title of the RecentActivity section in the home page")
diff --git a/DuckDuckGo/Common/Utilities/UserDefaultsWrapper.swift b/DuckDuckGo/Common/Utilities/UserDefaultsWrapper.swift
index 272d63cca0..66216b4343 100644
--- a/DuckDuckGo/Common/Utilities/UserDefaultsWrapper.swift
+++ b/DuckDuckGo/Common/Utilities/UserDefaultsWrapper.swift
@@ -111,8 +111,10 @@ public struct UserDefaultsWrapper {
case homePageShowDuckPlayer = "home.page.show.duck.player"
case homePageShowEmailProtection = "home.page.show.email.protection"
case homePageShowSurveyDay0 = "home.page.show.survey.0"
+ case homePageShowSurveyDay0in10Percent = "home.page.show.survey.0.in.10.pervent"
+ case homePageShowSurveyDay14in10Percent = "home.page.show.survey.0.in.14.pervent"
case homePageUserInteractedWithSurveyDay0 = "home.page.user.interacted.with.survey.0"
- case homePageShowSurveyDay7 = "home.page.show.survey.7"
+ case homePageShowSurveyDay14 = "home.page.show.survey.14"
case homePageShowPageTitles = "home.page.show.page.titles"
case homePageShowRecentlyVisited = "home.page.show.recently.visited"
case homePageContinueSetUpImport = "home.page.continue.set.up.import"
diff --git a/DuckDuckGo/HomePage/Model/HomePageContinueSetUpModel.swift b/DuckDuckGo/HomePage/Model/HomePageContinueSetUpModel.swift
index 33e2482333..1e7a137548 100644
--- a/DuckDuckGo/HomePage/Model/HomePageContinueSetUpModel.swift
+++ b/DuckDuckGo/HomePage/Model/HomePageContinueSetUpModel.swift
@@ -51,10 +51,10 @@ extension HomePage.Models {
}
return false
}
- var isDay7SurveyEnabled: Bool {
+ var isDay14SurveyEnabled: Bool {
let newTabContinueSetUpSettings = privacyConfigurationManager.privacyConfig.settings(for: .newTabContinueSetUp)
- if let day7SurveyString = newTabContinueSetUpSettings["surveyCardDay7"] as? String {
- if day7SurveyString == "enabled" {
+ if let day14SurveyString = newTabContinueSetUpSettings["surveyCardDay14"] as? String {
+ if day14SurveyString == "enabled" {
return true
}
}
@@ -64,8 +64,8 @@ extension HomePage.Models {
let duckPlayerSettings = privacyConfigurationManager.privacyConfig.settings(for: .duckPlayer)
return duckPlayerSettings["tryDuckPlayerLink"] as? String ?? "https://www.youtube.com/watch?v=yKWIA-Pys4c"
}
- var day0SurveyURL: String = "https://selfserve.decipherinc.com/survey/selfserve/32ab/230701?list=1"
- var day7SurveyURL: String = "https://selfserve.decipherinc.com/survey/selfserve/32ab/230702?list=1"
+ var day0SurveyURL: String = "https://selfserve.decipherinc.com/survey/selfserve/32ab/240300?list=1"
+ var day14SurveyURL: String = "https://selfserve.decipherinc.com/survey/selfserve/32ab/240300?list=2"
private let defaultBrowserProvider: DefaultBrowserProvider
private let dataImportProvider: DataImportStatusProviding
@@ -73,6 +73,7 @@ extension HomePage.Models {
private let emailManager: EmailManager
private let privacyPreferences: PrivacySecurityPreferences
private let duckPlayerPreferences: DuckPlayerPreferencesPersistor
+ private let randomNumberGenerator: RandomNumberGenerating
@UserDefaultsWrapper(key: .homePageShowAllFeatures, defaultValue: false)
var shouldShowAllFeatures: Bool {
@@ -102,12 +103,18 @@ extension HomePage.Models {
@UserDefaultsWrapper(key: .shouldShowDBPWaitlistInvitedCardUI, defaultValue: false)
private var shouldShowDBPWaitlistInvitedCardUI: Bool
- @UserDefaultsWrapper(key: .homePageShowSurveyDay7, defaultValue: true)
- private var shouldShowSurveyDay7: Bool
+ @UserDefaultsWrapper(key: .homePageShowSurveyDay14, defaultValue: true)
+ private var shouldShowSurveyDay14: Bool
@UserDefaultsWrapper(key: .homePageIsFirstSession, defaultValue: true)
private var isFirstSession: Bool
+ @UserDefaultsWrapper(key: .homePageShowSurveyDay0in10Percent, defaultValue: nil)
+ private var isPartOfSurveyDay0On10Percent: Bool?
+
+ @UserDefaultsWrapper(key: .homePageShowSurveyDay14in10Percent, defaultValue: nil)
+ private var isPartOfSurveyDay14On10Percent: Bool?
+
@UserDefaultsWrapper(key: .firstLaunchDate, defaultValue: Calendar.current.date(byAdding: .month, value: -1, to: Date())!)
private var firstLaunchDate: Date
@@ -138,7 +145,8 @@ extension HomePage.Models {
privacyPreferences: PrivacySecurityPreferences = PrivacySecurityPreferences.shared,
duckPlayerPreferences: DuckPlayerPreferencesPersistor,
homePageRemoteMessaging: HomePageRemoteMessaging,
- privacyConfigurationManager: PrivacyConfigurationManaging = AppPrivacyFeatures.shared.contentBlocking.privacyConfigurationManager) {
+ privacyConfigurationManager: PrivacyConfigurationManaging = AppPrivacyFeatures.shared.contentBlocking.privacyConfigurationManager,
+ randomNumberGenerator: RandomNumberGenerating = RandomNumberGenerator()) {
self.defaultBrowserProvider = defaultBrowserProvider
self.dataImportProvider = dataImportProvider
self.tabCollectionViewModel = tabCollectionViewModel
@@ -147,6 +155,7 @@ extension HomePage.Models {
self.duckPlayerPreferences = duckPlayerPreferences
self.homePageRemoteMessaging = homePageRemoteMessaging
self.privacyConfigurationManager = privacyConfigurationManager
+ self.randomNumberGenerator = randomNumberGenerator
refreshFeaturesMatrix()
@@ -175,8 +184,8 @@ extension HomePage.Models {
tabCollectionViewModel.append(tab: tab)
case .surveyDay0:
visitSurvey(day: .day0)
- case .surveyDay7:
- visitSurvey(day: .day7)
+ case .surveyDay14:
+ visitSurvey(day: .day14)
case .networkProtectionRemoteMessage(let message):
handle(remoteMessage: message)
case .dataBrokerProtectionRemoteMessage(let message):
@@ -200,8 +209,8 @@ extension HomePage.Models {
shouldShowEmailProtectionSetting = false
case .surveyDay0:
shouldShowSurveyDay0 = false
- case .surveyDay7:
- shouldShowSurveyDay7 = false
+ case .surveyDay14:
+ shouldShowSurveyDay14 = false
case .networkProtectionRemoteMessage(let message):
#if NETWORK_PROTECTION
homePageRemoteMessaging.networkProtectionRemoteMessaging.dismiss(message: message)
@@ -268,9 +277,10 @@ extension HomePage.Models {
case .surveyDay0:
if shouldSurveyDay0BeVisible {
features.append(feature)
+ userInteractedWithSurveyDay0 = true
}
- case .surveyDay7:
- if shouldSurveyDay7BeVisible {
+ case .surveyDay14:
+ if shouldSurveyDay14BeVisible {
features.append(feature)
}
case .networkProtectionRemoteMessage, .dataBrokerProtectionRemoteMessage, .dataBrokerProtectionWaitlistInvited:
@@ -355,22 +365,39 @@ extension HomePage.Models {
let oneDayAgo = Calendar.current.date(byAdding: .weekday, value: -1, to: Date())!
return isDay0SurveyEnabled &&
shouldShowSurveyDay0 &&
- !userInteractedWithSurveyDay0 &&
- firstLaunchDate > oneDayAgo
+ firstLaunchDate >= oneDayAgo &&
+ Bundle.main.preferredLocalizations.first == "en" &&
+ isPartOfSurveyDay0On10Percent ?? calculateIfIn10percent(day: .day0)
}
- private var shouldSurveyDay7BeVisible: Bool {
- let oneWeekAgo = Calendar.current.date(byAdding: .weekOfYear, value: -1, to: Date())!
- return isDay7SurveyEnabled &&
+ private var shouldSurveyDay14BeVisible: Bool {
+ let fourteenDaysAgo = Calendar.current.date(byAdding: .weekday, value: -14, to: Date())!
+ let fifteenDaysAgo = Calendar.current.date(byAdding: .weekday, value: -15, to: Date())!
+ return isDay14SurveyEnabled &&
shouldShowSurveyDay0 &&
- shouldShowSurveyDay7 &&
+ shouldShowSurveyDay14 &&
!userInteractedWithSurveyDay0 &&
- firstLaunchDate <= oneWeekAgo
+ firstLaunchDate >= fifteenDaysAgo &&
+ firstLaunchDate <= fourteenDaysAgo &&
+ Bundle.main.preferredLocalizations.first == "en" &&
+ isPartOfSurveyDay14On10Percent ?? calculateIfIn10percent(day: .day14)
+ }
+
+ private func calculateIfIn10percent(day: SurveyDay) -> Bool {
+ let randomNumber0To99 = randomNumberGenerator.random(in: 0..<100)
+ let isInSurvey10Percent = randomNumber0To99 < 10
+ switch day {
+ case .day0:
+ isPartOfSurveyDay0On10Percent = isInSurvey10Percent
+ case .day14:
+ isPartOfSurveyDay14On10Percent = isInSurvey10Percent
+ }
+ return isInSurvey10Percent
}
private enum SurveyDay {
case day0
- case day7
+ case day14
}
@MainActor private func visitSurvey(day: SurveyDay) {
@@ -378,11 +405,8 @@ extension HomePage.Models {
switch day {
case .day0:
surveyURLString = day0SurveyURL
- case .day7:
- surveyURLString = day7SurveyURL
- }
- if let atb = statisticsStore.atb {
- surveyURLString += "&atb=\(atb)"
+ case .day14:
+ surveyURLString = day14SurveyURL
}
if let url = URL(string: surveyURLString) {
@@ -390,9 +414,9 @@ extension HomePage.Models {
tabCollectionViewModel.append(tab: tab)
switch day {
case .day0:
- userInteractedWithSurveyDay0 = true
- case .day7:
- shouldShowSurveyDay7 = false
+ shouldShowSurveyDay0 = false
+ case .day14:
+ shouldShowSurveyDay14 = false
}
}
}
@@ -457,7 +481,7 @@ extension HomePage.Models {
// We ignore the `networkProtectionRemoteMessage` case here to avoid it getting accidentally included - it has special handling and will get
// included elsewhere.
static var allCases: [HomePage.Models.FeatureType] {
- [.duckplayer, .emailProtection, .defaultBrowser, .importBookmarksAndPasswords, .surveyDay0, .surveyDay7]
+ [.duckplayer, .emailProtection, .defaultBrowser, .importBookmarksAndPasswords, .surveyDay0, .surveyDay14]
}
case duckplayer
@@ -465,7 +489,7 @@ extension HomePage.Models {
case defaultBrowser
case importBookmarksAndPasswords
case surveyDay0
- case surveyDay7
+ case surveyDay14
case networkProtectionRemoteMessage(NetworkProtectionRemoteMessage)
case dataBrokerProtectionRemoteMessage(DataBrokerProtectionRemoteMessage)
case dataBrokerProtectionWaitlistInvited
@@ -482,8 +506,8 @@ extension HomePage.Models {
return UserText.newTabSetUpEmailProtectionCardTitle
case .surveyDay0:
return UserText.newTabSetUpSurveyDay0CardTitle
- case .surveyDay7:
- return UserText.newTabSetUpSurveyDay7CardTitle
+ case .surveyDay14:
+ return UserText.newTabSetUpSurveyDay14CardTitle
case .networkProtectionRemoteMessage(let message):
return message.cardTitle
case .dataBrokerProtectionRemoteMessage(let message):
@@ -505,8 +529,8 @@ extension HomePage.Models {
return UserText.newTabSetUpEmailProtectionSummary
case .surveyDay0:
return UserText.newTabSetUpSurveyDay0Summary
- case .surveyDay7:
- return UserText.newTabSetUpSurveyDay7Summary
+ case .surveyDay14:
+ return UserText.newTabSetUpSurveyDay14Summary
case .networkProtectionRemoteMessage(let message):
return message.cardDescription
case .dataBrokerProtectionRemoteMessage(let message):
@@ -528,8 +552,8 @@ extension HomePage.Models {
return UserText.newTabSetUpEmailProtectionAction
case .surveyDay0:
return UserText.newTabSetUpSurveyDay0Action
- case .surveyDay7:
- return UserText.newTabSetUpSurveyDay7Action
+ case .surveyDay14:
+ return UserText.newTabSetUpSurveyDay14Action
case .networkProtectionRemoteMessage(let message):
return message.action.actionTitle
case .dataBrokerProtectionRemoteMessage(let message):
@@ -552,9 +576,9 @@ extension HomePage.Models {
case .emailProtection:
return .inbox128.resized(to: iconSize)!
case .surveyDay0:
- return .survey128.resized(to: iconSize)!
- case .surveyDay7:
- return .survey128.resized(to: iconSize)!
+ return .qandA128.resized(to: iconSize)!
+ case .surveyDay14:
+ return .qandA128.resized(to: iconSize)!
case .networkProtectionRemoteMessage:
return .vpnEnded.resized(to: iconSize)!
case .dataBrokerProtectionRemoteMessage:
@@ -617,3 +641,13 @@ struct HomePageRemoteMessaging {
#endif
}
+
+public protocol RandomNumberGenerating {
+ func random(in range: Range) -> Int
+}
+
+struct RandomNumberGenerator: RandomNumberGenerating {
+ func random(in range: Range) -> Int {
+ return Int.random(in: range)
+ }
+}
diff --git a/DuckDuckGo/Localizable.xcstrings b/DuckDuckGo/Localizable.xcstrings
index 9347c6977d..a00894c192 100644
--- a/DuckDuckGo/Localizable.xcstrings
+++ b/DuckDuckGo/Localizable.xcstrings
@@ -29509,120 +29509,120 @@
}
},
"newTab.setup.survey.day.0.action" : {
- "comment" : "Action title of the Day 0 durvey of the Set Up section in the home page",
+ "comment" : "Action title of the Day 0 survey of the Set Up section in the home page",
"extractionState" : "extracted_with_value",
"localizations" : {
"de" : {
"stringUnit" : {
- "state" : "translated",
+ "state" : "needs_review",
"value" : "Teile deine Gedanken"
}
},
"en" : {
"stringUnit" : {
"state" : "new",
- "value" : "Share Your Thoughts"
+ "value" : "Sign Up To Participate"
}
},
"es" : {
"stringUnit" : {
- "state" : "translated",
+ "state" : "needs_review",
"value" : "Comparte tus ideas"
}
},
"fr" : {
"stringUnit" : {
- "state" : "translated",
+ "state" : "needs_review",
"value" : "Partagez votre avis"
}
},
"it" : {
"stringUnit" : {
- "state" : "translated",
+ "state" : "needs_review",
"value" : "Comunicaci la tua opinione"
}
},
"nl" : {
"stringUnit" : {
- "state" : "translated",
+ "state" : "needs_review",
"value" : "Deel je gedachten"
}
},
"pl" : {
"stringUnit" : {
- "state" : "translated",
+ "state" : "needs_review",
"value" : "Podziel się przemyśleniami"
}
},
"pt" : {
"stringUnit" : {
- "state" : "translated",
+ "state" : "needs_review",
"value" : "Partilha as tuas opiniões"
}
},
"ru" : {
"stringUnit" : {
- "state" : "translated",
+ "state" : "needs_review",
"value" : "Поделиться соображениями"
}
}
}
},
"newTab.setup.survey.day.0.summary" : {
- "comment" : "Summary of the Day 0 durvey of the Set Up section in the home page",
+ "comment" : "Summary of the card on the new tab page that invites users to partecipate to a survey",
"extractionState" : "extracted_with_value",
"localizations" : {
"de" : {
"stringUnit" : {
- "state" : "translated",
+ "state" : "needs_review",
"value" : "Nimm an unserer kurzen Umfrage teil und hilf uns, den besten Browser zu entwickeln."
}
},
"en" : {
"stringUnit" : {
"state" : "new",
- "value" : "Take our short survey and help us build the best browser."
+ "value" : "Join an interview with a member of our research team to help us build the best browser."
}
},
"es" : {
"stringUnit" : {
- "state" : "translated",
+ "state" : "needs_review",
"value" : "Responde a nuestra breve encuesta y ayúdanos a crear el mejor navegador."
}
},
"fr" : {
"stringUnit" : {
- "state" : "translated",
+ "state" : "needs_review",
"value" : "Répondez à notre courte enquête et aidez-nous à créer le meilleur navigateur."
}
},
"it" : {
"stringUnit" : {
- "state" : "translated",
+ "state" : "needs_review",
"value" : "Rispondi al nostro breve sondaggio e aiutaci a creare il browser migliore."
}
},
"nl" : {
"stringUnit" : {
- "state" : "translated",
+ "state" : "needs_review",
"value" : "Vul onze korte enquête in en help ons de beste browser te bouwen."
}
},
"pl" : {
"stringUnit" : {
- "state" : "translated",
+ "state" : "needs_review",
"value" : "Weź udział w krótkiej ankiecie i pomóż nam opracować najlepszą przeglądarkę."
}
},
"pt" : {
"stringUnit" : {
- "state" : "translated",
+ "state" : "needs_review",
"value" : "Responde ao nosso curto inquérito e ajuda-nos a criar o melhor navegador."
}
},
"ru" : {
"stringUnit" : {
- "state" : "translated",
+ "state" : "needs_review",
"value" : "Пройдите короткий опрос и помогите DuckDuckGo стать лучшим из браузеров."
}
}
@@ -29634,55 +29634,55 @@
"localizations" : {
"de" : {
"stringUnit" : {
- "state" : "translated",
+ "state" : "needs_review",
"value" : "Sag uns, was dich hierher gebracht hat"
}
},
"en" : {
"stringUnit" : {
"state" : "new",
- "value" : "Tell Us What Brought You Here"
+ "value" : "Share Your Thoughts With Us"
}
},
"es" : {
"stringUnit" : {
- "state" : "translated",
+ "state" : "needs_review",
"value" : "Cuéntanos qué te ha traído hasta aquí"
}
},
"fr" : {
"stringUnit" : {
- "state" : "translated",
+ "state" : "needs_review",
"value" : "Dites-nous ce qui vous amène ici"
}
},
"it" : {
"stringUnit" : {
- "state" : "translated",
+ "state" : "needs_review",
"value" : "Raccontaci cosa ti ha portato qui"
}
},
"nl" : {
"stringUnit" : {
- "state" : "translated",
+ "state" : "needs_review",
"value" : "Vertel ons wat je hier heeft gebracht"
}
},
"pl" : {
"stringUnit" : {
- "state" : "translated",
+ "state" : "needs_review",
"value" : "Powiedz nam, co Cię tu sprowadziło"
}
},
"pt" : {
"stringUnit" : {
- "state" : "translated",
+ "state" : "needs_review",
"value" : "Diz-nos o que te trouxe aqui"
}
},
"ru" : {
"stringUnit" : {
- "state" : "translated",
+ "state" : "needs_review",
"value" : "Что привело вас к нам"
}
}
@@ -29690,7 +29690,7 @@
},
"newTab.setup.survey.day.7.action" : {
"comment" : "Action title of the Day 7 durvey of the Set Up section in the home page",
- "extractionState" : "extracted_with_value",
+ "extractionState" : "stale",
"localizations" : {
"de" : {
"stringUnit" : {
@@ -29750,7 +29750,7 @@
},
"newTab.setup.survey.day.7.summary" : {
"comment" : "Summary of the Day 7 durvey of the Set Up section in the home page",
- "extractionState" : "extracted_with_value",
+ "extractionState" : "stale",
"localizations" : {
"de" : {
"stringUnit" : {
@@ -29810,7 +29810,7 @@
},
"newTab.setup.survey.day.7.title" : {
"comment" : "Title of the Day 7 durvey of the Set Up section in the home page",
- "extractionState" : "extracted_with_value",
+ "extractionState" : "stale",
"localizations" : {
"de" : {
"stringUnit" : {
@@ -29868,6 +29868,42 @@
}
}
},
+ "newTab.setup.survey.day.14.action" : {
+ "comment" : "Action title of the Day 14 survey of the Set Up section in the home page",
+ "extractionState" : "extracted_with_value",
+ "localizations" : {
+ "en" : {
+ "stringUnit" : {
+ "state" : "new",
+ "value" : "Sign Up To Participate"
+ }
+ }
+ }
+ },
+ "newTab.setup.survey.day.14.summary" : {
+ "comment" : "Summary of the card on the new tab page that invites users to partecipate to a survey",
+ "extractionState" : "extracted_with_value",
+ "localizations" : {
+ "en" : {
+ "stringUnit" : {
+ "state" : "new",
+ "value" : "Join an interview with a member of our research team to help us build the best browser."
+ }
+ }
+ }
+ },
+ "newTab.setup.survey.day.14.title" : {
+ "comment" : "Title of the Day 14 durvey of the Set Up section in the home page",
+ "extractionState" : "extracted_with_value",
+ "localizations" : {
+ "en" : {
+ "stringUnit" : {
+ "state" : "new",
+ "value" : "Share Your Thoughts With Us"
+ }
+ }
+ }
+ },
"next" : {
"comment" : "Next button",
"extractionState" : "extracted_with_value",
@@ -50524,4 +50560,4 @@
}
},
"version" : "1.0"
-}
+}
\ No newline at end of file
diff --git a/DuckDuckGo/Menus/MainMenu.swift b/DuckDuckGo/Menus/MainMenu.swift
index da7c0d9984..6c881a0dad 100644
--- a/DuckDuckGo/Menus/MainMenu.swift
+++ b/DuckDuckGo/Menus/MainMenu.swift
@@ -575,11 +575,14 @@ import SubscriptionUI
NSMenuItem(title: "Reset Pinned Tabs", action: #selector(MainViewController.resetPinnedTabs))
NSMenuItem(title: "Reset YouTube Overlay Interactions", action: #selector(MainViewController.resetDuckPlayerOverlayInteractions))
NSMenuItem(title: "Reset MakeDuckDuckYours user settings", action: #selector(MainViewController.resetMakeDuckDuckGoYoursUserSettings))
+ NSMenuItem(title: "Survey 10% on", action: #selector(MainViewController.in10PercentSurveyOn))
+ NSMenuItem(title: "Survey 10% off", action: #selector(MainViewController.in10PercentSurveyOff))
NSMenuItem(title: "Change Activation Date") {
NSMenuItem(title: "Today", action: #selector(MainViewController.changeInstallDateToToday), keyEquivalent: "N")
- NSMenuItem(title: "Less Than a 21 days Ago", action: #selector(MainViewController.changeInstallDateToLessThan21DaysAgo))
- NSMenuItem(title: "More Than 21 Days Ago", action: #selector(MainViewController.changeInstallDateToMoreThan21DaysAgoButLessThan27))
- NSMenuItem(title: "More Than 27 Days Ago", action: #selector(MainViewController.changeInstallDateToMoreThan27DaysAgo))
+ NSMenuItem(title: "Less Than a 1 days Ago", action: #selector(MainViewController.changeInstallDateToLessThan1DayAgo(_:)))
+ NSMenuItem(title: "More Than 1 Days Ago", action: #selector(MainViewController.changeInstallDateToMoreThan1DayAgoButLessThan14(_:)))
+ NSMenuItem(title: "More Than 14 Days Ago", action: #selector(MainViewController.changeInstallDateToMoreThan14DaysAgoButLessThan15(_:)))
+ NSMenuItem(title: "More Than 15 Days Ago", action: #selector(MainViewController.changeInstallDateToMoreThan15DaysAgo(_:)))
}
NSMenuItem(title: "Reset Email Protection InContext Signup Prompt", action: #selector(MainViewController.resetEmailProtectionInContextPrompt))
NSMenuItem(title: "Reset Daily Pixels", action: #selector(MainViewController.resetDailyPixels))
diff --git a/DuckDuckGo/Menus/MainMenuActions.swift b/DuckDuckGo/Menus/MainMenuActions.swift
index 2f4c286472..f3f9c43c19 100644
--- a/DuckDuckGo/Menus/MainMenuActions.swift
+++ b/DuckDuckGo/Menus/MainMenuActions.swift
@@ -708,7 +708,7 @@ extension MainViewController {
UserDefaults.standard.set(true, forKey: UserDefaultsWrapper.Key.homePageShowDuckPlayer.rawValue)
UserDefaults.standard.set(true, forKey: UserDefaultsWrapper.Key.homePageShowEmailProtection.rawValue)
UserDefaults.standard.set(true, forKey: UserDefaultsWrapper.Key.homePageShowSurveyDay0.rawValue)
- UserDefaults.standard.set(true, forKey: UserDefaultsWrapper.Key.homePageShowSurveyDay7.rawValue)
+ UserDefaults.standard.set(true, forKey: UserDefaultsWrapper.Key.homePageShowSurveyDay14.rawValue)
UserDefaults.standard.set(false, forKey: UserDefaultsWrapper.Key.homePageUserInteractedWithSurveyDay0.rawValue)
}
@@ -722,22 +722,37 @@ extension MainViewController {
UserDefaults.standard.removePersistentDomain(forName: DailyPixel.Constant.dailyPixelStorageIdentifier)
}
+ @objc func in10PercentSurveyOn(_ sender: Any?) {
+ UserDefaults.standard.set(true, forKey: UserDefaultsWrapper.Key.homePageShowSurveyDay14in10Percent.rawValue)
+ UserDefaults.standard.set(true, forKey: UserDefaultsWrapper.Key.homePageShowSurveyDay0in10Percent.rawValue)
+ }
+
+ @objc func in10PercentSurveyOff(_ sender: Any?) {
+ UserDefaults.standard.set(false, forKey: UserDefaultsWrapper.Key.homePageShowSurveyDay14in10Percent.rawValue)
+ UserDefaults.standard.set(false, forKey: UserDefaultsWrapper.Key.homePageShowSurveyDay0in10Percent.rawValue)
+ }
+
@objc func changeInstallDateToToday(_ sender: Any?) {
UserDefaults.standard.set(Date(), forKey: UserDefaultsWrapper.Key.firstLaunchDate.rawValue)
}
- @objc func changeInstallDateToLessThan21DaysAgo(_ sender: Any?) {
- let lessThanTwentyOneDaysAgo = Calendar.current.date(byAdding: .day, value: -20, to: Date())
- UserDefaults.standard.set(lessThanTwentyOneDaysAgo, forKey: UserDefaultsWrapper.Key.firstLaunchDate.rawValue)
+ @objc func changeInstallDateToLessThan1DayAgo(_ sender: Any?) {
+ let lessThanOneDaysAgo = Calendar.current.date(byAdding: .hour, value: -23, to: Date())
+ UserDefaults.standard.set(lessThanOneDaysAgo, forKey: UserDefaultsWrapper.Key.firstLaunchDate.rawValue)
}
- @objc func changeInstallDateToMoreThan21DaysAgoButLessThan27(_ sender: Any?) {
- let twentyOneDaysAgo = Calendar.current.date(byAdding: .day, value: -21, to: Date())
- UserDefaults.standard.set(twentyOneDaysAgo, forKey: UserDefaultsWrapper.Key.firstLaunchDate.rawValue)
+ @objc func changeInstallDateToMoreThan1DayAgoButLessThan14(_ sender: Any?) {
+ let between1And4DaysAgo = Calendar.current.date(byAdding: .day, value: -13, to: Date())
+ UserDefaults.standard.set(between1And4DaysAgo, forKey: UserDefaultsWrapper.Key.firstLaunchDate.rawValue)
+ }
+
+ @objc func changeInstallDateToMoreThan14DaysAgoButLessThan15(_ sender: Any?) {
+ let twentyEightDaysAgo = Calendar.current.date(byAdding: .day, value: -14, to: Date())
+ UserDefaults.standard.set(twentyEightDaysAgo, forKey: UserDefaultsWrapper.Key.firstLaunchDate.rawValue)
}
- @objc func changeInstallDateToMoreThan27DaysAgo(_ sender: Any?) {
- let twentyEightDaysAgo = Calendar.current.date(byAdding: .day, value: -28, to: Date())
+ @objc func changeInstallDateToMoreThan15DaysAgo(_ sender: Any?) {
+ let twentyEightDaysAgo = Calendar.current.date(byAdding: .day, value: -16, to: Date())
UserDefaults.standard.set(twentyEightDaysAgo, forKey: UserDefaultsWrapper.Key.firstLaunchDate.rawValue)
}
diff --git a/DuckDuckGo/Preferences/Model/AppearancePreferences.swift b/DuckDuckGo/Preferences/Model/AppearancePreferences.swift
index 28b4c55576..ab73548d08 100644
--- a/DuckDuckGo/Preferences/Model/AppearancePreferences.swift
+++ b/DuckDuckGo/Preferences/Model/AppearancePreferences.swift
@@ -248,8 +248,10 @@ final class AppearancePreferences: ObservableObject {
}
var isContinueSetUpAvailable: Bool {
+ let osVersion = ProcessInfo.processInfo.operatingSystemVersion
+
let privacyConfig = AppPrivacyFeatures.shared.contentBlocking.privacyConfigurationManager.privacyConfig
- return privacyConfig.isEnabled(featureKey: .newTabContinueSetUp)
+ return privacyConfig.isEnabled(featureKey: .newTabContinueSetUp) && osVersion.majorVersion >= 12
}
func updateUserInterfaceStyle() {
diff --git a/UnitTests/HomePage/ContinueSetUpModelTests.swift b/UnitTests/HomePage/ContinueSetUpModelTests.swift
index e9411db6e1..817fc5bfb0 100644
--- a/UnitTests/HomePage/ContinueSetUpModelTests.swift
+++ b/UnitTests/HomePage/ContinueSetUpModelTests.swift
@@ -71,12 +71,16 @@ final class ContinueSetUpModelTests: XCTestCase {
var privacyPreferences: PrivacySecurityPreferences!
var duckPlayerPreferences: DuckPlayerPreferencesPersistor!
var privacyConfigManager: MockPrivacyConfigurationManager!
+ var randomNumberGenerator: MockRandomNumberGenerator!
let userDefaults = UserDefaults(suiteName: "\(Bundle.main.bundleIdentifier!).\(NSApplication.runType)")!
@MainActor override func setUp() {
UserDefaultsWrapper.clearAll()
userDefaults.set(Date(), forKey: UserDefaultsWrapper.Key.firstLaunchDate.rawValue)
userDefaults.set(false, forKey: UserDefaultsWrapper.Key.homePageUserInteractedWithSurveyDay0.rawValue)
+ userDefaults.set(nil, forKey: UserDefaultsWrapper.Key.homePageShowSurveyDay0in10Percent.rawValue)
+ userDefaults.set(nil, forKey: UserDefaultsWrapper.Key.homePageShowSurveyDay14in10Percent.rawValue)
+ userDefaults.set(false, forKey: UserDefaultsWrapper.Key.homePageUserInteractedWithSurveyDay0.rawValue)
capturingDefaultBrowserProvider = CapturingDefaultBrowserProvider()
capturingDataImportProvider = CapturingDataImportProvider()
tabCollectionVM = TabCollectionViewModel()
@@ -88,9 +92,10 @@ final class ContinueSetUpModelTests: XCTestCase {
let config = MockPrivacyConfiguration()
config.featureSettings = [
"surveyCardDay0": "enabled",
- "surveyCardDay7": "enabled"
+ "surveyCardDay14": "enabled"
] as! [String: String]
privacyConfigManager.privacyConfig = config
+ randomNumberGenerator = MockRandomNumberGenerator()
#if NETWORK_PROTECTION && DBP
let messaging = HomePageRemoteMessaging(
@@ -121,7 +126,8 @@ final class ContinueSetUpModelTests: XCTestCase {
privacyPreferences: privacyPreferences,
duckPlayerPreferences: duckPlayerPreferences,
homePageRemoteMessaging: messaging,
- privacyConfigurationManager: privacyConfigManager
+ privacyConfigurationManager: privacyConfigManager,
+ randomNumberGenerator: randomNumberGenerator
)
}
@@ -178,11 +184,42 @@ final class ContinueSetUpModelTests: XCTestCase {
vm.shouldShowAllFeatures = true
- expectedMatrix = expectedFeatureMatrixWithout(types: [.surveyDay7])
+ expectedMatrix = expectedFeatureMatrixWithout(types: [.surveyDay14])
XCTAssertEqual(vm.visibleFeaturesMatrix, expectedMatrix)
}
+ @MainActor func testWhenInstallDateIsLessThanADayAgoThenRandomGeneratorIsRequestARandomNumberInTheCorrectRange() {
+ XCTAssertEqual(randomNumberGenerator.capturedRange, 0..<100)
+ }
+
+ @MainActor func WhenInstallDateIsMoreThan14daysAgoDay14ThenRandomGeneratorIsRequestARandomNumberInTheCorrectRange() {
+ let twoWeeksAgo = Calendar.current.date(byAdding: .day, value: -16, to: Date())!
+ userDefaults.set(twoWeeksAgo, forKey: UserDefaultsWrapper.Key.firstLaunchDate.rawValue)
+ userDefaults.set(false, forKey: UserDefaultsWrapper.Key.homePageUserInteractedWithSurveyDay0.rawValue)
+ vm = HomePage.Models.ContinueSetUpModel.fixture(appGroupUserDefaults: userDefaults)
+
+ XCTAssertEqual(randomNumberGenerator.capturedRange, 0..<100)
+ }
+
+ @MainActor func testWhenInstallDateIsLessThanADayAgoButUserNotIn10PercentNoSurveyCardIsShown() {
+ let aDayAgo = Calendar.current.date(byAdding: .day, value: -1, to: Date())!
+ userDefaults.set(aDayAgo, forKey: UserDefaultsWrapper.Key.firstLaunchDate.rawValue)
+ var randomGenerator = MockRandomNumberGenerator()
+ randomGenerator.numberToReturn = 10
+ vm = HomePage.Models.ContinueSetUpModel.fixture(appGroupUserDefaults: userDefaults, randomNumberGenerator: randomGenerator)
+ vm.shouldShowAllFeatures = true
+
+ XCTAssertFalse(vm.visibleFeaturesMatrix.reduce([], +).contains(HomePage.Models.FeatureType.surveyDay0))
+ XCTAssertFalse(vm.visibleFeaturesMatrix.reduce([], +).contains(HomePage.Models.FeatureType.surveyDay14))
+
+ userDefaults.set(aDayAgo, forKey: UserDefaultsWrapper.Key.firstLaunchDate.rawValue)
+ vm = HomePage.Models.ContinueSetUpModel.fixture(appGroupUserDefaults: userDefaults)
+
+ XCTAssertFalse(vm.visibleFeaturesMatrix.reduce([], +).contains(HomePage.Models.FeatureType.surveyDay0))
+ XCTAssertFalse(vm.visibleFeaturesMatrix.reduce([], +).contains(HomePage.Models.FeatureType.surveyDay14))
+ }
+
@MainActor func testWhenInstallDateIsMoreThanADayAgoButLessThanAWeekAgoNoSurveyCardIsShown() {
let aDayAgo = Calendar.current.date(byAdding: .day, value: -1, to: Date())!
userDefaults.set(aDayAgo, forKey: UserDefaultsWrapper.Key.firstLaunchDate.rawValue)
@@ -190,49 +227,78 @@ final class ContinueSetUpModelTests: XCTestCase {
vm.shouldShowAllFeatures = true
XCTAssertFalse(vm.visibleFeaturesMatrix.reduce([], +).contains(HomePage.Models.FeatureType.surveyDay0))
- XCTAssertFalse(vm.visibleFeaturesMatrix.reduce([], +).contains(HomePage.Models.FeatureType.surveyDay7))
+ XCTAssertFalse(vm.visibleFeaturesMatrix.reduce([], +).contains(HomePage.Models.FeatureType.surveyDay14))
userDefaults.set(aDayAgo, forKey: UserDefaultsWrapper.Key.firstLaunchDate.rawValue)
vm = HomePage.Models.ContinueSetUpModel.fixture(appGroupUserDefaults: userDefaults)
XCTAssertFalse(vm.visibleFeaturesMatrix.reduce([], +).contains(HomePage.Models.FeatureType.surveyDay0))
- XCTAssertFalse(vm.visibleFeaturesMatrix.reduce([], +).contains(HomePage.Models.FeatureType.surveyDay7))
+ XCTAssertFalse(vm.visibleFeaturesMatrix.reduce([], +).contains(HomePage.Models.FeatureType.surveyDay14))
}
- @MainActor func testWhenInstallDateIsMoreThanAWeekAgoDay7SurveyCardIsShown() {
- let aDayAgo = Calendar.current.date(byAdding: .day, value: -7, to: Date())!
- userDefaults.set(aDayAgo, forKey: UserDefaultsWrapper.Key.firstLaunchDate.rawValue)
+ @MainActor func testWhenInstallDateIsMoreThan14daysAgoDay14SurveyCardIsShown() {
+ let twoWeeksAgo = Calendar.current.date(byAdding: .day, value: -14, to: Date())!
+ userDefaults.set(twoWeeksAgo, forKey: UserDefaultsWrapper.Key.firstLaunchDate.rawValue)
+ userDefaults.set(false, forKey: UserDefaultsWrapper.Key.homePageUserInteractedWithSurveyDay0.rawValue)
vm = HomePage.Models.ContinueSetUpModel.fixture(appGroupUserDefaults: userDefaults)
vm.shouldShowAllFeatures = true
XCTAssertFalse(vm.visibleFeaturesMatrix.reduce([], +).contains(HomePage.Models.FeatureType.surveyDay0))
- XCTAssertTrue(vm.visibleFeaturesMatrix.reduce([], +).contains(HomePage.Models.FeatureType.surveyDay7))
+ XCTAssertTrue(vm.visibleFeaturesMatrix.reduce([], +).contains(HomePage.Models.FeatureType.surveyDay14))
}
- @MainActor func testWhenInstallDateIsMoreThanAWeekAgoAndUserInteractedWithDay0SurveyDay7SurveyCardIsNotShown() {
+ @MainActor func testWhenInstallDateIsMoreThan14daysAgoDay14ButUserNotIn10percentSurveyCardIsNotShown() {
+ let twoWeeksAgo = Calendar.current.date(byAdding: .day, value: -14, to: Date())!
+ userDefaults.set(twoWeeksAgo, forKey: UserDefaultsWrapper.Key.firstLaunchDate.rawValue)
+ userDefaults.set(nil, forKey: UserDefaultsWrapper.Key.homePageShowSurveyDay14in10Percent.rawValue)
+ userDefaults.set(false, forKey: UserDefaultsWrapper.Key.homePageUserInteractedWithSurveyDay0.rawValue)
+
+ let randomGenerator = MockRandomNumberGenerator()
+ randomGenerator.numberToReturn = 10
+ vm = HomePage.Models.ContinueSetUpModel.fixture(appGroupUserDefaults: userDefaults, randomNumberGenerator: randomGenerator)
+ vm.shouldShowAllFeatures = true
+
+ XCTAssertFalse(vm.visibleFeaturesMatrix.reduce([], +).contains(HomePage.Models.FeatureType.surveyDay0))
+ XCTAssertFalse(vm.visibleFeaturesMatrix.reduce([], +).contains(HomePage.Models.FeatureType.surveyDay14))
+ }
+
+ @MainActor func testWhenInstallDateIsMoreThan15daysAgoDay14SurveyCardIsShown() {
+ let twoWeeksAgo = Calendar.current.date(byAdding: .day, value: -16, to: Date())!
+ userDefaults.set(twoWeeksAgo, forKey: UserDefaultsWrapper.Key.firstLaunchDate.rawValue)
+ userDefaults.set(false, forKey: UserDefaultsWrapper.Key.homePageUserInteractedWithSurveyDay0.rawValue)
+ vm = HomePage.Models.ContinueSetUpModel.fixture(appGroupUserDefaults: userDefaults)
+ vm.shouldShowAllFeatures = true
+
+ XCTAssertFalse(vm.visibleFeaturesMatrix.reduce([], +).contains(HomePage.Models.FeatureType.surveyDay0))
+ XCTAssertFalse(vm.visibleFeaturesMatrix.reduce([], +).contains(HomePage.Models.FeatureType.surveyDay14))
+ }
+
+ @MainActor func testWhenInstallDateIsMoreThan14daysAgoAndUserInteractedWithDay0SurveyDay14SurveyCardIsNotShown() {
let statisticStore = MockStatisticsStore()
vm.statisticsStore = statisticStore
vm.performAction(for: .surveyDay0)
- let aDayAgo = Calendar.current.date(byAdding: .day, value: -7, to: Date())!
+ let aDayAgo = Calendar.current.date(byAdding: .day, value: -14, to: Date())!
userDefaults.set(aDayAgo, forKey: UserDefaultsWrapper.Key.firstLaunchDate.rawValue)
+ userDefaults.set(false, forKey: UserDefaultsWrapper.Key.homePageUserInteractedWithSurveyDay0.rawValue)
vm = HomePage.Models.ContinueSetUpModel.fixture(appGroupUserDefaults: userDefaults)
vm.shouldShowAllFeatures = true
XCTAssertFalse(vm.visibleFeaturesMatrix.reduce([], +).contains(HomePage.Models.FeatureType.surveyDay0))
- XCTAssertFalse(vm.visibleFeaturesMatrix.reduce([], +).contains(HomePage.Models.FeatureType.surveyDay7))
+ XCTAssertFalse(vm.visibleFeaturesMatrix.reduce([], +).contains(HomePage.Models.FeatureType.surveyDay14))
}
- @MainActor func testWhenInstallDateIsMoreThanAWeekAgoAndUserDismissedDay0SurveyDay7SurveyCardIsNotShown() {
+ @MainActor func testWhenInstallDateIsMoreThanAWeekAgoAndUserDismissedDay0SurveyDay14SurveyCardIsNotShown() {
let statisticStore = MockStatisticsStore()
vm.statisticsStore = statisticStore
vm.removeItem(for: .surveyDay0)
- let aDayAgo = Calendar.current.date(byAdding: .day, value: -7, to: Date())!
+ let aDayAgo = Calendar.current.date(byAdding: .day, value: -14, to: Date())!
userDefaults.set(aDayAgo, forKey: UserDefaultsWrapper.Key.firstLaunchDate.rawValue)
+ userDefaults.set(false, forKey: UserDefaultsWrapper.Key.homePageUserInteractedWithSurveyDay0.rawValue)
vm = HomePage.Models.ContinueSetUpModel.fixture(appGroupUserDefaults: userDefaults)
vm.shouldShowAllFeatures = true
XCTAssertFalse(vm.visibleFeaturesMatrix.reduce([], +).contains(HomePage.Models.FeatureType.surveyDay0))
- XCTAssertFalse(vm.visibleFeaturesMatrix.reduce([], +).contains(HomePage.Models.FeatureType.surveyDay7))
+ XCTAssertFalse(vm.visibleFeaturesMatrix.reduce([], +).contains(HomePage.Models.FeatureType.surveyDay14))
}
@MainActor func testWhenInitializedNotForTheFirstTimeTheMatrixHasAllElementsInTheRightOrder() {
@@ -247,7 +313,7 @@ final class ContinueSetUpModelTests: XCTestCase {
}
func testWhenTogglingShowAllFeatureThenCorrectElementsAreVisible() {
- let expectedMatrix = expectedFeatureMatrixWithout(types: [.surveyDay7])
+ let expectedMatrix = expectedFeatureMatrixWithout(types: [.surveyDay14])
vm.shouldShowAllFeatures = true
@@ -275,7 +341,7 @@ final class ContinueSetUpModelTests: XCTestCase {
}
@MainActor func testWhenIsDefaultBrowserAndTogglingShowAllFeatureThenCorrectElementsAreVisible() {
- let expectedMatrix = expectedFeatureMatrixWithout(types: [.defaultBrowser, .surveyDay7])
+ let expectedMatrix = expectedFeatureMatrixWithout(types: [.defaultBrowser, .surveyDay14])
capturingDefaultBrowserProvider.isDefault = true
vm = HomePage.Models.ContinueSetUpModel.fixture(defaultBrowserProvider: capturingDefaultBrowserProvider, appGroupUserDefaults: userDefaults)
@@ -303,7 +369,7 @@ final class ContinueSetUpModelTests: XCTestCase {
}
@MainActor func testWhenUserHasUsedImportAndTogglingShowAllFeatureThenCorrectElementsAreVisible() {
- let expectedMatrix = expectedFeatureMatrixWithout(types: [.surveyDay7, .importBookmarksAndPasswords])
+ let expectedMatrix = expectedFeatureMatrixWithout(types: [.surveyDay14, .importBookmarksAndPasswords])
capturingDataImportProvider.didImport = true
vm = HomePage.Models.ContinueSetUpModel.fixture(dataImportProvider: capturingDataImportProvider, appGroupUserDefaults: userDefaults)
@@ -325,7 +391,7 @@ final class ContinueSetUpModelTests: XCTestCase {
}
@MainActor func testWhenUserHasEmailProtectionEnabledThenCorrectElementsAreVisible() {
- let expectedMatrix = expectedFeatureMatrixWithout(types: [.surveyDay7, .emailProtection])
+ let expectedMatrix = expectedFeatureMatrixWithout(types: [.surveyDay14, .emailProtection])
emailStorage.isEmailProtectionEnabled = true
vm = HomePage.Models.ContinueSetUpModel.fixture(emailManager: emailManager, appGroupUserDefaults: userDefaults)
@@ -341,7 +407,7 @@ final class ContinueSetUpModelTests: XCTestCase {
}
@MainActor func testWhenUserHasCookieConsentEnabledThenCorrectElementsAreVisible() {
- let expectedMatrix = expectedFeatureMatrixWithout(types: [.surveyDay7])
+ let expectedMatrix = expectedFeatureMatrixWithout(types: [.surveyDay14])
privacyPreferences.autoconsentEnabled = true
vm = HomePage.Models.ContinueSetUpModel.fixture(privacyPreferences: privacyPreferences, appGroupUserDefaults: userDefaults)
@@ -363,7 +429,7 @@ final class ContinueSetUpModelTests: XCTestCase {
}
@MainActor func testWhenUserHasDuckPlayerEnabledAndOverlayButtonNotPressedThenCorrectElementsAreVisible() {
- let expectedMatrix = expectedFeatureMatrixWithout(types: [.surveyDay7, .duckplayer])
+ let expectedMatrix = expectedFeatureMatrixWithout(types: [.surveyDay14, .duckplayer])
duckPlayerPreferences.youtubeOverlayAnyButtonPressed = false
duckPlayerPreferences.duckPlayerModeBool = true
@@ -380,7 +446,7 @@ final class ContinueSetUpModelTests: XCTestCase {
}
@MainActor func testWhenUserHasDuckPlayerDisabledAndOverlayButtonNotPressedThenCorrectElementsAreVisible() {
- let expectedMatrix = expectedFeatureMatrixWithout(types: [.surveyDay7, .duckplayer])
+ let expectedMatrix = expectedFeatureMatrixWithout(types: [.surveyDay14, .duckplayer])
duckPlayerPreferences.youtubeOverlayAnyButtonPressed = false
duckPlayerPreferences.duckPlayerModeBool = false
@@ -397,7 +463,7 @@ final class ContinueSetUpModelTests: XCTestCase {
}
@MainActor func testWhenUserHasDuckPlayerOnAlwaysAskAndOverlayButtonNotPressedThenCorrectElementsAreVisible() {
- let expectedMatrix = expectedFeatureMatrixWithout(types: [.surveyDay7])
+ let expectedMatrix = expectedFeatureMatrixWithout(types: [.surveyDay14])
duckPlayerPreferences.youtubeOverlayAnyButtonPressed = false
duckPlayerPreferences.duckPlayerModeBool = nil
@@ -414,7 +480,7 @@ final class ContinueSetUpModelTests: XCTestCase {
}
@MainActor func testWhenUserHasDuckPlayerOnAlwaysAskAndOverlayButtonIsPressedThenCorrectElementsAreVisible() {
- let expectedMatrix = expectedFeatureMatrixWithout(types: [.surveyDay7, .duckplayer])
+ let expectedMatrix = expectedFeatureMatrixWithout(types: [.surveyDay14, .duckplayer])
duckPlayerPreferences.youtubeOverlayAnyButtonPressed = true
duckPlayerPreferences.duckPlayerModeBool = nil
@@ -437,17 +503,17 @@ final class ContinueSetUpModelTests: XCTestCase {
vm.statisticsStore = statisticStore
vm.performAction(for: .surveyDay0)
- XCTAssertEqual(tabCollectionVM.tabs[1].url, URL(string: vm.day0SurveyURL + "&atb=" + atb))
+ XCTAssertEqual(tabCollectionVM.tabs[1].url, URL(string: vm.day0SurveyURL))
}
- @MainActor func testWhenAskedToPerformActionForSurveyDay7ShowsTheSurveySite() {
+ @MainActor func testWhenAskedToPerformActionForSurveyDay14ShowsTheSurveySite() {
let atb = "someAtb"
let statisticStore = MockStatisticsStore()
statisticStore.atb = atb
vm.statisticsStore = statisticStore
- vm.performAction(for: .surveyDay7)
- XCTAssertEqual(tabCollectionVM.tabs[1].url, URL(string: vm.day7SurveyURL + "&atb=" + atb))
+ vm.performAction(for: .surveyDay14)
+ XCTAssertEqual(tabCollectionVM.tabs[1].url, URL(string: vm.day14SurveyURL))
}
@MainActor func testThatWhenIfAllFeatureActiveThenVisibleMatrixIsEmpty() {
@@ -457,7 +523,7 @@ final class ContinueSetUpModelTests: XCTestCase {
duckPlayerPreferences.youtubeOverlayAnyButtonPressed = true
capturingDataImportProvider.didImport = true
userDefaults.set(false, forKey: UserDefaultsWrapper.Key.homePageShowSurveyDay0.rawValue)
- userDefaults.set(false, forKey: UserDefaultsWrapper.Key.homePageShowSurveyDay7.rawValue)
+ userDefaults.set(false, forKey: UserDefaultsWrapper.Key.homePageShowSurveyDay14.rawValue)
vm = HomePage.Models.ContinueSetUpModel(
defaultBrowserProvider: capturingDefaultBrowserProvider,
@@ -474,7 +540,7 @@ final class ContinueSetUpModelTests: XCTestCase {
@MainActor func testDismissedItemsAreRemovedFromVisibleMatrixAndChoicesArePersisted() {
vm.shouldShowAllFeatures = true
- let expectedMatrix = expectedFeatureMatrixWithout(types: [.surveyDay7])
+ let expectedMatrix = expectedFeatureMatrixWithout(types: [.surveyDay14])
XCTAssertEqual(expectedMatrix, vm.visibleFeaturesMatrix)
vm.removeItem(for: .surveyDay0)
@@ -483,8 +549,8 @@ final class ContinueSetUpModelTests: XCTestCase {
userDefaults.set(Calendar.current.date(byAdding: .month, value: -1, to: Date())!, forKey: UserDefaultsWrapper.Key.firstLaunchDate.rawValue)
vm = HomePage.Models.ContinueSetUpModel.fixture(appGroupUserDefaults: userDefaults)
- vm.removeItem(for: .surveyDay7)
- XCTAssertFalse(vm.visibleFeaturesMatrix.flatMap { $0 }.contains(.surveyDay7))
+ vm.removeItem(for: .surveyDay14)
+ XCTAssertFalse(vm.visibleFeaturesMatrix.flatMap { $0 }.contains(.surveyDay14))
vm.removeItem(for: .defaultBrowser)
XCTAssertFalse(vm.visibleFeaturesMatrix.flatMap { $0 }.contains(.defaultBrowser))
@@ -564,11 +630,12 @@ extension HomePage.Models.ContinueSetUpModel {
privacyPreferences: PrivacySecurityPreferences = PrivacySecurityPreferences.shared,
duckPlayerPreferences: DuckPlayerPreferencesPersistor = DuckPlayerPreferencesPersistorMock(),
privacyConfig: MockPrivacyConfiguration = MockPrivacyConfiguration(),
- appGroupUserDefaults: UserDefaults
+ appGroupUserDefaults: UserDefaults,
+ randomNumberGenerator: RandomNumberGenerating = MockRandomNumberGenerator()
) -> HomePage.Models.ContinueSetUpModel {
privacyConfig.featureSettings = [
"surveyCardDay0": "enabled",
- "surveyCardDay7": "enabled",
+ "surveyCardDay14": "enabled",
"networkProtection": "disabled"
] as! [String: String]
let manager = MockPrivacyConfigurationManager()
@@ -603,6 +670,16 @@ extension HomePage.Models.ContinueSetUpModel {
privacyPreferences: privacyPreferences,
duckPlayerPreferences: duckPlayerPreferences,
homePageRemoteMessaging: messaging,
- privacyConfigurationManager: manager)
+ privacyConfigurationManager: manager,
+ randomNumberGenerator: randomNumberGenerator)
+ }
+}
+
+class MockRandomNumberGenerator: RandomNumberGenerating {
+ var numberToReturn = 0
+ var capturedRange: Range?
+ func random(in range: Range) -> Int {
+ capturedRange = range
+ return numberToReturn
}
}