diff --git a/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionNavBarPopoverManager.swift b/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionNavBarPopoverManager.swift index e7dbaf19e9..37d8daa09e 100644 --- a/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionNavBarPopoverManager.swift +++ b/DuckDuckGo/NetworkProtection/AppTargets/BothAppTargets/NetworkProtectionNavBarPopoverManager.swift @@ -92,7 +92,8 @@ final class NetworkProtectionNavBarPopoverManager { ] } }, - agentLoginItem: LoginItem.vpnMenu + agentLoginItem: LoginItem.vpnMenu, + isMenuBarStatusView: false ) popover.delegate = delegate diff --git a/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift b/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift index e72b57d055..6a5f9bc6df 100644 --- a/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift +++ b/DuckDuckGoVPN/DuckDuckGoVPNAppDelegate.swift @@ -159,7 +159,8 @@ final class DuckDuckGoVPNAppDelegate: NSObject, NSApplicationDelegate { }) ] }, - agentLoginItem: nil) + agentLoginItem: nil, + isMenuBarStatusView: true) } @MainActor diff --git a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Extensions/UserText+NetworkProtectionUI.swift b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Extensions/UserText+NetworkProtectionUI.swift index 78f279d80a..ccd9a73ef7 100644 --- a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Extensions/UserText+NetworkProtectionUI.swift +++ b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Extensions/UserText+NetworkProtectionUI.swift @@ -40,6 +40,7 @@ final class UserText { static let networkProtectionOnboardingAllowVPNDescPrefix = NSLocalizedString("network.protection.onboarding.allow.vpn.desc.prefix", value: "Select ", comment: "Non-bold prefix for the onboarding allow-VPN description") static let networkProtectionOnboardingAllowVPNDescAllow = NSLocalizedString("network.protection.onboarding.allow.vpn.desc.allow", value: "Allow", comment: "'Allow' word between the prefix and suffix for the onboarding allow-VPN description") static let networkProtectionOnboardingAllowVPNDescSuffix = NSLocalizedString("network.protection.onboarding.allow.vpn.desc.suffix", value: " when prompted to finish setting up Network Protection.", comment: "Non-bold suffix for the onboarding allow-VPN description") + static let networkProtectionOnboardingAllowVPNDescExpandedSuffix = NSLocalizedString("network.protection.onboarding.allow.vpn.desc.expanded.suffix", value: " when prompted to finish setting up Network Protection.\n\nThis adds a shortcut in the menu bar so you can still access the VPN if the browser isn't running.", comment: "Non-bold suffix for the onboarding allow-VPN description") static let networkProtectionOnboardingAllowVPNAction = NSLocalizedString("network.protection.onboarding.allow.vpn.action", value: "Add VPN Configuration...", comment: "Action button title for the onboarding allow-VPN view") static let networkProtectionOnboardingMoveToApplicationsTitle = NSLocalizedString("network.protection.onboarding.move.to.applications.title", value: "Move DuckDuckGo App", comment: "Title for the onboarding move-app-to-applications step") diff --git a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Menu/StatusBarMenu.swift b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Menu/StatusBarMenu.swift index 996df614b1..cba2d5573a 100644 --- a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Menu/StatusBarMenu.swift +++ b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Menu/StatusBarMenu.swift @@ -55,7 +55,8 @@ public final class StatusBarMenu: NSObject { iconProvider: IconProvider, appLauncher: AppLaunching, menuItems: @escaping () -> [MenuItem], - agentLoginItem: LoginItem?) { + agentLoginItem: LoginItem?, + isMenuBarStatusView: Bool) { self.model = model let statusItem = statusItem ?? NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength) @@ -67,7 +68,8 @@ public final class StatusBarMenu: NSObject { statusReporter: statusReporter, appLauncher: appLauncher, menuItems: menuItems, - agentLoginItem: agentLoginItem) + agentLoginItem: agentLoginItem, + isMenuBarStatusView: isMenuBarStatusView) popover.behavior = .transient super.init() diff --git a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/NetworkProtectionPopover.swift b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/NetworkProtectionPopover.swift index 85485aa0f1..efbe5872eb 100644 --- a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/NetworkProtectionPopover.swift +++ b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/NetworkProtectionPopover.swift @@ -55,16 +55,18 @@ public final class NetworkProtectionPopover: NSPopover { statusReporter: NetworkProtectionStatusReporter, appLauncher: AppLaunching, menuItems: @escaping () -> [MenuItem], - agentLoginItem: LoginItem?) { + agentLoginItem: LoginItem?, + isMenuBarStatusView: Bool) { self.statusReporter = statusReporter self.model = NetworkProtectionStatusView.Model(controller: controller, - onboardingStatusPublisher: onboardingStatusPublisher, - statusReporter: statusReporter, - debugInformationPublisher: debugInformationPublisher.eraseToAnyPublisher(), - appLauncher: appLauncher, - menuItems: menuItems, - agentLoginItem: agentLoginItem) + onboardingStatusPublisher: onboardingStatusPublisher, + statusReporter: statusReporter, + debugInformationPublisher: debugInformationPublisher.eraseToAnyPublisher(), + appLauncher: appLauncher, + menuItems: menuItems, + agentLoginItem: agentLoginItem, + isMenuBarStatusView: isMenuBarStatusView) super.init() diff --git a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/PromptActionView/PromptActionViewModel.swift b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/PromptActionView/PromptActionViewModel.swift index 9a6d9abae5..907a81f576 100644 --- a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/PromptActionView/PromptActionViewModel.swift +++ b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/PromptActionView/PromptActionViewModel.swift @@ -25,32 +25,47 @@ extension PromptActionView { /// final class Model: ObservableObject { - private let presentationData: PromptPresentable + private(set) var icon: NetworkProtectionAsset + private(set) var title: String + private(set) var description: [StyledTextFragment] + private(set) var actionTitle: String + private(set) var actionScreenshot: NetworkProtectionAsset? let action: () -> Void - init(presentationData: PromptPresentable, action: @escaping () -> Void) { - self.presentationData = presentationData - self.action = action - } - - var icon: NetworkProtectionAsset { - presentationData.icon - } - - var title: String { - presentationData.title - } - - var description: [StyledTextFragment] { - presentationData.description + convenience init(onboardingStep: OnboardingStep, isMenuBar: Bool, action: @escaping () -> Void) { + self.init( + icon: onboardingStep.icon, + title: onboardingStep.title, + description: onboardingStep.description(isMenuBar: isMenuBar), + actionTitle: onboardingStep.actionTitle, + actionScreenshot: onboardingStep.actionScreenshot, + action: action + ) } - var actionTitle: String { - presentationData.actionTitle + convenience init(presentationData data: PromptPresentable, action: @escaping () -> Void) { + self.init( + icon: data.icon, + title: data.title, + description: data.description, + actionTitle: data.actionTitle, + actionScreenshot: data.actionScreenshot, + action: action + ) } - var actionScreenshot: NetworkProtectionAsset? { - presentationData.actionScreenshot + init(icon: NetworkProtectionAsset, + title: String, + description: [StyledTextFragment], + actionTitle: String, + actionScreenshot: NetworkProtectionAsset? = nil, + action: @escaping () -> Void) { + self.icon = icon + self.title = title + self.description = description + self.actionTitle = actionTitle + self.actionScreenshot = actionScreenshot + self.action = action } } } @@ -77,7 +92,7 @@ struct StyledTextFragment { } } -extension OnboardingStep: PromptPresentable { +extension OnboardingStep { var icon: NetworkProtectionAsset { switch self { case .userNeedsToAllowExtension: @@ -96,7 +111,7 @@ extension OnboardingStep: PromptPresentable { } } - var description: [StyledTextFragment] { + func description(isMenuBar: Bool) -> [StyledTextFragment] { switch self { case .userNeedsToAllowExtension: return [ @@ -105,11 +120,19 @@ extension OnboardingStep: PromptPresentable { .init(text: UserText.networkProtectionOnboardingAllowExtensionDescSuffix), ] case .userNeedsToAllowVPNConfiguration: - return [ - .init(text: UserText.networkProtectionOnboardingAllowVPNDescPrefix), - .init(text: UserText.networkProtectionOnboardingAllowVPNDescAllow, isEmphasized: true), - .init(text: UserText.networkProtectionOnboardingAllowVPNDescSuffix), - ] + if isMenuBar { + return [ + .init(text: UserText.networkProtectionOnboardingAllowVPNDescPrefix), + .init(text: UserText.networkProtectionOnboardingAllowVPNDescAllow, isEmphasized: true), + .init(text: UserText.networkProtectionOnboardingAllowVPNDescSuffix) + ] + } else { + return [ + .init(text: UserText.networkProtectionOnboardingAllowVPNDescPrefix), + .init(text: UserText.networkProtectionOnboardingAllowVPNDescAllow, isEmphasized: true), + .init(text: UserText.networkProtectionOnboardingAllowVPNDescExpandedSuffix) + ] + } } } diff --git a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/StatusView/NetworkProtectionStatusViewModel.swift b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/StatusView/NetworkProtectionStatusViewModel.swift index 2a86e999d0..430d5f17b3 100644 --- a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/StatusView/NetworkProtectionStatusViewModel.swift +++ b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/StatusView/NetworkProtectionStatusViewModel.swift @@ -82,6 +82,7 @@ extension NetworkProtectionStatusView { var showDebugInformation: Bool public let agentLoginItem: LoginItem? + private let isMenuBarStatusView: Bool // MARK: - Extra Menu Items @@ -111,6 +112,7 @@ extension NetworkProtectionStatusView { appLauncher: AppLaunching, menuItems: @escaping () -> [MenuItem], agentLoginItem: LoginItem?, + isMenuBarStatusView: Bool, runLoopMode: RunLoop.Mode? = nil) { self.tunnelController = controller @@ -119,6 +121,7 @@ extension NetworkProtectionStatusView { self.debugInformationPublisher = debugInformationPublisher self.menuItems = menuItems self.agentLoginItem = agentLoginItem + self.isMenuBarStatusView = isMenuBarStatusView self.runLoopMode = runLoopMode tunnelControllerViewModel = TunnelControllerViewModel(controller: tunnelController, @@ -303,7 +306,7 @@ extension NetworkProtectionStatusView { switch step { case .userNeedsToAllowExtension, .userNeedsToAllowVPNConfiguration: - return PromptActionView.Model(presentationData: step) { [weak self] in + return PromptActionView.Model(onboardingStep: step, isMenuBar: self.isMenuBarStatusView) { [weak self] in self?.tunnelControllerViewModel.startNetworkProtection() } } diff --git a/LocalPackages/NetworkProtectionMac/Tests/NetworkProtectionUITests/NetworkProtectionStatusBarMenuTests.swift b/LocalPackages/NetworkProtectionMac/Tests/NetworkProtectionUITests/NetworkProtectionStatusBarMenuTests.swift index 90cd3dc3ae..b680b062b6 100644 --- a/LocalPackages/NetworkProtectionMac/Tests/NetworkProtectionUITests/NetworkProtectionStatusBarMenuTests.swift +++ b/LocalPackages/NetworkProtectionMac/Tests/NetworkProtectionUITests/NetworkProtectionStatusBarMenuTests.swift @@ -55,7 +55,8 @@ final class StatusBarMenuTests: XCTestCase { iconProvider: MenuIconProvider(), appLauncher: MockAppLauncher(), menuItems: { [] }, - agentLoginItem: nil) + agentLoginItem: nil, + isMenuBarStatusView: false) menu.show() @@ -77,7 +78,8 @@ final class StatusBarMenuTests: XCTestCase { iconProvider: MenuIconProvider(), appLauncher: MockAppLauncher(), menuItems: { [] }, - agentLoginItem: nil) + agentLoginItem: nil, + isMenuBarStatusView: false) menu.hide()