diff --git a/.ruby-version b/.ruby-version
index b0f2dcb32f..a0891f563f 100644
--- a/.ruby-version
+++ b/.ruby-version
@@ -1 +1 @@
-3.0.4
+3.3.4
diff --git a/Configuration/BuildNumber.xcconfig b/Configuration/BuildNumber.xcconfig
index 1c2c93afcc..03d9d44d8b 100644
--- a/Configuration/BuildNumber.xcconfig
+++ b/Configuration/BuildNumber.xcconfig
@@ -1 +1 @@
-CURRENT_PROJECT_VERSION = 298
+CURRENT_PROJECT_VERSION = 300
diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj
index ba2d78553d..ed21f5ef87 100644
--- a/DuckDuckGo.xcodeproj/project.pbxproj
+++ b/DuckDuckGo.xcodeproj/project.pbxproj
@@ -14777,8 +14777,8 @@
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/duckduckgo/BrowserServicesKit";
requirement = {
- branch = "sam/vpn-clean-up";
- kind = branch;
+ kind = exactVersion;
+ version = 204.0.0;
};
};
9FF521422BAA8FF300B9819B /* XCRemoteSwiftPackageReference "lottie-spm" */ = {
diff --git a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved
index d5eb6f23ea..549b97007b 100644
--- a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved
+++ b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved
@@ -32,8 +32,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/duckduckgo/BrowserServicesKit",
"state" : {
- "branch" : "sam/vpn-clean-up",
- "revision" : "6fe4744a917154ca05e03308e0c44d0049cd3e54"
+ "revision" : "14594b6f3f3ddbea65be2818298e2e79305d8a26",
+ "version" : "204.0.0"
}
},
{
@@ -41,8 +41,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/duckduckgo/content-scope-scripts",
"state" : {
- "revision" : "48fee2508995d4ac02d18b3d55424adedcb4ce4f",
- "version" : "6.28.0"
+ "revision" : "6cab7bdb584653a5dc007cc1ae827ec41c5a91bc",
+ "version" : "6.29.0"
}
},
{
@@ -75,7 +75,7 @@
{
"identity" : "lottie-spm",
"kind" : "remoteSourceControl",
- "location" : "https://github.com/airbnb/lottie-spm.git",
+ "location" : "https://github.com/airbnb/lottie-spm",
"state" : {
"revision" : "1d29eccc24cc8b75bff9f6804155112c0ffc9605",
"version" : "4.4.3"
diff --git a/DuckDuckGo/Application/AppDelegate.swift b/DuckDuckGo/Application/AppDelegate.swift
index 8bce0390f3..14ae61f423 100644
--- a/DuckDuckGo/Application/AppDelegate.swift
+++ b/DuckDuckGo/Application/AppDelegate.swift
@@ -471,6 +471,8 @@ final class AppDelegate: NSObject, NSApplicationDelegate {
freemiumDBPScanResultPolling = DefaultFreemiumDBPScanResultPolling(dataManager: DataBrokerProtectionManager.shared.dataManager, freemiumDBPUserStateManager: freemiumDBPUserStateManager)
freemiumDBPScanResultPolling?.startPollingOrObserving()
+
+ PixelKit.fire(NonStandardEvent(GeneralPixel.launch(isDefault: DefaultBrowserPreferences().isDefault)))
}
private func fireFailedCompilationsPixelIfNeeded() {
diff --git a/DuckDuckGo/Assets.xcassets/Images/DefaultBrowserMenuItem.imageset/Contents.json b/DuckDuckGo/Assets.xcassets/Images/DefaultBrowserMenuItem.imageset/Contents.json
new file mode 100644
index 0000000000..6ad6fd43b8
--- /dev/null
+++ b/DuckDuckGo/Assets.xcassets/Images/DefaultBrowserMenuItem.imageset/Contents.json
@@ -0,0 +1,16 @@
+{
+ "images" : [
+ {
+ "filename" : "Set-as-Default-16D.svg",
+ "idiom" : "universal"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ },
+ "properties" : {
+ "preserves-vector-representation" : true,
+ "template-rendering-intent" : "template"
+ }
+}
diff --git a/DuckDuckGo/Assets.xcassets/Images/DefaultBrowserMenuItem.imageset/Set-as-Default-16D.svg b/DuckDuckGo/Assets.xcassets/Images/DefaultBrowserMenuItem.imageset/Set-as-Default-16D.svg
new file mode 100644
index 0000000000..b7cd82425a
--- /dev/null
+++ b/DuckDuckGo/Assets.xcassets/Images/DefaultBrowserMenuItem.imageset/Set-as-Default-16D.svg
@@ -0,0 +1,4 @@
+
diff --git a/DuckDuckGo/Assets.xcassets/Information-Remover-128.imageset/Contents.json b/DuckDuckGo/Assets.xcassets/Information-Remover-128.imageset/Contents.json
new file mode 100644
index 0000000000..6b0b87b470
--- /dev/null
+++ b/DuckDuckGo/Assets.xcassets/Information-Remover-128.imageset/Contents.json
@@ -0,0 +1,15 @@
+{
+ "images" : [
+ {
+ "filename" : "Information-Remover-128.pdf",
+ "idiom" : "universal"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ },
+ "properties" : {
+ "preserves-vector-representation" : true
+ }
+}
diff --git a/DuckDuckGo/Assets.xcassets/Information-Remover-128.imageset/Information-Remover-128.pdf b/DuckDuckGo/Assets.xcassets/Information-Remover-128.imageset/Information-Remover-128.pdf
new file mode 100644
index 0000000000..a770d6b848
Binary files /dev/null and b/DuckDuckGo/Assets.xcassets/Information-Remover-128.imageset/Information-Remover-128.pdf differ
diff --git a/DuckDuckGo/Bookmarks/Extensions/Bookmarks+Tab.swift b/DuckDuckGo/Bookmarks/Extensions/Bookmarks+Tab.swift
index 78c60f30ea..689cdc742e 100644
--- a/DuckDuckGo/Bookmarks/Extensions/Bookmarks+Tab.swift
+++ b/DuckDuckGo/Bookmarks/Extensions/Bookmarks+Tab.swift
@@ -28,6 +28,13 @@ extension Tab {
}
}
+ @MainActor
+ static func with(contentsOf bookmarks: [Bookmark], burnerMode: BurnerMode) -> [Tab] {
+ bookmarks.compactMap { bookmark -> Tab? in
+ guard let url = bookmark.urlObject else { return nil }
+ return Tab(content: .url(url, source: .bookmark), shouldLoadInBackground: true, burnerMode: burnerMode)
+ }
+ }
}
extension TabCollection {
diff --git a/DuckDuckGo/Bookmarks/Services/BookmarksContextMenu.swift b/DuckDuckGo/Bookmarks/Services/BookmarksContextMenu.swift
index 7fe6569ed6..17032a82e5 100644
--- a/DuckDuckGo/Bookmarks/Services/BookmarksContextMenu.swift
+++ b/DuckDuckGo/Bookmarks/Services/BookmarksContextMenu.swift
@@ -308,13 +308,17 @@ extension BookmarksContextMenu: BookmarkMenuItemSelectors {
}
@objc func toggleBookmarkAsFavorite(_ sender: NSMenuItem) {
- guard let bookmark = sender.representedObject as? Bookmark else {
+ if let bookmark = sender.representedObject as? Bookmark{
+ bookmark.isFavorite.toggle()
+ bookmarkManager.update(bookmark: bookmark)
+ } else if let bookmarks = sender.representedObject as? [Bookmark] {
+ bookmarks.forEach { bookmark in
+ bookmark.isFavorite.toggle()
+ bookmarkManager.update(bookmark: bookmark)
+ }
+ } else {
assertionFailure("Failed to cast menu represented object to Bookmark")
- return
}
-
- bookmark.isFavorite.toggle()
- bookmarkManager.update(bookmark: bookmark)
}
@MainActor
@@ -424,16 +428,20 @@ extension BookmarksContextMenu: FolderMenuItemSelectors {
@MainActor
@objc func openInNewTabs(_ sender: NSMenuItem) {
- guard let tabCollection = windowControllersManager.lastKeyMainWindowController?.mainViewController.tabCollectionViewModel,
- let folder = sender.representedObject as? BookmarkFolder
- else {
+ guard let tabCollection = windowControllersManager.lastKeyMainWindowController?.mainViewController.tabCollectionViewModel else {
assertionFailure("Cannot open all in new tabs")
return
}
- let tabs = Tab.withContentOfBookmark(folder: folder, burnerMode: tabCollection.burnerMode)
- tabCollection.append(tabs: tabs)
- PixelExperiment.fireOnboardingBookmarkUsed5to7Pixel()
+ if let folder = sender.representedObject as? BookmarkFolder {
+ let tabs = Tab.withContentOfBookmark(folder: folder, burnerMode: tabCollection.burnerMode)
+ tabCollection.append(tabs: tabs)
+ PixelExperiment.fireOnboardingBookmarkUsed5to7Pixel()
+ } else if let bookmarks = sender.representedObject as? [Bookmark] {
+ let tabs = Tab.with(contentsOf: bookmarks, burnerMode: tabCollection.burnerMode)
+ tabCollection.append(tabs: tabs)
+ PixelExperiment.fireOnboardingBookmarkUsed5to7Pixel()
+ }
}
@MainActor
diff --git a/DuckDuckGo/Common/Localizables/UserText.swift b/DuckDuckGo/Common/Localizables/UserText.swift
index e71f1e97ec..dc024a5a30 100644
--- a/DuckDuckGo/Common/Localizables/UserText.swift
+++ b/DuckDuckGo/Common/Localizables/UserText.swift
@@ -710,6 +710,7 @@ struct UserText {
static let aboutDuckDuckGo = NSLocalizedString("preferences.about.about-duckduckgo", value: "About DuckDuckGo", comment: "About screen")
static let duckduckgoTagline = NSLocalizedString("preferences.about.duckduckgo-tagline", value: "Your protection, our priority.", comment: "About screen")
+ static let setAsDefaultBrowser = NSLocalizedString("preferences.set-as-default", value: "Set DuckDuckGo As Default Browser", comment: "Menu option to set the browser as default")
static let aboutUnsupportedDeviceInfo1 = NSLocalizedString("preferences.about.unsupported-device-info1", value: "DuckDuckGo is no longer providing browser updates for your version of macOS.", comment: "This string represents a message informing the user that DuckDuckGo is no longer providing browser updates for their version of macOS")
static func aboutUnsupportedDeviceInfo2(version: String) -> String {
let localized = NSLocalizedString("preferences.about.unsupported-device-info2", value: "Please update to macOS %@ or later to use the most recent version of DuckDuckGo. You can also keep using your current version of the browser, but it will not receive further updates.", comment: "Copy in section that tells the user to update their macOS version since their current version is unsupported")
@@ -1382,41 +1383,49 @@ struct UserText {
// Comment: "Title for Freemium Personal Information Removal (Scan-Only) item in the options menu"
static let freemiumDBPOptionsMenuItem = "Free Personal Information Scan"
- // Key: "home.page.promotion.freemium.dbp.text"
- // Comment: "Text for the Freemium DBP Home Page Promotion"
- static let homePagePromotionFreemiumDBPText = "Find your personal info on sites that sell it."
+ // Key: "home.page.promotion.freemium.dbp.title"
+ // Comment: "Title for the Freemium DBP Home Page Promotion"
+ static let homePagePromotionFreemiumDBPTitle = "Personal Information Removal"
+
+ // Key: "home.page.promotion.freemium.dbp.description.markdown"
+ // Comment: "Markdown Description for the Freemium DBP Home Page Promotion"
+ static let homePagePromotionFreemiumDBPDescriptionMarkdown = "Find out which sites are selling **your info.**"
+
+ // Key: "home.page.promotion.freemium.dbp.description"
+ // Comment: "Description for the Freemium DBP Home Page Promotion"
+ static let homePagePromotionFreemiumDBPDescription = "Find out which sites are selling your info."
// Key: "home.page.promotion.freemium.dbp.button.title"
// Comment: "Title for the Freemium DBP Home Page Promotion Button"
static let homePagePromotionFreemiumDBPButtonTitle = "Free Scan"
- // Key: "home.page.promotion.freemium.dbp.post.scan.engagement.result.single.match.text"
- // Comment: "Text for the Freemium DBP Home Page Post Scan Engagement Promotion When Only One Record is Found"
- static let homePagePromotionFreemiumDBPPostScanEngagementResultSingleMatchText = "Your free personal info scan found 1 record about you on 1 site."
+ // Key: "home.page.promotion.freemium.dbp.post.scan.engagement.result.single.match.description"
+ // Comment: "Description for the Freemium DBP Home Page Post Scan Engagement Promotion When Only One Record is Found"
+ static let homePagePromotionFreemiumDBPPostScanEngagementResultSingleMatchDescription = "Your free personal info scan found 1 record about you on 1 site."
- /// Generates Text for the Freemium DBP Home Page Post Scan Engagement Promotion when records are found on a single broker site.
- /// Key: "home.page.promotion.freemium.dbp.post.scan.engagement.result.single.broker.text"
+ /// Generates Description for the Freemium DBP Home Page Post Scan Engagement Promotion when records are found on a single broker site.
+ /// Key: "home.page.promotion.freemium.dbp.post.scan.engagement.result.single.broker.description"
///
/// - Parameter resultCount: The number of records found.
/// - Returns: A formatted string indicating the number of records found on 1 site.
- static func homePagePromotionFreemiumDBPPostScanEngagementResultSingleBrokerText(resultCount: Int) -> String {
+ static func homePagePromotionFreemiumDBPPostScanEngagementResultSingleBrokerDescription(resultCount: Int) -> String {
String(format: "Your free personal info scan found %d records about you on 1 site.", resultCount)
}
- /// Generates Text for the Freemium DBP Home Page Post Scan Engagement Promotion when records are found on multiple broker sites.
- /// Key: "home.page.promotion.freemium.dbp.post.scan.engagement.result.plural.text"
+ /// Generates Description for the Freemium DBP Home Page Post Scan Engagement Promotion when records are found on multiple broker sites.
+ /// Key: "home.page.promotion.freemium.dbp.post.scan.engagement.result.plural.description"
///
/// - Parameters:
/// - resultCount: The number of records found.
/// - brokerCount: The number of broker sites where records were found.
/// - Returns: A formatted string indicating the number of records found on multiple sites.
- static func homePagePromotionFreemiumDBPPostScanEngagementResultPluralText(resultCount: Int, brokerCount: Int) -> String {
+ static func homePagePromotionFreemiumDBPPostScanEngagementResultPluralDescription(resultCount: Int, brokerCount: Int) -> String {
String(format: "Your free personal info scan found %d records about you on %d different sites.", resultCount, brokerCount)
}
- // Key: "home.page.promotion.freemium.dbp.post.scan.engagement.no.results.text"
- // Comment: "Text for the Freemium DBP Home Page Post Scan Engagement Promotion When There Are No Results"
- static let homePagePromotionFreemiumDBPPostScanEngagementNoResultsText = "Good news, your free personal info scan didn't find any records about you. We'll keep checking periodically."
+ // Key: "home.page.promotion.freemium.dbp.post.scan.engagement.no.results.description"
+ // Comment: "Description for the Freemium DBP Home Page Post Scan Engagement Promotion When There Are No Results"
+ static let homePagePromotionFreemiumDBPPostScanEngagementNoResultsDescription = "Good news, your free personal info scan didn't find any records about you. We'll keep checking periodically."
// Key: "home.page.promotion.freemium.dbp.post.scan.engagement.button.title"
// Comment: "Title for the Freemium DBP Home Page Post Scan Engagement Promotion Button"
diff --git a/DuckDuckGo/Common/Logger+Multiple.swift b/DuckDuckGo/Common/Logger+Multiple.swift
index f29c3e8b7e..8c48febea8 100644
--- a/DuckDuckGo/Common/Logger+Multiple.swift
+++ b/DuckDuckGo/Common/Logger+Multiple.swift
@@ -28,4 +28,5 @@ extension Logger {
static var tabSnapshots = { Logger(subsystem: "Tab Snapshots", category: "") }()
static var tabLazyLoading = { Logger(subsystem: "Lazy Loading", category: "") }()
static var updates = { Logger(subsystem: "Updates", category: "") }()
+ static var tabPreview = { Logger(subsystem: "Tab Preview", category: "") }()
}
diff --git a/DuckDuckGo/DBP/DataBrokerProtectionPixelsHandler.swift b/DuckDuckGo/DBP/DataBrokerProtectionPixelsHandler.swift
index cc4c928d89..223a57ee63 100644
--- a/DuckDuckGo/DBP/DataBrokerProtectionPixelsHandler.swift
+++ b/DuckDuckGo/DBP/DataBrokerProtectionPixelsHandler.swift
@@ -40,7 +40,7 @@ public class DataBrokerProtectionPixelsHandler: EventMapping
com.apple.security.device.camera
- com.apple.security.device.usb
-
com.apple.security.files.downloads.read-write
com.apple.security.files.user-selected.read-write
diff --git a/DuckDuckGo/DuckDuckGoAppStoreCI.entitlements b/DuckDuckGo/DuckDuckGoAppStoreCI.entitlements
index 789e45511c..f3cfd39790 100644
--- a/DuckDuckGo/DuckDuckGoAppStoreCI.entitlements
+++ b/DuckDuckGo/DuckDuckGoAppStoreCI.entitlements
@@ -16,8 +16,6 @@
com.apple.security.device.camera
- com.apple.security.device.usb
-
com.apple.security.files.downloads.read-write
com.apple.security.files.user-selected.read-write
diff --git a/DuckDuckGo/DuckDuckGoAppStoreDebug.entitlements b/DuckDuckGo/DuckDuckGoAppStoreDebug.entitlements
index 884910dc38..7502df54c6 100644
--- a/DuckDuckGo/DuckDuckGoAppStoreDebug.entitlements
+++ b/DuckDuckGo/DuckDuckGoAppStoreDebug.entitlements
@@ -21,8 +21,6 @@
com.apple.security.device.camera
- com.apple.security.device.usb
-
com.apple.security.files.downloads.read-write
com.apple.security.files.user-selected.read-write
diff --git a/DuckDuckGo/Freemium/DBP/Extensions/PromotionView+FreemiumDBP.swift b/DuckDuckGo/Freemium/DBP/Extensions/PromotionView+FreemiumDBP.swift
index d744e99b4f..c9119ed6b1 100644
--- a/DuckDuckGo/Freemium/DBP/Extensions/PromotionView+FreemiumDBP.swift
+++ b/DuckDuckGo/Freemium/DBP/Extensions/PromotionView+FreemiumDBP.swift
@@ -22,11 +22,18 @@ extension PromotionViewModel {
static func freemiumDBPPromotion(proceedAction: @escaping () -> Void,
closeAction: @escaping () -> Void) -> PromotionViewModel {
- let text = UserText.homePagePromotionFreemiumDBPText
+ let title = UserText.homePagePromotionFreemiumDBPTitle
+ var description = UserText.homePagePromotionFreemiumDBPDescription
+
+ if #available(macOS 12.0, *) {
+ description = UserText.homePagePromotionFreemiumDBPDescriptionMarkdown
+ }
+
let actionButtonText = UserText.homePagePromotionFreemiumDBPButtonTitle
- return PromotionViewModel(image: .radarCheck,
- text: text,
+ return PromotionViewModel(image: .informationRemover128,
+ title: title,
+ description: description,
proceedButtonText: actionButtonText,
proceedAction: proceedAction,
closeAction: closeAction)
@@ -37,22 +44,22 @@ extension PromotionViewModel {
proceedAction: @escaping () -> Void,
closeAction: @escaping () -> Void) -> PromotionViewModel {
- var text = ""
+ var description = ""
switch (resultCount, brokerCount) {
case (1, _):
- text = UserText.homePagePromotionFreemiumDBPPostScanEngagementResultSingleMatchText
+ description = UserText.homePagePromotionFreemiumDBPPostScanEngagementResultSingleMatchDescription
case (let resultCount, 1):
- text = UserText.homePagePromotionFreemiumDBPPostScanEngagementResultSingleBrokerText(resultCount: resultCount)
+ description = UserText.homePagePromotionFreemiumDBPPostScanEngagementResultSingleBrokerDescription(resultCount: resultCount)
default:
- text = UserText.homePagePromotionFreemiumDBPPostScanEngagementResultPluralText(resultCount: resultCount,
+ description = UserText.homePagePromotionFreemiumDBPPostScanEngagementResultPluralDescription(resultCount: resultCount,
brokerCount: brokerCount)
}
let actionButtonText = UserText.homePagePromotionFreemiumDBPPostScanEngagementButtonTitle
- return PromotionViewModel(image: .radarCheck,
- text: text,
+ return PromotionViewModel(image: .informationRemover128,
+ description: description,
proceedButtonText: actionButtonText,
proceedAction: proceedAction,
closeAction: closeAction)
@@ -61,11 +68,11 @@ extension PromotionViewModel {
static func freemiumDBPPromotionScanEngagementNoResults(proceedAction: @escaping () -> Void,
closeAction: @escaping () -> Void) -> PromotionViewModel {
- let text = UserText.homePagePromotionFreemiumDBPPostScanEngagementNoResultsText
+ let description = UserText.homePagePromotionFreemiumDBPPostScanEngagementNoResultsDescription
let actionButtonText = UserText.homePagePromotionFreemiumDBPPostScanEngagementButtonTitle
- return PromotionViewModel(image: .radarCheck,
- text: text,
+ return PromotionViewModel(image: .informationRemover128,
+ description: description,
proceedButtonText: actionButtonText,
proceedAction: proceedAction,
closeAction: closeAction)
diff --git a/DuckDuckGo/HomePage/Model/PromotionViewModel.swift b/DuckDuckGo/HomePage/Model/PromotionViewModel.swift
index 069ec55a92..b0f57261cb 100644
--- a/DuckDuckGo/HomePage/Model/PromotionViewModel.swift
+++ b/DuckDuckGo/HomePage/Model/PromotionViewModel.swift
@@ -24,14 +24,16 @@ extension HomePage.Models {
final class PromotionViewModel: ObservableObject {
let image: ImageResource
- let text: String
+ let title: String?
+ let description: String
let proceedButtonText: String
let proceedAction: () -> Void
let closeAction: () -> Void
- init(image: ImageResource, text: String, proceedButtonText: String, proceedAction: @escaping () -> Void, closeAction: @escaping () -> Void) {
+ init(image: ImageResource, title: String? = nil, description: String, proceedButtonText: String, proceedAction: @escaping () -> Void, closeAction: @escaping () -> Void) {
self.image = image
- self.text = text
+ self.title = title
+ self.description = description
self.proceedButtonText = proceedButtonText
self.proceedAction = proceedAction
self.closeAction = closeAction
diff --git a/DuckDuckGo/HomePage/View/PromotionView.swift b/DuckDuckGo/HomePage/View/PromotionView.swift
index 1a6bec0437..0bf4d56f41 100644
--- a/DuckDuckGo/HomePage/View/PromotionView.swift
+++ b/DuckDuckGo/HomePage/View/PromotionView.swift
@@ -41,8 +41,7 @@ extension HomePage.Views {
HStack(spacing: 8) {
image
- text
- .padding(.leading, 0)
+ textContent
Spacer(minLength: 4)
@@ -85,14 +84,37 @@ extension HomePage.Views {
}
}
- private var text: some View {
- Text(viewModel.text)
+ private var textContent: some View {
+ VStack(alignment: .leading, spacing: viewModel.title == nil ? 0 : 8) {
+ title
+ description.foregroundColor(Color(.greyText))
+ }
+ }
+
+ private var title: some View {
+ Group {
+ if let title = viewModel.title {
+ Text(verbatim: title)
+ .font(.system(size: 13).bold())
+ } else {
+ EmptyView()
+ }
+ }
+ }
+
+ @ViewBuilder
+ private var description: some View {
+ if #available(macOS 12.0, *), let attributed = try? AttributedString(markdown: viewModel.description) {
+ Text(attributed)
+ } else {
+ Text(verbatim: viewModel.description)
+ }
}
private var button: some View {
Group {
Button(action: viewModel.proceedAction) {
- Text(viewModel.proceedButtonText)
+ Text(verbatim: viewModel.proceedButtonText)
}
.controlSize(.large)
}
diff --git a/DuckDuckGo/Info.plist b/DuckDuckGo/Info.plist
index a6011aea11..68f7172023 100644
--- a/DuckDuckGo/Info.plist
+++ b/DuckDuckGo/Info.plist
@@ -521,21 +521,19 @@
NSCameraUsageDescription
- Allows you to upload photographs and videos
+ Lets websites ask permission to use your camera for video calls, recording and uploading videos, or taking and uploading photos.
NSHumanReadableCopyright
Copyright © 2024 DuckDuckGo. All rights reserved.
NSLocationUsageDescription
- Allows you to share your geolocation
- NSLocationWhenInUseUsageDescription
- Allows you to share your location
+ Lets websites ask permission to use your location to improve search results, provide weather and directions, or show nearby map locations.
NSMicrophoneUsageDescription
- Allows you to share recordings
+ Lets websites ask permission to use your microphone for audio and video calls or for recording and uploading audio.
NSDownloadsFolderUsageDescription
- Allows you to save downloaded files to this folder.
+ Lets you save files to the Downloads folder on your computer.
NSDesktopFolderUsageDescription
- Allows you to save downloaded files to this folder.
+ Lets you save files to the Desktop folder on your computer.
NSDocumentsFolderUsageDescription
- Allows you to save downloaded files to this folder.
+ Lets you save files to the Documents folder on your computer.
NSPrincipalClass
$(INFOPLIST_KEY_NSPrincipalClass)
NSSupportsAutomaticTermination
diff --git a/DuckDuckGo/Localizable.xcstrings b/DuckDuckGo/Localizable.xcstrings
index ad91e2e3be..7e7a19cd25 100644
--- a/DuckDuckGo/Localizable.xcstrings
+++ b/DuckDuckGo/Localizable.xcstrings
@@ -44025,6 +44025,9 @@
}
}
}
+ },
+ "Personal Information Removal" : {
+
},
"phishing-detection.enabled.checkbox" : {
"comment" : "Checkbox that enables or disables the phishing detection feature in the browser",
@@ -53582,6 +53585,66 @@
}
}
},
+ "preferences.set-as-default" : {
+ "comment" : "Menu option to set the browser as default",
+ "extractionState" : "extracted_with_value",
+ "localizations" : {
+ "de" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "DuckDuckGo als Standard-Browser festlegen"
+ }
+ },
+ "en" : {
+ "stringUnit" : {
+ "state" : "new",
+ "value" : "Set DuckDuckGo As Default Browser"
+ }
+ },
+ "es" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Establece DuckDuckGo como tu navegador predeterminado"
+ }
+ },
+ "fr" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Définir DuckDuckGo comme navigateur par défaut"
+ }
+ },
+ "it" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Imposta DuckDuckGo come browser predefinito"
+ }
+ },
+ "nl" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "DuckDuckGo instellen als standaardbrowser"
+ }
+ },
+ "pl" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Ustaw DuckDuckGo jako domyślną przeglądarkę"
+ }
+ },
+ "pt" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Definir o DuckDuckGo como navegador predefinido"
+ }
+ },
+ "ru" : {
+ "stringUnit" : {
+ "state" : "translated",
+ "value" : "Сделать DuckDuckGo браузером по умолчанию"
+ }
+ }
+ }
+ },
"preferences.shortcuts" : {
"comment" : "Name of the preferences section related to shortcuts",
"extractionState" : "extracted_with_value",
diff --git a/DuckDuckGo/LoginItems/LoginItemsManager.swift b/DuckDuckGo/LoginItems/LoginItemsManager.swift
index 98688c4da2..38bd1427df 100644
--- a/DuckDuckGo/LoginItems/LoginItemsManager.swift
+++ b/DuckDuckGo/LoginItems/LoginItemsManager.swift
@@ -95,7 +95,7 @@ final class LoginItemsManager: LoginItemsManaging {
action: "enable",
buildType: AppVersion.shared.buildType,
osVersion: AppVersion.shared.osVersion)
- PixelKit.fire(DebugEvent(event, error: error), frequency: .dailyAndCount)
+ PixelKit.fire(DebugEvent(event, error: error), frequency: .legacyDailyAndCount)
Logger.networkProtection.error("Could not enable \(item.debugDescription, privacy: .public): \(error.debugDescription, privacy: .public)")
}
diff --git a/DuckDuckGo/MainWindow/MainViewController.swift b/DuckDuckGo/MainWindow/MainViewController.swift
index 997c390578..ef6c352471 100644
--- a/DuckDuckGo/MainWindow/MainViewController.swift
+++ b/DuckDuckGo/MainWindow/MainViewController.swift
@@ -215,6 +215,7 @@ final class MainViewController: NSViewController {
func windowDidResignKey() {
browserTabViewController.windowDidResignKey()
+ tabBarViewController.hideTabPreview()
}
func showBookmarkPromptIfNeeded() {
diff --git a/DuckDuckGo/Menus/MainMenu.swift b/DuckDuckGo/Menus/MainMenu.swift
index 4b89758f67..ce940baf61 100644
--- a/DuckDuckGo/Menus/MainMenu.swift
+++ b/DuckDuckGo/Menus/MainMenu.swift
@@ -101,9 +101,12 @@ final class MainMenu: NSMenu {
let helpMenu = NSMenu(title: UserText.mainMenuHelp)
let aboutMenuItem = NSMenuItem(title: UserText.about, action: #selector(AppDelegate.showAbout))
+ let setAsDefaultMenuItem = NSMenuItem(title: UserText.setAsDefaultBrowser + "…", action: #selector(AppDelegate.setAsDefault))
let releaseNotesMenuItem = NSMenuItem(title: UserText.releaseNotesMenuItem, action: #selector(AppDelegate.showReleaseNotes))
let whatIsNewMenuItem = NSMenuItem(title: UserText.whatsNewMenuItem, action: #selector(AppDelegate.showWhatIsNew))
let sendFeedbackMenuItem = NSMenuItem(title: UserText.sendFeedback, action: #selector(AppDelegate.openFeedback))
+
+ private let defaultBrowserPreferences: DefaultBrowserPreferences
private let aiChatMenuConfig: AIChatMenuVisibilityConfigurable
// MARK: - Initialization
@@ -112,8 +115,10 @@ final class MainMenu: NSMenu {
init(featureFlagger: FeatureFlagger,
bookmarkManager: BookmarkManager,
faviconManager: FaviconManagement,
+ defaultBrowserPreferences: DefaultBrowserPreferences = .shared,
aiChatMenuConfig: AIChatMenuVisibilityConfigurable) {
+ self.defaultBrowserPreferences = defaultBrowserPreferences
self.aiChatMenuConfig = aiChatMenuConfig
super.init(title: UserText.duckDuckGo)
@@ -142,6 +147,7 @@ final class MainMenu: NSMenu {
NSMenuItem.separator()
preferencesMenuItem
+ setAsDefaultMenuItem
NSMenuItem.separator()
@@ -163,6 +169,7 @@ final class MainMenu: NSMenu {
}
}
+ @MainActor
func buildFileMenu() -> NSMenuItem {
NSMenuItem(title: UserText.mainMenuFile) {
newTabMenuItem
@@ -300,6 +307,7 @@ final class MainMenu: NSMenu {
}
}
+ @MainActor
func buildHistoryMenu() -> NSMenuItem {
NSMenuItem(title: UserText.mainMenuHistory)
.submenu(historyMenu)
@@ -426,6 +434,8 @@ final class MainMenu: NSMenu {
override func update() {
super.update()
+ setAsDefaultMenuItem.isHidden = defaultBrowserPreferences.isDefault
+
// To be safe, hide the NetP shortcut menu item by default.
toggleNetworkProtectionShortcutMenuItem.isHidden = true
toggleAIChatShortcutMenuItem.isHidden = true
diff --git a/DuckDuckGo/Menus/MainMenuActions.swift b/DuckDuckGo/Menus/MainMenuActions.swift
index 41b56eccbe..b97665c7ec 100644
--- a/DuckDuckGo/Menus/MainMenuActions.swift
+++ b/DuckDuckGo/Menus/MainMenuActions.swift
@@ -159,6 +159,12 @@ extension AppDelegate {
WindowControllersManager.shared.showTab(with: .settings(pane: .about))
}
+ @MainActor
+ @objc func setAsDefault(_ sender: Any?) {
+ PixelKit.fire(GeneralPixel.defaultRequestedFromMainMenu)
+ DefaultBrowserPreferences.shared.becomeDefault()
+ }
+
@MainActor
@objc func showReleaseNotes(_ sender: Any?) {
WindowControllersManager.shared.showTab(with: .releaseNotes)
diff --git a/DuckDuckGo/NavigationBar/View/MoreOptionsMenu.swift b/DuckDuckGo/NavigationBar/View/MoreOptionsMenu.swift
index c0625778b8..d419d26dc7 100644
--- a/DuckDuckGo/NavigationBar/View/MoreOptionsMenu.swift
+++ b/DuckDuckGo/NavigationBar/View/MoreOptionsMenu.swift
@@ -65,6 +65,7 @@ final class MoreOptionsMenu: NSMenu, NSMenuDelegate {
private let freemiumDBPFeature: FreemiumDBPFeature
private let freemiumDBPPresenter: FreemiumDBPPresenter
private let appearancePreferences: AppearancePreferences
+ private let defaultBrowserPreferences: DefaultBrowserPreferences
private let notificationCenter: NotificationCenter
@@ -92,6 +93,7 @@ final class MoreOptionsMenu: NSMenu, NSMenuDelegate {
freemiumDBPFeature: FreemiumDBPFeature,
freemiumDBPPresenter: FreemiumDBPPresenter = DefaultFreemiumDBPPresenter(),
appearancePreferences: AppearancePreferences = .shared,
+ defaultBrowserPreferences: DefaultBrowserPreferences = .shared,
notificationCenter: NotificationCenter = .default,
freemiumDBPExperimentPixelHandler: EventMapping = FreemiumDBPExperimentPixelHandler(),
aiChatMenuConfiguration: AIChatMenuVisibilityConfigurable = AIChatMenuConfiguration()) {
@@ -107,6 +109,7 @@ final class MoreOptionsMenu: NSMenu, NSMenuDelegate {
self.freemiumDBPFeature = freemiumDBPFeature
self.freemiumDBPPresenter = freemiumDBPPresenter
self.appearancePreferences = appearancePreferences
+ self.defaultBrowserPreferences = defaultBrowserPreferences
self.notificationCenter = notificationCenter
self.freemiumDBPExperimentPixelHandler = freemiumDBPExperimentPixelHandler
self.aiChatMenuConfiguration = aiChatMenuConfiguration
@@ -145,10 +148,17 @@ final class MoreOptionsMenu: NSMenu, NSMenuDelegate {
accountManager: accountManager)
addItem(feedbackMenuItem)
- addItem(NSMenuItem.separator())
-
#endif // FEEDBACK
+ if !defaultBrowserPreferences.isDefault {
+ let setAsDefaultMenuItem = NSMenuItem(title: UserText.setAsDefaultBrowser, action: #selector(setAsDefault(_:)))
+ .targetting(self)
+ .withImage(.defaultBrowserMenuItem)
+ addItem(setAsDefaultMenuItem)
+ }
+
+ addItem(NSMenuItem.separator())
+
addWindowItems()
zoomMenuItem.submenu = ZoomSubMenu(targetting: self, tabCollectionViewModel: tabCollectionViewModel)
@@ -186,6 +196,12 @@ final class MoreOptionsMenu: NSMenu, NSMenuDelegate {
actionDelegate?.optionsButtonMenuRequestedNetworkProtectionPopover(self)
}
+ @MainActor
+ @objc func setAsDefault(_ sender: NSMenuItem) {
+ PixelKit.fire(GeneralPixel.defaultRequestedFromMoreOptionsMenu)
+ defaultBrowserPreferences.becomeDefault()
+ }
+
@MainActor
@objc func newTab(_ sender: NSMenuItem) {
tabCollectionViewModel.appendNewTab()
diff --git a/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/EventMapping+NetworkProtectionError.swift b/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/EventMapping+NetworkProtectionError.swift
index 74aa514278..02daf1230f 100644
--- a/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/EventMapping+NetworkProtectionError.swift
+++ b/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/EventMapping+NetworkProtectionError.swift
@@ -50,10 +50,10 @@ extension EventMapping where Event == NetworkProtectionError {
frequency = .standard
case .failedToFetchLocationList(let error):
domainEvent = .networkProtectionClientFailedToFetchLocations(error)
- frequency = .dailyAndCount
+ frequency = .legacyDailyAndCount
case .failedToParseLocationListResponse(let error):
domainEvent = .networkProtectionClientFailedToParseLocationsResponse(error)
- frequency = .dailyAndCount
+ frequency = .legacyDailyAndCount
case .noServerRegistrationInfo,
.couldNotSelectClosestServer,
.couldNotGetPeerPublicKey,
diff --git a/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionTunnelController.swift b/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionTunnelController.swift
index 3a49d0dda0..72d6255c4b 100644
--- a/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionTunnelController.swift
+++ b/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionTunnelController.swift
@@ -537,7 +537,7 @@ final class NetworkProtectionTunnelController: TunnelController, TunnelSessionPr
func start() async {
VPNOperationErrorRecorder().beginRecordingControllerStart()
PixelKit.fire(NetworkProtectionPixelEvent.networkProtectionControllerStartAttempt,
- frequency: .dailyAndCount)
+ frequency: .legacyDailyAndCount)
controllerErrorStore.lastErrorMessage = nil
do {
@@ -580,7 +580,7 @@ final class NetworkProtectionTunnelController: TunnelController, TunnelSessionPr
// in the packet tunnel provider side that can be used to debug additional logic.
//
PixelKit.fire(NetworkProtectionPixelEvent.networkProtectionControllerStartSuccess,
- frequency: .dailyAndCount)
+ frequency: .legacyDailyAndCount)
}
} catch {
VPNOperationErrorRecorder().recordControllerStartFailure(error)
@@ -588,11 +588,11 @@ final class NetworkProtectionTunnelController: TunnelController, TunnelSessionPr
if case StartError.cancelled = error {
PixelKit.fire(
- NetworkProtectionPixelEvent.networkProtectionControllerStartCancelled, frequency: .dailyAndCount, includeAppVersionParameter: true
+ NetworkProtectionPixelEvent.networkProtectionControllerStartCancelled, frequency: .legacyDailyAndCount, includeAppVersionParameter: true
)
} else {
PixelKit.fire(
- NetworkProtectionPixelEvent.networkProtectionControllerStartFailure(error), frequency: .dailyAndCount, includeAppVersionParameter: true
+ NetworkProtectionPixelEvent.networkProtectionControllerStartFailure(error), frequency: .legacyDailyAndCount, includeAppVersionParameter: true
)
}
diff --git a/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/VPNLocation/VPNLocationViewModel.swift b/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/VPNLocation/VPNLocationViewModel.swift
index 3f9f0f86e4..7908ed6474 100644
--- a/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/VPNLocation/VPNLocationViewModel.swift
+++ b/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/VPNLocation/VPNLocationViewModel.swift
@@ -74,13 +74,13 @@ final class VPNLocationViewModel: ObservableObject {
}
func onNearestItemSelection() async {
- PixelKit.fire(GeneralPixel.networkProtectionGeoswitchingSetNearest, frequency: .dailyAndCount)
+ PixelKit.fire(GeneralPixel.networkProtectionGeoswitchingSetNearest, frequency: .legacyDailyAndCount)
selectedLocation = .nearest
await reloadList()
}
func onCountryItemSelection(id: String, cityId: String? = nil) async {
- PixelKit.fire(GeneralPixel.networkProtectionGeoswitchingSetCustom, frequency: .dailyAndCount)
+ PixelKit.fire(GeneralPixel.networkProtectionGeoswitchingSetCustom, frequency: .legacyDailyAndCount)
let city = cityId == VPNCityItemModel.nearest.id ? nil : cityId
let location = NetworkProtectionSelectedLocation(country: id, city: city)
selectedLocation = .location(location)
@@ -95,7 +95,7 @@ final class VPNLocationViewModel: ObservableObject {
private func reloadList() async {
guard let locations = try? await locationListRepository.fetchLocationList().sortedByName() else { return }
if locations.isEmpty {
- PixelKit.fire(GeneralPixel.networkProtectionGeoswitchingNoLocations, frequency: .dailyAndCount)
+ PixelKit.fire(GeneralPixel.networkProtectionGeoswitchingNoLocations, frequency: .legacyDailyAndCount)
}
let isNearestSelected = selectedLocation == .nearest
self.isNearestSelected = isNearestSelected
diff --git a/DuckDuckGo/NetworkProtection/AppTargets/DeveloperIDTarget/NetworkProtectionIPCTunnelController.swift b/DuckDuckGo/NetworkProtection/AppTargets/DeveloperIDTarget/NetworkProtectionIPCTunnelController.swift
index 4bc5ec17c5..f9febc6a09 100644
--- a/DuckDuckGo/NetworkProtection/AppTargets/DeveloperIDTarget/NetworkProtectionIPCTunnelController.swift
+++ b/DuckDuckGo/NetworkProtection/AppTargets/DeveloperIDTarget/NetworkProtectionIPCTunnelController.swift
@@ -96,7 +96,7 @@ extension NetworkProtectionIPCTunnelController: TunnelController {
knownFailureStore.lastKnownFailure = KnownFailure(error)
errorRecorder.recordIPCStartFailure(error)
log(error)
- pixelKit?.fire(StartAttempt.failure(error), frequency: .dailyAndCount)
+ pixelKit?.fire(StartAttempt.failure(error), frequency: .legacyDailyAndCount)
}
do {
@@ -112,7 +112,7 @@ extension NetworkProtectionIPCTunnelController: TunnelController {
if let error {
handleFailure(error)
} else {
- pixelKit?.fire(StartAttempt.success, frequency: .dailyAndCount)
+ pixelKit?.fire(StartAttempt.success, frequency: .legacyDailyAndCount)
}
}
} catch {
@@ -126,7 +126,7 @@ extension NetworkProtectionIPCTunnelController: TunnelController {
func handleFailure(_ error: Error) {
log(error)
- pixelKit?.fire(StopAttempt.failure(error), frequency: .dailyAndCount)
+ pixelKit?.fire(StopAttempt.failure(error), frequency: .legacyDailyAndCount)
}
do {
@@ -136,7 +136,7 @@ extension NetworkProtectionIPCTunnelController: TunnelController {
if let error {
handleFailure(error)
} else {
- pixelKit?.fire(StopAttempt.success, frequency: .dailyAndCount)
+ pixelKit?.fire(StopAttempt.success, frequency: .legacyDailyAndCount)
}
}
} catch {
diff --git a/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/NetworkExtensionTargets/MacPacketTunnelProvider.swift b/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/NetworkExtensionTargets/MacPacketTunnelProvider.swift
index 57d9bce1f5..ec7c79bd5b 100644
--- a/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/NetworkExtensionTargets/MacPacketTunnelProvider.swift
+++ b/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/NetworkExtensionTargets/MacPacketTunnelProvider.swift
@@ -124,7 +124,7 @@ final class MacPacketTunnelProvider: PacketTunnelProvider {
return
}
- PixelKit.fire(domainEvent, frequency: .dailyAndCount, includeAppVersionParameter: true)
+ PixelKit.fire(domainEvent, frequency: .legacyDailyAndCount, includeAppVersionParameter: true)
}
}
@@ -164,7 +164,7 @@ final class MacPacketTunnelProvider: PacketTunnelProvider {
PixelKit.fire(
pixel,
- frequency: .dailyAndCount,
+ frequency: .legacyDailyAndCount,
includeAppVersionParameter: true)
case .recovered(let duration, let failureCount):
let pixel: NetworkProtectionPixelEvent = {
@@ -178,7 +178,7 @@ final class MacPacketTunnelProvider: PacketTunnelProvider {
PixelKit.fire(
pixel,
- frequency: .dailyAndCount,
+ frequency: .legacyDailyAndCount,
includeAppVersionParameter: true)
}
case .reportConnectionAttempt(attempt: let attempt):
@@ -188,17 +188,17 @@ final class MacPacketTunnelProvider: PacketTunnelProvider {
case .connecting:
PixelKit.fire(
NetworkProtectionPixelEvent.networkProtectionEnableAttemptConnecting,
- frequency: .dailyAndCount,
+ frequency: .legacyDailyAndCount,
includeAppVersionParameter: true)
case .success:
PixelKit.fire(
NetworkProtectionPixelEvent.networkProtectionEnableAttemptSuccess,
- frequency: .dailyAndCount,
+ frequency: .legacyDailyAndCount,
includeAppVersionParameter: true)
case .failure:
PixelKit.fire(
NetworkProtectionPixelEvent.networkProtectionEnableAttemptFailure,
- frequency: .dailyAndCount,
+ frequency: .legacyDailyAndCount,
includeAppVersionParameter: true)
}
case .reportTunnelFailure(result: let result):
@@ -208,12 +208,12 @@ final class MacPacketTunnelProvider: PacketTunnelProvider {
case .failureDetected:
PixelKit.fire(
NetworkProtectionPixelEvent.networkProtectionTunnelFailureDetected,
- frequency: .dailyAndCount,
+ frequency: .legacyDailyAndCount,
includeAppVersionParameter: true)
case .failureRecovered:
PixelKit.fire(
NetworkProtectionPixelEvent.networkProtectionTunnelFailureRecovered,
- frequency: .dailyAndCount,
+ frequency: .legacyDailyAndCount,
includeAppVersionParameter: true)
case .networkPathChanged:
break
@@ -231,7 +231,7 @@ final class MacPacketTunnelProvider: PacketTunnelProvider {
guard quality != .unknown else { return }
PixelKit.fire(
NetworkProtectionPixelEvent.networkProtectionLatency(quality: quality),
- frequency: .dailyAndCount,
+ frequency: .legacyDailyAndCount,
includeAppVersionParameter: true)
}
case .rekeyAttempt(let step):
@@ -241,17 +241,17 @@ final class MacPacketTunnelProvider: PacketTunnelProvider {
case .begin:
PixelKit.fire(
NetworkProtectionPixelEvent.networkProtectionRekeyAttempt,
- frequency: .dailyAndCount,
+ frequency: .legacyDailyAndCount,
includeAppVersionParameter: true)
case .failure(let error):
PixelKit.fire(
NetworkProtectionPixelEvent.networkProtectionRekeyFailure(error),
- frequency: .dailyAndCount,
+ frequency: .legacyDailyAndCount,
includeAppVersionParameter: true)
case .success:
PixelKit.fire(
NetworkProtectionPixelEvent.networkProtectionRekeyCompleted,
- frequency: .dailyAndCount,
+ frequency: .legacyDailyAndCount,
includeAppVersionParameter: true)
}
case .tunnelStartAttempt(let step):
@@ -261,17 +261,17 @@ final class MacPacketTunnelProvider: PacketTunnelProvider {
case .begin:
PixelKit.fire(
NetworkProtectionPixelEvent.networkProtectionTunnelStartAttempt,
- frequency: .dailyAndCount,
+ frequency: .legacyDailyAndCount,
includeAppVersionParameter: true)
case .failure(let error):
PixelKit.fire(
NetworkProtectionPixelEvent.networkProtectionTunnelStartFailure(error),
- frequency: .dailyAndCount,
+ frequency: .legacyDailyAndCount,
includeAppVersionParameter: true)
case .success:
PixelKit.fire(
NetworkProtectionPixelEvent.networkProtectionTunnelStartSuccess,
- frequency: .dailyAndCount,
+ frequency: .legacyDailyAndCount,
includeAppVersionParameter: true)
}
case .tunnelStopAttempt(let step):
@@ -286,12 +286,12 @@ final class MacPacketTunnelProvider: PacketTunnelProvider {
case .failure(let error):
PixelKit.fire(
NetworkProtectionPixelEvent.networkProtectionTunnelStopFailure(error),
- frequency: .dailyAndCount,
+ frequency: .legacyDailyAndCount,
includeAppVersionParameter: true)
case .success:
PixelKit.fire(
NetworkProtectionPixelEvent.networkProtectionTunnelStopSuccess,
- frequency: .dailyAndCount,
+ frequency: .legacyDailyAndCount,
includeAppVersionParameter: true)
}
case .tunnelUpdateAttempt(let step):
@@ -301,17 +301,17 @@ final class MacPacketTunnelProvider: PacketTunnelProvider {
case .begin:
PixelKit.fire(
NetworkProtectionPixelEvent.networkProtectionTunnelUpdateAttempt,
- frequency: .dailyAndCount,
+ frequency: .legacyDailyAndCount,
includeAppVersionParameter: true)
case .failure(let error):
PixelKit.fire(
NetworkProtectionPixelEvent.networkProtectionTunnelUpdateFailure(error),
- frequency: .dailyAndCount,
+ frequency: .legacyDailyAndCount,
includeAppVersionParameter: true)
case .success:
PixelKit.fire(
NetworkProtectionPixelEvent.networkProtectionTunnelUpdateSuccess,
- frequency: .dailyAndCount,
+ frequency: .legacyDailyAndCount,
includeAppVersionParameter: true)
}
case .tunnelWakeAttempt(let step):
@@ -321,17 +321,17 @@ final class MacPacketTunnelProvider: PacketTunnelProvider {
case .begin:
PixelKit.fire(
NetworkProtectionPixelEvent.networkProtectionTunnelWakeAttempt,
- frequency: .dailyAndCount,
+ frequency: .legacyDailyAndCount,
includeAppVersionParameter: true)
case .failure(let error):
PixelKit.fire(
NetworkProtectionPixelEvent.networkProtectionTunnelWakeFailure(error),
- frequency: .dailyAndCount,
+ frequency: .legacyDailyAndCount,
includeAppVersionParameter: true)
case .success:
PixelKit.fire(
NetworkProtectionPixelEvent.networkProtectionTunnelWakeSuccess,
- frequency: .dailyAndCount,
+ frequency: .legacyDailyAndCount,
includeAppVersionParameter: true)
}
case .failureRecoveryAttempt(let step):
@@ -341,25 +341,25 @@ final class MacPacketTunnelProvider: PacketTunnelProvider {
case .started:
PixelKit.fire(
VPNFailureRecoveryPixel.vpnFailureRecoveryStarted,
- frequency: .dailyAndCount,
+ frequency: .legacyDailyAndCount,
includeAppVersionParameter: true
)
case .completed(.healthy):
PixelKit.fire(
VPNFailureRecoveryPixel.vpnFailureRecoveryCompletedHealthy,
- frequency: .dailyAndCount,
+ frequency: .legacyDailyAndCount,
includeAppVersionParameter: true
)
case .completed(.unhealthy):
PixelKit.fire(
VPNFailureRecoveryPixel.vpnFailureRecoveryCompletedUnhealthy,
- frequency: .dailyAndCount,
+ frequency: .legacyDailyAndCount,
includeAppVersionParameter: true
)
case .failed(let error):
PixelKit.fire(
VPNFailureRecoveryPixel.vpnFailureRecoveryFailed(error),
- frequency: .dailyAndCount,
+ frequency: .legacyDailyAndCount,
includeAppVersionParameter: true
)
}
@@ -370,17 +370,17 @@ final class MacPacketTunnelProvider: PacketTunnelProvider {
case .begin:
PixelKit.fire(
NetworkProtectionPixelEvent.networkProtectionServerMigrationAttempt,
- frequency: .dailyAndCount,
+ frequency: .legacyDailyAndCount,
includeAppVersionParameter: true)
case .failure(let error):
PixelKit.fire(
NetworkProtectionPixelEvent.networkProtectionServerMigrationFailure(error),
- frequency: .dailyAndCount,
+ frequency: .legacyDailyAndCount,
includeAppVersionParameter: true)
case .success:
PixelKit.fire(
NetworkProtectionPixelEvent.networkProtectionServerMigrationSuccess,
- frequency: .dailyAndCount,
+ frequency: .legacyDailyAndCount,
includeAppVersionParameter: true)
}
case .tunnelStartOnDemandWithoutAccessToken:
@@ -388,12 +388,12 @@ final class MacPacketTunnelProvider: PacketTunnelProvider {
PixelKit.fire(
NetworkProtectionPixelEvent.networkProtectionTunnelStartAttemptOnDemandWithoutAccessToken,
- frequency: .dailyAndCount,
+ frequency: .legacyDailyAndCount,
includeAppVersionParameter: true)
case .malformedErrorDetected(let error):
PixelKit.fire(
NetworkProtectionPixelEvent.networkProtectionMalformedErrorDetected(error),
- frequency: .dailyAndCount,
+ frequency: .legacyDailyAndCount,
includeAppVersionParameter: true)
}
}
@@ -661,6 +661,6 @@ extension MacPacketTunnelProvider: AccountManagerKeychainAccessDelegate {
public func accountManagerKeychainAccessFailed(accessType: AccountKeychainAccessType, error: AccountKeychainAccessError) {
PixelKit.fire(PrivacyProErrorPixel.privacyProKeychainAccessError(accessType: accessType, accessError: error),
- frequency: .dailyAndCount)
+ frequency: .legacyDailyAndCount)
}
}
diff --git a/DuckDuckGo/Preferences/View/PreferencesRootView.swift b/DuckDuckGo/Preferences/View/PreferencesRootView.swift
index 2d2f4f6448..195309d2d8 100644
--- a/DuckDuckGo/Preferences/View/PreferencesRootView.swift
+++ b/DuckDuckGo/Preferences/View/PreferencesRootView.swift
@@ -161,11 +161,11 @@ enum Preferences {
case .iHaveASubscriptionClick:
PixelKit.fire(PrivacyProPixel.privacyProRestorePurchaseClick)
case .activateAddEmailClick:
- PixelKit.fire(PrivacyProPixel.privacyProRestorePurchaseEmailStart, frequency: .dailyAndCount)
+ PixelKit.fire(PrivacyProPixel.privacyProRestorePurchaseEmailStart, frequency: .legacyDailyAndCount)
case .postSubscriptionAddEmailClick:
PixelKit.fire(PrivacyProPixel.privacyProWelcomeAddDevice, frequency: .unique)
case .restorePurchaseStoreClick:
- PixelKit.fire(PrivacyProPixel.privacyProRestorePurchaseStoreStart, frequency: .dailyAndCount)
+ PixelKit.fire(PrivacyProPixel.privacyProRestorePurchaseStoreStart, frequency: .legacyDailyAndCount)
case .addDeviceEnterEmail:
PixelKit.fire(PrivacyProPixel.privacyProAddDeviceEnterEmail)
case .activeSubscriptionSettingsClick:
diff --git a/DuckDuckGo/Preferences/View/PreferencesVPNView.swift b/DuckDuckGo/Preferences/View/PreferencesVPNView.swift
index 7d0c793bc2..02ea780844 100644
--- a/DuckDuckGo/Preferences/View/PreferencesVPNView.swift
+++ b/DuckDuckGo/Preferences/View/PreferencesVPNView.swift
@@ -139,7 +139,7 @@ extension Preferences {
showsCustomDNSServerPageSheet.toggle()
} else {
model.resetDNSSettings()
- PixelKit.fire(NetworkProtectionPixelEvent.networkProtectionDNSUpdateDefault, frequency: .dailyAndCount)
+ PixelKit.fire(NetworkProtectionPixelEvent.networkProtectionDNSUpdateDefault, frequency: .legacyDailyAndCount)
}
}
.onChange(of: showsCustomDNSServerPageSheet) { showsCustomDNSServerPageSheet in
@@ -242,9 +242,9 @@ struct CustomDNSServerPageSheet: View {
/// Updating `dnsSettings` does an IPv4 conversion before actually commiting the change,
/// so we do a final check to see which outcome the user ends up with
if settings.dnsSettings.usesCustomDNS {
- PixelKit.fire(NetworkProtectionPixelEvent.networkProtectionDNSUpdateCustom, frequency: .dailyAndCount)
+ PixelKit.fire(NetworkProtectionPixelEvent.networkProtectionDNSUpdateCustom, frequency: .legacyDailyAndCount)
} else {
- PixelKit.fire(NetworkProtectionPixelEvent.networkProtectionDNSUpdateDefault, frequency: .dailyAndCount)
+ PixelKit.fire(NetworkProtectionPixelEvent.networkProtectionDNSUpdateDefault, frequency: .legacyDailyAndCount)
}
}
diff --git a/DuckDuckGo/SmarterEncryption/PrivacyFeatures.swift b/DuckDuckGo/SmarterEncryption/PrivacyFeatures.swift
index 73fd8c7bf1..fd861aeb2b 100644
--- a/DuckDuckGo/SmarterEncryption/PrivacyFeatures.swift
+++ b/DuckDuckGo/SmarterEncryption/PrivacyFeatures.swift
@@ -66,14 +66,14 @@ final class AppPrivacyFeatures: PrivacyFeaturesProtocol {
if dailyAndCount {
PixelKit.fire(DebugEvent(domainEvent, error: error),
- frequency: .dailyAndCount,
+ frequency: .legacyDailyAndCount,
withAdditionalParameters: parameters,
includeAppVersionParameter: true) { _, error in
onComplete(error)
}
} else {
PixelKit.fire(DebugEvent(domainEvent, error: error),
- frequency: .dailyAndCount,
+ frequency: .legacyDailyAndCount,
withAdditionalParameters: parameters) { _, error in
onComplete(error)
}
diff --git a/DuckDuckGo/Statistics/GeneralPixel.swift b/DuckDuckGo/Statistics/GeneralPixel.swift
index 51cf05406e..21bf3f4687 100644
--- a/DuckDuckGo/Statistics/GeneralPixel.swift
+++ b/DuckDuckGo/Statistics/GeneralPixel.swift
@@ -28,6 +28,7 @@ enum GeneralPixel: PixelKitEventV2 {
case crashOnCrashHandlersSetUp
case compileRulesWait(onboardingShown: OnboardingShown, waitTime: CompileRulesWaitTime, result: WaitResult)
case launchInitial(cohort: String)
+ case launch(isDefault: Bool)
case serp(cohort: String?)
case serpInitial(cohort: String)
@@ -212,6 +213,8 @@ enum GeneralPixel: PixelKitEventV2 {
case defaultRequestedFromHomepageSetupView
case defaultRequestedFromSettings
case defaultRequestedFromOnboarding
+ case defaultRequestedFromMainMenu
+ case defaultRequestedFromMoreOptionsMenu
// Adding to the Dock
case addToDockOnboardingStepPresented
@@ -409,6 +412,7 @@ enum GeneralPixel: PixelKitEventV2 {
case syncDeleteAccountError(error: Error)
case syncLoginExistingAccountError(error: Error)
case syncCannotCreateRecoveryPDF
+ case syncSecureStorageReadError(error: Error)
case bookmarksCleanupFailed
case bookmarksCleanupAttemptedWhileSyncWasEnabled
@@ -450,6 +454,9 @@ enum GeneralPixel: PixelKitEventV2 {
case .compileRulesWait(onboardingShown: let onboardingShown, waitTime: let waitTime, result: let result):
return "m_mac_cbr-wait_\(onboardingShown)_\(waitTime)_\(result)"
+ case .launch(let isDefault):
+ return isDefault ? "ml_mac_app-launch_as-default" : "ml_mac_app-launch_as-nondefault"
+
case .serp:
return "m_mac_navigation_search"
@@ -754,6 +761,8 @@ enum GeneralPixel: PixelKitEventV2 {
case .defaultRequestedFromHomepageSetupView: return "m_mac_default_requested_from_homepage_setup_view"
case .defaultRequestedFromSettings: return "m_mac_default_requested_from_settings"
case .defaultRequestedFromOnboarding: return "m_mac_default_requested_from_onboarding"
+ case .defaultRequestedFromMainMenu: return "m_mac_default_requested_from_main_menu"
+ case .defaultRequestedFromMoreOptionsMenu: return "m_mac_default_requested_from_more_options_menu"
case .addToDockOnboardingStepPresented: return "m_mac_add_to_dock_onboarding_step_presented"
case .userAddedToDockDuringOnboarding: return "m_mac_user_added_to_dock_during_onboarding"
@@ -1038,6 +1047,7 @@ enum GeneralPixel: PixelKitEventV2 {
case .syncDeleteAccountError: return "sync_delete_account_error"
case .syncLoginExistingAccountError: return "sync_login_existing_account_error"
case .syncCannotCreateRecoveryPDF: return "sync_cannot_create_recovery_pdf"
+ case .syncSecureStorageReadError: return "sync_secure_storage_read_error"
case .bookmarksCleanupFailed: return "bookmarks_cleanup_failed"
case .bookmarksCleanupAttemptedWhileSyncWasEnabled: return "bookmarks_cleanup_attempted_while_sync_was_enabled"
@@ -1093,6 +1103,7 @@ enum GeneralPixel: PixelKitEventV2 {
.syncRefreshDevicesError(let error),
.syncDeleteAccountError(let error),
.syncLoginExistingAccountError(let error),
+ .syncSecureStorageReadError(let error),
.bookmarksCouldNotLoadDatabase(let error?):
return error
default: return nil
diff --git a/DuckDuckGo/Subscription/SubscriptionManager+StandardConfiguration.swift b/DuckDuckGo/Subscription/SubscriptionManager+StandardConfiguration.swift
index c92a66516d..360ddb541e 100644
--- a/DuckDuckGo/Subscription/SubscriptionManager+StandardConfiguration.swift
+++ b/DuckDuckGo/Subscription/SubscriptionManager+StandardConfiguration.swift
@@ -63,6 +63,6 @@ extension DefaultSubscriptionManager: AccountManagerKeychainAccessDelegate {
public func accountManagerKeychainAccessFailed(accessType: AccountKeychainAccessType, error: AccountKeychainAccessError) {
PixelKit.fire(PrivacyProErrorPixel.privacyProKeychainAccessError(accessType: accessType, accessError: error),
- frequency: .dailyAndCount)
+ frequency: .legacyDailyAndCount)
}
}
diff --git a/DuckDuckGo/Sync/SyncDiagnosisHelper.swift b/DuckDuckGo/Sync/SyncDiagnosisHelper.swift
index dcce535fe3..091f5939e3 100644
--- a/DuckDuckGo/Sync/SyncDiagnosisHelper.swift
+++ b/DuckDuckGo/Sync/SyncDiagnosisHelper.swift
@@ -46,7 +46,7 @@ struct SyncDiagnosisHelper {
// Nil value means sync was never on in the first place. So don't fire in this case.
if syncManuallyDisabled == false,
!syncWasDisabledUnexpectedlyPixelFired {
- PixelKit.fire(DebugEvent(GeneralPixel.syncDebugWasDisabledUnexpectedly), frequency: .dailyAndCount)
+ PixelKit.fire(DebugEvent(GeneralPixel.syncDebugWasDisabledUnexpectedly), frequency: .legacyDailyAndCount)
syncWasDisabledUnexpectedlyPixelFired = true
}
} else {
diff --git a/DuckDuckGo/Sync/SyncErrorHandler.swift b/DuckDuckGo/Sync/SyncErrorHandler.swift
index f44cf0edf1..beca1a0e2c 100644
--- a/DuckDuckGo/Sync/SyncErrorHandler.swift
+++ b/DuckDuckGo/Sync/SyncErrorHandler.swift
@@ -91,7 +91,12 @@ public class SyncErrorHandler: EventMapping, ObservableObject {
public init(alertPresenter: SyncAlertsPresenting = SyncAlertsPresenter()) {
self.alertPresenter = alertPresenter
super.init { event, _, _, _ in
- PixelKit.fire(DebugEvent(GeneralPixel.syncSentUnauthenticatedRequest, error: event))
+ switch event {
+ case .failedToReadSecureStore(let status):
+ PixelKit.fire(DebugEvent(GeneralPixel.syncSecureStorageReadError(error: event), error: event))
+ default:
+ PixelKit.fire(DebugEvent(GeneralPixel.syncSentUnauthenticatedRequest, error: event))
+ }
}
}
diff --git a/DuckDuckGo/Tab/TabExtensions/NetworkProtectionControllerTabExtension.swift b/DuckDuckGo/Tab/TabExtensions/NetworkProtectionControllerTabExtension.swift
index 7f86b0f766..b71ba50678 100644
--- a/DuckDuckGo/Tab/TabExtensions/NetworkProtectionControllerTabExtension.swift
+++ b/DuckDuckGo/Tab/TabExtensions/NetworkProtectionControllerTabExtension.swift
@@ -32,7 +32,7 @@ final class NetworkProtectionControllerTabExtension {
extension NetworkProtectionControllerTabExtension: NavigationResponder {
func navigationDidFinish(_ navigation: Navigation) {
if navigation.url.isDuckDuckGoSearch, tunnelController.isConnected == true {
- PixelKit.fire(GeneralPixel.networkProtectionEnabledOnSearch, frequency: .dailyAndCount)
+ PixelKit.fire(GeneralPixel.networkProtectionEnabledOnSearch, frequency: .legacyDailyAndCount)
}
}
}
diff --git a/DuckDuckGo/Tab/UserScripts/Subscription/SubscriptionAppStoreRestorer.swift b/DuckDuckGo/Tab/UserScripts/Subscription/SubscriptionAppStoreRestorer.swift
index 12a157cd95..2aa44c3e83 100644
--- a/DuckDuckGo/Tab/UserScripts/Subscription/SubscriptionAppStoreRestorer.swift
+++ b/DuckDuckGo/Tab/UserScripts/Subscription/SubscriptionAppStoreRestorer.swift
@@ -72,12 +72,12 @@ struct DefaultSubscriptionAppStoreRestorer: SubscriptionAppStoreRestorer {
await uiHandler.dismissProgressViewController()
switch result {
case .success:
- PixelKit.fire(PrivacyProPixel.privacyProRestorePurchaseStoreSuccess, frequency: .dailyAndCount)
+ PixelKit.fire(PrivacyProPixel.privacyProRestorePurchaseStoreSuccess, frequency: .legacyDailyAndCount)
case .failure(let error):
switch error {
case .missingAccountOrTransactions: break
default:
- PixelKit.fire(PrivacyProPixel.privacyProRestorePurchaseStoreFailureOther, frequency: .dailyAndCount)
+ PixelKit.fire(PrivacyProPixel.privacyProRestorePurchaseStoreFailureOther, frequency: .legacyDailyAndCount)
}
switch error {
case .missingAccountOrTransactions:
@@ -96,7 +96,7 @@ struct DefaultSubscriptionAppStoreRestorer: SubscriptionAppStoreRestorer {
// MARK: - UI interactions
private func showSomethingWentWrongAlert() async {
- PixelKit.fire(PrivacyProPixel.privacyProPurchaseFailure, frequency: .dailyAndCount)
+ PixelKit.fire(PrivacyProPixel.privacyProPurchaseFailure, frequency: .legacyDailyAndCount)
await uiHandler.show(alertType: .somethingWentWrong)
}
diff --git a/DuckDuckGo/Tab/UserScripts/Subscription/SubscriptionErrorReporter.swift b/DuckDuckGo/Tab/UserScripts/Subscription/SubscriptionErrorReporter.swift
index c1d62a8033..ae370e03f4 100644
--- a/DuckDuckGo/Tab/UserScripts/Subscription/SubscriptionErrorReporter.swift
+++ b/DuckDuckGo/Tab/UserScripts/Subscription/SubscriptionErrorReporter.swift
@@ -65,7 +65,7 @@ struct DefaultSubscriptionErrorReporter: SubscriptionErrorReporter {
case .failedToRestorePastPurchase:
isStoreError = true
case .subscriptionNotFound:
- PixelKit.fire(PrivacyProPixel.privacyProRestorePurchaseStoreFailureNotFound, frequency: .dailyAndCount)
+ PixelKit.fire(PrivacyProPixel.privacyProRestorePurchaseStoreFailureNotFound, frequency: .legacyDailyAndCount)
isStoreError = true
case .subscriptionExpired:
isStoreError = true
@@ -74,17 +74,17 @@ struct DefaultSubscriptionErrorReporter: SubscriptionErrorReporter {
isBackendError = true
case .cancelledByUser: break
case .accountCreationFailed:
- PixelKit.fire(PrivacyProPixel.privacyProPurchaseFailureAccountNotCreated, frequency: .dailyAndCount)
+ PixelKit.fire(PrivacyProPixel.privacyProPurchaseFailureAccountNotCreated, frequency: .legacyDailyAndCount)
case .activeSubscriptionAlreadyPresent: break
case .generalError: break
}
if isStoreError {
- PixelKit.fire(PrivacyProPixel.privacyProPurchaseFailureStoreError, frequency: .dailyAndCount)
+ PixelKit.fire(PrivacyProPixel.privacyProPurchaseFailureStoreError, frequency: .legacyDailyAndCount)
}
if isBackendError {
- PixelKit.fire(PrivacyProPixel.privacyProPurchaseFailureBackendError, frequency: .dailyAndCount)
+ PixelKit.fire(PrivacyProPixel.privacyProPurchaseFailureBackendError, frequency: .legacyDailyAndCount)
}
}
}
diff --git a/DuckDuckGo/Tab/UserScripts/Subscription/SubscriptionPagesUseSubscriptionFeature.swift b/DuckDuckGo/Tab/UserScripts/Subscription/SubscriptionPagesUseSubscriptionFeature.swift
index a2d90a4a19..204d9228c5 100644
--- a/DuckDuckGo/Tab/UserScripts/Subscription/SubscriptionPagesUseSubscriptionFeature.swift
+++ b/DuckDuckGo/Tab/UserScripts/Subscription/SubscriptionPagesUseSubscriptionFeature.swift
@@ -136,7 +136,7 @@ final class SubscriptionPagesUseSubscriptionFeature: Subfeature {
func setSubscription(params: Any, original: WKScriptMessage) async throws -> Encodable? {
- PixelKit.fire(PrivacyProPixel.privacyProRestorePurchaseEmailSuccess, frequency: .dailyAndCount)
+ PixelKit.fire(PrivacyProPixel.privacyProRestorePurchaseEmailSuccess, frequency: .legacyDailyAndCount)
guard let subscriptionValues: SubscriptionValues = DecodableHelper.decode(from: params) else {
assertionFailure("SubscriptionPagesUserScript: expected JSON representation of SubscriptionValues")
@@ -189,7 +189,7 @@ final class SubscriptionPagesUseSubscriptionFeature: Subfeature {
}
func subscriptionSelected(params: Any, original: WKScriptMessage) async throws -> Encodable? {
- PixelKit.fire(PrivacyProPixel.privacyProPurchaseAttempt, frequency: .dailyAndCount)
+ PixelKit.fire(PrivacyProPixel.privacyProPurchaseAttempt, frequency: .legacyDailyAndCount)
struct SubscriptionSelection: Decodable {
let id: String
}
@@ -273,7 +273,7 @@ final class SubscriptionPagesUseSubscriptionFeature: Subfeature {
switch completePurchaseResult {
case .success(let purchaseUpdate):
Logger.subscription.info("[Purchase] Purchase complete")
- PixelKit.fire(PrivacyProPixel.privacyProPurchaseSuccess, frequency: .dailyAndCount)
+ PixelKit.fire(PrivacyProPixel.privacyProPurchaseSuccess, frequency: .legacyDailyAndCount)
sendFreemiumSubscriptionPixelIfFreemiumActivated()
saveSubscriptionUpgradeTimestampIfFreemiumActivated()
PixelKit.fire(PrivacyProPixel.privacyProSubscriptionActivated, frequency: .unique)
@@ -385,7 +385,7 @@ final class SubscriptionPagesUseSubscriptionFeature: Subfeature {
await stripePurchaseFlow.completeSubscriptionPurchase()
await uiHandler.dismissProgressViewController()
- PixelKit.fire(PrivacyProPixel.privacyProPurchaseStripeSuccess, frequency: .dailyAndCount)
+ PixelKit.fire(PrivacyProPixel.privacyProPurchaseStripeSuccess, frequency: .legacyDailyAndCount)
sendFreemiumSubscriptionPixelIfFreemiumActivated()
saveSubscriptionUpgradeTimestampIfFreemiumActivated()
subscriptionSuccessPixelHandler.fireSuccessfulSubscriptionAttributionPixel()
@@ -457,7 +457,7 @@ final class SubscriptionPagesUseSubscriptionFeature: Subfeature {
// MARK: - UI interactions
func showSomethingWentWrongAlert() async {
- PixelKit.fire(PrivacyProPixel.privacyProPurchaseFailure, frequency: .dailyAndCount)
+ PixelKit.fire(PrivacyProPixel.privacyProPurchaseFailure, frequency: .legacyDailyAndCount)
switch await uiHandler.dismissProgressViewAndShow(alertType: .somethingWentWrong, text: nil) {
case .alertFirstButtonReturn:
let url = subscriptionManager.url(for: .purchase)
@@ -478,7 +478,7 @@ final class SubscriptionPagesUseSubscriptionFeature: Subfeature {
authEndpointService: subscriptionManager.authEndpointService)
let result = await appStoreRestoreFlow.restoreAccountFromPastPurchase()
switch result {
- case .success: PixelKit.fire(PrivacyProPixel.privacyProRestorePurchaseStoreSuccess, frequency: .dailyAndCount)
+ case .success: PixelKit.fire(PrivacyProPixel.privacyProRestorePurchaseStoreSuccess, frequency: .legacyDailyAndCount)
case .failure: break
}
Task { @MainActor in
@@ -529,7 +529,7 @@ extension SubscriptionPagesUseSubscriptionFeature: SubscriptionAccessActionHandl
func subscriptionAccessActionHandleAction(event: SubscriptionAccessActionHandlingEvent) {
switch event {
case .activateAddEmailClick:
- PixelKit.fire(PrivacyProPixel.privacyProRestorePurchaseEmailStart, frequency: .dailyAndCount)
+ PixelKit.fire(PrivacyProPixel.privacyProRestorePurchaseEmailStart, frequency: .legacyDailyAndCount)
default: break
}
}
diff --git a/DuckDuckGo/TabPreview/TabPreviewWindowController.swift b/DuckDuckGo/TabPreview/TabPreviewWindowController.swift
index b6df9be63d..0a240918fe 100644
--- a/DuckDuckGo/TabPreview/TabPreviewWindowController.swift
+++ b/DuckDuckGo/TabPreview/TabPreviewWindowController.swift
@@ -73,7 +73,11 @@ final class TabPreviewWindowController: NSWindowController {
}
func show(parentWindow: NSWindow, topLeftPointInWindow: CGPoint) {
+ Logger.tabPreview.log("Showing tab preview")
+
func presentPreview(tabPreviewWindow: NSWindow) {
+ Logger.tabPreview.log("Presenting tab preview")
+
parentWindow.addChildWindow(tabPreviewWindow, ordered: .above)
self.layout(topLeftPoint: parentWindow.convertPoint(toScreen: topLeftPointInWindow))
}
@@ -83,7 +87,7 @@ final class TabPreviewWindowController: NSWindowController {
guard let childWindows = parentWindow.childWindows,
let tabPreviewWindow = self.window else {
- Logger.general.error("TabPreviewWindowController: Showing tab preview window failed")
+ Logger.general.error("Showing tab preview window failed")
return
}
@@ -107,7 +111,11 @@ final class TabPreviewWindowController: NSWindowController {
}
func hide(allowQuickRedisplay: Bool = false, withDelay delay: Bool = false) {
+ Logger.tabPreview.log("Hiding tab preview allowQuickRedisplay:\(allowQuickRedisplay) delay:\(delay)")
+
func removePreview(allowQuickRedisplay: Bool) {
+ Logger.tabPreview.log("Removing tab preview allowQuickRedisplay:\(allowQuickRedisplay)")
+
guard let window = window else {
lastHideTime = nil
return
@@ -117,11 +125,12 @@ final class TabPreviewWindowController: NSWindowController {
if !allowQuickRedisplay {
lastHideTime = nil
}
+ window.orderOut(nil)
return
}
parentWindow.removeChildWindow(window)
- (window).orderOut(nil)
+ window.orderOut(nil)
// Record the hide time
lastHideTime = allowQuickRedisplay ? Date() : nil
diff --git a/DuckDuckGo/UnifiedFeedbackForm/UnifiedFeedbackSender.swift b/DuckDuckGo/UnifiedFeedbackForm/UnifiedFeedbackSender.swift
index 79f86b8f68..98ba6100bc 100644
--- a/DuckDuckGo/UnifiedFeedbackForm/UnifiedFeedbackSender.swift
+++ b/DuckDuckGo/UnifiedFeedbackForm/UnifiedFeedbackSender.swift
@@ -111,7 +111,7 @@ struct DefaultFeedbackSender: UnifiedFeedbackSender {
}
func sendFormShowPixel() {
- PixelKit.fire(GeneralPixel.pproFeedbackFormShow, frequency: .dailyAndCount)
+ PixelKit.fire(GeneralPixel.pproFeedbackFormShow, frequency: .legacyDailyAndCount)
}
func sendSubmitScreenShowPixel(source: UnifiedFeedbackSource, reportType: String, category: String, subcategory: String) {
@@ -119,7 +119,7 @@ struct DefaultFeedbackSender: UnifiedFeedbackSender {
reportType: ReportType.from(reportType),
category: Category.from(category),
subcategory: Subcategory.from(subcategory)),
- frequency: .dailyAndCount)
+ frequency: .legacyDailyAndCount)
}
func sendSubmitScreenFAQClickPixel(source: UnifiedFeedbackSource, reportType: String, category: String, subcategory: String) {
@@ -127,6 +127,6 @@ struct DefaultFeedbackSender: UnifiedFeedbackSender {
reportType: ReportType.from(reportType),
category: Category.from(category),
subcategory: Subcategory.from(subcategory)),
- frequency: .dailyAndCount)
+ frequency: .legacyDailyAndCount)
}
}
diff --git a/DuckDuckGo/Waitlist/VPNUninstaller.swift b/DuckDuckGo/Waitlist/VPNUninstaller.swift
index d164cf21b3..084f31e106 100644
--- a/DuckDuckGo/Waitlist/VPNUninstaller.swift
+++ b/DuckDuckGo/Waitlist/VPNUninstaller.swift
@@ -176,15 +176,15 @@ final class VPNUninstaller: VPNUninstalling {
return
}
- pixelKit?.fire(IPCUninstallAttempt.begin, frequency: .dailyAndCount)
+ pixelKit?.fire(IPCUninstallAttempt.begin, frequency: .legacyDailyAndCount)
do {
try await executeUninstallSequence(removeSystemExtension: removeSystemExtension)
- pixelKit?.fire(IPCUninstallAttempt.success, frequency: .dailyAndCount)
+ pixelKit?.fire(IPCUninstallAttempt.success, frequency: .legacyDailyAndCount)
} catch UninstallError.cancelled(let reason) {
- pixelKit?.fire(IPCUninstallAttempt.cancelled(reason), frequency: .dailyAndCount)
+ pixelKit?.fire(IPCUninstallAttempt.cancelled(reason), frequency: .legacyDailyAndCount)
} catch {
- pixelKit?.fire(IPCUninstallAttempt.failure(error), frequency: .dailyAndCount)
+ pixelKit?.fire(IPCUninstallAttempt.failure(error), frequency: .legacyDailyAndCount)
}
}
diff --git a/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift b/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift
index 40ecf9650b..b183d84e51 100644
--- a/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift
+++ b/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift
@@ -468,6 +468,6 @@ extension DuckDuckGoVPNAppDelegate: AccountManagerKeychainAccessDelegate {
public func accountManagerKeychainAccessFailed(accessType: AccountKeychainAccessType, error: AccountKeychainAccessError) {
PixelKit.fire(PrivacyProErrorPixel.privacyProKeychainAccessError(accessType: accessType, accessError: error),
- frequency: .dailyAndCount)
+ frequency: .legacyDailyAndCount)
}
}
diff --git a/DuckDuckGoVPN/VPNUninstaller.swift b/DuckDuckGoVPN/VPNUninstaller.swift
index 1ae6a706cb..b6efdda308 100644
--- a/DuckDuckGoVPN/VPNUninstaller.swift
+++ b/DuckDuckGoVPN/VPNUninstaller.swift
@@ -48,7 +48,7 @@ final class VPNUninstaller: VPNUninstalling {
}
func uninstall(includingSystemExtension: Bool) async throws {
- pixelKit?.fire(VPNUninstallAttempt.begin, frequency: .dailyAndCount)
+ pixelKit?.fire(VPNUninstallAttempt.begin, frequency: .legacyDailyAndCount)
do {
try await removeSystemExtension()
@@ -59,15 +59,15 @@ final class VPNUninstaller: VPNUninstalling {
}
defaults.networkProtectionShouldShowVPNUninstalledMessage = true
- pixelKit?.fire(VPNUninstallAttempt.success, frequency: .dailyAndCount)
+ pixelKit?.fire(VPNUninstallAttempt.success, frequency: .legacyDailyAndCount)
} catch {
switch error {
case OSSystemExtensionError.requestCanceled:
- pixelKit?.fire(VPNUninstallAttempt.cancelled(.sysexInstallationCancelled), frequency: .dailyAndCount)
+ pixelKit?.fire(VPNUninstallAttempt.cancelled(.sysexInstallationCancelled), frequency: .legacyDailyAndCount)
case OSSystemExtensionError.authorizationRequired:
- pixelKit?.fire(VPNUninstallAttempt.cancelled(.sysexInstallationRequiresAuthorization), frequency: .dailyAndCount)
+ pixelKit?.fire(VPNUninstallAttempt.cancelled(.sysexInstallationRequiresAuthorization), frequency: .legacyDailyAndCount)
default:
- pixelKit?.fire(VPNUninstallAttempt.failure(error), frequency: .dailyAndCount)
+ pixelKit?.fire(VPNUninstallAttempt.failure(error), frequency: .legacyDailyAndCount)
}
throw error
diff --git a/LocalPackages/DataBrokerProtection/Package.swift b/LocalPackages/DataBrokerProtection/Package.swift
index 33cc4173f6..1bdbfe2119 100644
--- a/LocalPackages/DataBrokerProtection/Package.swift
+++ b/LocalPackages/DataBrokerProtection/Package.swift
@@ -29,7 +29,7 @@ let package = Package(
targets: ["DataBrokerProtection"])
],
dependencies: [
- .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "203.1.0"),
+ .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "204.0.0"),
.package(path: "../SwiftUIExtensions"),
.package(path: "../XPCHelper"),
.package(path: "../Freemium"),
diff --git a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Pixels/DataBrokerProtectionPixels.swift b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Pixels/DataBrokerProtectionPixels.swift
index f5fdcd9ce4..44f111e928 100644
--- a/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Pixels/DataBrokerProtectionPixels.swift
+++ b/LocalPackages/DataBrokerProtection/Sources/DataBrokerProtection/Pixels/DataBrokerProtectionPixels.swift
@@ -550,7 +550,7 @@ public class DataBrokerProtectionPixelsHandler: EventMapping