From b9279ce709ff96e190063d0a0af03c72c83e1137 Mon Sep 17 00:00:00 2001 From: Doug Date: Tue, 5 Sep 2023 17:21:53 +0100 Subject: [PATCH] Initial skeleton for Universal Link handling. --- .../Sources/Application/AppCoordinator.swift | 42 ++++++++++++------- .../Application/AppCoordinatorProtocol.swift | 1 + .../Sources/Application/Application.swift | 1 + .../UITests/UITestsAppCoordinator.swift | 4 ++ .../UnitTests/UnitTestsAppCoordinator.swift | 4 ++ 5 files changed, 37 insertions(+), 15 deletions(-) diff --git a/ElementX/Sources/Application/AppCoordinator.swift b/ElementX/Sources/Application/AppCoordinator.swift index 591c11d7d..a8bfe6294 100644 --- a/ElementX/Sources/Application/AppCoordinator.swift +++ b/ElementX/Sources/Application/AppCoordinator.swift @@ -24,6 +24,7 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationCoordinatorDelegate, private let stateMachine: AppCoordinatorStateMachine private let navigationRootCoordinator: NavigationRootCoordinator private let userSessionStore: UserSessionStoreProtocol + private let appSettings: AppSettings /// Common background task to continue long-running tasks in the background. private var backgroundTask: BackgroundTaskProtocol? @@ -71,6 +72,8 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationCoordinatorDelegate, AppSettings.reset() } + self.appSettings = appSettings + navigationRootCoordinator = NavigationRootCoordinator() Self.setupServiceLocator(navigationRootCoordinator: navigationRootCoordinator, appSettings: appSettings) @@ -88,7 +91,7 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationCoordinatorDelegate, userSessionStore = UserSessionStore(backgroundTaskService: backgroundTaskService) notificationManager = NotificationManager(notificationCenter: UNUserNotificationCenter.current(), - appSettings: ServiceLocator.shared.settings) + appSettings: appSettings) notificationManager.delegate = self notificationManager.start() @@ -96,13 +99,13 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationCoordinatorDelegate, fatalError("The app's version number **must** use semver for migration purposes.") } - if let previousVersion = ServiceLocator.shared.settings.lastVersionLaunched.flatMap(Version.init) { + if let previousVersion = appSettings.lastVersionLaunched.flatMap(Version.init) { performMigrationsIfNecessary(from: previousVersion, to: currentVersion) } else { // The app has been deleted since the previous run. Reset everything. wipeUserData(includingSettings: true) } - ServiceLocator.shared.settings.lastVersionLaunched = currentVersion.description + appSettings.lastVersionLaunched = currentVersion.description setupStateMachine() @@ -132,6 +135,15 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationCoordinatorDelegate, ) } + func handleUniversalLink(_ url: URL) { + // Parse into an AppRoute to redirect these in a type safe way. + + // Until we have an OIDC callback AppRoute, handle it manually. + if url.absoluteString.starts(with: appSettings.oidcRedirectURL.absoluteString) { + MXLog.error("OIDC callback through Universal Links not implemented.") + } + } + // MARK: - AuthenticationCoordinatorDelegate func authenticationCoordinator(_ authenticationCoordinator: AuthenticationCoordinator, didLoginWithSession userSession: UserSessionProtocol) { @@ -207,13 +219,13 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationCoordinatorDelegate, ServiceLocator.shared.register(userIndicatorController: UserIndicatorController(rootCoordinator: navigationRootCoordinator)) ServiceLocator.shared.register(appSettings: appSettings) ServiceLocator.shared.register(networkMonitor: NetworkMonitor()) - ServiceLocator.shared.register(bugReportService: BugReportService(withBaseURL: ServiceLocator.shared.settings.bugReportServiceBaseURL, - sentryURL: ServiceLocator.shared.settings.bugReportSentryURL, - applicationId: ServiceLocator.shared.settings.bugReportApplicationId, + ServiceLocator.shared.register(bugReportService: BugReportService(withBaseURL: appSettings.bugReportServiceBaseURL, + sentryURL: appSettings.bugReportSentryURL, + applicationId: appSettings.bugReportApplicationId, sdkGitSHA: sdkGitSha(), - maxUploadSize: ServiceLocator.shared.settings.bugReportMaxUploadSize)) + maxUploadSize: appSettings.bugReportMaxUploadSize)) ServiceLocator.shared.register(analytics: AnalyticsService(client: PostHogAnalyticsClient(), - appSettings: ServiceLocator.shared.settings, + appSettings: appSettings, bugReportService: ServiceLocator.shared.bugReportService)) } @@ -231,7 +243,7 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationCoordinatorDelegate, if oldVersion < Version(1, 1, 7) { MXLog.info("Migrating to v1.1.0, marking accounts as migrated.") for userID in userSessionStore.userIDs { - ServiceLocator.shared.settings.migratedAccounts[userID] = true + appSettings.migratedAccounts[userID] = true } } } @@ -300,10 +312,10 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationCoordinatorDelegate, private func startAuthentication() { let authenticationNavigationStackCoordinator = NavigationStackCoordinator() - let authenticationService = AuthenticationServiceProxy(userSessionStore: userSessionStore, appSettings: ServiceLocator.shared.settings) + let authenticationService = AuthenticationServiceProxy(userSessionStore: userSessionStore, appSettings: appSettings) authenticationCoordinator = AuthenticationCoordinator(authenticationService: authenticationService, navigationStackCoordinator: authenticationNavigationStackCoordinator, - appSettings: ServiceLocator.shared.settings, + appSettings: appSettings, analytics: ServiceLocator.shared.analytics, userIndicatorController: ServiceLocator.shared.userIndicatorController) authenticationCoordinator?.delegate = self @@ -329,7 +341,7 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationCoordinatorDelegate, userDisplayName: displayName, deviceID: userSession.deviceID) - let authenticationService = AuthenticationServiceProxy(userSessionStore: userSessionStore, appSettings: ServiceLocator.shared.settings) + let authenticationService = AuthenticationServiceProxy(userSessionStore: userSessionStore, appSettings: appSettings) _ = await authenticationService.configure(for: userSession.homeserver) let parameters = SoftLogoutScreenCoordinatorParameters(authenticationService: authenticationService, @@ -361,7 +373,7 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationCoordinatorDelegate, navigationSplitCoordinator: navigationSplitCoordinator, bugReportService: ServiceLocator.shared.bugReportService, roomTimelineControllerFactory: RoomTimelineControllerFactory(), - appSettings: ServiceLocator.shared.settings, + appSettings: appSettings, analytics: ServiceLocator.shared.analytics) userSessionFlowCoordinator.callback = { [weak self] action in @@ -668,7 +680,7 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationCoordinatorDelegate, // MARK: Background app refresh private func registerBackgroundAppRefresh() { - let result = BGTaskScheduler.shared.register(forTaskWithIdentifier: ServiceLocator.shared.settings.backgroundAppRefreshTaskIdentifier, using: .main) { [weak self] task in + let result = BGTaskScheduler.shared.register(forTaskWithIdentifier: appSettings.backgroundAppRefreshTaskIdentifier, using: .main) { [weak self] task in guard let task = task as? BGAppRefreshTask else { MXLog.error("Invalid background app refresh configuration") return @@ -681,7 +693,7 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationCoordinatorDelegate, } private func scheduleBackgroundAppRefresh() { - let request = BGAppRefreshTaskRequest(identifier: ServiceLocator.shared.settings.backgroundAppRefreshTaskIdentifier) + let request = BGAppRefreshTaskRequest(identifier: appSettings.backgroundAppRefreshTaskIdentifier) // We have other background tasks that keep the app alive request.earliestBeginDate = Date(timeIntervalSinceNow: 30) diff --git a/ElementX/Sources/Application/AppCoordinatorProtocol.swift b/ElementX/Sources/Application/AppCoordinatorProtocol.swift index 4cff930e3..0915c220e 100644 --- a/ElementX/Sources/Application/AppCoordinatorProtocol.swift +++ b/ElementX/Sources/Application/AppCoordinatorProtocol.swift @@ -18,4 +18,5 @@ import Foundation protocol AppCoordinatorProtocol: CoordinatorProtocol { var notificationManager: NotificationManagerProtocol { get } + func handleUniversalLink(_ url: URL) } diff --git a/ElementX/Sources/Application/Application.swift b/ElementX/Sources/Application/Application.swift index b300b1d62..ea98ace65 100644 --- a/ElementX/Sources/Application/Application.swift +++ b/ElementX/Sources/Application/Application.swift @@ -35,6 +35,7 @@ struct Application: App { WindowGroup { appCoordinator.toPresentable() .statusBarHidden(shouldHideStatusBar) + .onOpenURL { appCoordinator.handleUniversalLink($0) } .introspect(.window, on: .iOS(.v16)) { window in // Workaround for SwiftUI not consistently applying the tint colour to Alerts/Confirmation Dialogs. window.tintColor = .compound.textActionPrimary diff --git a/ElementX/Sources/UITests/UITestsAppCoordinator.swift b/ElementX/Sources/UITests/UITestsAppCoordinator.swift index c82837815..67320e757 100644 --- a/ElementX/Sources/UITests/UITestsAppCoordinator.swift +++ b/ElementX/Sources/UITests/UITestsAppCoordinator.swift @@ -60,6 +60,10 @@ class UITestsAppCoordinator: AppCoordinatorProtocol { func toPresentable() -> AnyView { navigationRootCoordinator.toPresentable() } + + func handleUniversalLink(_ url: URL) { + fatalError("Not implemented.") + } } @MainActor diff --git a/ElementX/Sources/UnitTests/UnitTestsAppCoordinator.swift b/ElementX/Sources/UnitTests/UnitTestsAppCoordinator.swift index 0ae1ab250..1191f2f6c 100644 --- a/ElementX/Sources/UnitTests/UnitTestsAppCoordinator.swift +++ b/ElementX/Sources/UnitTests/UnitTestsAppCoordinator.swift @@ -36,4 +36,8 @@ class UnitTestsAppCoordinator: AppCoordinatorProtocol { func toPresentable() -> AnyView { AnyView(ProgressView("Running Unit Tests")) } + + func handleUniversalLink(_ url: URL) { + fatalError("Not implemented.") + } }