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