Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Show VPN onboarding tips #3410

Merged
merged 35 commits into from
Nov 28, 2024
Merged

Show VPN onboarding tips #3410

merged 35 commits into from
Nov 28, 2024

Conversation

diegoreymendez
Copy link
Contributor

@diegoreymendez diegoreymendez commented Oct 17, 2024

Task/Issue URL: https://app.asana.com/0/1206580121312550/1208795272851000/f

iOS PR: duckduckgo/iOS#3429
BSK PR: duckduckgo/BrowserServicesKit#1024

Description

Shows VPN onboarding tips.

Steps to test this PR:

  1. Debug Menu > TipKit > Reset
  2. Relaunch app
  3. Connect to the VPN. You should see the geoswitching tip. This can be dismissed either by clicking on the X or clicking on geoswitching.
  4. Once disable, hide the status view.
  5. Open a site
  6. Open the VPN status view again. You should see a tip to exclude the site. It can be dismissed either by clicking on X or excluding the site.
  7. Once the tip is dismissed you should see a tip to enable autoconnect. It can be dismissed by clicking X or by enabling autoconnect.

Testing Pixels:

Pixels are fired when the tips are shown, ignored (popover closed with no action), dismissed (x button) or actioned.

This is an example run:

17:06:09.691987+0100    47896: 0x290678 debug   com.duckduckgo.PixelKit DuckDuckGo  PixelKit    👾[Standard-Fired] m_mac_vpn_tip_geoswitching_shown ["appVersion": "1.115.0", "pixelSource": "browser-dmg"]
17:06:23.544059+0100    47896: 0x290678 debug   com.duckduckgo.PixelKit DuckDuckGo  PixelKit    👾[Standard-Fired] m_mac_vpn_tip_geoswitching_ignored ["appVersion": "1.115.0", "pixelSource": "browser-dmg"]
17:06:23.591129+0100    47896: 0x290678 debug   com.duckduckgo.PixelKit DuckDuckGo  PixelKit    👾[Standard-Fired] m_mac_vpn_tip_geoswitching_shown ["appVersion": "1.115.0", "pixelSource": "browser-dmg"]
17:06:24.088411+0100    47896: 0x290678 debug   com.duckduckgo.PixelKit DuckDuckGo  PixelKit    👾[Standard-Fired] m_mac_vpn_tip_geoswitching_ignored ["pixelSource": "browser-dmg", "appVersion": "1.115.0"]
17:06:40.386342+0100    47896: 0x290678 debug   com.duckduckgo.PixelKit DuckDuckGo  PixelKit    👾[Standard-Fired] m_mac_vpn_tip_geoswitching_shown ["appVersion": "1.115.0", "pixelSource": "browser-dmg"]
17:06:42.404464+0100    47896: 0x290678 debug   com.duckduckgo.PixelKit DuckDuckGo  PixelKit    👾[Standard-Fired] m_mac_vpn_tip_geoswitching_dismissed ["pixelSource": "browser-dmg", "appVersion": "1.115.0"]
17:06:46.882659+0100    47896: 0x290678 debug   com.duckduckgo.PixelKit DuckDuckGo  PixelKit    👾[Standard-Fired] m_mac_vpn_tip_site-exclusion_shown ["appVersion": "1.115.0", "pixelSource": "browser-dmg"]
17:06:48.425812+0100    47896: 0x290678 debug   com.duckduckgo.PixelKit DuckDuckGo  PixelKit    👾[Standard-Fired] m_mac_vpn_tip_site-exclusion_ignored ["pixelSource": "browser-dmg", "appVersion": "1.115.0"]
17:07:10.872572+0100    47896: 0x290678 debug   com.duckduckgo.PixelKit DuckDuckGo  PixelKit    👾[Standard-Fired] m_mac_vpn_tip_site-exclusion_shown ["appVersion": "1.115.0", "pixelSource": "browser-dmg"]
17:07:14.716291+0100    47896: 0x290678 debug   com.duckduckgo.PixelKit DuckDuckGo  PixelKit    👾[Standard-Fired] m_mac_vpn_tip_site-exclusion_actioned ["appVersion": "1.115.0", "pixelSource": "browser-dmg"]
17:07:24.012298+0100    47896: 0x290678 debug   com.duckduckgo.PixelKit DuckDuckGo  PixelKit    👾[Standard-Fired] m_mac_vpn_tip_autoconnect_shown ["pixelSource": "browser-dmg", "appVersion": "1.115.0"]
17:07:25.525160+0100    47896: 0x290678 debug   com.duckduckgo.PixelKit DuckDuckGo  PixelKit    👾[Standard-Fired] m_mac_vpn_tip_autoconnect_ignored ["appVersion": "1.115.0", "pixelSource": "browser-dmg"]
17:07:50.759011+0100    47896: 0x290678 debug   com.duckduckgo.PixelKit DuckDuckGo  PixelKit    👾[Standard-Fired] m_mac_vpn_tip_autoconnect_actioned ["appVersion": "1.115.0", "pixelSource": "browser-dmg"]

Definition of Done:


Internal references:

Pull Request Review Checklist
Software Engineering Expectations
Technical Design Template
Pull Request Documentation

@diegoreymendez diegoreymendez changed the title Diego/add vpn tips Show VPN onboarding tips Oct 17, 2024
diegoreymendez added a commit to duckduckgo/iOS that referenced this pull request Oct 28, 2024
Copy link
Contributor

github-actions bot commented Oct 28, 2024

Warnings
⚠️ PR has more than 500 lines of code changing. Consider splitting into smaller PRs if possible.

Generated by 🚫 dangerJS against d1bb000

@@ -19,7 +19,7 @@
import AppKit
import Foundation

public struct SiteTroubleshootingInfo {
public struct ActiveSiteInfo {
Copy link
Contributor Author

@diegoreymendez diegoreymendez Nov 19, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a rename because the original name didn't describe this very well and this is really describing what's the active site.

Comment on lines +185 to +190
let tipsModel = VPNTipsModel(featureFlagPublisher: tipsFeatureFlagPublisher,
statusObserver: statusReporter.statusObserver,
activeSitePublisher: activeSitePublisher,
forMenuApp: false,
vpnSettings: vpnSettings,
logger: Logger(subsystem: "DuckDuckGo", category: "TipKit"))
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A new model for handling the tips.

Comment on lines +35 to +37
guard settings.connectOnLogin != connectOnLogin else {
return
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To prevent an infinite loop when the change is coming from a different place. I actually got this to happen when enabling connect on login from the tips.

Comment on lines +126 to +127
subscribeToConnectOnLoginSettingChanges()
subscribeToExcludeLocalNetworksSettingChanges()
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These were missing so if settings was open, the checkboxes weren't refreshing live.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Damn, really good catch - thanks!

@@ -375,6 +375,10 @@ final class DuckDuckGoVPNAppDelegate: NSObject, NSApplicationDelegate {
// Load cached config (if any)
privacyConfigurationManager.reload(etag: configurationStore.loadEtag(for: .privacyConfiguration), data: configurationStore.loadData(for: .privacyConfiguration))

// It's important for this to be set-up after the privacy configuration is loaded
// as it relies on it for the remote feature flag.
TipKitAppEventHandler(featureFlagger: featureFlagger).appDidFinishLaunching()
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Even though we're not showing tips in the VPN menu app, I left this in, in hopes we'll be able to eventually enable it again.

import Combine
import Foundation

public final class CurrentValuePublisher<Output, Failure: Error> {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could be moved to shared space, or be replaced with CurrentValueSubject if we don't mind it being mutable.

The gist of it is I wanted to have an initial value to use for the UI and avoid flickering (there still is some we can improve using this).

@@ -28,14 +28,14 @@ extension LottieView where Placeholder: View {
let loopEndFrame: AnimationFrameTime
}

public func playing(withIntro timing: LoopWithIntroTiming, isAnimating: Binding<Bool> = .constant(true)) -> Lottie.LottieView<Placeholder> {
public func playing(withIntro timing: LoopWithIntroTiming, isAnimating: Bool = true) -> Lottie.LottieView<Placeholder> {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method wasn't using the binding at all, just the wrapped value... so we might as well just request a Bool instead and offer a cleaner method.

Comment on lines +149 to +151
let tipsFeatureFlagPublisher = CurrentValuePublisher<Bool, Never>(
initialValue: false,
publisher: Just(false).eraseToAnyPublisher())
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Feature flag disabled, but we could wire this easily to test.

Comment on lines -37 to +48
@Published
public var isVPNEnabled = false
///
public var isVPNEnabled: Bool {
get {
switch connectionStatus {
case .connected, .connecting:
return true
default:
return false
}
}
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to store the same state twice if this can be a calculated var.

Comment on lines -150 to -158
Task { @MainActor in
self.connectionStatus = status
switch status {
case .connected, .connecting:
self.isVPNEnabled = true
default:
self.isVPNEnabled = false
}
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was duplicated in the code I simplified above... so it can now be reduced and simplified.

.store(in: &cancellables)
}

private func subscribeToServerInfoChanges() {
statusReporter.serverInfoObserver.publisher
.subscribe(on: Self.serverInfoDispatchQueue)
.receive(on: DispatchQueue.main)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moving all to the main dispatch queue because I was getting odd flickering in the status view.

Comment on lines -85 to -88
private static let statusDispatchQueue = DispatchQueue(label: "com.duckduckgo.NetworkProtectionStatusView.statusDispatchQueue", qos: .userInteractive)
private static let connectivityIssuesDispatchQueue = DispatchQueue(label: "com.duckduckgo.NetworkProtectionStatusView.connectivityIssuesDispatchQueue", qos: .userInteractive)
private static let serverInfoDispatchQueue = DispatchQueue(label: "com.duckduckgo.NetworkProtectionStatusView.serverInfoDispatchQueue", qos: .userInteractive)
private static let dataVolumeDispatchQueue = DispatchQueue(label: "com.duckduckgo.NetworkProtectionStatusView.dataVolumeDispatchQueue", qos: .userInteractive)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Most of these are for refreshing the UI so I moved everything to the main queue.

@@ -180,7 +166,6 @@ public final class TunnelControllerViewModel: ObservableObject {

private func subscribeToDataVolumeUpdates() {
statusReporter.dataVolumeObserver.publisher
.subscribe(on: Self.dataVolumeDispatchQueue)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note do self: I have to dispatch this on main queue.

Comment on lines +30 to +31
@EnvironmentObject
private var tipsModel: VPNTipsModel
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note to self: the tips model should likely be handled by the main models. Would be cleaner.

@diegoreymendez diegoreymendez self-assigned this Nov 20, 2024
@diegoreymendez diegoreymendez marked this pull request as ready for review November 20, 2024 16:40
Copy link
Collaborator

@samsymons samsymons left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don;t have any major issues here, the feature is working nicely for me. I also tested with the feature flag disabled, which worked as expected. Great work pushing through the issues to get this implementation over the line!

@diegoreymendez diegoreymendez merged commit 79f07a8 into main Nov 28, 2024
20 checks passed
@diegoreymendez diegoreymendez deleted the diego/add-vpn-tips branch November 28, 2024 22:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants