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

Refactor app startup code - extracting services #3859

Open
wants to merge 17 commits into
base: main
Choose a base branch
from
Open
4 changes: 0 additions & 4 deletions DuckDuckGo.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -1034,7 +1034,6 @@
CBAD0F0A2CFF418F006267B8 /* AppShortcuts.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBAD0F092CFF4185006267B8 /* AppShortcuts.swift */; };
CBAD0F0C2CFF4EE1006267B8 /* AppDependencies.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBAD0F0B2CFF4EDD006267B8 /* AppDependencies.swift */; };
CBAD0F102D0062A7006267B8 /* UIService.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBAD0F0F2D0062A3006267B8 /* UIService.swift */; };
CBAD0F122D00F1C8006267B8 /* UNService.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBAD0F112D00F1C8006267B8 /* UNService.swift */; };
CBAD0F142D01EE45006267B8 /* SubscriptionService.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBAD0F132D01EE40006267B8 /* SubscriptionService.swift */; };
CBC83E3429B631780008E19C /* Configuration in Frameworks */ = {isa = PBXBuildFile; productRef = CBC83E3329B631780008E19C /* Configuration */; };
CBC88EE12C7F834300F0F8C5 /* SpecialErrorPageUserScriptTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBC88EE02C7F834300F0F8C5 /* SpecialErrorPageUserScriptTests.swift */; };
Expand Down Expand Up @@ -2979,7 +2978,6 @@
CBAD0F092CFF4185006267B8 /* AppShortcuts.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppShortcuts.swift; sourceTree = "<group>"; };
CBAD0F0B2CFF4EDD006267B8 /* AppDependencies.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDependencies.swift; sourceTree = "<group>"; };
CBAD0F0F2D0062A3006267B8 /* UIService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIService.swift; sourceTree = "<group>"; };
CBAD0F112D00F1C8006267B8 /* UNService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UNService.swift; sourceTree = "<group>"; };
CBAD0F132D01EE40006267B8 /* SubscriptionService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SubscriptionService.swift; sourceTree = "<group>"; };
CBB6B2542AF6D543006B777C /* lt */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = lt; path = lt.lproj/InfoPlist.strings; sourceTree = "<group>"; };
CBC7AB542AF6D583008CB798 /* ro */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ro; path = ro.lproj/InfoPlist.strings; sourceTree = "<group>"; };
Expand Down Expand Up @@ -5795,7 +5793,6 @@
CBF259552D3A960600AC63E4 /* SyncService.swift */,
CBF259532D3A4C1200AC63E4 /* CrashService.swift */,
CBAD0F0F2D0062A3006267B8 /* UIService.swift */,
CBAD0F112D00F1C8006267B8 /* UNService.swift */,
CBAD0F132D01EE40006267B8 /* SubscriptionService.swift */,
CBF259782D3FC36C00AC63E4 /* AutofillService.swift */,
CBF2597A2D414B6D00AC63E4 /* PersistenceService.swift */,
Expand Down Expand Up @@ -8053,7 +8050,6 @@
8505836E219F424500ED4EDB /* RoundedRectangleView.swift in Sources */,
EE8594992A44791C008A6D06 /* NetworkProtectionTunnelController.swift in Sources */,
1EEF123F2850A68A003DDE57 /* PrivacyInfoContainerView.swift in Sources */,
CBAD0F122D00F1C8006267B8 /* UNService.swift in Sources */,
CBF259582D3AA85900AC63E4 /* VPNService.swift in Sources */,
F4B0B796252CB35700830156 /* OnboardingWidgetsDetailsViewController.swift in Sources */,
CB258D1329A4F24E00DEBA24 /* ConfigurationStore.swift in Sources */,
Expand Down
11 changes: 5 additions & 6 deletions DuckDuckGo/AppLifecycle/AppStates/Launching.swift
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,8 @@ struct Launching: AppState {
private let didFinishLaunchingStartTime = CFAbsoluteTimeGetCurrent()

private let uiService: UIService
private let unService: UNService
private let syncService: SyncService
private let vpnService: VPNService = VPNService()
private let vpnService: VPNService
private let autofillService: AutofillService = AutofillService()
private let persistenceService = PersistenceService()
private let pixelKitService: PixelService
Expand Down Expand Up @@ -180,14 +179,15 @@ struct Launching: AppState {
}
}

let privacyConfigurationManager = ContentBlocking.shared.privacyConfigurationManager
syncService = SyncService(bookmarksDatabase: persistenceService.bookmarksDatabase)
remoteMessagingService = RemoteMessagingService(persistenceService: persistenceService,
appSettings: appSettings,
internalUserDecider: AppDependencyProvider.shared.internalUserDecider,
configurationStore: AppDependencyProvider.shared.configurationStore,
privacyConfigurationManager: ContentBlocking.shared.privacyConfigurationManager)
privacyConfigurationManager: privacyConfigurationManager)

subscriptionService = SubscriptionService(privacyConfigurationManager: ContentBlocking.shared.privacyConfigurationManager)
subscriptionService = SubscriptionService(privacyConfigurationManager: privacyConfigurationManager)

let homePageConfiguration = HomePageConfiguration(variantManager: AppDependencyProvider.shared.variantManager,
remoteMessagingClient: remoteMessagingService.remoteMessagingClient,
Expand Down Expand Up @@ -235,19 +235,18 @@ struct Launching: AppState {
let autoClear = AutoClear(worker: mainViewController)
self.autoClear = autoClear
let applicationState = application.applicationState
vpnService = VPNService(window: window)
Task { [vpnService] in
await autoClear.clearDataIfEnabled(applicationState: .init(with: applicationState))
await vpnService.installRedditSessionWorkaround()
}

unService = UNService(window: window, accountManager: accountManager)
uiService = UIService(window: window)

// Task handler registration needs to happen before the end of `didFinishLaunching`, otherwise submitting a task can throw an exception.
// Having both in `didBecomeActive` can sometimes cause the exception when running on a physical device, so registration happens here.
AppConfigurationFetch.registerBackgroundRefreshTaskHandler()

UNUserNotificationCenter.current().delegate = unService
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm not sure it's the best solution to encapsulate UserNotificationCenter inside VPN. Given VPNService conforms to UNUserNotificationCenterDelegate there can be NotificationService which holds an array of conforming instances, where one of those will be VPNService. This way those two are decoupled from each other and we're ready for easier handling of other cases outside of the VPN purpose. It's only a suggestion, since it may increase already quite big scope of the project.

window.windowScene?.screenshotService?.delegate = uiService
ThemeManager.shared.updateUserInterfaceStyle(window: window)

Expand Down
70 changes: 0 additions & 70 deletions DuckDuckGo/AppServices/UNService.swift

This file was deleted.

49 changes: 46 additions & 3 deletions DuckDuckGo/AppServices/VPNService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,10 @@
import NetworkProtection
import Subscription
import UIKit
import NotificationCenter
import Core

final class VPNService {
final class VPNService: NSObject {

private let tunnelController = AppDependencyProvider.shared.networkProtectionTunnelController
private let widgetRefreshModel = NetworkProtectionWidgetRefreshModel()
Expand All @@ -31,12 +33,19 @@ final class VPNService {
tunnelController: tunnelController)
private let vpnFeatureVisibility: DefaultNetworkProtectionVisibility = AppDependencyProvider.shared.vpnFeatureVisibility

private let window: UIWindow
private let accountManager: AccountManager
private let application: UIApplication
init(accountManager: AccountManager = AppDependencyProvider.shared.accountManager,
application: UIApplication = UIApplication.shared) {
init(window: UIWindow,
accountManager: AccountManager = AppDependencyProvider.shared.accountManager,
application: UIApplication = UIApplication.shared,
notificationCenter: UNUserNotificationCenter = .current()) {
self.window = window
self.accountManager = accountManager
self.application = application
super.init()

notificationCenter.delegate = self
}

func beginObservingVPNStatus() {
Expand Down Expand Up @@ -131,3 +140,37 @@ final class VPNService {
}

}

extension VPNService: UNUserNotificationCenterDelegate {

func userNotificationCenter(_ center: UNUserNotificationCenter,
willPresent notification: UNNotification,
withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
completionHandler(.banner)
}

func userNotificationCenter(_ center: UNUserNotificationCenter,
didReceive response: UNNotificationResponse,
withCompletionHandler completionHandler: @escaping () -> Void) {
if response.actionIdentifier == UNNotificationDefaultActionIdentifier {
let identifier = response.notification.request.identifier

if NetworkProtectionNotificationIdentifier(rawValue: identifier) != nil {
presentNetworkProtectionStatusSettingsModal()
}
}
completionHandler()
}

// TODO: should be moved to (future) AppCoordinator
private func presentNetworkProtectionStatusSettingsModal() {
Task { @MainActor in
if case .success(let hasEntitlements) = await accountManager.hasEntitlement(forProductName: .networkProtection), hasEntitlements {
(window.rootViewController as? MainViewController)?.segueToVPN()
} else {
(window.rootViewController as? MainViewController)?.segueToPrivacyPro()
}
}
}

}