diff --git a/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionNavBarButtonModel.swift b/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionNavBarButtonModel.swift index d8d1aaedf2..ee8b4d550b 100644 --- a/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionNavBarButtonModel.swift +++ b/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionNavBarButtonModel.swift @@ -36,8 +36,9 @@ final class NetworkProtectionNavBarButtonModel: NSObject, ObservableObject { private var cancellables = Set() - // MARK: - NetP Icon publisher + // MARK: - VPN + private let vpnVisibility: NetworkProtectionFeatureVisibility private let iconPublisher: NetworkProtectionIconPublisher private var iconPublisherCancellable: AnyCancellable? @@ -70,10 +71,12 @@ final class NetworkProtectionNavBarButtonModel: NSObject, ObservableObject { init(popoverManager: NetPPopoverManager, pinningManager: PinningManager = LocalPinningManager.shared, + vpnVisibility: NetworkProtectionFeatureVisibility = DefaultNetworkProtectionVisibility(), statusReporter: NetworkProtectionStatusReporter, iconProvider: IconProvider = NavigationBarIconProvider()) { self.popoverManager = popoverManager + self.vpnVisibility = vpnVisibility self.networkProtectionStatusReporter = statusReporter self.iconPublisher = NetworkProtectionIconPublisher(statusReporter: networkProtectionStatusReporter, iconProvider: iconProvider) self.pinningManager = pinningManager @@ -175,8 +178,7 @@ final class NetworkProtectionNavBarButtonModel: NSObject, ObservableObject { @MainActor func updateVisibility() { // The button is visible in the case where NetP has not been activated, but the user has been invited and they haven't accepted T&Cs. - let networkProtectionVisibility = DefaultNetworkProtectionVisibility() - if networkProtectionVisibility.isNetworkProtectionBetaVisible() { + if vpnVisibility.isNetworkProtectionBetaVisible() { if NetworkProtectionWaitlist().readyToAcceptTermsAndConditions { showButton = true return diff --git a/DuckDuckGo/Preferences/Model/PreferencesSidebarModel.swift b/DuckDuckGo/Preferences/Model/PreferencesSidebarModel.swift index 3cb7adc0a7..98de79c2a5 100644 --- a/DuckDuckGo/Preferences/Model/PreferencesSidebarModel.swift +++ b/DuckDuckGo/Preferences/Model/PreferencesSidebarModel.swift @@ -32,6 +32,7 @@ final class PreferencesSidebarModel: ObservableObject { @Published private(set) var sections: [PreferencesSection] = [] @Published var selectedTabIndex: Int = 0 @Published private(set) var selectedPane: PreferencePaneIdentifier = .defaultBrowser + private let vpnVisibility: NetworkProtectionFeatureVisibility var selectedTabContent: AnyPublisher { $selectedTabIndex.map { [tabSwitcherTabs] in tabSwitcherTabs[$0] }.eraseToAnyPublisher() @@ -43,10 +44,12 @@ final class PreferencesSidebarModel: ObservableObject { loadSections: @escaping () -> [PreferencesSection], tabSwitcherTabs: [Tab.TabContent], privacyConfigurationManager: PrivacyConfigurationManaging, - syncService: DDGSyncing + syncService: DDGSyncing, + vpnVisibility: NetworkProtectionFeatureVisibility = DefaultNetworkProtectionVisibility() ) { self.loadSections = loadSections self.tabSwitcherTabs = tabSwitcherTabs + self.vpnVisibility = vpnVisibility resetTabSelectionIfNeeded() refreshSections() @@ -77,11 +80,12 @@ final class PreferencesSidebarModel: ObservableObject { tabSwitcherTabs: [Tab.TabContent] = Tab.TabContent.displayableTabTypes, privacyConfigurationManager: PrivacyConfigurationManaging = ContentBlocking.shared.privacyConfigurationManager, syncService: DDGSyncing, + vpnVisibility: NetworkProtectionFeatureVisibility = DefaultNetworkProtectionVisibility(), includeDuckPlayer: Bool, userDefaults: UserDefaults = .netP ) { let loadSections = { - let includingVPN = DefaultNetworkProtectionVisibility().isInstalled + let includingVPN = vpnVisibility.isInstalled return PreferencesSection.defaultSections( includingDuckPlayer: includeDuckPlayer, @@ -93,13 +97,14 @@ final class PreferencesSidebarModel: ObservableObject { self.init(loadSections: loadSections, tabSwitcherTabs: tabSwitcherTabs, privacyConfigurationManager: privacyConfigurationManager, - syncService: syncService) + syncService: syncService, + vpnVisibility: vpnVisibility) } // MARK: - Setup private func setupVPNPaneVisibility() { - DefaultNetworkProtectionVisibility().onboardStatusPublisher + vpnVisibility.onboardStatusPublisher .receive(on: DispatchQueue.main) .sink { [weak self] _ in guard let self else { return } diff --git a/DuckDuckGo/PrivacyDashboard/View/PrivacyDashboardViewController.swift b/DuckDuckGo/PrivacyDashboard/View/PrivacyDashboardViewController.swift index 4a5d5113f3..dd06a09fb7 100644 --- a/DuckDuckGo/PrivacyDashboard/View/PrivacyDashboardViewController.swift +++ b/DuckDuckGo/PrivacyDashboard/View/PrivacyDashboardViewController.swift @@ -367,7 +367,7 @@ extension PrivacyDashboardViewController { errors: errors, httpStatusCodes: statusCodes, openerContext: currentTab.inferredOpenerContext, - vpnOn: currentTab.tunnelController?.isConnected ?? false, + vpnOn: currentTab.tunnelController.isConnected, jsPerformance: webVitals, userRefreshCount: currentTab.refreshCountSinceLoad, didOpenReportInfo: didOpenReportInfo, diff --git a/DuckDuckGo/Tab/Model/Tab.swift b/DuckDuckGo/Tab/Model/Tab.swift index 643da5aa94..bfa43c24e3 100644 --- a/DuckDuckGo/Tab/Model/Tab.swift +++ b/DuckDuckGo/Tab/Model/Tab.swift @@ -341,7 +341,7 @@ protocol NewWindowPolicyDecisionMaker { private let internalUserDecider: InternalUserDecider? let pinnedTabsManager: PinnedTabsManager - private(set) var tunnelController: NetworkProtectionIPCTunnelController? + private(set) var tunnelController: NetworkProtectionIPCTunnelController private let webViewConfiguration: WKWebViewConfiguration @@ -510,6 +510,10 @@ protocol NewWindowPolicyDecisionMaker { duckPlayer: duckPlayer, downloadManager: downloadManager)) + let ipcClient = TunnelControllerIPCClient() + ipcClient.register() + tunnelController = NetworkProtectionIPCTunnelController(ipcClient: ipcClient) + super.init() tabGetter = { [weak self] in self } userContentController.map(userContentControllerPromise.fulfill) @@ -529,17 +533,6 @@ protocol NewWindowPolicyDecisionMaker { self?.onDuckDuckGoEmailSignOut(notification) } - netPOnboardStatusCancellabel = DefaultNetworkProtectionVisibility().onboardStatusPublisher - .receive(on: DispatchQueue.main) - .sink { [weak self] onboardingStatus in - guard onboardingStatus == .completed else { return } - - let ipcClient = TunnelControllerIPCClient() - ipcClient.register() - - self?.tunnelController = NetworkProtectionIPCTunnelController(ipcClient: ipcClient) - } - self.audioState = webView.audioState() addDeallocationChecks(for: webView) } @@ -1170,8 +1163,6 @@ protocol NewWindowPolicyDecisionMaker { private var webViewCancellables = Set() private var emailDidSignOutCancellable: AnyCancellable? - private var netPOnboardStatusCancellabel: AnyCancellable? - private func setupWebView(shouldLoadInBackground: Bool) { webView.navigationDelegate = navigationDelegate webView.uiDelegate = self @@ -1456,7 +1447,7 @@ extension Tab/*: NavigationResponder*/ { // to be moved to Tab+Navigation.swift } } - if navigation.url.isDuckDuckGoSearch, tunnelController?.isConnected == true { + if navigation.url.isDuckDuckGoSearch, tunnelController.isConnected == true { DailyPixel.fire(pixel: .networkProtectionEnabledOnSearch, frequency: .dailyAndCount) } } diff --git a/DuckDuckGo/Waitlist/NetworkProtectionFeatureVisibility.swift b/DuckDuckGo/Waitlist/NetworkProtectionFeatureVisibility.swift index 72d787249c..6ce1842ef4 100644 --- a/DuckDuckGo/Waitlist/NetworkProtectionFeatureVisibility.swift +++ b/DuckDuckGo/Waitlist/NetworkProtectionFeatureVisibility.swift @@ -41,6 +41,8 @@ protocol NetworkProtectionFeatureVisibility { func disableForWaitlistUsers() @discardableResult func disableIfUserHasNoAccess() async -> Bool + + var onboardStatusPublisher: AnyPublisher { get } } struct DefaultNetworkProtectionVisibility: NetworkProtectionFeatureVisibility { diff --git a/UnitTests/Menus/MoreOptionsMenuTests.swift b/UnitTests/Menus/MoreOptionsMenuTests.swift index 1aec539d0c..f468cc4a28 100644 --- a/UnitTests/Menus/MoreOptionsMenuTests.swift +++ b/UnitTests/Menus/MoreOptionsMenuTests.swift @@ -16,14 +16,15 @@ // limitations under the License. // +import Combine +import NetworkProtection +import NetworkProtectionUI import XCTest #if SUBSCRIPTION import Subscription #endif -import NetworkProtection - @testable import DuckDuckGo_Privacy_Browser final class MoreOptionsMenuTests: XCTestCase { @@ -165,6 +166,9 @@ final class MoreOptionsMenuTests: XCTestCase { } final class NetworkProtectionVisibilityMock: NetworkProtectionFeatureVisibility { + var onboardStatusPublisher: AnyPublisher { + Just(.default).eraseToAnyPublisher() + } var isInstalled: Bool var visible: Bool