Skip to content

Commit

Permalink
Ugly hack to get the waitlist working, now needs refinement and tests.
Browse files Browse the repository at this point in the history
  • Loading branch information
samsymons committed Aug 13, 2023
1 parent edc7754 commit 9677df5
Show file tree
Hide file tree
Showing 12 changed files with 117 additions and 12 deletions.
8 changes: 8 additions & 0 deletions DuckDuckGo/AppDelegate/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,14 @@ final class AppDelegate: NSObject, NSApplicationDelegate, FileDownloadManagerDel
func applicationDidBecomeActive(_ notification: Notification) {
syncService?.initializeIfNeeded(isInternalUser: internalUserDecider?.isInternalUser ?? false)
syncService?.scheduler.notifyAppLifecycleEvent()

NetworkProtectionWaitlist.shared.fetchInviteCodeIfAvailable { error in
if error != nil {
print("DEBUG: Got error fetching invite code: \(String(describing: error))")
} else {
print("DEBUG: Got invite code!")
}
}
}

func applicationShouldTerminate(_ sender: NSApplication) -> NSApplication.TerminateReply {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "Toolbar Button.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
Binary file not shown.
2 changes: 1 addition & 1 deletion DuckDuckGo/Menus/MainMenu.swift
Original file line number Diff line number Diff line change
Expand Up @@ -292,7 +292,7 @@ final class MainMenu: NSMenu {
#if NETWORK_PROTECTION
let networkProtectionFeatureVisibility: NetworkProtectionFeatureVisibility = NetworkProtectionKeychainTokenStore()
if #available(macOS 11.4, *),
networkProtectionFeatureVisibility.isFeatureActivated {
networkProtectionFeatureVisibility.isFeatureActivated || true { // TODO: Check for waitlist feature flag
toggleNetworkProtectionShortcutMenuItem?.isHidden = false
toggleNetworkProtectionShortcutMenuItem?.title = LocalPinningManager.shared.toggleShortcutInterfaceTitle(for: .networkProtection)
} else {
Expand Down
2 changes: 1 addition & 1 deletion DuckDuckGo/NavigationBar/View/MoreOptionsMenu.swift
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ final class MoreOptionsMenu: NSMenu {
.withSubmenu(EmailOptionsButtonSubMenu(tabCollectionViewModel: tabCollectionViewModel, emailManager: emailManager))

#if NETWORK_PROTECTION
if networkProtectionFeatureVisibility.isFeatureActivated {
if networkProtectionFeatureVisibility.isFeatureActivated || true { // TODO: Add waitlist flag check
addItem(withTitle: UserText.networkProtection, action: #selector(showNetworkProtectionStatus(_:)), keyEquivalent: "")
.targetting(self)
.withImage(.image(for: .vpnIcon))
Expand Down
33 changes: 29 additions & 4 deletions DuckDuckGo/NavigationBar/View/NavigationBarViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ final class NavigationBarViewController: NSViewController {
listenToMessageNotifications()
subscribeToDownloads()
addContextMenu()
subscribeToActivateNotification()

optionsButton.sendAction(on: .leftMouseDown)
bookmarkListButton.sendAction(on: .leftMouseDown)
Expand Down Expand Up @@ -269,9 +270,27 @@ final class NavigationBarViewController: NSViewController {
}

#if NETWORK_PROTECTION
private func subscribeToActivateNotification() {
NotificationCenter.default.addObserver(forName: .networkProtectionWaitlistShowPopover, object: nil, queue: .main) { _ in
if #available(macOS 11.4, *) {
self.showNetworkProtectionPopover()
}
}
}

@available(macOS 11.4, *)
@IBAction func networkProtectionButtonAction(_ sender: NSButton) {
popovers.toggleNetworkProtectionPopover(usingView: networkProtectionButton, withDelegate: networkProtectionButtonModel)
showNetworkProtectionPopover()
}

@available(macOS 11.4, *)
private func showNetworkProtectionPopover() {
let viewModel = WaitlistViewModel(waitlist: NetworkProtectionWaitlist.shared)
if NetworkProtectionWaitlist.shared.waitlistStorage.isInvited && !viewModel.acceptedNetworkProtectionTermsAndConditions {
WaitlistModalViewController.show()
} else {
popovers.toggleNetworkProtectionPopover(usingView: networkProtectionButton, withDelegate: networkProtectionButtonModel)
}
}
#endif

Expand Down Expand Up @@ -704,7 +723,7 @@ extension NavigationBarViewController: NSMenuDelegate {
#if NETWORK_PROTECTION
let isPopUpWindow = view.window?.isPopUpWindow ?? false

if !isPopUpWindow && networkProtectionFeatureVisibility.isFeatureActivated {
if !isPopUpWindow && (networkProtectionFeatureVisibility.isFeatureActivated || true) { // TODO: Check for waitlist flag
let networkProtectionTitle = LocalPinningManager.shared.toggleShortcutInterfaceTitle(for: .networkProtection)
menu.addItem(withTitle: networkProtectionTitle, action: #selector(toggleNetworkProtectionPanelPinning), keyEquivalent: "N")
}
Expand Down Expand Up @@ -797,8 +816,14 @@ extension NavigationBarViewController: OptionsButtonMenuDelegate {
func optionsButtonMenuRequestedNetworkProtectionPopover(_ menu: NSMenu) {
#if NETWORK_PROTECTION
print("SHOWING NETP")
WaitlistModalViewController.show()
// showNetworkProtectionStatus()
let viewModel = WaitlistViewModel(waitlist: NetworkProtectionWaitlist.shared)
if NetworkProtectionKeychainTokenStore().isFeatureActivated {
showNetworkProtectionStatus()
} else if NetworkProtectionWaitlist.shared.waitlistStorage.isInvited && viewModel.acceptedNetworkProtectionTermsAndConditions {
showNetworkProtectionStatus()
} else {
WaitlistModalViewController.show()
}
#else
fatalError("Tried to open Network Protection when it was disabled")
#endif
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,11 +101,17 @@ final class NetworkProtectionNavBarButtonModel: NSObject, ObservableObject {
setupIconSubscription()
setupStatusSubscription()
setupInterruptionSubscription()
setupWaitlistAvailabilitySubscription()
}

private func setupIconSubscription() {
iconPublisherCancellable = iconPublisher.$icon.sink { [weak self] icon in
self?.buttonImage = .image(for: icon)
let viewModel = WaitlistViewModel(waitlist: NetworkProtectionWaitlist.shared)
if NetworkProtectionWaitlist.shared.waitlistStorage.isInvited && !viewModel.acceptedNetworkProtectionTermsAndConditions {
self?.buttonImage = NSImage(named: "NetworkProtectionAvailableButton")! // .image(for: icon)
} else {
self?.buttonImage = .image(for: icon)
}
}
}

Expand Down Expand Up @@ -135,8 +141,23 @@ final class NetworkProtectionNavBarButtonModel: NSObject, ObservableObject {
}
}

private func setupWaitlistAvailabilitySubscription() {
NotificationCenter.default.addObserver(forName: .networkProtectionWaitlistAccessChanged, object: nil, queue: .main) { _ in
self.buttonImage = NSImage(named: "NetworkProtectionAvailableButton")!
self.updateVisibility()
}
}

@MainActor
private func updateVisibility() {
let waitlist = NetworkProtectionWaitlist.shared
let viewModel = WaitlistViewModel(waitlist: waitlist)

if waitlist.waitlistStorage.isInvited && !viewModel.acceptedNetworkProtectionTermsAndConditions {
showButton = true
return
}

guard !isPinned,
!popovers.isNetworkProtectionPopoverShown else {
showButton = true
Expand Down
11 changes: 9 additions & 2 deletions DuckDuckGo/Waitlist/Models/WaitlistViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ public final class WaitlistViewModel: ObservableObject {
case showTermsAndConditions
case acceptTermsAndConditions
case close
case closeAndPresentNetworkProtectionPopover
}

enum NotificationPermissionState {
Expand All @@ -51,8 +52,8 @@ public final class WaitlistViewModel: ObservableObject {

@Published var viewState: ViewState

@UserDefaultsWrapper(key: .spellingCheckEnabledOnce, defaultValue: false)
private var acceptedNetworkProtectionTermsAndConditions: Bool
@UserDefaultsWrapper(key: .networkProtectionTermsAndConditionsAccepted, defaultValue: false)
var acceptedNetworkProtectionTermsAndConditions: Bool

weak var delegate: WaitlistViewModelDelegate?

Expand Down Expand Up @@ -94,6 +95,12 @@ public final class WaitlistViewModel: ObservableObject {
case .showTermsAndConditions: showTermsAndConditions()
case .acceptTermsAndConditions: acceptTermsAndConditions()
case .close: close()
case .closeAndPresentNetworkProtectionPopover:
close()

DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
NotificationCenter.default.post(name: .networkProtectionWaitlistShowPopover, object: nil)
}
}
}

Expand Down
1 change: 0 additions & 1 deletion DuckDuckGo/Waitlist/Views/WaitlistRootView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ struct WaitlistRootView: View {

@State var viewHeight: CGFloat = 0.0 {
didSet {
print("DEBUG: Got new view height in root view: \(viewHeight)")
sizeChanged(viewHeight)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ struct EnableNetworkProtectionView: View {
}
} buttons: {
Button("Got It") {
model.perform(action: .close)
model.perform(action: .closeAndPresentNetworkProtectionPopover)
}
.buttonStyle(DefaultActionButtonStyle(enabled: true))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,31 @@ import SwiftUI
import SwiftUIExtensions

struct NetworkProtectionTermsAndConditionsView: View {

static func terms() -> String {
return """
Privacy Policy
• We don’t ask for any personal information from you in order to use this beta service.
• This Privacy Policy is for our limited waitlist beta VPN product.
• Our main Privacy Policy also applies here.
We don’t keep any logs of your online activity.
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:
• Website visits
• DNS requests
• Connections made
• IP addresses used
• Session lengths
We only keep anonymous performance metrics that we cannot connect to your online activity.
• 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.
We 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.
"""
}

@EnvironmentObject var model: WaitlistViewModel

var body: some View {
Expand All @@ -31,7 +56,7 @@ struct NetworkProtectionTermsAndConditionsView: View {

Group {
ScrollView {
Text("TODO: actual terms and conditions go here")
Text(Self.terms())
}
.padding(20.0)
}
Expand Down
8 changes: 8 additions & 0 deletions DuckDuckGo/Waitlist/Waitlist.swift
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,13 @@ public enum WaitlistInviteCodeFetchError: Error, Equatable {
}
}

extension Notification.Name {

static let networkProtectionWaitlistAccessChanged = Notification.Name(rawValue: "networkProtectionWaitlistAccessChanged")
static let networkProtectionWaitlistShowPopover = Notification.Name(rawValue: "networkProtectionWaitlistShowPopover")

}

public extension Waitlist {

func fetchInviteCodeIfAvailable() async -> WaitlistInviteCodeFetchError? {
Expand Down Expand Up @@ -89,6 +96,7 @@ public extension Waitlist {
switch inviteCodeResult {
case .success(let inviteCode):
waitlistStorage.store(inviteCode: inviteCode.code)
NotificationCenter.default.post(name: .networkProtectionWaitlistAccessChanged, object: nil)
completion(nil)
case .failure(let inviteCodeError):
completion(.failure(inviteCodeError))
Expand Down

0 comments on commit 9677df5

Please sign in to comment.