diff --git a/Configuration/BuildNumber.xcconfig b/Configuration/BuildNumber.xcconfig index 610113ea86..78ac15dc98 100644 --- a/Configuration/BuildNumber.xcconfig +++ b/Configuration/BuildNumber.xcconfig @@ -1 +1 @@ -CURRENT_PROJECT_VERSION = 330 +CURRENT_PROJECT_VERSION = 332 diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index 50887e402a..12f63ecaf6 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -1319,6 +1319,9 @@ 37FC2A192CF903080048E226 /* MockPrivacyStats.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37FC2A172CF903060048E226 /* MockPrivacyStats.swift */; }; 37FD78112A29EBD100B36DB1 /* SyncErrorHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37FD78102A29EBD100B36DB1 /* SyncErrorHandler.swift */; }; 37FD78122A29EBD100B36DB1 /* SyncErrorHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37FD78102A29EBD100B36DB1 /* SyncErrorHandler.swift */; }; + 46066CBC2D1330A100AB683B /* Persistence in Frameworks */ = {isa = PBXBuildFile; productRef = 46066CBB2D1330A100AB683B /* Persistence */; }; + 467D16672D0C98D5007C020A /* CrashReportSenderExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 467D16662D0C98D5007C020A /* CrashReportSenderExtensions.swift */; }; + 467D16682D0C98D5007C020A /* CrashReportSenderExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 467D16662D0C98D5007C020A /* CrashReportSenderExtensions.swift */; }; 4B0135CE2729F1AA00D54834 /* NSPasteboardExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B0135CD2729F1AA00D54834 /* NSPasteboardExtension.swift */; }; 4B02198925E05FAC00ED7DEA /* FireproofingURLExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B02197F25E05FAC00ED7DEA /* FireproofingURLExtensions.swift */; }; 4B02198A25E05FAC00ED7DEA /* FireproofDomains.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B02198125E05FAC00ED7DEA /* FireproofDomains.swift */; }; @@ -3796,6 +3799,7 @@ 37F8ABD22CE3EE5B00CB0294 /* FeatureFlagOverridesMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeatureFlagOverridesMenu.swift; sourceTree = ""; }; 37FC2A172CF903060048E226 /* MockPrivacyStats.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockPrivacyStats.swift; sourceTree = ""; }; 37FD78102A29EBD100B36DB1 /* SyncErrorHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SyncErrorHandler.swift; sourceTree = ""; }; + 467D16662D0C98D5007C020A /* CrashReportSenderExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CrashReportSenderExtensions.swift; sourceTree = ""; }; 4B0135CD2729F1AA00D54834 /* NSPasteboardExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NSPasteboardExtension.swift; sourceTree = ""; }; 4B02197F25E05FAC00ED7DEA /* FireproofingURLExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FireproofingURLExtensions.swift; sourceTree = ""; }; 4B02198125E05FAC00ED7DEA /* FireproofDomains.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FireproofDomains.swift; sourceTree = ""; }; @@ -5345,6 +5349,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 46066CBC2D1330A100AB683B /* Persistence in Frameworks */, B6DA44172616C13800DD1EC2 /* OHHTTPStubs in Frameworks */, F116A7C32BD1924B00F3FCF7 /* PixelKitTestingUtilities in Frameworks */, 84BBC8012CFA0D3800BAE57A /* TestUtils in Frameworks */, @@ -8639,6 +8644,7 @@ AAC30A27268E045400D2D9CD /* CrashReportReader.swift */, AAC30A2D268F1EE300D2D9CD /* CrashReportPromptPresenter.swift */, AAC30A29268E239100D2D9CD /* CrashReport.swift */, + 467D16662D0C98D5007C020A /* CrashReportSenderExtensions.swift */, ); path = Model; sourceTree = ""; @@ -10497,6 +10503,7 @@ 9DC5FACA2C6B8E050011F068 /* AppKitExtensions */, 84BBC8002CFA0D3800BAE57A /* TestUtils */, 374EFDEE2D01C70300B30939 /* Utilities */, + 46066CBB2D1330A100AB683B /* Persistence */, ); productName = DuckDuckGoTests; productReference = AA585D90248FD31400E9A3E2 /* Unit Tests.xctest */; @@ -11571,6 +11578,7 @@ 37197EA82942443D00394917 /* BrowserTabViewController.swift in Sources */, 3706FB39293F65D500E42796 /* PrivacyDashboardPopover.swift in Sources */, 3706FB3B293F65D500E42796 /* RootView.swift in Sources */, + 467D16672D0C98D5007C020A /* CrashReportSenderExtensions.swift in Sources */, 3706FB3C293F65D500E42796 /* AddressBarTextField.swift in Sources */, 3706FB3D293F65D500E42796 /* FocusRingView.swift in Sources */, 3706FB3E293F65D500E42796 /* BookmarksBarViewModel.swift in Sources */, @@ -13085,6 +13093,7 @@ AABEE6A524AA0A7F0043105B /* SuggestionViewController.swift in Sources */, 1D6216B229069BBF00386B2C /* BWKeyStorage.swift in Sources */, AA7E919F287872EA00AB6B62 /* VisitViewModel.swift in Sources */, + 467D16682D0C98D5007C020A /* CrashReportSenderExtensions.swift in Sources */, 7BD7B0012C19D3830039D20A /* VPNIPCResources.swift in Sources */, C1935A1B2C88F9ED001AD72D /* SyncPromoViewModel.swift in Sources */, B6676BE12AA986A700525A21 /* AddressBarTextEditor.swift in Sources */, @@ -15297,7 +15306,7 @@ repositoryURL = "https://github.com/duckduckgo/BrowserServicesKit"; requirement = { kind = exactVersion; - version = 221.3.0; + version = 222.1.0; }; }; 9FF521422BAA8FF300B9819B /* XCRemoteSwiftPackageReference "lottie-spm" */ = { @@ -15700,6 +15709,11 @@ package = 9807F643278CA16F00E1547B /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; productName = Navigation; }; + 46066CBB2D1330A100AB683B /* Persistence */ = { + isa = XCSwiftPackageProductDependency; + package = 9807F643278CA16F00E1547B /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; + productName = Persistence; + }; 4B2D062B2A11C0E100DE1F49 /* Networking */ = { isa = XCSwiftPackageProductDependency; package = 9807F643278CA16F00E1547B /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; diff --git a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index f38fb5f4a6..602e95e476 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" : { - "revision" : "b71ed70ce9b0ef3ce51d4f96da0193ab70493944", - "version" : "221.3.0" + "revision" : "5704d77e3b4c77c7387518d796d31a35f7a1ffcf", + "version" : "222.1.0" } }, { diff --git a/DuckDuckGo/Application/AppDelegate.swift b/DuckDuckGo/Application/AppDelegate.swift index 1b0788355b..3aa256fb0f 100644 --- a/DuckDuckGo/Application/AppDelegate.swift +++ b/DuckDuckGo/Application/AppDelegate.swift @@ -71,7 +71,8 @@ final class AppDelegate: NSObject, NSApplicationDelegate { let fileStore: FileStore #if APPSTORE - private let crashCollection = CrashCollection(platform: .macOSAppStore) + private let crashCollection = CrashCollection(crashReportSender: CrashReportSender(platform: .macOSAppStore, + pixelEvents: CrashReportSender.pixelEvents)) #else private let crashReporter = CrashReporter() #endif diff --git a/DuckDuckGo/CrashReports/Model/CrashReportSenderExtensions.swift b/DuckDuckGo/CrashReports/Model/CrashReportSenderExtensions.swift new file mode 100644 index 0000000000..85618d2d99 --- /dev/null +++ b/DuckDuckGo/CrashReports/Model/CrashReportSenderExtensions.swift @@ -0,0 +1,43 @@ +// +// CrashReportSenderExtensions.swift +// +// Copyright © 2024 DuckDuckGo. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import Crashes +import Common +import PixelKit + +extension CrashReportSender { + + static let pixelEvents: EventMapping = .init { event, _, _, _ in + switch event { + case CrashReportSenderError.crcidMissing: + PixelKit.fire(GeneralPixel.crashReportCRCIDMissing) + + case CrashReportSenderError.submissionFailed(let error): + if let error { + PixelKit.fire(DebugEvent(GeneralPixel.crashReportingSubmissionFailed), + frequency: .standard, + withHeaders: [:], + withAdditionalParameters: ["HTTPStatusCode": "\(error.statusCode)"], + withError: nil, + allowedQueryReservedCharacters: nil) + } else { + PixelKit.fire(GeneralPixel.crashReportingSubmissionFailed) + } + } + } +} diff --git a/DuckDuckGo/CrashReports/Model/CrashReporter.swift b/DuckDuckGo/CrashReports/Model/CrashReporter.swift index b3456a3adb..4883679907 100644 --- a/DuckDuckGo/CrashReports/Model/CrashReporter.swift +++ b/DuckDuckGo/CrashReports/Model/CrashReporter.swift @@ -24,7 +24,8 @@ import PixelKit final class CrashReporter { private let reader = CrashReportReader() - private lazy var sender = CrashReportSender(platform: .macOS) + private lazy var sender = CrashReportSender(platform: .macOS, pixelEvents: CrashReportSender.pixelEvents) + private lazy var crcidManager = CRCIDManager() private lazy var promptPresenter = CrashReportPromptPresenter() @UserDefaultsWrapper(key: .lastCrashReportCheckDate, defaultValue: nil) @@ -56,7 +57,9 @@ final class CrashReporter { return } Task { - await self.sender.send(contentData) + let crcid = self.crcidManager.crcid + let result = await self.sender.send(contentData, crcid: crcid) + self.crcidManager.handleCrashSenderResult(result: result.result, response: result.response) } } diff --git a/DuckDuckGo/Localizable.xcstrings b/DuckDuckGo/Localizable.xcstrings index ba0c0a8fe9..f0dbc2e23a 100644 --- a/DuckDuckGo/Localizable.xcstrings +++ b/DuckDuckGo/Localizable.xcstrings @@ -37013,11 +37013,59 @@ "comment" : "Title shown in an error page tab that warn users of security risks on a website that has been flagged as Malware.", "extractionState" : "extracted_with_value", "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Warnung: Website ist möglicherweise bösartig" + } + }, "en" : { "stringUnit" : { "state" : "new", "value" : "Warning: Site May Be Malicious" } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Advertencia: el sitio puede ser malicioso" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Avertissement : le site est peut-être malveillant" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Attenzione: il sito potrebbe essere dannoso" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Opgelet: Deze website kan schadelijk zijn" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ostrzeżenie: witryna może być złośliwa" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Aviso: o site pode ser malicioso" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Внимание! Потенциально вредоносный сайт" + } } } }, @@ -47104,8 +47152,8 @@ "localizations" : { "de" : { "stringUnit" : { - "state" : "needs_review", - "value" : "Erlaube DuckDuckGo, dich zu warnen, bevor eine Webseite geladen wird, die als bösartig oder betrügerisch gekennzeichnet wurde." + "state" : "translated", + "value" : "Warne mich auf Websites, die als Phishing- oder Malware-Websites gekennzeichnet sind." } }, "en" : { @@ -47116,44 +47164,44 @@ }, "es" : { "stringUnit" : { - "state" : "needs_review", - "value" : "Permite que DuckDuckGo te avise antes de cargar una página web que se haya marcado como maliciosa o fraudulenta." + "state" : "translated", + "value" : "Avisarme sobre sitios marcados como phishing o malware." } }, "fr" : { "stringUnit" : { - "state" : "needs_review", - "value" : "Autorisez DuckDuckGo à vous avertir avant de charger une page Web signalée comme malveillante ou frauduleuse." + "state" : "translated", + "value" : "Mettez-moi en garde contre les sites signalés pour hameçonnage ou comme étant des logiciels malveillants." } }, "it" : { "stringUnit" : { - "state" : "needs_review", - "value" : "Consenti a DuckDuckGo di avvisarti prima di caricare una pagina web contrassegnata come dannosa o fraudolenta." + "state" : "translated", + "value" : "Avvisami sui siti contrassegnati per phishing o malware." } }, "nl" : { "stringUnit" : { - "state" : "needs_review", - "value" : "Laat DuckDuckGo je waarschuwen voordat je een webpagina laadt die als kwaadaardig of frauduleus is gemarkeerd." + "state" : "translated", + "value" : "Waarschuw me op websites die zijn aangeduid als phishing of malware." } }, "pl" : { "stringUnit" : { - "state" : "needs_review", - "value" : "Zezwól DuckDuckGo na ostrzeganie przed załadowaniem strony internetowej, która została oznaczona jako złośliwa lub jako oszustwo." + "state" : "translated", + "value" : "Ostrzegaj mnie przed witrynami oznaczonymi jako wyłudzanie informacji lub złośliwe oprogramowanie." } }, "pt" : { "stringUnit" : { - "state" : "needs_review", - "value" : "Permitir que o DuckDuckGo te avise antes de carregar uma página que foi sinalizada como maliciosa ou fraudulenta." + "state" : "translated", + "value" : "Avisar-me sobre sites sinalizados como phishing ou malware." } }, "ru" : { "stringUnit" : { - "state" : "needs_review", - "value" : "Разрешить DuckDuckGo предупреждать вас о потенциально вредоносных или мошеннических сайтах перед загрузкой страницы." + "state" : "translated", + "value" : "Предупреждать о вредоносных и фишинговых сайтах" } } } @@ -47224,8 +47272,8 @@ "localizations" : { "de" : { "stringUnit" : { - "state" : "needs_review", - "value" : "Das Deaktivieren dieser Funktion kann deine persönlichen Daten gefährden. Wenn du dir über die damit verbundenen Risiken im Klaren bist, kannst du trotzdem fortfahren." + "state" : "translated", + "value" : "Das Deaktivieren dieser Funktion kann deine persönlichen Daten gefährden." } }, "en" : { @@ -47236,44 +47284,44 @@ }, "es" : { "stringUnit" : { - "state" : "needs_review", - "value" : "Desactivar esta función puede poner en riesgo tu información personal. Hazlo solo si entiendes completamente el riesgo que implica." + "state" : "translated", + "value" : "Desactivar esta función puede poner en riesgo tu información personal." } }, "fr" : { "stringUnit" : { - "state" : "needs_review", - "value" : "La désactivation de cette fonctionnalité peut mettre vos informations personnelles en danger. Faites-le uniquement si vous comprenez parfaitement les risques encourus." + "state" : "translated", + "value" : "La désactivation de cette fonctionnalité peut mettre vos informations personnelles en danger." } }, "it" : { "stringUnit" : { - "state" : "needs_review", - "value" : "Disabilitando questa funzione, potresti mettere a rischio i tuoi dati personali. Fallo solo se comprendi appieno il rischio che comporta." + "state" : "translated", + "value" : "Disabilitando questa funzione, potresti mettere a rischio i tuoi dati personali." } }, "nl" : { "stringUnit" : { - "state" : "needs_review", - "value" : "Als je deze functie uitschakelt, kunnen je persoonlijke gegevens in gevaar komen. Doe dit alleen als je het risico volledig begrijpt." + "state" : "translated", + "value" : "Als je deze functie uitschakelt, kunnen je persoonlijke gegevens in gevaar komen." } }, "pl" : { "stringUnit" : { - "state" : "needs_review", - "value" : "Wyłączenie tej funkcji może narazić Twoje dane osobowe na ryzyko. Rób to tylko wtedy, gdy rozumiesz związane z tym zagrożenie." + "state" : "translated", + "value" : "Wyłączenie tej funkcji może narazić Twoje dane osobowe na ryzyko." } }, "pt" : { "stringUnit" : { - "state" : "needs_review", - "value" : "Desativar esta funcionalidade pode pôr em risco as tuas informações pessoais. Não desatives a menos que compreendas os riscos." + "state" : "translated", + "value" : "Desativar esta funcionalidade pode pôr em risco as tuas informações pessoais." } }, "ru" : { "stringUnit" : { - "state" : "needs_review", - "value" : "При отключении этой функции ваши личные данные могут оказаться под угрозой. Эту функцию следует деактивировать только в том случае, если вы осознаете связанные с этим риски." + "state" : "translated", + "value" : "При отключении этой функции ваши личные данные могут оказаться под угрозой." } } } diff --git a/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/NetworkExtensionAndNotificationTargets/Localizable.xcstrings b/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/NetworkExtensionAndNotificationTargets/Localizable.xcstrings index a4d7368f52..b3cab01392 100644 --- a/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/NetworkExtensionAndNotificationTargets/Localizable.xcstrings +++ b/DuckDuckGo/NetworkProtection/NetworkExtensionTargets/NetworkExtensionAndNotificationTargets/Localizable.xcstrings @@ -557,6 +557,12 @@ "value" : "Reconnect" } }, + "en-US" : { + "stringUnit" : { + "state" : "translated", + "value" : "Reconnect" + } + }, "es" : { "stringUnit" : { "state" : "translated", diff --git a/DuckDuckGo/Statistics/GeneralPixel.swift b/DuckDuckGo/Statistics/GeneralPixel.swift index 2a92aa9845..0c24d26481 100644 --- a/DuckDuckGo/Statistics/GeneralPixel.swift +++ b/DuckDuckGo/Statistics/GeneralPixel.swift @@ -26,6 +26,8 @@ enum GeneralPixel: PixelKitEventV2 { case crash case crashOnCrashHandlersSetUp + case crashReportingSubmissionFailed + case crashReportCRCIDMissing case compileRulesWait(onboardingShown: OnboardingShown, waitTime: CompileRulesWaitTime, result: WaitResult) case launchInitial(cohort: String) case launch(isDefault: Bool) @@ -473,6 +475,12 @@ enum GeneralPixel: PixelKitEventV2 { case .crashOnCrashHandlersSetUp: return "m_mac_crash_on_handlers_setup" + case .crashReportCRCIDMissing: + return "m_mac_crashreporting_crcid-missing" + + case .crashReportingSubmissionFailed: + return "m_mac_crashreporting_submission-failed" + case .compileRulesWait(onboardingShown: let onboardingShown, waitTime: let waitTime, result: let result): return "m_mac_cbr-wait_\(onboardingShown)_\(waitTime)_\(result)" diff --git a/DuckDuckGoVPN/Localizable.xcstrings b/DuckDuckGoVPN/Localizable.xcstrings index c18410e568..43636be9c4 100644 --- a/DuckDuckGoVPN/Localizable.xcstrings +++ b/DuckDuckGoVPN/Localizable.xcstrings @@ -557,6 +557,12 @@ "value" : "DuckDuckGo VPN" } }, + "en-US" : { + "stringUnit" : { + "state" : "translated", + "value" : "DuckDuckGo VPN" + } + }, "es" : { "stringUnit" : { "state" : "translated", diff --git a/LocalPackages/DataBrokerProtection/Package.swift b/LocalPackages/DataBrokerProtection/Package.swift index 79e021c472..2cb2248e15 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: "221.3.0"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "222.1.0"), .package(path: "../SwiftUIExtensions"), .package(path: "../AppKitExtensions"), .package(path: "../XPCHelper"), diff --git a/LocalPackages/FeatureFlags/Package.swift b/LocalPackages/FeatureFlags/Package.swift index dcb3d9194f..c552f688dd 100644 --- a/LocalPackages/FeatureFlags/Package.swift +++ b/LocalPackages/FeatureFlags/Package.swift @@ -32,7 +32,7 @@ let package = Package( targets: ["FeatureFlags"]), ], dependencies: [ - .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "221.3.0"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "222.1.0"), ], targets: [ // Targets are the basic building blocks of a package, defining a module or a test suite. diff --git a/LocalPackages/NetworkProtectionMac/Package.swift b/LocalPackages/NetworkProtectionMac/Package.swift index 3431d62c5a..ba1c4334a4 100644 --- a/LocalPackages/NetworkProtectionMac/Package.swift +++ b/LocalPackages/NetworkProtectionMac/Package.swift @@ -33,7 +33,7 @@ let package = Package( .library(name: "VPNAppLauncher", targets: ["VPNAppLauncher"]), ], dependencies: [ - .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "221.3.0"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "222.1.0"), .package(url: "https://github.com/airbnb/lottie-spm", exact: "4.4.3"), .package(path: "../AppLauncher"), .package(path: "../UDSHelper"), diff --git a/LocalPackages/NewTabPage/Package.swift b/LocalPackages/NewTabPage/Package.swift index 46ba37e00c..f062a29127 100644 --- a/LocalPackages/NewTabPage/Package.swift +++ b/LocalPackages/NewTabPage/Package.swift @@ -32,7 +32,7 @@ let package = Package( targets: ["NewTabPage"]), ], dependencies: [ - .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "221.3.0"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "222.1.0"), .package(path: "../WebKitExtensions"), .package(path: "../Utilities"), ], diff --git a/LocalPackages/SubscriptionUI/Package.swift b/LocalPackages/SubscriptionUI/Package.swift index 40bb88836f..1b4ee7bdce 100644 --- a/LocalPackages/SubscriptionUI/Package.swift +++ b/LocalPackages/SubscriptionUI/Package.swift @@ -13,7 +13,7 @@ let package = Package( targets: ["SubscriptionUI"]), ], dependencies: [ - .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "221.3.0"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "222.1.0"), .package(path: "../SwiftUIExtensions"), .package(path: "../FeatureFlags") ], diff --git a/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/Preferences/PreferencesSubscriptionModel.swift b/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/Preferences/PreferencesSubscriptionModel.swift index dfed042d42..e0a7bab18c 100644 --- a/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/Preferences/PreferencesSubscriptionModel.swift +++ b/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/Preferences/PreferencesSubscriptionModel.swift @@ -315,6 +315,11 @@ public final class PreferencesSubscriptionModel: ObservableObject { userEventHandler(.openFeedback) } + @MainActor + func openPrivacyPolicy() { + openURLHandler(URL(string: "https://duckduckgo.com/pro/privacy-terms")!) + } + @MainActor func refreshSubscriptionPendingState() { if subscriptionManager.currentEnvironment.purchasePlatform == .appStore { diff --git a/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/Preferences/PreferencesSubscriptionView.swift b/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/Preferences/PreferencesSubscriptionView.swift index ec66c0b134..8bcc0f4ba0 100644 --- a/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/Preferences/PreferencesSubscriptionView.swift +++ b/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/Preferences/PreferencesSubscriptionView.swift @@ -101,11 +101,6 @@ public struct PreferencesSubscriptionView: View { // Help section helpSection - - // Feedback section - if subscriptionFeatureAvailability.usesUnifiedFeedbackForm, state == .subscriptionActive { - feedbackSection - } } .onAppear(perform: { model.didAppear() @@ -303,24 +298,21 @@ public struct PreferencesSubscriptionView: View { private var helpSection: some View { PreferencePaneSection { TextMenuItemHeader(UserText.preferencesSubscriptionFooterTitle, bottomPadding: 0) - HStack(alignment: .top, spacing: 6) { - if !model.isROWLaunched { - TextMenuItemCaption(UserText.preferencesSubscriptionFooterCaption) - } else { - TextMenuItemCaption(UserText.preferencesSubscriptionHelpFooterCaption) - } - Button(UserText.viewFaqsButton) { model.openFAQ() } + if !model.isROWLaunched { + TextMenuItemCaption(UserText.preferencesSubscriptionFooterCaption) + .padding(.bottom, 8) + } else { + TextMenuItemCaption(UserText.preferencesSubscriptionHelpFooterCaption) + .padding(.bottom, 8) } - } - } + VStack(alignment: .leading, spacing: 16) { + TextButton(UserText.viewFaqsButton, weight: .semibold) { model.openFAQ() } - @ViewBuilder - private var feedbackSection: some View { - PreferencePaneSection { - TextMenuItemHeader(UserText.preferencesSubscriptionFeedbackTitle, bottomPadding: 0) - HStack(alignment: .top, spacing: 6) { - TextMenuItemCaption(UserText.preferencesSubscriptionFeedbackCaption) - Button(UserText.preferencesSubscriptionFeedbackButton) { model.openUnifiedFeedbackForm() } + if subscriptionFeatureAvailability.usesUnifiedFeedbackForm, state == .subscriptionActive { + TextButton(UserText.preferencesSubscriptionFeedbackButton, weight: .semibold) { model.openUnifiedFeedbackForm() } + } + + TextButton(UserText.preferencesPrivacyPolicyButton, weight: .semibold) { model.openPrivacyPolicy() } } } } @@ -495,6 +487,7 @@ private struct SubscriptionDialog: View where Buttons: View { .fixMultilineScrollableText() .foregroundColor(Color(.textPrimary)) } buttons: { + Spacer() buttons() } } diff --git a/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/Resources/Localizable.xcstrings b/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/Resources/Localizable.xcstrings index c7836d0be0..f909d5486a 100644 --- a/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/Resources/Localizable.xcstrings +++ b/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/Resources/Localizable.xcstrings @@ -2265,6 +2265,66 @@ } } }, + "subscription.preferences.privacypolicy.button" : { + "comment" : "Title for the privacy policy button", + "extractionState" : "extracted_with_value", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Datenschutzerklärung und Nutzungsbedingungen" + } + }, + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Privacy Policy and Terms of Service" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Política de privacidad y condiciones del servicio" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Politique de confidentialité et conditions d'utilisation" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Privacy policy e Termini del servizio" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Privacybeleid en servicevoorwaarden" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Polityka prywatności i warunki użytkowania" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Política de Privacidade e Termos de Serviço" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Политика конфиденциальности и условия обслуживания" + } + } + } + }, "subscription.preferences.purchase.button" : { "comment" : "Button to open a page where user can learn more and purchase the subscription", "extractionState" : "extracted_with_value", diff --git a/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/UserText.swift b/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/UserText.swift index a0c9d163a0..8f4e5a018a 100644 --- a/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/UserText.swift +++ b/LocalPackages/SubscriptionUI/Sources/SubscriptionUI/UserText.swift @@ -54,6 +54,7 @@ enum UserText { static let preferencesSubscriptionFeedbackTitle = NSLocalizedString("subscription.preferences.feedback.title", bundle: Bundle.module, value: "Send Feedback", comment: "Title for the subscription feedback section") static let preferencesSubscriptionFeedbackCaption = NSLocalizedString("subscription.preferences.feedback.caption", bundle: Bundle.module, value: "Help improve Privacy Pro. Your feedback matters to us. Feel free to report any issues or provide general feedback.", comment: "Caption for the subscription feedback section") static let preferencesSubscriptionFeedbackButton = NSLocalizedString("subscription.preferences.feedback.button", bundle: Bundle.module, value: "Send Feedback", comment: "Title for the subscription feedback button") + static let preferencesPrivacyPolicyButton = NSLocalizedString("subscription.preferences.privacypolicy.button", bundle: Bundle.module, value: "Privacy Policy and Terms of Service", comment: "Title for the privacy policy button") static func preferencesSubscriptionRenewingCaption(billingPeriod: Subscription.BillingPeriod, formattedDate: String) -> String { let localized: String diff --git a/LocalPackages/WebKitExtensions/Package.swift b/LocalPackages/WebKitExtensions/Package.swift index 44e660355b..00965ec758 100644 --- a/LocalPackages/WebKitExtensions/Package.swift +++ b/LocalPackages/WebKitExtensions/Package.swift @@ -32,7 +32,7 @@ let package = Package( ), ], dependencies: [ - .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "221.3.0"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "222.1.0"), .package(path: "../AppKitExtensions") ], targets: [