From 607feb02ff04f931e3785c2c7968857818ae24ff Mon Sep 17 00:00:00 2001 From: Diego Rey Mendez Date: Tue, 22 Oct 2024 11:30:07 +0200 Subject: [PATCH] WIP --- DuckDuckGo.xcodeproj/project.pbxproj | 2 + .../xcshareddata/swiftpm/Package.resolved | 8 -- .../DuckDuckGo Privacy Browser.xcscheme | 2 +- DuckDuckGo/InfoPlist.xcstrings | 2 +- DuckDuckGo/Localizable.xcstrings | 10 +- ...etworkProtectionNavBarPopoverManager.swift | 8 +- .../TipKit/TipKitAppEventHandling.swift | 7 +- DuckDuckGoVPN/DuckDuckGoVPNDebug.entitlements | 1 + .../Menu/StatusBarMenu.swift | 8 +- .../TipViews/Model/VPNAutoconnectTip.swift | 6 +- .../Model/VPNDomainExclusionsTip.swift | 18 ++-- .../TipViews/Model/VPNGeoswitchingTip.swift | 4 +- .../Views/TipViews/Model/VPNTipsModel.swift | 95 ++++++++++++------- .../TipViews/VPNAutoconnectTipView.swift | 2 +- .../TipViews/VPNDomainExclusionsTipView.swift | 2 +- .../TipViews/VPNGeoswitchingTipView.swift | 2 +- .../TunnelControllerView.swift | 20 +++- .../TunnelControllerViewModel.swift | 16 ++-- 18 files changed, 124 insertions(+), 89 deletions(-) diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index d0ead5690f..3d8cb8ae18 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -3827,6 +3827,7 @@ 7B1E819C27C8874900FF0E60 /* ContentOverlay.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = ContentOverlay.storyboard; sourceTree = ""; }; 7B1E819D27C8874900FF0E60 /* ContentOverlayViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContentOverlayViewController.swift; sourceTree = ""; }; 7B25FE322AD12C990012AFAB /* NetworkProtectionMac */ = {isa = PBXFileReference; lastKnownFileType = wrapper; path = NetworkProtectionMac; sourceTree = ""; }; + 7B26AEE52CC674C900D66678 /* BrowserServicesKit */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = BrowserServicesKit; path = ../BrowserServicesKit; sourceTree = SOURCE_ROOT; }; 7B2DDCF72A93A8BB0039D884 /* NetworkProtectionAppEvents.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkProtectionAppEvents.swift; sourceTree = ""; }; 7B2E52242A5FEC09000C6D39 /* NetworkProtectionAgentNotificationsPresenter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NetworkProtectionAgentNotificationsPresenter.swift; sourceTree = ""; }; 7B3618C12ADE75C8000D6154 /* NetworkProtectionNavBarPopoverManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkProtectionNavBarPopoverManager.swift; sourceTree = ""; }; @@ -5519,6 +5520,7 @@ 378E279C2970217400FCADA2 /* LocalPackages */ = { isa = PBXGroup; children = ( + 7B26AEE52CC674C900D66678 /* BrowserServicesKit */, 9D9DE5712C63A96400D20B15 /* AppKitExtensions */, 7B9167A82C09E88800322310 /* AppLauncher */, 378E279D2970217400FCADA2 /* BuildToolPlugins */, diff --git a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 0c2dfcbf1b..06c52ecb68 100644 --- a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -27,14 +27,6 @@ "version" : "3.0.0" } }, - { - "identity" : "browserserviceskit", - "kind" : "remoteSourceControl", - "location" : "https://github.com/duckduckgo/BrowserServicesKit", - "state" : { - "revision" : "c05ef03b3320ccecdace3b1d53d945313585c170" - } - }, { "identity" : "content-scope-scripts", "kind" : "remoteSourceControl", diff --git a/DuckDuckGo.xcodeproj/xcshareddata/xcschemes/DuckDuckGo Privacy Browser.xcscheme b/DuckDuckGo.xcodeproj/xcshareddata/xcschemes/DuckDuckGo Privacy Browser.xcscheme index 5cd264a90f..a0ad0111f9 100644 --- a/DuckDuckGo.xcodeproj/xcshareddata/xcschemes/DuckDuckGo Privacy Browser.xcscheme +++ b/DuckDuckGo.xcodeproj/xcshareddata/xcschemes/DuckDuckGo Privacy Browser.xcscheme @@ -79,7 +79,7 @@ $(NETP_APP_GROUP) $(IPC_APP_GROUP) $(SUBSCRIPTION_APP_GROUP) + $(APP_CONFIGURATION_APP_GROUP) keychain-access-groups diff --git a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Menu/StatusBarMenu.swift b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Menu/StatusBarMenu.swift index 90f4f27a82..73087cd3fd 100644 --- a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Menu/StatusBarMenu.swift +++ b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Menu/StatusBarMenu.swift @@ -20,9 +20,10 @@ import AppKit import Foundation import Combine import Common -import SwiftUI -import NetworkProtection import LoginItems +import NetworkProtection +import os.log +import SwiftUI import TipKitUtils /// Abstraction of the the VPN status bar menu with a simple interface. @@ -150,7 +151,8 @@ public final class StatusBarMenu: NSObject { statusObserver: statusReporter.statusObserver, activeSitePublisher: activeSitePublisher, forMenuApp: true, - vpnSettings: VPNSettings(defaults: userDefaults)) + vpnSettings: VPNSettings(defaults: userDefaults), + logger: Logger.init(subsystem: "DuckDuckGo", category: "TipKit")) let debugInformationViewModel = DebugInformationViewModel(showDebugInformation: isOptionKeyPressed) diff --git a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/TipViews/Model/VPNAutoconnectTip.swift b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/TipViews/Model/VPNAutoconnectTip.swift index 51ca3cb0b0..8881f62dee 100644 --- a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/TipViews/Model/VPNAutoconnectTip.swift +++ b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/TipViews/Model/VPNAutoconnectTip.swift @@ -21,12 +21,8 @@ import TipKit /// A tip to suggest to the user to use the autoconnect option for the VPN. /// -struct VPNAutoconnectTip {} - -/// Necessary split to support older iOS versions. -/// @available(macOS 14.0, *) -extension VPNAutoconnectTip: Tip { +struct VPNAutoconnectTip: Tip { enum ActionIdentifiers: String { case enable = "com.duckduckgo.vpn.tip.autoconnect.action.enable" diff --git a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/TipViews/Model/VPNDomainExclusionsTip.swift b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/TipViews/Model/VPNDomainExclusionsTip.swift index 026524c062..a2886fe7e3 100644 --- a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/TipViews/Model/VPNDomainExclusionsTip.swift +++ b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/TipViews/Model/VPNDomainExclusionsTip.swift @@ -21,12 +21,8 @@ import TipKit /// A tip to suggest using domain exclusions when a site doesn't work. /// -struct VPNDomainExclusionsTip {} - -/// Necessary split to support older iOS versions. -/// @available(macOS 14.0, *) -extension VPNDomainExclusionsTip: Tip { +struct VPNDomainExclusionsTip: Tip { @Parameter(.transient) static var vpnEnabled: Bool = false @@ -39,7 +35,7 @@ extension VPNDomainExclusionsTip: Tip { /// This condition may be indicative that the user is struggling, so they might want /// to exclude a site. /// - static let viewOpenedWhehVPNAlreadyConnectedEvent = Tips.Event(id: "com.duckduckgo.vpn.tip.domainExclusions.popoverOpenedWhileAlreadyConnected") + static let viewOpenedWhenVPNAlreadyConnectedEvent = Tips.Event(id: "com.duckduckgo.vpn.tip.domainExclusions.popoverOpenedWhileAlreadyConnected") var id: String { "com.duckduckgo.vpn.tip.domainExclusions" @@ -57,15 +53,15 @@ extension VPNDomainExclusionsTip: Tip { Image(.domainExclusionsTip) } - var rules: [Rule] { + var rules: [Self.Rule] { #Rule(Self.$hasActiveSite) { - $0 == true + $0 } #Rule(Self.$vpnEnabled) { - $0 == true + $0 } - #Rule(Self.viewOpenedWhehVPNAlreadyConnectedEvent) { - $0.donations.count > 1 + #Rule(Self.viewOpenedWhenVPNAlreadyConnectedEvent) { + $0.donations.count > 0 } } } diff --git a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/TipViews/Model/VPNGeoswitchingTip.swift b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/TipViews/Model/VPNGeoswitchingTip.swift index 9d609f39c8..27aac17ebb 100644 --- a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/TipViews/Model/VPNGeoswitchingTip.swift +++ b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/TipViews/Model/VPNGeoswitchingTip.swift @@ -21,10 +21,8 @@ import TipKit /// A tip to suggest to the user to change their location using geo-switching /// -struct VPNGeoswitchingTip {} - @available(macOS 14.0, *) -extension VPNGeoswitchingTip: Tip { +struct VPNGeoswitchingTip: Tip { static let vpnConnectedEvent = Tips.Event(id: "com.duckduckgo.vpn.tip.geoswitching.vpnConnectedEvent") diff --git a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/TipViews/Model/VPNTipsModel.swift b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/TipViews/Model/VPNTipsModel.swift index 27f9057a0c..5ca9a33128 100644 --- a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/TipViews/Model/VPNTipsModel.swift +++ b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/TipViews/Model/VPNTipsModel.swift @@ -20,14 +20,16 @@ import AppKit import Combine import Common import NetworkProtection +import os.log import TipKit import TipKitUtils +@MainActor public final class VPNTipsModel: ObservableObject { @Published private(set) var activeSiteInfo: ActiveSiteInfo? { - didSet { + willSet { guard #available(macOS 14.0, *) else { return } @@ -38,13 +40,20 @@ public final class VPNTipsModel: ObservableObject { @Published private(set) var connectionStatus: ConnectionStatus { - didSet { + willSet { guard #available(macOS 14.0, *) else { return } - switch connectionStatus { + switch newValue { case .connected: + if case connectionStatus = .connecting { + Task { + print("🧉💎 Geoswitching tip donated") + await VPNGeoswitchingTip.vpnConnectedEvent.donate() + } + } + VPNAutoconnectTip.vpnEnabled = true VPNDomainExclusionsTip.vpnEnabled = true default: @@ -56,44 +65,58 @@ public final class VPNTipsModel: ObservableObject { @Published private(set) var featureFlag: Bool - let tips: TipGrouping + + @Published + private var tips: TipGrouping private let vpnSettings: VPNSettings + private let logger: Logger private var cancellables = Set() - static func makeTips(forMenuApp isMenuApp: Bool) -> TipGrouping { + static func makeTips(forMenuApp isMenuApp: Bool, logger: Logger) -> TipGrouping { + + logger.debug("🧉🤌 makeTips") + + guard #available(macOS 14.0, *) else { + return EmptyTipGroup() + } + + let domainExclusionsTip = VPNDomainExclusionsTip() + let geoswitchingTip = VPNGeoswitchingTip() + + Task { + for await statusUpdate in geoswitchingTip.statusUpdates { + logger.debug("🧉 VPNGeoswitchingTip status updated: \(String(describing: statusUpdate), privacy: .public)") + logger.debug("🪙 VPNGeoswitchingTip summary:\nL shouldDisplay: \(String(describing: geoswitchingTip.shouldDisplay), privacy: .public)") + } + } + + Task { + for await statusUpdate in domainExclusionsTip.statusUpdates { + logger.debug("🧉 VPNDomainExclusionsTip status updated: \(String(describing: statusUpdate), privacy: .public)") + logger.debug("🪙 VPNDomainExclusionsTip summary:\nL shouldDisplay: \(String(describing: domainExclusionsTip.shouldDisplay), privacy: .public)\nL hasActiveSite: \(String(describing: VPNDomainExclusionsTip.hasActiveSite), privacy: .public)\nL vpnEnabled: \(String(describing: VPNDomainExclusionsTip.vpnEnabled), privacy: .public)") + } + } + // This is temporarily disabled until Xcode 16 is available. // Ref: https://app.asana.com/0/414235014887631/1208528787265444/f // // if #available(macOS 15.0, *) { - // if isMenuApp { - // return TipGroup(.ordered) { - // VPNGeoswitchingTip() - // VPNAutoconnectTip() - // } - // } else { - // return TipGroup(.ordered) { - // VPNGeoswitchingTip() - // VPNDomainExclusionsTip() - // VPNAutoconnectTip() - // } + // return TipGroup(.ordered) { + // tips // } - // } - if #available(macOS 14, *) { - if isMenuApp { - return LegacyTipGroup(.ordered) { - VPNGeoswitchingTip() - VPNAutoconnectTip() - } - } else { - return LegacyTipGroup(.ordered) { - VPNGeoswitchingTip() - VPNDomainExclusionsTip() - VPNAutoconnectTip() - } + // } else { ... what's below + if isMenuApp { + return LegacyTipGroup(.ordered) { + VPNGeoswitchingTip() + VPNAutoconnectTip() } } else { - return EmptyTipGroup() + return LegacyTipGroup(.ordered) { + VPNGeoswitchingTip() + VPNDomainExclusionsTip() + VPNAutoconnectTip() + } } } @@ -101,12 +124,15 @@ public final class VPNTipsModel: ObservableObject { statusObserver: ConnectionStatusObserver, activeSitePublisher: CurrentValuePublisher, forMenuApp isMenuApp: Bool, - vpnSettings: VPNSettings) { + vpnSettings: VPNSettings, + logger: Logger) { + print("🧉🟢 New model instance") self.activeSiteInfo = activeSitePublisher.value self.connectionStatus = statusObserver.recentValue self.featureFlag = featureFlagPublisher.value - self.tips = Self.makeTips(forMenuApp: isMenuApp) + self.logger = logger + self.tips = Self.makeTips(forMenuApp: isMenuApp, logger: logger) self.vpnSettings = vpnSettings if #available(macOS 14.0, *) { @@ -152,4 +178,9 @@ public final class VPNTipsModel: ObservableObject { vpnSettings.connectOnLogin = true } } + + @available(macOS 14.0, *) + var currentTip: (any Tip)? { + tips.currentTip + } } diff --git a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/TipViews/VPNAutoconnectTipView.swift b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/TipViews/VPNAutoconnectTipView.swift index c484541551..539cc41501 100644 --- a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/TipViews/VPNAutoconnectTipView.swift +++ b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/TipViews/VPNAutoconnectTipView.swift @@ -34,7 +34,7 @@ struct VPNAutoconnectTipView: View { public var body: some View { if tipsModel.featureFlag, - let tip = tipsModel.tips.currentTip as? VPNAutoconnectTip { + let tip = tipsModel.currentTip as? VPNAutoconnectTip { TipView(tip, action: tipsModel.autoconnectTipActionHandler) } diff --git a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/TipViews/VPNDomainExclusionsTipView.swift b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/TipViews/VPNDomainExclusionsTipView.swift index f068902345..629e1ed3b2 100644 --- a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/TipViews/VPNDomainExclusionsTipView.swift +++ b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/TipViews/VPNDomainExclusionsTipView.swift @@ -34,7 +34,7 @@ struct VPNDomainExclusionsTipView: View { public var body: some View { if tipsModel.featureFlag, - let tip = tipsModel.tips.currentTip as? VPNDomainExclusionsTip { + let tip = tipsModel.currentTip as? VPNDomainExclusionsTip { TipView(tip) } diff --git a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/TipViews/VPNGeoswitchingTipView.swift b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/TipViews/VPNGeoswitchingTipView.swift index 8ef6442b54..9b197e7456 100644 --- a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/TipViews/VPNGeoswitchingTipView.swift +++ b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/TipViews/VPNGeoswitchingTipView.swift @@ -33,7 +33,7 @@ struct VPNGeoswitchingTipView: View { @ViewBuilder public var body: some View { if tipsModel.featureFlag, - let tip = tipsModel.tips.currentTip as? VPNGeoswitchingTip { + let tip = tipsModel.currentTip as? VPNGeoswitchingTip { TipView(tip) } diff --git a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/TunnelControllerView/TunnelControllerView.swift b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/TunnelControllerView/TunnelControllerView.swift index 7ebb3c8a1d..58357954be 100644 --- a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/TunnelControllerView/TunnelControllerView.swift +++ b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/TunnelControllerView/TunnelControllerView.swift @@ -22,6 +22,7 @@ import Combine import NetworkProtection import Lottie import TipKit +import TipKitUtils public struct TunnelControllerView: View { @@ -41,6 +42,9 @@ public struct TunnelControllerView: View { self.model = model } + @EnvironmentObject + private var tipsModel: VPNTipsModel + // MARK: - View Contents public var body: some View { @@ -60,9 +64,17 @@ public struct TunnelControllerView: View { .padding(.top, 5) if #available(macOS 15.0, *) { - VPNDomainExclusionsTipView() - .padding(.horizontal, 9) - .padding(.vertical, 6) + //VPNDomainExclusionsTipView() + //.padding(.horizontal, 9) + //.padding(.vertical, 6) + + if tipsModel.featureFlag {//, + //let tip = tipsModel.currentTip as? VPNDomainExclusionsTip { + + TipView(VPNDomainExclusionsTip()) + .padding(.horizontal, 9) + .padding(.vertical, 6) + } } Divider() @@ -187,7 +199,7 @@ public struct TunnelControllerView: View { } if #available(macOS 15.0, *) { - VPNGeoswitchingTipView() + TipView(VPNGeoswitchingTip()) .padding(.horizontal, 9) .padding(.vertical, 6) } diff --git a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/TunnelControllerView/TunnelControllerViewModel.swift b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/TunnelControllerView/TunnelControllerViewModel.swift index 35a5bc317a..9f9c02ed69 100644 --- a/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/TunnelControllerView/TunnelControllerViewModel.swift +++ b/LocalPackages/NetworkProtectionMac/Sources/NetworkProtectionUI/Views/TunnelControllerView/TunnelControllerViewModel.swift @@ -181,11 +181,15 @@ public final class TunnelControllerViewModel: ObservableObject { } refreshTimeLapsed() - let call = refreshTimeLapsed - let newTimer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { _ in + let newTimer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { [weak self] _ in + + guard let self else { + return + } + Task { @MainActor in - call() + self.refreshTimeLapsed() } } @@ -503,10 +507,6 @@ public final class TunnelControllerViewModel: ObservableObject { } Task { @MainActor in - if #available(macOS 14.0, *) { - await VPNGeoswitchingTip.vpnConnectedEvent.donate() - } - await tunnelController.start() refreshInternalIsRunning() } @@ -541,7 +541,7 @@ public final class TunnelControllerViewModel: ObservableObject { func handleTunnelControllerShown() async { if #available(macOS 14.0, *) { - await VPNDomainExclusionsTip.viewOpenedWhehVPNAlreadyConnectedEvent.donate() + await VPNDomainExclusionsTip.viewOpenedWhenVPNAlreadyConnectedEvent.donate() } } }