diff --git a/.github/actions/asana-create-action-item/action.yml b/.github/actions/asana-create-action-item/action.yml index e235d9d511..f3c5455006 100644 --- a/.github/actions/asana-create-action-item/action.yml +++ b/.github/actions/asana-create-action-item/action.yml @@ -44,6 +44,7 @@ runs: task-url: ${{ inputs.release-task-url }} - id: get-asana-user-id + if: github.event_name != "schedule" uses: duckduckgo/apple-infra/actions/asana-get-user-id-for-github-handle@main with: access-token: ${{ inputs.access-token }} diff --git a/.github/actions/asana-log-message/action.yml b/.github/actions/asana-log-message/action.yml index 7ab78fdd4b..86940852bf 100644 --- a/.github/actions/asana-log-message/action.yml +++ b/.github/actions/asana-log-message/action.yml @@ -30,6 +30,7 @@ runs: task-url: ${{ inputs.task-url }} - id: get-asana-user-id + if: github.event_name != "schedule" uses: duckduckgo/apple-infra/actions/asana-get-user-id-for-github-handle@main with: access-token: ${{ inputs.access-token }} diff --git a/.github/workflows/bump_internal_release.yml b/.github/workflows/bump_internal_release.yml index 43e0f88084..ba06acdcc6 100644 --- a/.github/workflows/bump_internal_release.yml +++ b/.github/workflows/bump_internal_release.yml @@ -2,7 +2,7 @@ name: Bump Internal Release on: schedule: - - cron: '0 7 * * 2-5' # Run at 07:00 UTC, Tuesday through Friday + - cron: '0 5 * * 2-5' # Run at 05:00 UTC, Tuesday through Friday workflow_dispatch: inputs: asana-task-url: @@ -63,13 +63,13 @@ jobs: echo "skip-release=false" >> $GITHUB_OUTPUT else latest_tag="$(git describe --tags --abbrev=0)" - changed_files="$(git diff --name-only "$latest_tag".."origin/${release_branch}" | grep -v -E '.github|scripts')" + changed_files="$(git diff --name-only "$latest_tag".."origin/${release_branch}")" - if [[ ${#changed_files} == 0 ]]; then - echo "::warning::No changes to the release branch (or only scripts and workflows). Skipping automatic release." - echo "skip-release=true" >> $GITHUB_OUTPUT - else + if grep -q -v -e '.github' -e 'scripts' <<< "$changed_files"; then echo "skip-release=false" >> $GITHUB_OUTPUT + else + echo "::warning::No changes to the release branch (or only changes to scripts and workflows). Skipping automatic release." + echo "skip-release=true" >> $GITHUB_OUTPUT fi fi diff --git a/Configuration/BuildNumber.xcconfig b/Configuration/BuildNumber.xcconfig index 7bd323987a..9a14499d7a 100644 --- a/Configuration/BuildNumber.xcconfig +++ b/Configuration/BuildNumber.xcconfig @@ -1 +1 @@ -CURRENT_PROJECT_VERSION = 141 +CURRENT_PROJECT_VERSION = 143 diff --git a/Configuration/Extensions/NetworkProtection/NetworkProtectionSystemExtension.xcconfig b/Configuration/Extensions/NetworkProtection/NetworkProtectionSystemExtension.xcconfig index c6b581e569..9cc1c7ae28 100644 --- a/Configuration/Extensions/NetworkProtection/NetworkProtectionSystemExtension.xcconfig +++ b/Configuration/Extensions/NetworkProtection/NetworkProtectionSystemExtension.xcconfig @@ -29,7 +29,7 @@ CODE_SIGN_IDENTITY[config=Debug][sdk=macosx*] = Apple Development GENERATE_INFOPLIST_FILE = YES INFOPLIST_FILE = NetworkProtectionSystemExtension/Info.plist INFOPLIST_KEY_NSHumanReadableCopyright = Copyright © 2023 DuckDuckGo. All rights reserved. -INFOPLIST_KEY_NSSystemExtensionUsageDescription = Network Protection +INFOPLIST_KEY_NSSystemExtensionUsageDescription = DuckDuckGo VPN FEATURE_FLAGS[arch=*][sdk=*] = NETP_SYSTEM_EXTENSION NETWORK_EXTENSION NETWORK_PROTECTION FEATURE_FLAGS[config=CI][arch=*][sdk=*] = NETP_SYSTEM_EXTENSION NETWORK_EXTENSION NETWORK_PROTECTION diff --git a/Configuration/Global.xcconfig b/Configuration/Global.xcconfig index 39c875ee65..37ab4747ad 100644 --- a/Configuration/Global.xcconfig +++ b/Configuration/Global.xcconfig @@ -91,7 +91,7 @@ SWIFT_COMPILATION_MODE = wholemodule SWIFT_COMPILATION_MODE[config=CI][arch=*][sdk=*] = SWIFT_COMPILATION_MODE[config=Debug][arch=*][sdk=*] = -// This is temporarily set back to its default value, as a part of merging Network Protection. There are a small number of warnings introduced in +// This is temporarily set back to its default value, as a part of merging the VPN. There are a small number of warnings introduced in // that feature, and more time is needed to address them. To avoid bothering other developers, this is being disabled and a task to fix it will be // prioritized. SWIFT_STRICT_CONCURRENCY = minimal; diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index 83b000d3c0..4ee7964ed8 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -2177,6 +2177,8 @@ 7B1E819E27C8874900FF0E60 /* ContentOverlayPopover.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B1E819B27C8874900FF0E60 /* ContentOverlayPopover.swift */; }; 7B1E819F27C8874900FF0E60 /* ContentOverlay.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 7B1E819C27C8874900FF0E60 /* ContentOverlay.storyboard */; }; 7B1E81A027C8874900FF0E60 /* ContentOverlayViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B1E819D27C8874900FF0E60 /* ContentOverlayViewController.swift */; }; + 7B25856C2BA2F2D000D49F79 /* AppLauncher.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEAD7A6E2A1D3E1F002A24E7 /* AppLauncher.swift */; }; + 7B25856E2BA2F2ED00D49F79 /* NetworkProtectionUI in Frameworks */ = {isa = PBXBuildFile; productRef = 7B25856D2BA2F2ED00D49F79 /* NetworkProtectionUI */; }; 7B2DDCF82A93A8BB0039D884 /* NetworkProtectionAppEvents.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B2DDCF72A93A8BB0039D884 /* NetworkProtectionAppEvents.swift */; }; 7B2DDCFA2A93B25F0039D884 /* KeychainType+ClientDefault.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BD3AF5C2A8E7AF1006F9F56 /* KeychainType+ClientDefault.swift */; }; 7B2DDCFB2A93B25F0039D884 /* KeychainType+ClientDefault.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BD3AF5C2A8E7AF1006F9F56 /* KeychainType+ClientDefault.swift */; }; @@ -2190,6 +2192,7 @@ 7B4CE8E726F02135009134B1 /* TabBarTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B4CE8E626F02134009134B1 /* TabBarTests.swift */; }; 7B5DD69A2AE51FFA001DE99C /* PixelKit in Frameworks */ = {isa = PBXBuildFile; productRef = 7B5DD6992AE51FFA001DE99C /* PixelKit */; }; 7B5F9A752AE2BE4E002AEBC0 /* PixelKit in Frameworks */ = {isa = PBXBuildFile; productRef = 7B5F9A742AE2BE4E002AEBC0 /* PixelKit */; }; + 7B624F172BA25C1F00A6C544 /* NetworkProtectionUI in Frameworks */ = {isa = PBXBuildFile; productRef = 7B624F162BA25C1F00A6C544 /* NetworkProtectionUI */; }; 7B7DFB202B7E736B009EA1A3 /* MacPacketTunnelProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEF12E6D2A2111880023E6BF /* MacPacketTunnelProvider.swift */; }; 7B7DFB222B7E7473009EA1A3 /* Networking in Frameworks */ = {isa = PBXBuildFile; productRef = 7B7DFB212B7E7473009EA1A3 /* Networking */; }; 7B8C083C2AE1268E00F4C67F /* PixelKit in Frameworks */ = {isa = PBXBuildFile; productRef = 7B8C083B2AE1268E00F4C67F /* PixelKit */; }; @@ -2581,6 +2584,9 @@ B31055C427A1BA1D001AC618 /* AutoconsentUserScript.swift in Sources */ = {isa = PBXBuildFile; fileRef = B31055BC27A1BA1D001AC618 /* AutoconsentUserScript.swift */; }; B31055C627A1BA1D001AC618 /* userscript.js in Resources */ = {isa = PBXBuildFile; fileRef = B31055BE27A1BA1D001AC618 /* userscript.js */; }; B31055CB27A1BA1D001AC618 /* autoconsent-bundle.js in Resources */ = {isa = PBXBuildFile; fileRef = B31055C327A1BA1D001AC618 /* autoconsent-bundle.js */; }; + B60293E62BA19ECD0033186B /* NetPPopoverManagerMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = B60293E52BA19ECD0033186B /* NetPPopoverManagerMock.swift */; }; + B60293E72BA19ECD0033186B /* NetPPopoverManagerMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = B60293E52BA19ECD0033186B /* NetPPopoverManagerMock.swift */; }; + B60293E82BA19ECD0033186B /* NetPPopoverManagerMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = B60293E52BA19ECD0033186B /* NetPPopoverManagerMock.swift */; }; B602E7CF2A93A5FF00F12201 /* WKBackForwardListExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = B602E7CE2A93A5FF00F12201 /* WKBackForwardListExtension.swift */; }; B602E7D02A93A5FF00F12201 /* WKBackForwardListExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = B602E7CE2A93A5FF00F12201 /* WKBackForwardListExtension.swift */; }; B602E8162A1E2570006D261F /* URL+NetworkProtection.swift in Sources */ = {isa = PBXBuildFile; fileRef = B602E8152A1E2570006D261F /* URL+NetworkProtection.swift */; }; @@ -3075,6 +3081,13 @@ C168B9AC2B31DC7E001AFAD9 /* AutofillNeverPromptWebsitesManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C168B9AB2B31DC7E001AFAD9 /* AutofillNeverPromptWebsitesManager.swift */; }; C168B9AD2B31DC7F001AFAD9 /* AutofillNeverPromptWebsitesManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C168B9AB2B31DC7E001AFAD9 /* AutofillNeverPromptWebsitesManager.swift */; }; C168B9AE2B31DC7F001AFAD9 /* AutofillNeverPromptWebsitesManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C168B9AB2B31DC7E001AFAD9 /* AutofillNeverPromptWebsitesManager.swift */; }; + C17CA7AD2B9B52E6008EC3C1 /* NavigationBarPopoversTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C17CA7AC2B9B52E6008EC3C1 /* NavigationBarPopoversTests.swift */; }; + C17CA7AE2B9B52E6008EC3C1 /* NavigationBarPopoversTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C17CA7AC2B9B52E6008EC3C1 /* NavigationBarPopoversTests.swift */; }; + C17CA7B22B9B5317008EC3C1 /* MockAutofillPopoverPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C17CA7B12B9B5317008EC3C1 /* MockAutofillPopoverPresenter.swift */; }; + C17CA7B32B9B5317008EC3C1 /* MockAutofillPopoverPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C17CA7B12B9B5317008EC3C1 /* MockAutofillPopoverPresenter.swift */; }; + C1DAF3B52B9A44860059244F /* AutofillPopoverPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1DAF3B42B9A44860059244F /* AutofillPopoverPresenter.swift */; }; + C1DAF3B62B9A44860059244F /* AutofillPopoverPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1DAF3B42B9A44860059244F /* AutofillPopoverPresenter.swift */; }; + C1DAF3B72B9A44860059244F /* AutofillPopoverPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1DAF3B42B9A44860059244F /* AutofillPopoverPresenter.swift */; }; C1E961EB2B879E79001760E1 /* MockAutofillActionPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E961E72B879E4D001760E1 /* MockAutofillActionPresenter.swift */; }; C1E961ED2B879ED9001760E1 /* MockAutofillActionExecutor.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E961EC2B879ED9001760E1 /* MockAutofillActionExecutor.swift */; }; C1E961EF2B87AA29001760E1 /* AutofillActionBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1E961EE2B87AA29001760E1 /* AutofillActionBuilder.swift */; }; @@ -3115,13 +3128,10 @@ EE7295E32A545B9A008C0991 /* NetworkProtection in Frameworks */ = {isa = PBXBuildFile; productRef = EE7295E22A545B9A008C0991 /* NetworkProtection */; }; EE7295E72A545BBB008C0991 /* NetworkProtection in Frameworks */ = {isa = PBXBuildFile; productRef = EE7295E62A545BBB008C0991 /* NetworkProtection */; }; EE7295E92A545BC4008C0991 /* NetworkProtection in Frameworks */ = {isa = PBXBuildFile; productRef = EE7295E82A545BC4008C0991 /* NetworkProtection */; }; - EE7295EB2A545BFC008C0991 /* NetworkProtection in Frameworks */ = {isa = PBXBuildFile; productRef = EE7295EA2A545BFC008C0991 /* NetworkProtection */; }; EE7295ED2A545C0A008C0991 /* NetworkProtection in Frameworks */ = {isa = PBXBuildFile; productRef = EE7295EC2A545C0A008C0991 /* NetworkProtection */; }; EE7295EF2A545C12008C0991 /* NetworkProtection in Frameworks */ = {isa = PBXBuildFile; productRef = EE7295EE2A545C12008C0991 /* NetworkProtection */; }; EEA3EEB12B24EBD000E8333A /* NetworkProtectionVPNCountryLabelsModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEA3EEB02B24EBD000E8333A /* NetworkProtectionVPNCountryLabelsModel.swift */; }; EEA3EEB32B24EC0600E8333A /* VPNLocationViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEA3EEB22B24EC0600E8333A /* VPNLocationViewModel.swift */; }; - EEAD7A7A2A1D3E20002A24E7 /* AppLauncher.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEAD7A6E2A1D3E1F002A24E7 /* AppLauncher.swift */; }; - EEAD7A7B2A1D3E20002A24E7 /* AppLauncher.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEAD7A6E2A1D3E1F002A24E7 /* AppLauncher.swift */; }; EEAD7A7C2A1D3E20002A24E7 /* AppLauncher.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEAD7A6E2A1D3E1F002A24E7 /* AppLauncher.swift */; }; EEC111E4294D06020086524F /* JSAlert.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = EEC111E3294D06020086524F /* JSAlert.storyboard */; }; EEC111E6294D06290086524F /* JSAlertViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEC111E5294D06290086524F /* JSAlertViewModel.swift */; }; @@ -4164,6 +4174,7 @@ B31055BC27A1BA1D001AC618 /* AutoconsentUserScript.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AutoconsentUserScript.swift; sourceTree = ""; }; B31055BE27A1BA1D001AC618 /* userscript.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = userscript.js; sourceTree = ""; }; B31055C327A1BA1D001AC618 /* autoconsent-bundle.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = "autoconsent-bundle.js"; sourceTree = ""; }; + B60293E52BA19ECD0033186B /* NetPPopoverManagerMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetPPopoverManagerMock.swift; sourceTree = ""; }; B602E7CE2A93A5FF00F12201 /* WKBackForwardListExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WKBackForwardListExtension.swift; sourceTree = ""; }; B602E8152A1E2570006D261F /* URL+NetworkProtection.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "URL+NetworkProtection.swift"; sourceTree = ""; }; B602E81C2A1E25B0006D261F /* NEOnDemandRuleExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NEOnDemandRuleExtension.swift; sourceTree = ""; }; @@ -4463,6 +4474,9 @@ C13909F32B85FD79001626ED /* AutofillDeleteAllPasswordsExecutorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutofillDeleteAllPasswordsExecutorTests.swift; sourceTree = ""; }; C13909FA2B861039001626ED /* AutofillActionPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutofillActionPresenter.swift; sourceTree = ""; }; C168B9AB2B31DC7E001AFAD9 /* AutofillNeverPromptWebsitesManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AutofillNeverPromptWebsitesManager.swift; sourceTree = ""; }; + C17CA7AC2B9B52E6008EC3C1 /* NavigationBarPopoversTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationBarPopoversTests.swift; sourceTree = ""; }; + C17CA7B12B9B5317008EC3C1 /* MockAutofillPopoverPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockAutofillPopoverPresenter.swift; sourceTree = ""; }; + C1DAF3B42B9A44860059244F /* AutofillPopoverPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutofillPopoverPresenter.swift; sourceTree = ""; }; C1E961E72B879E4D001760E1 /* MockAutofillActionPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockAutofillActionPresenter.swift; sourceTree = ""; }; C1E961EC2B879ED9001760E1 /* MockAutofillActionExecutor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockAutofillActionExecutor.swift; sourceTree = ""; }; C1E961EE2B87AA29001760E1 /* AutofillActionBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutofillActionBuilder.swift; sourceTree = ""; }; @@ -4622,7 +4636,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - EE7295EB2A545BFC008C0991 /* NetworkProtection in Frameworks */, + 7B624F172BA25C1F00A6C544 /* NetworkProtectionUI in Frameworks */, 37269F052B3332C2005E8E46 /* Common in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -4635,6 +4649,7 @@ EE7295E72A545BBB008C0991 /* NetworkProtection in Frameworks */, 4B4D60982A0B2A5C00BCD287 /* PixelKit in Frameworks */, 4B4D60AF2A0C837F00BCD287 /* Networking in Frameworks */, + 7B25856E2BA2F2ED00D49F79 /* NetworkProtectionUI in Frameworks */, 4B4D603F2A0B290200BCD287 /* NetworkExtension.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -6544,6 +6559,7 @@ 4B8A4DFE27C83B29005F40E8 /* SaveIdentityViewController.swift */, 4BE4005227CF3DC3007D3161 /* SavePaymentMethodPopover.swift */, 4BE4005427CF3F19007D3161 /* SavePaymentMethodViewController.swift */, + C1DAF3B42B9A44860059244F /* AutofillPopoverPresenter.swift */, ); path = View; sourceTree = ""; @@ -7225,6 +7241,7 @@ AAA0CC32252F181A0079BC96 /* NavigationButtonMenuDelegate.swift */, 85012B0129133F9F003D0DCC /* NavigationBarPopovers.swift */, AA68C3D22490ED62001B8783 /* NavigationBarViewController.swift */, + B60293E52BA19ECD0033186B /* NetPPopoverManagerMock.swift */, D64A5FF72AEA5C2B00B6D6E7 /* HomeButtonMenuFactory.swift */, ); path = View; @@ -7297,9 +7314,11 @@ AA91F83627076ED100771A0D /* NavigationBar */ = { isa = PBXGroup; children = ( + C17CA7B02B9B52FF008EC3C1 /* Mocks */, AA91F83727076EEE00771A0D /* ViewModel */, 4BF6961F28BEEE8B00D402D4 /* LocalPinningManagerTests.swift */, 56B234BE2A84EFD200F2A1CC /* NavigationBarUrlExtensionsTests.swift */, + C17CA7AF2B9B52EB008EC3C1 /* View */, ); path = NavigationBar; sourceTree = ""; @@ -8305,6 +8324,22 @@ path = Tests; sourceTree = ""; }; + C17CA7AF2B9B52EB008EC3C1 /* View */ = { + isa = PBXGroup; + children = ( + C17CA7AC2B9B52E6008EC3C1 /* NavigationBarPopoversTests.swift */, + ); + path = View; + sourceTree = ""; + }; + C17CA7B02B9B52FF008EC3C1 /* Mocks */ = { + isa = PBXGroup; + children = ( + C17CA7B12B9B5317008EC3C1 /* MockAutofillPopoverPresenter.swift */, + ); + path = Mocks; + sourceTree = ""; + }; C1E961E62B879E2A001760E1 /* Mocks */ = { isa = PBXGroup; children = ( @@ -8639,8 +8674,8 @@ ); name = DuckDuckGoNotifications; packageProductDependencies = ( - EE7295EA2A545BFC008C0991 /* NetworkProtection */, 37269F042B3332C2005E8E46 /* Common */, + 7B624F162BA25C1F00A6C544 /* NetworkProtectionUI */, ); productName = DuckDuckGoNotifications; productReference = 4B4BEC202A11B4E2001D9AC5 /* DuckDuckGo Notifications.app */; @@ -8666,6 +8701,7 @@ 4B4D60AE2A0C837F00BCD287 /* Networking */, EE7295E62A545BBB008C0991 /* NetworkProtection */, 37269EFE2B332FBB005E8E46 /* Common */, + 7B25856D2BA2F2ED00D49F79 /* NetworkProtectionUI */, ); productName = NetworkProtectionAppExtension; productReference = 4B4D603D2A0B290200BCD287 /* NetworkProtectionAppExtension.appex */; @@ -10259,6 +10295,7 @@ 4B9DB0452A983B24000927DB /* WaitlistModalViewController.swift in Sources */, B66CA41F2AD910B300447CF0 /* DataImportView.swift in Sources */, 3706FC0C293F65D500E42796 /* NSAttributedStringExtension.swift in Sources */, + C1DAF3B62B9A44860059244F /* AutofillPopoverPresenter.swift in Sources */, 3706FC0D293F65D500E42796 /* AnimationView.swift in Sources */, 3706FC0E293F65D500E42796 /* NSRectExtension.swift in Sources */, 3706FC0F293F65D500E42796 /* YoutubeOverlayUserScript.swift in Sources */, @@ -10345,6 +10382,7 @@ 3706FC51293F65D500E42796 /* RecentlyVisitedView.swift in Sources */, B645D8F729FA95440024461F /* WKProcessPoolExtension.swift in Sources */, 3706FC52293F65D500E42796 /* MouseOverAnimationButton.swift in Sources */, + B60293E72BA19ECD0033186B /* NetPPopoverManagerMock.swift in Sources */, 3706FC53293F65D500E42796 /* TabBarScrollView.swift in Sources */, 3706FC54293F65D500E42796 /* BookmarkListTreeControllerDataSource.swift in Sources */, 3706FC55293F65D500E42796 /* AddressBarViewController.swift in Sources */, @@ -10548,6 +10586,7 @@ B6619EF72B10DFF700CD9186 /* InstructionsFormatParserTests.swift in Sources */, 3706FE21293F661700E42796 /* DownloadsPreferencesTests.swift in Sources */, 3706FE22293F661700E42796 /* FireproofDomainsTests.swift in Sources */, + C17CA7AE2B9B52E6008EC3C1 /* NavigationBarPopoversTests.swift in Sources */, 3706FE23293F661700E42796 /* SuggestionLoadingMock.swift in Sources */, 3706FE24293F661700E42796 /* PasteboardFolderTests.swift in Sources */, B603971229B9D67E00902A34 /* PublishersExtensions.swift in Sources */, @@ -10585,6 +10624,7 @@ 3706FE3C293F661700E42796 /* FireproofDomainsStoreMock.swift in Sources */, 3706FE3D293F661700E42796 /* DataEncryptionTests.swift in Sources */, 3706FE3E293F661700E42796 /* ClickToLoadModelTests.swift in Sources */, + C17CA7B32B9B5317008EC3C1 /* MockAutofillPopoverPresenter.swift in Sources */, 3706FE3F293F661700E42796 /* FileStoreMock.swift in Sources */, B6619F042B17123200CD9186 /* DataImportViewModelTests.swift in Sources */, 1D8C2FE62B70F4C4005E4BBD /* TabSnapshotExtensionTests.swift in Sources */, @@ -10779,7 +10819,6 @@ 4B2D062D2A11C12300DE1F49 /* Logging.swift in Sources */, 7B2E52252A5FEC09000C6D39 /* NetworkProtectionAgentNotificationsPresenter.swift in Sources */, B602E8232A1E260E006D261F /* Bundle+NetworkProtectionExtensions.swift in Sources */, - EEAD7A7B2A1D3E20002A24E7 /* AppLauncher.swift in Sources */, 4B2D062A2A11C0C900DE1F49 /* NetworkProtectionOptionKeyExtension.swift in Sources */, B602E8192A1E2570006D261F /* URL+NetworkProtection.swift in Sources */, 4B2D06322A11C1D300DE1F49 /* NSApplicationExtension.swift in Sources */, @@ -10883,6 +10922,7 @@ buildActionMask = 2147483647; files = ( 4B41EDA02B15437A001EEDF4 /* NetworkProtectionNotificationsPresenterFactory.swift in Sources */, + 7B25856C2BA2F2D000D49F79 /* AppLauncher.swift in Sources */, 4B4D609F2A0B2C7300BCD287 /* Logging.swift in Sources */, 7B7DFB202B7E736B009EA1A3 /* MacPacketTunnelProvider.swift in Sources */, 4B4D60A12A0B2D6100BCD287 /* NetworkProtectionOptionKeyExtension.swift in Sources */, @@ -10895,7 +10935,6 @@ 4BF0E50C2AD2552300FFEC9E /* NetworkProtectionPixelEvent.swift in Sources */, 4B4D60AC2A0C804B00BCD287 /* OptionalExtension.swift in Sources */, B65DA5F22A77D3C600CBEE8D /* UserDefaultsWrapper.swift in Sources */, - EEAD7A7A2A1D3E20002A24E7 /* AppLauncher.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -11177,6 +11216,7 @@ 4B957A3E2AC7AE700062CA31 /* EnableWaitlistFeatureView.swift in Sources */, 4B957A3F2AC7AE700062CA31 /* GrammarFeaturesManager.swift in Sources */, 4B957A402AC7AE700062CA31 /* WaitlistModalViewController.swift in Sources */, + B60293E82BA19ECD0033186B /* NetPPopoverManagerMock.swift in Sources */, B6BCC53E2AFD15DF002C5499 /* DataImportProfilePicker.swift in Sources */, 4B957A412AC7AE700062CA31 /* WKMenuItemIdentifier.swift in Sources */, 4B957A422AC7AE700062CA31 /* SafariFaviconsReader.swift in Sources */, @@ -11531,6 +11571,7 @@ 4B957B7B2AC7AE700062CA31 /* DeviceAuthenticator.swift in Sources */, 4B957B7C2AC7AE700062CA31 /* NetworkProtectionWaitlistFeatureFlagOverridesMenu.swift in Sources */, 4B957B7D2AC7AE700062CA31 /* TabBarCollectionView.swift in Sources */, + C1DAF3B72B9A44860059244F /* AutofillPopoverPresenter.swift in Sources */, 4B957B7E2AC7AE700062CA31 /* NetworkProtection+ConvenienceInitializers.swift in Sources */, 7BA7CC502AD11F6F0042E5CE /* NetworkProtectionIPCTunnelController.swift in Sources */, 4B957B7F2AC7AE700062CA31 /* NavigationActionExtension.swift in Sources */, @@ -11963,6 +12004,7 @@ 4B9DB0442A983B24000927DB /* WaitlistModalViewController.swift in Sources */, B6DA06E8291401D700225DE2 /* WKMenuItemIdentifier.swift in Sources */, 4B0AACAE28BC6FD0001038AC /* SafariFaviconsReader.swift in Sources */, + B60293E62BA19ECD0033186B /* NetPPopoverManagerMock.swift in Sources */, B6B3E0E12657EA7A0040E0A2 /* NSScreenExtension.swift in Sources */, B65E6BA026D9F10600095F96 /* NSBezierPathExtension.swift in Sources */, 4B4D60E02A0C875F00BCD287 /* Bundle+VPN.swift in Sources */, @@ -12317,6 +12359,7 @@ 4B9292AF26670F5300AD2C21 /* NSOutlineViewExtensions.swift in Sources */, AA585D82248FD31100E9A3E2 /* AppDelegate.swift in Sources */, 7B1E81A027C8874900FF0E60 /* ContentOverlayViewController.swift in Sources */, + C1DAF3B52B9A44860059244F /* AutofillPopoverPresenter.swift in Sources */, B687B7CA2947A029001DEA6F /* ContentBlockingTabExtension.swift in Sources */, 85B7184C27677C6500B4277F /* OnboardingViewController.swift in Sources */, 4B379C1E27BDB7FF008A968E /* DeviceAuthenticator.swift in Sources */, @@ -12439,6 +12482,7 @@ 569277C429DEE09D00B633EF /* ContinueSetUpModelTests.swift in Sources */, 85F1B0C925EF9759004792B6 /* URLEventHandlerTests.swift in Sources */, 4B9292BD2667103100AD2C21 /* BookmarkOutlineViewDataSourceTests.swift in Sources */, + C17CA7B22B9B5317008EC3C1 /* MockAutofillPopoverPresenter.swift in Sources */, 4BF6961D28BE911100D402D4 /* RecentlyVisitedSiteModelTests.swift in Sources */, B6619F062B17138D00CD9186 /* DataImportSourceViewModelTests.swift in Sources */, 4BBF0917282DD6EF00EE1418 /* TemporaryFileHandlerTests.swift in Sources */, @@ -12650,6 +12694,7 @@ B6C2C9EF276081AB005B7F0A /* DeallocationTests.swift in Sources */, B63ED0D826AE729600A9DAD1 /* PermissionModelTests.swift in Sources */, B69B504B2726CA2900758A2B /* MockStatisticsStore.swift in Sources */, + C17CA7AD2B9B52E6008EC3C1 /* NavigationBarPopoversTests.swift in Sources */, 37CD54BD27F2ECAE00F1F7B9 /* AutofillPreferencesModelTests.swift in Sources */, C1E961ED2B879ED9001760E1 /* MockAutofillActionExecutor.swift in Sources */, 37D23789288009CF00BCE03B /* TabCollectionViewModelTests+PinnedTabs.swift in Sources */, @@ -13713,7 +13758,7 @@ repositoryURL = "https://github.com/duckduckgo/BrowserServicesKit"; requirement = { kind = revision; - revision = 2570250a6c9d6b0818872be3e8df0b6ee8f3a45c; + revision = a451cf5e02a7d1632c470f7093c7f30021af9142; }; }; AA06B6B52672AF8100F541C5 /* XCRemoteSwiftPackageReference "Sparkle" */ = { @@ -14139,6 +14184,10 @@ isa = XCSwiftPackageProductDependency; productName = NetworkProtectionProxy; }; + 7B25856D2BA2F2ED00D49F79 /* NetworkProtectionUI */ = { + isa = XCSwiftPackageProductDependency; + productName = NetworkProtectionUI; + }; 7B31FD8B2AD125620086AA24 /* NetworkProtectionIPC */ = { isa = XCSwiftPackageProductDependency; productName = NetworkProtectionIPC; @@ -14155,6 +14204,10 @@ isa = XCSwiftPackageProductDependency; productName = PixelKit; }; + 7B624F162BA25C1F00A6C544 /* NetworkProtectionUI */ = { + isa = XCSwiftPackageProductDependency; + productName = NetworkProtectionUI; + }; 7B7DFB212B7E7473009EA1A3 /* Networking */ = { isa = XCSwiftPackageProductDependency; package = 9807F643278CA16F00E1547B /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; @@ -14420,11 +14473,6 @@ package = 9807F643278CA16F00E1547B /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; productName = NetworkProtection; }; - EE7295EA2A545BFC008C0991 /* NetworkProtection */ = { - isa = XCSwiftPackageProductDependency; - package = 9807F643278CA16F00E1547B /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; - productName = NetworkProtection; - }; EE7295EC2A545C0A008C0991 /* NetworkProtection */ = { 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 8004e24475..7f8548488a 100644 --- a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -32,7 +32,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/duckduckgo/BrowserServicesKit", "state" : { - "revision" : "2570250a6c9d6b0818872be3e8df0b6ee8f3a45c" + "revision" : "838cb53a8f7050d87ae6931b45ce126ece994359", + "version" : "123.0.1" } }, { diff --git a/DuckDuckGo/Application/URLEventHandler.swift b/DuckDuckGo/Application/URLEventHandler.swift index 3af3ef418f..d73a1ea414 100644 --- a/DuckDuckGo/Application/URLEventHandler.swift +++ b/DuckDuckGo/Application/URLEventHandler.swift @@ -21,7 +21,7 @@ import Foundation import AppKit #if NETWORK_PROTECTION -import NetworkProtection +import NetworkProtectionUI #endif #if DBP diff --git a/DuckDuckGo/Assets.xcassets/Images/QandA-128.imageset/Contents.json b/DuckDuckGo/Assets.xcassets/Images/QandA-128.imageset/Contents.json new file mode 100644 index 0000000000..e708cce2ed --- /dev/null +++ b/DuckDuckGo/Assets.xcassets/Images/QandA-128.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "QandA-128.svg", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/DuckDuckGo/Assets.xcassets/Images/QandA-128.imageset/QandA-128.svg b/DuckDuckGo/Assets.xcassets/Images/QandA-128.imageset/QandA-128.svg new file mode 100644 index 0000000000..4e2ca57aaf --- /dev/null +++ b/DuckDuckGo/Assets.xcassets/Images/QandA-128.imageset/QandA-128.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/DuckDuckGo/Common/Extensions/NSAlertExtension.swift b/DuckDuckGo/Common/Extensions/NSAlertExtension.swift index 8aa901b548..feafa950f9 100644 --- a/DuckDuckGo/Common/Extensions/NSAlertExtension.swift +++ b/DuckDuckGo/Common/Extensions/NSAlertExtension.swift @@ -88,11 +88,11 @@ extension NSAlert { static func resetNetworkProtectionAlert() -> NSAlert { let alert = NSAlert() - alert.messageText = "Reset Network Protection?" + alert.messageText = "Reset VPN?" alert.informativeText = """ This will remove your stored network configuration (including private key) and disable the VPN. - You can re-enable the VPN from the Network Protection view. + You can re-enable the VPN from the status view. """ alert.alertStyle = .warning alert.addButton(withTitle: "Reset") @@ -108,7 +108,7 @@ extension NSAlert { let sysExText = "" #endif alert.messageText = "Uninstall \(sysExText)Login Items?" - alert.informativeText = "This will remove the Network Protection \(sysExText)Status Menu icon and disable the VPN." + alert.informativeText = "This will remove the VPN \(sysExText)Status Menu icon and disable the VPN." alert.alertStyle = .warning alert.addButton(withTitle: "Uninstall") alert.addButton(withTitle: UserText.cancel) diff --git a/DuckDuckGo/Common/Localizables/UserText+NetworkProtection.swift b/DuckDuckGo/Common/Localizables/UserText+NetworkProtection.swift index 8653bba9e2..b77431c7ef 100644 --- a/DuckDuckGo/Common/Localizables/UserText+NetworkProtection.swift +++ b/DuckDuckGo/Common/Localizables/UserText+NetworkProtection.swift @@ -21,37 +21,39 @@ import Foundation extension UserText { // "network.protection.tunnel.name" - The name of the NetP VPN that will be visible in the system to the user - static let networkProtectionTunnelName = "DuckDuckGo Network Protection" - // "network.protection" - Menu item for opening Network Protection - static let networkProtection = "Network Protection" + static let networkProtectionTunnelName = "DuckDuckGo VPN" + // "network.protection" - Menu item for opening the VPN + static let networkProtection = "VPN" // MARK: - Navigation Bar // "network.protection.status.button.tooltip" - The tooltip for NetP's nav bar button - static let networkProtectionButtonTooltip = "Network Protection" + static let networkProtectionButtonTooltip = "VPN" // MARK: - Invite Code - // "network.protection.invite.dialog.title" - Title for the network protection invite dialog + // "network.protection.invite.dialog.title" - Title for the VPN invite dialog static let networkProtectionInviteDialogTitle = "Enter your invite code" - // "network.protection.invite.dialog.message" - Message for the network protection invite dialog + // "network.protection.invite.dialog.message" - Message for the VPN invite dialog static let networkProtectionInviteDialogMessage = "Enter your invite code to get started." - // "network.protection.invite.field.prompt" - Prompt for the network protection invite code text field + // "network.protection.invite.field.prompt" - Prompt for the VPN invite code text field static let networkProtectionInviteFieldPrompt = "Code" - // "network.protection.invite.success.title" - Title for the network protection invite success view + // "network.protection.invite.success.title" - Title for the VPN invite success view static let networkProtectionInviteSuccessTitle = "Success! You’re in." - // "network.protection.invite.success.title" - Message for the network protection invite success view + // "network.protection.invite.success.title" - Message for the VPN invite success view static let networkProtectionInviteSuccessMessage = "DuckDuckGo's VPN secures all of your device's Internet traffic anytime, anywhere." // MARK: - Navigation Bar Status View - // "network.protection.navbar.status.view.share.feedback" - Menu item for 'Send VPN Feedback' in the Network Protection status view that's shown in the navigation bar + // "network.protection.navbar.status.view.share.feedback" - Menu item for 'Send VPN Feedback' in the VPN status view that's shown in the navigation bar static let networkProtectionNavBarStatusViewShareFeedback = "Send VPN Feedback…" // "network.protection.status.menu.vpn.settings" - The status menu 'VPN Settings' menu item static let networkProtectionNavBarStatusMenuVPNSettings = "VPN Settings…" + // "network.protection.status.menu.faq" - The status menu 'FAQ' menu item + static let networkProtectionNavBarStatusMenuFAQ = "Frequently Asked Questions…" // MARK: - System Extension Installation Messages - // "network.protection.configuration.system-settings.legacy" - Text for a label in the Network Protection popover, displayed after attempting to enable Network Protection for the first time while using macOS 12 and below - private static let networkProtectionSystemSettingsLegacy = "Go to Security & Privacy in System Preferences to allow Network Protection to activate" - // "network.protection.configuration.system-settings.modern" - Text for a label in the Network Protection popover, displayed after attempting to enable Network Protection for the first time while using macOS 13 and above - private static let networkProtectionSystemSettingsModern = "Go to Privacy & Security in System Settings to allow Network Protection to activate" + // "network.protection.configuration.system-settings.legacy" - Text for a label in the VPN popover, displayed after attempting to enable the VPN for the first time while using macOS 12 and below + private static let networkProtectionSystemSettingsLegacy = "Go to Security & Privacy in System Preferences to allow DuckDuckGo VPN to activate" + // "network.protection.configuration.system-settings.modern" - Text for a label in the VPN popover, displayed after attempting to enable the VPN for the first time while using macOS 13 and above + private static let networkProtectionSystemSettingsModern = "Go to Privacy & Security in System Settings to allow DuckDuckGo VPN to activate" // Dynamically selected based on macOS version, not directly convertible to static string static var networkProtectionSystemSettings: String { @@ -65,161 +67,161 @@ extension UserText { // "network.protection.system.extension.unknown.activation.error" - Message shown to users when they try to enable NetP and there is an unexpected activation error. static let networkProtectionUnknownActivationError = "There as an unexpected error. Please try again." // "network.protection.system.extension.please.reboot" - Message shown to users when they try to enable NetP and they need to reboot the computer to complete the installation - static let networkProtectionPleaseReboot = "Please reboot to activate Network Protection" + static let networkProtectionPleaseReboot = "Please reboot to activate the VPN" } -// MARK: - Network Protection Waitlist +// MARK: - VPN Waitlist extension UserText { - // "network-protection.waitlist.notification.title" - Title for Network Protection waitlist notification - static let networkProtectionWaitlistNotificationTitle = "Network Protection beta is ready!" - // "network-protection.waitlist.notification.text" - Title for Network Protection waitlist notification + // "network-protection.waitlist.notification.title" - Title for VPN waitlist notification + static let networkProtectionWaitlistNotificationTitle = "DuckDuckGo VPN beta is ready!" + // "network-protection.waitlist.notification.text" - Title for VPN waitlist notification static let networkProtectionWaitlistNotificationText = "Open your invite" - // "network-protection.waitlist.join.title" - Title for Network Protection join waitlist screen - static let networkProtectionWaitlistJoinTitle = "Network Protection Beta" - // "network-protection.waitlist.join.subtitle.1" - First subtitle for Network Protection join waitlist screen - static let networkProtectionWaitlistJoinSubtitle1 = "Secure your connection anytime, anywhere with Network Protection, the VPN from DuckDuckGo." - // "network-protection.waitlist.join.subtitle.2" - Second subtitle for Network Protection join waitlist screen + // "network-protection.waitlist.join.title" - Title for VPN join waitlist screen + static let networkProtectionWaitlistJoinTitle = "DuckDuckGo VPN Beta" + // "network-protection.waitlist.join.subtitle.1" - First subtitle for VPN join waitlist screen + static let networkProtectionWaitlistJoinSubtitle1 = "Secure your connection anytime, anywhere with DuckDuckGo VPN." + // "network-protection.waitlist.join.subtitle.2" - Second subtitle for VPN join waitlist screen static let networkProtectionWaitlistJoinSubtitle2 = "Join the waitlist, and we’ll notify you when it’s your turn." - // "network-protection.waitlist.joined.title" - Title for Network Protection joined waitlist screen + // "network-protection.waitlist.joined.title" - Title for VPN joined waitlist screen static let networkProtectionWaitlistJoinedTitle = "You’re on the list!" - // "network-protection.waitlist.joined.with-notifications.subtitle.1" - Subtitle 1 for Network Protection joined waitlist screen when notifications are enabled + // "network-protection.waitlist.joined.with-notifications.subtitle.1" - Subtitle 1 for VPN joined waitlist screen when notifications are enabled static let networkProtectionWaitlistJoinedWithNotificationsSubtitle1 = "New invites are sent every few days, on a first come, first served basis." - // "network-protection.waitlist.joined.with-notifications.subtitle.2" - Subtitle 2 for Network Protection joined waitlist screen when notifications are enabled + // "network-protection.waitlist.joined.with-notifications.subtitle.2" - Subtitle 2 for VPN joined waitlist screen when notifications are enabled static let networkProtectionWaitlistJoinedWithNotificationsSubtitle2 = "We’ll notify you when your invite is ready." - // "network-protection.waitlist.enable-notifications" - Enable notifications prompt for Network Protection joined waitlist screen - static let networkProtectionWaitlistEnableNotifications = "Want to get a notification when your Network Protection invite is ready?" + // "network-protection.waitlist.enable-notifications" - Enable notifications prompt for VPN joined waitlist screen + static let networkProtectionWaitlistEnableNotifications = "Want to get a notification when your VPN invite is ready?" - // "network-protection.waitlist.invited.title" - Title for Network Protection invited screen - static let networkProtectionWaitlistInvitedTitle = "You’re invited to try\nNetwork Protection beta!" - // "network-protection.waitlist.invited.subtitle" - Subtitle for Network Protection invited screen + // "network-protection.waitlist.invited.title" - Title for VPN invited screen + static let networkProtectionWaitlistInvitedTitle = "You’re invited to try\nDuckDuckGo VPN beta!" + // "network-protection.waitlist.invited.subtitle" - Subtitle for VPN invited screen static let networkProtectionWaitlistInvitedSubtitle = "Get an extra layer of protection online with the VPN built for speed and simplicity. Encrypt your internet connection across your entire device and hide your location and IP address from sites you visit." - // "network-protection.waitlist.invited.section-1.title" - Title for section 1 of the Network Protection invited screen + // "network-protection.waitlist.invited.section-1.title" - Title for section 1 of the VPN invited screen static let networkProtectionWaitlistInvitedSection1Title = "Full-device coverage" - // "network-protection.waitlist.invited.section-1.subtitle" - Subtitle for section 1 of the Network Protection invited screen + // "network-protection.waitlist.invited.section-1.subtitle" - Subtitle for section 1 of the VPN invited screen static let networkProtectionWaitlistInvitedSection1Subtitle = "Encrypt online traffic across your browsers and apps." - // "network-protection.waitlist.invited.section-2.title" - Title for section 2 of the Network Protection invited screen + // "network-protection.waitlist.invited.section-2.title" - Title for section 2 of the VPN invited screen static let networkProtectionWaitlistInvitedSection2Title = "Fast, reliable, and easy to use" - // "network-protection.waitlist.invited.section-2.subtitle" - Subtitle for section 2 of the Network Protection invited screen + // "network-protection.waitlist.invited.section-2.subtitle" - Subtitle for section 2 of the VPN invited screen static let networkProtectionWaitlistInvitedSection2Subtitle = "No need for a separate app. Connect in one click and see your connection status at a glance." - // "network-protection.waitlist.invited.section-3.title" - Title for section 3 of the Network Protection invited screen + // "network-protection.waitlist.invited.section-3.title" - Title for section 3 of the VPN invited screen static let networkProtectionWaitlistInvitedSection3Title = "Strict no-logging policy" - // "network-protection.waitlist.invited.section-3.subtitle" - Subtitle for section 3 of the Network Protection invited screen + // "network-protection.waitlist.invited.section-3.subtitle" - Subtitle for section 3 of the VPN invited screen static let networkProtectionWaitlistInvitedSection3Subtitle = "We do not log or save any data that can connect you to your online activity." - // "network-protection.waitlist.enable.title" - Title for Network Protection enable screen - static let networkProtectionWaitlistEnableTitle = "Ready to enable Network Protection?" - // "network-protection.waitlist.enable.subtitle" - Subtitle for Network Protection enable screen - static let networkProtectionWaitlistEnableSubtitle = "Look for the globe icon in the browser toolbar or in the Mac menu bar.\n\nYou'll be asked to Allow a VPN connection once when setting up Network Protection the first time." + // "network-protection.waitlist.enable.title" - Title for VPN enable screen + static let networkProtectionWaitlistEnableTitle = "Ready to enable DuckDuckGo VPN?" + // "network-protection.waitlist.enable.subtitle" - Subtitle for VPN enable screen + static let networkProtectionWaitlistEnableSubtitle = "Look for the globe icon in the browser toolbar or in the Mac menu bar.\n\nYou'll be asked to Allow a VPN connection once when setting up DuckDuckGo VPN the first time." - // "network-protection.waitlist.availability-disclaimer" - Availability disclaimer for Network Protection join waitlist screen - static let networkProtectionWaitlistAvailabilityDisclaimer = "Network Protection is free to use during the beta." + // "network-protection.waitlist.availability-disclaimer" - Availability disclaimer for VPN join waitlist screen + static let networkProtectionWaitlistAvailabilityDisclaimer = "DuckDuckGo VPN is free to use during the beta." - // "network-protection.waitlist.button.close" - Close button for Network Protection join waitlist screen + // "network-protection.waitlist.button.close" - Close button for VPN join waitlist screen static let networkProtectionWaitlistButtonClose = "Close" - // "network-protection.waitlist.button.done" - Close button for Network Protection joined waitlist screen + // "network-protection.waitlist.button.done" - Close button for VPN joined waitlist screen static let networkProtectionWaitlistButtonDone = "Done" - // "network-protection.waitlist.button.dismiss" - Dismiss button for Network Protection join waitlist screen + // "network-protection.waitlist.button.dismiss" - Dismiss button for VPN join waitlist screen static let networkProtectionWaitlistButtonDismiss = "Dismiss" - // "network-protection.waitlist.button.cancel" - Cancel button for Network Protection join waitlist screen + // "network-protection.waitlist.button.cancel" - Cancel button for VPN join waitlist screen static let networkProtectionWaitlistButtonCancel = "Cancel" - // "network-protection.waitlist.button.no-thanks" - No Thanks button for Network Protection joined waitlist screen + // "network-protection.waitlist.button.no-thanks" - No Thanks button for VPN joined waitlist screen static let networkProtectionWaitlistButtonNoThanks = "No Thanks" - // "network-protection.waitlist.button.get-started" - Get Started button for Network Protection joined waitlist screen + // "network-protection.waitlist.button.get-started" - Get Started button for VPN joined waitlist screen static let networkProtectionWaitlistButtonGetStarted = "Get Started" - // "network-protection.waitlist.button.got-it" - Got It button for Network Protection joined waitlist screen + // "network-protection.waitlist.button.got-it" - Got It button for VPN joined waitlist screen static let networkProtectionWaitlistButtonGotIt = "Got It" - // "network-protection.waitlist.button.enable-notifications" - Enable Notifications button for Network Protection joined waitlist screen + // "network-protection.waitlist.button.enable-notifications" - Enable Notifications button for VPN joined waitlist screen static let networkProtectionWaitlistButtonEnableNotifications = "Enable Notifications" - // "network-protection.waitlist.button.join-waitlist" - Join Waitlist button for Network Protection join waitlist screen + // "network-protection.waitlist.button.join-waitlist" - Join Waitlist button for VPN join waitlist screen static let networkProtectionWaitlistButtonJoinWaitlist = "Join the Waitlist" - // "network-protection.waitlist.button.agree-and-continue" - Agree and Continue button for Network Protection join waitlist screen + // "network-protection.waitlist.button.agree-and-continue" - Agree and Continue button for VPN join waitlist screen static let networkProtectionWaitlistButtonAgreeAndContinue = "Agree and Continue" } -// MARK: - Network Protection Terms of Service +// MARK: - VPN Terms of Service extension UserText { - // "network-protection.privacy-policy.title" - Privacy Policy title for Network Protection + // "network-protection.privacy-policy.title" - Privacy Policy title for VPN static let networkProtectionPrivacyPolicyTitle = "Privacy Policy" - // "network-protection.privacy-policy.section.1.title" - Privacy Policy title for Network Protection + // "network-protection.privacy-policy.section.1.title" - Privacy Policy title for VPN static let networkProtectionPrivacyPolicySection1Title = "We don’t ask for any personal information from you in order to use this beta service." - // "network-protection.privacy-policy.section.1.list" - Privacy Policy list for Network Protection (Markdown version) + // "network-protection.privacy-policy.section.1.list" - Privacy Policy list for VPN (Markdown version) static let networkProtectionPrivacyPolicySection1ListMarkdown = "This Privacy Policy is for our limited waitlist beta VPN product.\n\nOur main [Privacy Policy](https://duckduckgo.com/privacy) also applies here." - // "network-protection.privacy-policy.section.1.list" - Privacy Policy list for Network Protection (Non-Markdown version) + // "network-protection.privacy-policy.section.1.list" - Privacy Policy list for VPN (Non-Markdown version) static let networkProtectionPrivacyPolicySection1ListNonMarkdown = "This Privacy Policy is for our limited waitlist beta VPN product.\n\nOur main Privacy Policy also applies here." - // "network-protection.privacy-policy.section.2.title" - Privacy Policy title for Network Protection + // "network-protection.privacy-policy.section.2.title" - Privacy Policy title for VPN static let networkProtectionPrivacyPolicySection2Title = "We don’t keep any logs of your online activity." - // "network-protection.privacy-policy.section.2.list" - Privacy Policy list for Network Protection + // "network-protection.privacy-policy.section.2.list" - Privacy Policy list for VPN static let networkProtectionPrivacyPolicySection2List = "That means we have no way to tie what you do online to you as an individual and we don’t have any record of things like:\n • Website visits\n • DNS requests\n • Connections made\n • IP addresses used\n • Session lengths" - // "network-protection.privacy-policy.section.3.title" - Privacy Policy title for Network Protection + // "network-protection.privacy-policy.section.3.title" - Privacy Policy title for VPN static let networkProtectionPrivacyPolicySection3Title = "We only keep anonymous performance metrics that we cannot connect to your online activity." - // "network-protection.privacy-policy.section.3.list" - Privacy Policy list for Network Protection + // "network-protection.privacy-policy.section.3.list" - Privacy Policy list for VPN static let networkProtectionPrivacyPolicySection3List = "Our servers store generic usage (for example, CPU load) and diagnostic data (for example, errors), but none of that data is connected to any individual’s activity.\n\nWe use this non-identifying information to monitor and ensure the performance and quality of the service, for example to make sure servers aren’t overloaded." - // "network-protection.privacy-policy.section.4.title" - Privacy Policy title for Network Protection + // "network-protection.privacy-policy.section.4.title" - Privacy Policy title for VPN static let networkProtectionPrivacyPolicySection4Title = "We use dedicated servers for all VPN traffic." - // "network-protection.privacy-policy.section.4.list" - Privacy Policy list for Network Protection + // "network-protection.privacy-policy.section.4.list" - Privacy Policy list for VPN static let networkProtectionPrivacyPolicySection4List = "Dedicated servers means they are not shared with anyone else.\n\nWe rent our servers from providers we carefully selected because they meet our privacy requirements.\n\nWe have strict access controls in place so that only limited DuckDuckGo team members have access to our servers." - // "network-protection.privacy-policy.section.5.title" - Privacy Policy title for Network Protection + // "network-protection.privacy-policy.section.5.title" - Privacy Policy title for VPN static let networkProtectionPrivacyPolicySection5Title = "We protect and limit use of your data when you communicate directly with DuckDuckGo." - // "network-protection.privacy-policy.section.5.list" - Privacy Policy list for Network Protection + // "network-protection.privacy-policy.section.5.list" - Privacy Policy list for VPN static let networkProtectionPrivacyPolicySection5List = "If you reach out to us for support by submitting a bug report or through email and agree to be contacted to troubleshoot the issue, we’ll contact you using the information you provide.\n\nIf you participate in a voluntary product survey or questionnaire and agree to provide further feedback, we may contact you using the information you provide.\n\nWe will permanently delete all personal information you provided to us (email, contact information), within 30 days after closing a support case or, in the case of follow up feedback, within 60 days after ending this beta service." - // "network-protection.terms-of-service.title" - Terms of Service title for Network Protection + // "network-protection.terms-of-service.title" - Terms of Service title for VPN static let networkProtectionTermsOfServiceTitle = "Terms of Service" - // "network-protection.terms-of-service.section.1.title" - Terms of Service title for Network Protection + // "network-protection.terms-of-service.section.1.title" - Terms of Service title for VPN static let networkProtectionTermsOfServiceSection1Title = "The service is for limited and personal use only." - // "network-protection.terms-of-service.section.1.list" - Terms of Service list for Network Protection + // "network-protection.terms-of-service.section.1.list" - Terms of Service list for VPN static let networkProtectionTermsOfServiceSection1List = "This service is provided for your personal use only.\n\nYou are responsible for all activity in the service that occurs on or through your device.\n\nThis service may only be used through the DuckDuckGo app on the device on which you are given access. If you delete the DuckDuckGo app, you will lose access to the service.\n\nYou may not use this service through a third-party client." - // "network-protection.terms-of-service.section.2.title" - Terms of Service title for Network Protection + // "network-protection.terms-of-service.section.2.title" - Terms of Service title for VPN static let networkProtectionTermsOfServiceSection2Title = "You agree to comply with all applicable laws, rules, and regulations." - // "network-protection.terms-of-service.section.2.list" - Terms of Service list for Network Protection (Markdown version) + // "network-protection.terms-of-service.section.2.list" - Terms of Service list for VPN (Markdown version) static let networkProtectionTermsOfServiceSection2ListMarkdown = "You agree that you will not use the service for any unlawful, illicit, criminal, or fraudulent purpose, or in any manner that could give rise to civil or criminal liability under applicable law.\n\nYou agree to comply with our [DuckDuckGo Terms of Service](https://duckduckgo.com/terms), which are incorporated by reference." - // "network-protection.terms-of-service.section.2.list" - Terms of Service list for Network Protection (Non-Markdown version) + // "network-protection.terms-of-service.section.2.list" - Terms of Service list for VPN (Non-Markdown version) static let networkProtectionTermsOfServiceSection2ListNonMarkdown = "You agree that you will not use the service for any unlawful, illicit, criminal, or fraudulent purpose, or in any manner that could give rise to civil or criminal liability under applicable law.\n\nYou agree to comply with our DuckDuckGo Terms of Service, which are incorporated by reference." - // "network-protection.terms-of-service.section.3.title" - Terms of Service title for Network Protection + // "network-protection.terms-of-service.section.3.title" - Terms of Service title for VPN static let networkProtectionTermsOfServiceSection3Title = "You must be eligible to use this service." - // "network-protection.terms-of-service.section.3.list" - Terms of Service list for Network Protection + // "network-protection.terms-of-service.section.3.list" - Terms of Service list for VPN static let networkProtectionTermsOfServiceSection3List = "Access to this beta is randomly awarded. You are responsible for ensuring eligibility.\n\nYou must be at least 18 years old and live in a location where use of a VPN is legal in order to be eligible to use this service." - // "network-protection.terms-of-service.section.4.title" - Terms of Service title for Network Protection + // "network-protection.terms-of-service.section.4.title" - Terms of Service title for VPN static let networkProtectionTermsOfServiceSection4Title = "We provide this beta service as-is and without warranty." - // "network-protection.terms-of-service.section.4.list" - Terms of Service list for Network Protection + // "network-protection.terms-of-service.section.4.list" - Terms of Service list for VPN static let networkProtectionTermsOfServiceSection4List = "This service is provided as-is and without warranties or guarantees of any kind.\n\nTo the extent possible under applicable law, DuckDuckGo will not be liable for any damage or loss arising from your use of the service. In any event, the total aggregate liability of DuckDuckGo shall not exceed $25 or the equivalent in your local currency.\n\nWe may in the future transfer responsibility for the service to a subsidiary of DuckDuckGo. If that happens, you agree that references to “DuckDuckGo” will refer to our subsidiary, which will then become responsible for providing the service and for any liabilities relating to it." - // "network-protection.terms-of-service.section.5.title" - Terms of Service title for Network Protection + // "network-protection.terms-of-service.section.5.title" - Terms of Service title for VPN static let networkProtectionTermsOfServiceSection5Title = "We may terminate access at any time." - // "network-protection.terms-of-service.section.5.list" - Terms of Service list for Network Protection + // "network-protection.terms-of-service.section.5.list" - Terms of Service list for VPN static let networkProtectionTermsOfServiceSection5List = "We reserve the right to revoke access to the service at any time in our sole discretion.\n\nWe may also terminate access for violation of these terms, including for repeated infringement of the intellectual property rights of others." - // "network-protection.terms-of-service.section.6.title" - Terms of Service title for Network Protection + // "network-protection.terms-of-service.section.6.title" - Terms of Service title for VPN static let networkProtectionTermsOfServiceSection6Title = "The service is free during the beta period." - // "network-protection.terms-of-service.section.6.list" - Terms of Service list for Network Protection + // "network-protection.terms-of-service.section.6.list" - Terms of Service list for VPN static let networkProtectionTermsOfServiceSection6List = "Access to this service is currently free of charge, but that is limited to this beta period.\n\nYou understand and agree that this service is provided on a temporary, testing basis only." - // "network-protection.terms-of-service.section.7.title" - Terms of Service title for Network Protection + // "network-protection.terms-of-service.section.7.title" - Terms of Service title for VPN static let networkProtectionTermsOfServiceSection7Title = "We are continually updating the service." - // "network-protection.terms-of-service.section.7.list" - Terms of Service list for Network Protection + // "network-protection.terms-of-service.section.7.list" - Terms of Service list for VPN static let networkProtectionTermsOfServiceSection7List = "The service is in beta, and we are regularly changing it.\n\nService coverage, speed, server locations, and quality may vary without warning." - // "network-protection.terms-of-service.section.8.title" - Terms of Service title for Network Protection + // "network-protection.terms-of-service.section.8.title" - Terms of Service title for VPN static let networkProtectionTermsOfServiceSection8Title = "We need your feedback." - // "network-protection.terms-of-service.section.8.list" - Terms of Service list for Network Protection + // "network-protection.terms-of-service.section.8.list" - Terms of Service list for VPN static let networkProtectionTermsOfServiceSection8List = "You may be asked during the beta period to provide feedback about your experience. Doing so is optional and your feedback may be used to improve the service.\n\nIf you have enabled notifications for the DuckDuckGo app, we may use notifications to ask about your experience. You can disable notifications if you do not want to receive them." // MARK: - Feedback Form diff --git a/DuckDuckGo/Common/Localizables/UserText.swift b/DuckDuckGo/Common/Localizables/UserText.swift index 8fad1dff04..a5149fcee7 100644 --- a/DuckDuckGo/Common/Localizables/UserText.swift +++ b/DuckDuckGo/Common/Localizables/UserText.swift @@ -974,23 +974,23 @@ struct UserText { static let newTabSetUpImportCardTitle = NSLocalizedString("newTab.setup.import.title", value: "Bring Your Stuff", comment: "Title of the Import card of the Set Up section in the home page") static let newTabSetUpDuckPlayerCardTitle = NSLocalizedString("newTab.setup.duck.player.title", value: "Clean Up YouTube", comment: "Title of the Duck Player card of the Set Up section in the home page") static let newTabSetUpEmailProtectionCardTitle = NSLocalizedString("newTab.setup.email.protection.title", value: "Protect Your Inbox", comment: "Title of the Email Protection card of the Set Up section in the home page") - static let newTabSetUpSurveyDay0CardTitle = NSLocalizedString("newTab.setup.survey.day.0.title", value: "Tell Us What Brought You Here", comment: "Title of the Day 0 durvey of the Set Up section in the home page") - static let newTabSetUpSurveyDay7CardTitle = NSLocalizedString("newTab.setup.survey.day.7.title", value: "Help Us Improve", comment: "Title of the Day 7 durvey of the Set Up section in the home page") + static let newTabSetUpSurveyDay0CardTitle = NSLocalizedString("newTab.setup.survey.day.0.title", value: "Share Your Thoughts With Us", comment: "Title of the Day 0 durvey of the Set Up section in the home page") + static let newTabSetUpSurveyDay14CardTitle = NSLocalizedString("newTab.setup.survey.day.14.title", value: "Share Your Thoughts With Us", comment: "Title of the Day 14 durvey of the Set Up section in the home page") static let newTabSetUpDefaultBrowserAction = NSLocalizedString("newTab.setup.default.browser.action", value: "Make Default Browser", comment: "Action title on the action menu of the Default Browser card") static let newTabSetUpImportAction = NSLocalizedString("newTab.setup.Import.action", value: "Import Now", comment: "Action title on the action menu of the Import card of the Set Up section in the home page") static let newTabSetUpDuckPlayerAction = NSLocalizedString("newTab.setup.duck.player.action", value: "Try Duck Player", comment: "Action title on the action menu of the Duck Player card of the Set Up section in the home page") static let newTabSetUpEmailProtectionAction = NSLocalizedString("newTab.setup.email.protection.action", value: "Get a Duck Address", comment: "Action title on the action menu of the Email Protection card of the Set Up section in the home page") static let newTabSetUpRemoveItemAction = NSLocalizedString("newTab.setup.remove.item", value: "Dismiss", comment: "Action title on the action menu of the set up cards card of the SetUp section in the home page to remove the item") - static let newTabSetUpSurveyDay0Action = NSLocalizedString("newTab.setup.survey.day.0.action", value: "Share Your Thoughts", comment: "Action title of the Day 0 durvey of the Set Up section in the home page") - static let newTabSetUpSurveyDay7Action = NSLocalizedString("newTab.setup.survey.day.7.action", value: "Share Your Thoughts", comment: "Action title of the Day 7 durvey of the Set Up section in the home page") + static let newTabSetUpSurveyDay0Action = NSLocalizedString("newTab.setup.survey.day.0.action", value: "Sign Up To Participate", comment: "Action title of the Day 0 survey of the Set Up section in the home page") + static let newTabSetUpSurveyDay14Action = NSLocalizedString("newTab.setup.survey.day.14.action", value: "Sign Up To Participate", comment: "Action title of the Day 14 survey of the Set Up section in the home page") static let newTabSetUpDefaultBrowserSummary = NSLocalizedString("newTab.setup.default.browser.summary", value: "We automatically block trackers as you browse. It's privacy, simplified.", comment: "Summary of the Default Browser card") static let newTabSetUpImportSummary = NSLocalizedString("newTab.setup.import.summary", value: "Import bookmarks, favorites, and passwords from your old browser.", comment: "Summary of the Import card of the Set Up section in the home page") static let newTabSetUpDuckPlayerSummary = NSLocalizedString("newTab.setup.duck.player.summary", value: "Enjoy a clean viewing experience without personalized ads.", comment: "Summary of the Duck Player card of the Set Up section in the home page") static let newTabSetUpEmailProtectionSummary = NSLocalizedString("newTab.setup.email.protection.summary", value: "Generate custom @duck.com addresses that clean trackers from incoming email.", comment: "Summary of the Email Protection card of the Set Up section in the home page") - static let newTabSetUpSurveyDay0Summary = NSLocalizedString("newTab.setup.survey.day.0.summary", value: "Take our short survey and help us build the best browser.", comment: "Summary of the Day 0 durvey of the Set Up section in the home page") - static let newTabSetUpSurveyDay7Summary = NSLocalizedString("newTab.setup.survey.day.7.summary", value: "Take our short survey and help us build the best browser.", comment: "Summary of the Day 7 durvey of the Set Up section in the home page") + static let newTabSetUpSurveyDay0Summary = NSLocalizedString("newTab.setup.survey.day.0.summary", value: "Join an interview with a member of our research team to help us build the best browser.", comment: "Summary of the card on the new tab page that invites users to partecipate to a survey") + static let newTabSetUpSurveyDay14Summary = NSLocalizedString("newTab.setup.survey.day.14.summary", value: "Join an interview with a member of our research team to help us build the best browser.", comment: "Summary of the card on the new tab page that invites users to partecipate to a survey") // Recent Activity static let newTabRecentActivitySectionTitle = NSLocalizedString("newTab.recent.activity.section.title", value: "Recent Activity", comment: "Title of the RecentActivity section in the home page") diff --git a/DuckDuckGo/Common/Logging/Logging.swift b/DuckDuckGo/Common/Logging/Logging.swift index e6c9d18b36..70b37f76b7 100644 --- a/DuckDuckGo/Common/Logging/Logging.swift +++ b/DuckDuckGo/Common/Logging/Logging.swift @@ -41,7 +41,7 @@ extension OSLog { case duckPlayer = "Duck Player" case tabSnapshots = "Tab Snapshots" case sync = "Sync" - case networkProtection = "Network Protection" + case networkProtection = "VPN" case dbp = "dbp" } diff --git a/DuckDuckGo/Common/Utilities/UserDefaultsWrapper.swift b/DuckDuckGo/Common/Utilities/UserDefaultsWrapper.swift index 272d63cca0..da443d381e 100644 --- a/DuckDuckGo/Common/Utilities/UserDefaultsWrapper.swift +++ b/DuckDuckGo/Common/Utilities/UserDefaultsWrapper.swift @@ -111,8 +111,10 @@ public struct UserDefaultsWrapper { case homePageShowDuckPlayer = "home.page.show.duck.player" case homePageShowEmailProtection = "home.page.show.email.protection" case homePageShowSurveyDay0 = "home.page.show.survey.0" + case homePageShowSurveyDay0in10Percent = "home.page.show.survey.0.in.10.pervent" + case homePageShowSurveyDay14in10Percent = "home.page.show.survey.0.in.14.pervent" case homePageUserInteractedWithSurveyDay0 = "home.page.user.interacted.with.survey.0" - case homePageShowSurveyDay7 = "home.page.show.survey.7" + case homePageShowSurveyDay14 = "home.page.show.survey.14" case homePageShowPageTitles = "home.page.show.page.titles" case homePageShowRecentlyVisited = "home.page.show.recently.visited" case homePageContinueSetUpImport = "home.page.continue.set.up.import" @@ -146,13 +148,13 @@ public struct UserDefaultsWrapper { case dataBrokerProtectionTermsAndConditionsAccepted = "data-broker-protection.waitlist-terms-and-conditions.accepted" case shouldShowDBPWaitlistInvitedCardUI = "shouldShowDBPWaitlistInvitedCardUI" - // Network Protection + // VPN case networkProtectionExcludedRoutes = "netp.excluded-routes" case networkProtectionTermsAndConditionsAccepted = "network-protection.waitlist-terms-and-conditions.accepted" case networkProtectionWaitlistSignUpPromptDismissed = "network-protection.waitlist.sign-up-prompt-dismissed" - // Network Protection: Shared Defaults + // VPN: Shared Defaults // --- // Please note that shared defaults MUST have a name that matches exactly their value, // or else KVO will just not work as of 2023-08-07 diff --git a/DuckDuckGo/DBP/DBPHomeViewController.swift b/DuckDuckGo/DBP/DBPHomeViewController.swift index e590867c10..b64fc689e8 100644 --- a/DuckDuckGo/DBP/DBPHomeViewController.swift +++ b/DuckDuckGo/DBP/DBPHomeViewController.swift @@ -163,6 +163,7 @@ public class DataBrokerProtectionPixelsHandler: EventMapping oneDayAgo + firstLaunchDate >= oneDayAgo && + Bundle.main.preferredLocalizations.first == "en" && + isPartOfSurveyDay0On10Percent ?? calculateIfIn10percent(day: .day0) } - private var shouldSurveyDay7BeVisible: Bool { - let oneWeekAgo = Calendar.current.date(byAdding: .weekOfYear, value: -1, to: Date())! - return isDay7SurveyEnabled && + private var shouldSurveyDay14BeVisible: Bool { + let fourteenDaysAgo = Calendar.current.date(byAdding: .weekday, value: -14, to: Date())! + let fifteenDaysAgo = Calendar.current.date(byAdding: .weekday, value: -15, to: Date())! + return isDay14SurveyEnabled && shouldShowSurveyDay0 && - shouldShowSurveyDay7 && + shouldShowSurveyDay14 && !userInteractedWithSurveyDay0 && - firstLaunchDate <= oneWeekAgo + firstLaunchDate >= fifteenDaysAgo && + firstLaunchDate <= fourteenDaysAgo && + Bundle.main.preferredLocalizations.first == "en" && + isPartOfSurveyDay14On10Percent ?? calculateIfIn10percent(day: .day14) + } + + private func calculateIfIn10percent(day: SurveyDay) -> Bool { + let randomNumber0To99 = randomNumberGenerator.random(in: 0..<100) + let isInSurvey10Percent = randomNumber0To99 < 10 + switch day { + case .day0: + isPartOfSurveyDay0On10Percent = isInSurvey10Percent + case .day14: + isPartOfSurveyDay14On10Percent = isInSurvey10Percent + } + return isInSurvey10Percent } private enum SurveyDay { case day0 - case day7 + case day14 } @MainActor private func visitSurvey(day: SurveyDay) { @@ -376,11 +403,8 @@ extension HomePage.Models { switch day { case .day0: surveyURLString = day0SurveyURL - case .day7: - surveyURLString = day7SurveyURL - } - if let atb = statisticsStore.atb { - surveyURLString += "&atb=\(atb)" + case .day14: + surveyURLString = day14SurveyURL } if let url = URL(string: surveyURLString) { @@ -388,9 +412,9 @@ extension HomePage.Models { tabCollectionViewModel.append(tab: tab) switch day { case .day0: - userInteractedWithSurveyDay0 = true - case .day7: - shouldShowSurveyDay7 = false + shouldShowSurveyDay0 = false + case .day14: + shouldShowSurveyDay14 = false } } } @@ -455,7 +479,7 @@ extension HomePage.Models { // We ignore the `networkProtectionRemoteMessage` case here to avoid it getting accidentally included - it has special handling and will get // included elsewhere. static var allCases: [HomePage.Models.FeatureType] { - [.duckplayer, .emailProtection, .defaultBrowser, .importBookmarksAndPasswords, .surveyDay0, .surveyDay7] + [.duckplayer, .emailProtection, .defaultBrowser, .importBookmarksAndPasswords, .surveyDay0, .surveyDay14] } case duckplayer @@ -463,7 +487,7 @@ extension HomePage.Models { case defaultBrowser case importBookmarksAndPasswords case surveyDay0 - case surveyDay7 + case surveyDay14 case networkProtectionRemoteMessage(NetworkProtectionRemoteMessage) case dataBrokerProtectionRemoteMessage(DataBrokerProtectionRemoteMessage) case dataBrokerProtectionWaitlistInvited @@ -480,8 +504,8 @@ extension HomePage.Models { return UserText.newTabSetUpEmailProtectionCardTitle case .surveyDay0: return UserText.newTabSetUpSurveyDay0CardTitle - case .surveyDay7: - return UserText.newTabSetUpSurveyDay7CardTitle + case .surveyDay14: + return UserText.newTabSetUpSurveyDay14CardTitle case .networkProtectionRemoteMessage(let message): return message.cardTitle case .dataBrokerProtectionRemoteMessage(let message): @@ -503,8 +527,8 @@ extension HomePage.Models { return UserText.newTabSetUpEmailProtectionSummary case .surveyDay0: return UserText.newTabSetUpSurveyDay0Summary - case .surveyDay7: - return UserText.newTabSetUpSurveyDay7Summary + case .surveyDay14: + return UserText.newTabSetUpSurveyDay14Summary case .networkProtectionRemoteMessage(let message): return message.cardDescription case .dataBrokerProtectionRemoteMessage(let message): @@ -526,8 +550,8 @@ extension HomePage.Models { return UserText.newTabSetUpEmailProtectionAction case .surveyDay0: return UserText.newTabSetUpSurveyDay0Action - case .surveyDay7: - return UserText.newTabSetUpSurveyDay7Action + case .surveyDay14: + return UserText.newTabSetUpSurveyDay14Action case .networkProtectionRemoteMessage(let message): return message.action.actionTitle case .dataBrokerProtectionRemoteMessage(let message): @@ -550,9 +574,9 @@ extension HomePage.Models { case .emailProtection: return .inbox128.resized(to: iconSize)! case .surveyDay0: - return .survey128.resized(to: iconSize)! - case .surveyDay7: - return .survey128.resized(to: iconSize)! + return .qandA128.resized(to: iconSize)! + case .surveyDay14: + return .qandA128.resized(to: iconSize)! case .networkProtectionRemoteMessage: return .vpnEnded.resized(to: iconSize)! case .dataBrokerProtectionRemoteMessage: @@ -615,3 +639,13 @@ struct HomePageRemoteMessaging { #endif } + +public protocol RandomNumberGenerating { + func random(in range: Range) -> Int +} + +struct RandomNumberGenerator: RandomNumberGenerating { + func random(in range: Range) -> Int { + return Int.random(in: range) + } +} diff --git a/DuckDuckGo/Info.plist b/DuckDuckGo/Info.plist index 8c7dca0e52..bdb809d70e 100644 --- a/DuckDuckGo/Info.plist +++ b/DuckDuckGo/Info.plist @@ -60,7 +60,7 @@ CFBundleTypeRole Viewer CFBundleURLName - Network Protection URLs + VPN URLs CFBundleURLSchemes networkprotection diff --git a/DuckDuckGo/Localizable.xcstrings b/DuckDuckGo/Localizable.xcstrings index 9347c6977d..a00894c192 100644 --- a/DuckDuckGo/Localizable.xcstrings +++ b/DuckDuckGo/Localizable.xcstrings @@ -29509,120 +29509,120 @@ } }, "newTab.setup.survey.day.0.action" : { - "comment" : "Action title of the Day 0 durvey of the Set Up section in the home page", + "comment" : "Action title of the Day 0 survey of the Set Up section in the home page", "extractionState" : "extracted_with_value", "localizations" : { "de" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "Teile deine Gedanken" } }, "en" : { "stringUnit" : { "state" : "new", - "value" : "Share Your Thoughts" + "value" : "Sign Up To Participate" } }, "es" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "Comparte tus ideas" } }, "fr" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "Partagez votre avis" } }, "it" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "Comunicaci la tua opinione" } }, "nl" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "Deel je gedachten" } }, "pl" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "Podziel się przemyśleniami" } }, "pt" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "Partilha as tuas opiniões" } }, "ru" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "Поделиться соображениями" } } } }, "newTab.setup.survey.day.0.summary" : { - "comment" : "Summary of the Day 0 durvey of the Set Up section in the home page", + "comment" : "Summary of the card on the new tab page that invites users to partecipate to a survey", "extractionState" : "extracted_with_value", "localizations" : { "de" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "Nimm an unserer kurzen Umfrage teil und hilf uns, den besten Browser zu entwickeln." } }, "en" : { "stringUnit" : { "state" : "new", - "value" : "Take our short survey and help us build the best browser." + "value" : "Join an interview with a member of our research team to help us build the best browser." } }, "es" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "Responde a nuestra breve encuesta y ayúdanos a crear el mejor navegador." } }, "fr" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "Répondez à notre courte enquête et aidez-nous à créer le meilleur navigateur." } }, "it" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "Rispondi al nostro breve sondaggio e aiutaci a creare il browser migliore." } }, "nl" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "Vul onze korte enquête in en help ons de beste browser te bouwen." } }, "pl" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "Weź udział w krótkiej ankiecie i pomóż nam opracować najlepszą przeglądarkę." } }, "pt" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "Responde ao nosso curto inquérito e ajuda-nos a criar o melhor navegador." } }, "ru" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "Пройдите короткий опрос и помогите DuckDuckGo стать лучшим из браузеров." } } @@ -29634,55 +29634,55 @@ "localizations" : { "de" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "Sag uns, was dich hierher gebracht hat" } }, "en" : { "stringUnit" : { "state" : "new", - "value" : "Tell Us What Brought You Here" + "value" : "Share Your Thoughts With Us" } }, "es" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "Cuéntanos qué te ha traído hasta aquí" } }, "fr" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "Dites-nous ce qui vous amène ici" } }, "it" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "Raccontaci cosa ti ha portato qui" } }, "nl" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "Vertel ons wat je hier heeft gebracht" } }, "pl" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "Powiedz nam, co Cię tu sprowadziło" } }, "pt" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "Diz-nos o que te trouxe aqui" } }, "ru" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "Что привело вас к нам" } } @@ -29690,7 +29690,7 @@ }, "newTab.setup.survey.day.7.action" : { "comment" : "Action title of the Day 7 durvey of the Set Up section in the home page", - "extractionState" : "extracted_with_value", + "extractionState" : "stale", "localizations" : { "de" : { "stringUnit" : { @@ -29750,7 +29750,7 @@ }, "newTab.setup.survey.day.7.summary" : { "comment" : "Summary of the Day 7 durvey of the Set Up section in the home page", - "extractionState" : "extracted_with_value", + "extractionState" : "stale", "localizations" : { "de" : { "stringUnit" : { @@ -29810,7 +29810,7 @@ }, "newTab.setup.survey.day.7.title" : { "comment" : "Title of the Day 7 durvey of the Set Up section in the home page", - "extractionState" : "extracted_with_value", + "extractionState" : "stale", "localizations" : { "de" : { "stringUnit" : { @@ -29868,6 +29868,42 @@ } } }, + "newTab.setup.survey.day.14.action" : { + "comment" : "Action title of the Day 14 survey of the Set Up section in the home page", + "extractionState" : "extracted_with_value", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Sign Up To Participate" + } + } + } + }, + "newTab.setup.survey.day.14.summary" : { + "comment" : "Summary of the card on the new tab page that invites users to partecipate to a survey", + "extractionState" : "extracted_with_value", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Join an interview with a member of our research team to help us build the best browser." + } + } + } + }, + "newTab.setup.survey.day.14.title" : { + "comment" : "Title of the Day 14 durvey of the Set Up section in the home page", + "extractionState" : "extracted_with_value", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Share Your Thoughts With Us" + } + } + } + }, "next" : { "comment" : "Next button", "extractionState" : "extracted_with_value", @@ -50524,4 +50560,4 @@ } }, "version" : "1.0" -} +} \ No newline at end of file diff --git a/DuckDuckGo/LoginItems/LoginItemsManager.swift b/DuckDuckGo/LoginItems/LoginItemsManager.swift index d8ab2356db..8fef5f953b 100644 --- a/DuckDuckGo/LoginItems/LoginItemsManager.swift +++ b/DuckDuckGo/LoginItems/LoginItemsManager.swift @@ -20,8 +20,8 @@ import Common import Foundation import LoginItems -/// Class to manage the login items for Network Protection and DBP -/// +/// Class to manage the login items for the VPN and DBP +/// final class LoginItemsManager { private enum Action: String { case enable diff --git a/DuckDuckGo/MainWindow/MainViewController.swift b/DuckDuckGo/MainWindow/MainViewController.swift index 5741f2f55e..5ef25c47e9 100644 --- a/DuckDuckGo/MainWindow/MainViewController.swift +++ b/DuckDuckGo/MainWindow/MainViewController.swift @@ -23,6 +23,7 @@ import Common #if NETWORK_PROTECTION import NetworkProtection +import NetworkProtectionIPC #endif final class MainViewController: NSViewController { @@ -56,14 +57,53 @@ final class MainViewController: NSViewController { fatalError("MainViewController: Bad initializer") } - init(tabCollectionViewModel: TabCollectionViewModel? = nil, - bookmarkManager: BookmarkManager = LocalBookmarkManager.shared) { + init(tabCollectionViewModel: TabCollectionViewModel? = nil, bookmarkManager: BookmarkManager = LocalBookmarkManager.shared, autofillPopoverPresenter: AutofillPopoverPresenter) { let tabCollectionViewModel = tabCollectionViewModel ?? TabCollectionViewModel() self.tabCollectionViewModel = tabCollectionViewModel self.isBurner = tabCollectionViewModel.isBurner tabBarViewController = TabBarViewController.create(tabCollectionViewModel: tabCollectionViewModel) - navigationBarViewController = NavigationBarViewController.create(tabCollectionViewModel: tabCollectionViewModel, isBurner: isBurner) + +#if NETWORK_PROTECTION + let networkProtectionPopoverManager: NetPPopoverManager = { +#if DEBUG + guard case .normal = NSApp.runType else { + return NetPPopoverManagerMock() + } +#endif + let vpnBundleID = Bundle.main.vpnMenuAgentBundleId + let ipcClient = TunnelControllerIPCClient(machServiceName: vpnBundleID) + ipcClient.register() + + return NetworkProtectionNavBarPopoverManager(ipcClient: ipcClient) + }() + let networkProtectionStatusReporter: NetworkProtectionStatusReporter = { + var connectivityIssuesObserver: ConnectivityIssueObserver! + var controllerErrorMessageObserver: ControllerErrorMesssageObserver! +#if DEBUG + if ![.normal, .integrationTests].contains(NSApp.runType) { + connectivityIssuesObserver = ConnectivityIssueObserverMock() + controllerErrorMessageObserver = ControllerErrorMesssageObserverMock() + } +#endif + connectivityIssuesObserver = connectivityIssuesObserver ?? DisabledConnectivityIssueObserver() + controllerErrorMessageObserver = controllerErrorMessageObserver ?? ControllerErrorMesssageObserverThroughDistributedNotifications() + + let ipcClient = networkProtectionPopoverManager.ipcClient + return DefaultNetworkProtectionStatusReporter( + statusObserver: ipcClient.ipcStatusObserver, + serverInfoObserver: ipcClient.ipcServerInfoObserver, + connectionErrorObserver: ipcClient.ipcConnectionErrorObserver, + connectivityIssuesObserver: connectivityIssuesObserver, + controllerErrorMessageObserver: controllerErrorMessageObserver + ) + }() + + navigationBarViewController = NavigationBarViewController.create(tabCollectionViewModel: tabCollectionViewModel, isBurner: isBurner, networkProtectionPopoverManager: networkProtectionPopoverManager, networkProtectionStatusReporter: networkProtectionStatusReporter, autofillPopoverPresenter: autofillPopoverPresenter) +#else + navigationBarViewController = NavigationBarViewController.create(tabCollectionViewModel: tabCollectionViewModel, isBurner: isBurner, autofillPopoverPresenter: AutofillPopoverPresenter) +#endif + browserTabViewController = BrowserTabViewController(tabCollectionViewModel: tabCollectionViewModel, bookmarkManager: bookmarkManager) findInPageViewController = FindInPageViewController.create() fireViewController = FireViewController.create(tabCollectionViewModel: tabCollectionViewModel) @@ -560,7 +600,7 @@ extension MainViewController { ])) bkman.loadBookmarks() - let vc = MainViewController(bookmarkManager: bkman) + let vc = MainViewController(bookmarkManager: bkman, autofillPopoverPresenter: DefaultAutofillPopoverPresenter()) var c: AnyCancellable! c = vc.publisher(for: \.view.window).sink { window in window?.titlebarAppearsTransparent = true diff --git a/DuckDuckGo/Menus/MainMenu.swift b/DuckDuckGo/Menus/MainMenu.swift index da7c0d9984..ff4aa75ff4 100644 --- a/DuckDuckGo/Menus/MainMenu.swift +++ b/DuckDuckGo/Menus/MainMenu.swift @@ -575,11 +575,14 @@ import SubscriptionUI NSMenuItem(title: "Reset Pinned Tabs", action: #selector(MainViewController.resetPinnedTabs)) NSMenuItem(title: "Reset YouTube Overlay Interactions", action: #selector(MainViewController.resetDuckPlayerOverlayInteractions)) NSMenuItem(title: "Reset MakeDuckDuckYours user settings", action: #selector(MainViewController.resetMakeDuckDuckGoYoursUserSettings)) + NSMenuItem(title: "Survey 10% on", action: #selector(MainViewController.in10PercentSurveyOn)) + NSMenuItem(title: "Survey 10% off", action: #selector(MainViewController.in10PercentSurveyOff)) NSMenuItem(title: "Change Activation Date") { NSMenuItem(title: "Today", action: #selector(MainViewController.changeInstallDateToToday), keyEquivalent: "N") - NSMenuItem(title: "Less Than a 21 days Ago", action: #selector(MainViewController.changeInstallDateToLessThan21DaysAgo)) - NSMenuItem(title: "More Than 21 Days Ago", action: #selector(MainViewController.changeInstallDateToMoreThan21DaysAgoButLessThan27)) - NSMenuItem(title: "More Than 27 Days Ago", action: #selector(MainViewController.changeInstallDateToMoreThan27DaysAgo)) + NSMenuItem(title: "Less Than a 1 days Ago", action: #selector(MainViewController.changeInstallDateToLessThan1DayAgo(_:))) + NSMenuItem(title: "More Than 1 Days Ago", action: #selector(MainViewController.changeInstallDateToMoreThan1DayAgoButLessThan14(_:))) + NSMenuItem(title: "More Than 14 Days Ago", action: #selector(MainViewController.changeInstallDateToMoreThan14DaysAgoButLessThan15(_:))) + NSMenuItem(title: "More Than 15 Days Ago", action: #selector(MainViewController.changeInstallDateToMoreThan15DaysAgo(_:))) } NSMenuItem(title: "Reset Email Protection InContext Signup Prompt", action: #selector(MainViewController.resetEmailProtectionInContextPrompt)) NSMenuItem(title: "Reset Daily Pixels", action: #selector(MainViewController.resetDailyPixels)) @@ -609,8 +612,10 @@ import SubscriptionUI #endif #if NETWORK_PROTECTION - NSMenuItem(title: "Network Protection") - .submenu(NetworkProtectionDebugMenu()) + if case .normal = NSApp.runType { + NSMenuItem(title: "VPN") + .submenu(NetworkProtectionDebugMenu()) + } #endif NSMenuItem(title: "Trigger Fatal Error", action: #selector(MainViewController.triggerFatalError)) diff --git a/DuckDuckGo/Menus/MainMenuActions.swift b/DuckDuckGo/Menus/MainMenuActions.swift index 2f4c286472..f3f9c43c19 100644 --- a/DuckDuckGo/Menus/MainMenuActions.swift +++ b/DuckDuckGo/Menus/MainMenuActions.swift @@ -708,7 +708,7 @@ extension MainViewController { UserDefaults.standard.set(true, forKey: UserDefaultsWrapper.Key.homePageShowDuckPlayer.rawValue) UserDefaults.standard.set(true, forKey: UserDefaultsWrapper.Key.homePageShowEmailProtection.rawValue) UserDefaults.standard.set(true, forKey: UserDefaultsWrapper.Key.homePageShowSurveyDay0.rawValue) - UserDefaults.standard.set(true, forKey: UserDefaultsWrapper.Key.homePageShowSurveyDay7.rawValue) + UserDefaults.standard.set(true, forKey: UserDefaultsWrapper.Key.homePageShowSurveyDay14.rawValue) UserDefaults.standard.set(false, forKey: UserDefaultsWrapper.Key.homePageUserInteractedWithSurveyDay0.rawValue) } @@ -722,22 +722,37 @@ extension MainViewController { UserDefaults.standard.removePersistentDomain(forName: DailyPixel.Constant.dailyPixelStorageIdentifier) } + @objc func in10PercentSurveyOn(_ sender: Any?) { + UserDefaults.standard.set(true, forKey: UserDefaultsWrapper.Key.homePageShowSurveyDay14in10Percent.rawValue) + UserDefaults.standard.set(true, forKey: UserDefaultsWrapper.Key.homePageShowSurveyDay0in10Percent.rawValue) + } + + @objc func in10PercentSurveyOff(_ sender: Any?) { + UserDefaults.standard.set(false, forKey: UserDefaultsWrapper.Key.homePageShowSurveyDay14in10Percent.rawValue) + UserDefaults.standard.set(false, forKey: UserDefaultsWrapper.Key.homePageShowSurveyDay0in10Percent.rawValue) + } + @objc func changeInstallDateToToday(_ sender: Any?) { UserDefaults.standard.set(Date(), forKey: UserDefaultsWrapper.Key.firstLaunchDate.rawValue) } - @objc func changeInstallDateToLessThan21DaysAgo(_ sender: Any?) { - let lessThanTwentyOneDaysAgo = Calendar.current.date(byAdding: .day, value: -20, to: Date()) - UserDefaults.standard.set(lessThanTwentyOneDaysAgo, forKey: UserDefaultsWrapper.Key.firstLaunchDate.rawValue) + @objc func changeInstallDateToLessThan1DayAgo(_ sender: Any?) { + let lessThanOneDaysAgo = Calendar.current.date(byAdding: .hour, value: -23, to: Date()) + UserDefaults.standard.set(lessThanOneDaysAgo, forKey: UserDefaultsWrapper.Key.firstLaunchDate.rawValue) } - @objc func changeInstallDateToMoreThan21DaysAgoButLessThan27(_ sender: Any?) { - let twentyOneDaysAgo = Calendar.current.date(byAdding: .day, value: -21, to: Date()) - UserDefaults.standard.set(twentyOneDaysAgo, forKey: UserDefaultsWrapper.Key.firstLaunchDate.rawValue) + @objc func changeInstallDateToMoreThan1DayAgoButLessThan14(_ sender: Any?) { + let between1And4DaysAgo = Calendar.current.date(byAdding: .day, value: -13, to: Date()) + UserDefaults.standard.set(between1And4DaysAgo, forKey: UserDefaultsWrapper.Key.firstLaunchDate.rawValue) + } + + @objc func changeInstallDateToMoreThan14DaysAgoButLessThan15(_ sender: Any?) { + let twentyEightDaysAgo = Calendar.current.date(byAdding: .day, value: -14, to: Date()) + UserDefaults.standard.set(twentyEightDaysAgo, forKey: UserDefaultsWrapper.Key.firstLaunchDate.rawValue) } - @objc func changeInstallDateToMoreThan27DaysAgo(_ sender: Any?) { - let twentyEightDaysAgo = Calendar.current.date(byAdding: .day, value: -28, to: Date()) + @objc func changeInstallDateToMoreThan15DaysAgo(_ sender: Any?) { + let twentyEightDaysAgo = Calendar.current.date(byAdding: .day, value: -16, to: Date()) UserDefaults.standard.set(twentyEightDaysAgo, forKey: UserDefaultsWrapper.Key.firstLaunchDate.rawValue) } diff --git a/DuckDuckGo/NavigationBar/PinningManager.swift b/DuckDuckGo/NavigationBar/PinningManager.swift index 64d29c104e..8a3e939e7e 100644 --- a/DuckDuckGo/NavigationBar/PinningManager.swift +++ b/DuckDuckGo/NavigationBar/PinningManager.swift @@ -133,7 +133,7 @@ final class LocalPinningManager: PinningManager { /// This method is useful for knowing if the view was manually toggled. /// It's particularly useful for initializing a pin to a certain value at a certain point during the execution of code, /// only if the user hasn't explicitly specified a desired state. - /// As an example: this is used in Network Protection for pinning the icon to the navigation bar the first time the + /// As an example: this is used in the VPN for pinning the icon to the navigation bar the first time the /// feature is enabled. /// func wasManuallyToggled(_ view: PinnableView) -> Bool { diff --git a/DuckDuckGo/NavigationBar/View/MoreOptionsMenu.swift b/DuckDuckGo/NavigationBar/View/MoreOptionsMenu.swift index 28c9122766..6ff8bfea32 100644 --- a/DuckDuckGo/NavigationBar/View/MoreOptionsMenu.swift +++ b/DuckDuckGo/NavigationBar/View/MoreOptionsMenu.swift @@ -164,15 +164,11 @@ final class MoreOptionsMenu: NSMenu { #if DBP @objc func openDataBrokerProtection(_ sender: NSMenuItem) { - #if SUBSCRIPTION - actionDelegate?.optionsButtonMenuRequestedDataBrokerProtection(self) - #else if !DefaultDataBrokerProtectionFeatureVisibility.bypassWaitlist && DataBrokerProtectionWaitlistViewControllerPresenter.shouldPresentWaitlist() { DataBrokerProtectionWaitlistViewControllerPresenter.show() } else { actionDelegate?.optionsButtonMenuRequestedDataBrokerProtection(self) } - #endif } #endif // DBP @@ -343,18 +339,9 @@ final class MoreOptionsMenu: NSMenu { #if NETWORK_PROTECTION if networkProtectionFeatureVisibility.isNetworkProtectionVisible() { - let isWaitlistUser = NetworkProtectionWaitlist().waitlistStorage.isWaitlistUser - let hasAuthToken = NetworkProtectionKeychainTokenStore().isFeatureActivated - let networkProtectionItem: NSMenuItem - // If the user can see the Network Protection option but they haven't joined the waitlist or don't have an auth token, show the "New" - // badge to bring it to their attention. - if !isWaitlistUser && !hasAuthToken { - networkProtectionItem = makeNetworkProtectionItem(showNewLabel: true) - } else { - networkProtectionItem = makeNetworkProtectionItem(showNewLabel: false) - } + networkProtectionItem = makeNetworkProtectionItem() items.append(networkProtectionItem) @@ -494,25 +481,12 @@ final class MoreOptionsMenu: NSMenu { } #if NETWORK_PROTECTION - private func makeNetworkProtectionItem(showNewLabel: Bool) -> NSMenuItem { + private func makeNetworkProtectionItem() -> NSMenuItem { let networkProtectionItem = NSMenuItem(title: "", action: #selector(showNetworkProtectionStatus(_:)), keyEquivalent: "") .targetting(self) .withImage(.image(for: .vpnIcon)) - if showNewLabel { - let attributedText = NSMutableAttributedString(string: UserText.networkProtection) - attributedText.append(NSAttributedString(string: " ")) - - let imageAttachment = NSTextAttachment() - imageAttachment.image = .newLabel - imageAttachment.setImageHeight(height: 16, offset: .init(x: 0, y: -4)) - - attributedText.append(NSAttributedString(attachment: imageAttachment)) - - networkProtectionItem.attributedTitle = attributedText - } else { - networkProtectionItem.title = UserText.networkProtection - } + networkProtectionItem.title = UserText.networkProtection return networkProtectionItem } diff --git a/DuckDuckGo/NavigationBar/View/NavigationBar.storyboard b/DuckDuckGo/NavigationBar/View/NavigationBar.storyboard index fe6b3f27ca..357dbe0d25 100644 --- a/DuckDuckGo/NavigationBar/View/NavigationBar.storyboard +++ b/DuckDuckGo/NavigationBar/View/NavigationBar.storyboard @@ -252,7 +252,7 @@ -