From 673b9fa45d6c37bd00eb79004ef7654423d649fb Mon Sep 17 00:00:00 2001 From: Hwee-Boon Yar Date: Fri, 21 Oct 2022 12:44:00 +0800 Subject: [PATCH] [Refactor] Move all code in AppDelegate to AppCoordinator --- AlphaWallet/AppCoordinator.swift | 73 ++++++++++++++++++- AlphaWallet/AppDelegate.swift | 65 +++-------------- .../Coordinators/AppCoordinatorTests.swift | 27 +++++-- 3 files changed, 98 insertions(+), 67 deletions(-) diff --git a/AlphaWallet/AppCoordinator.swift b/AlphaWallet/AppCoordinator.swift index a045991ca..c6e39ebe2 100644 --- a/AlphaWallet/AppCoordinator.swift +++ b/AlphaWallet/AppCoordinator.swift @@ -3,6 +3,7 @@ import Combine import UIKit import PromiseKit +import AlphaWalletAddress import AlphaWalletCore import AlphaWalletFoundation import AlphaWalletTrackAPICalls @@ -135,7 +136,32 @@ class AppCoordinator: NSObject, Coordinator { private lazy var sessionProvider = SessionsProvider(config: config, analytics: analytics) private let securedStorage: SecuredPasswordStorage & SecuredStorage - init(window: UIWindow, analytics: AnalyticsServiceType, keystore: Keystore, walletAddressesStore: WalletAddressesStore, navigationController: UINavigationController = .withOverridenBarAppearence(), securedStorage: SecuredPasswordStorage & SecuredStorage) throws { + private let addressStorage: FileAddressStorage + + //Unfortunate to have to have a factory method and not be able to use an initializer (because we can't override `init()` to throw) + static func create() throws -> AppCoordinator { + crashlytics.register(AlphaWallet.FirebaseCrashlyticsReporter.instance) + applyStyle() + + let window = UIWindow(frame: UIScreen.main.bounds) + let analytics = AnalyticsService() + let walletAddressesStore: WalletAddressesStore = EtherKeystore.migratedWalletAddressesStore(userDefaults: .standardOrForTests) + let securedStorage: SecuredStorage & SecuredPasswordStorage = try KeychainStorage() + let keystore: Keystore = EtherKeystore(keychain: securedStorage, walletAddressesStore: walletAddressesStore, analytics: analytics) + + let navigationController: UINavigationController = .withOverridenBarAppearence() + navigationController.view.backgroundColor = Colors.appWhite + + let result = try AppCoordinator(window: window, analytics: analytics, keystore: keystore, walletAddressesStore: walletAddressesStore, navigationController: navigationController, securedStorage: securedStorage) + result.keystore.delegate = result + return result + } + + init(window: UIWindow, analytics: AnalyticsServiceType, keystore: Keystore, walletAddressesStore: WalletAddressesStore, navigationController: UINavigationController, securedStorage: SecuredPasswordStorage & SecuredStorage) throws { + let addressStorage = FileAddressStorage() + register(addressStorage: addressStorage) + + self.addressStorage = addressStorage self.navigationController = navigationController self.window = window self.analytics = analytics @@ -166,7 +192,7 @@ class AppCoordinator: NSObject, Coordinator { }.store(in: &cancelable) } - func start() { + func start(launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) { //Want to start as soon as possible if AlphaWallet.Device.isSimulator { TrackApiCalls.shared.start() @@ -197,6 +223,20 @@ class AppCoordinator: NSObject, Coordinator { } assetDefinitionStore.delegate = self + + if let shortcutItem = launchOptions?[UIApplication.LaunchOptionsKey.shortcutItem] as? UIApplicationShortcutItem, shortcutItem.type == Constants.launchShortcutKey { + //Delay needed to work because app is launching.. + DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { + self.launchUniversalScanner() + } + } + } + + func applicationPerformActionFor(_ shortcutItem: UIApplicationShortcutItem, completionHandler: @escaping (Bool) -> Void) { + if shortcutItem.type == Constants.launchShortcutKey { + launchUniversalScanner() + } + completionHandler(true) } func applicationWillResignActive() { @@ -216,6 +256,31 @@ class AppCoordinator: NSObject, Coordinator { protectionCoordinator.applicationWillEnterForeground() } + func applicationShouldAllowExtensionPointIdentifier(_ extensionPointIdentifier: UIApplication.ExtensionPointIdentifier) -> Bool { + if extensionPointIdentifier == .keyboard { + return false + } + return true + } + + func applicationOpenUrl(_ url: URL, options: [UIApplication.OpenURLOptionsKey: Any] = [:]) -> Bool { + return handleUniversalLink(url: url, source: .customUrlScheme) + } + + func applicationContinueUserActivity(_ userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool { + let hasHandledIntent = handleIntent(userActivity: userActivity) + if hasHandledIntent { + return true + } + + var handled = false + if let url = userActivity.webpageURL { + handled = handleUniversalLink(url: url, source: .deeplink) + } + //TODO: if we handle other types of URLs, check if handled==false, then we pass the url to another handlers + return handled + } + private func setupSplashViewController(on navigationController: UINavigationController) { navigationController.viewControllers = [ SplashViewController() @@ -347,7 +412,7 @@ class AppCoordinator: NSObject, Coordinator { } /// Return true if handled - @discardableResult func handleUniversalLink(url: URL, source: UrlSource) -> Bool { + @discardableResult private func handleUniversalLink(url: URL, source: UrlSource) -> Bool { createInitialWalletIfMissing() showActiveWalletIfNeeded() @@ -375,7 +440,7 @@ class AppCoordinator: NSObject, Coordinator { activeWalletCoordinator?.didPressOpenWebPage(url, in: viewController) } - func handleIntent(userActivity: NSUserActivity) -> Bool { + private func handleIntent(userActivity: NSUserActivity) -> Bool { if let type = userActivity.userInfo?[WalletQrCodeDonation.userInfoType.key] as? String, type == WalletQrCodeDonation.userInfoType.value { analytics.log(navigation: Analytics.Navigation.openShortcut, properties: [ Analytics.Properties.type.rawValue: Analytics.ShortcutType.walletQrCode.rawValue diff --git a/AlphaWallet/AppDelegate.swift b/AlphaWallet/AppDelegate.swift index a0e331837..3383d128f 100644 --- a/AlphaWallet/AppDelegate.swift +++ b/AlphaWallet/AppDelegate.swift @@ -1,53 +1,24 @@ -// Copyright SIX DAY LLC. All rights reserved. +// Copyright © 2022 Stormbird PTE. LTD. + import UIKit -import AlphaWalletAddress -import AlphaWalletFoundation @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { - var window: UIWindow? private var appCoordinator: AppCoordinator! - private let addressStorage = FileAddressStorage() func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { - crashlytics.register(AlphaWallet.FirebaseCrashlyticsReporter.instance) - - applyStyle() - window = UIWindow(frame: UIScreen.main.bounds) - do { - register(addressStorage: addressStorage) - - let analytics = AnalyticsService() - let walletAddressesStore: WalletAddressesStore = EtherKeystore.migratedWalletAddressesStore(userDefaults: .standardOrForTests) - let securedStorage: SecuredStorage & SecuredPasswordStorage = try KeychainStorage() - var keystore: Keystore = EtherKeystore(keychain: securedStorage, walletAddressesStore: walletAddressesStore, analytics: analytics) - - let navigationController: UINavigationController = .withOverridenBarAppearence() - navigationController.view.backgroundColor = Colors.appWhite - - appCoordinator = try AppCoordinator(window: window!, analytics: analytics, keystore: keystore, walletAddressesStore: walletAddressesStore, navigationController: navigationController, securedStorage: securedStorage) - keystore.delegate = appCoordinator - appCoordinator.start() - - if let shortcutItem = launchOptions?[UIApplication.LaunchOptionsKey.shortcutItem] as? UIApplicationShortcutItem, shortcutItem.type == Constants.launchShortcutKey { - //Delay needed to work because app is launching.. - DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { - self.appCoordinator.launchUniversalScanner() - } - } + appCoordinator = try AppCoordinator.create() + appCoordinator.start(launchOptions: launchOptions) } catch { - + //no-op } return true } func application(_ application: UIApplication, performActionFor shortcutItem: UIApplicationShortcutItem, completionHandler: @escaping (Bool) -> Void) { - if shortcutItem.type == Constants.launchShortcutKey { - appCoordinator.launchUniversalScanner() - } - completionHandler(true) + appCoordinator.applicationPerformActionFor(shortcutItem, completionHandler: completionHandler) } func applicationWillResignActive(_ application: UIApplication) { @@ -67,37 +38,19 @@ class AppDelegate: UIResponder, UIApplicationDelegate { } func application(_ application: UIApplication, shouldAllowExtensionPointIdentifier extensionPointIdentifier: UIApplication.ExtensionPointIdentifier) -> Bool { - if extensionPointIdentifier == .keyboard { - return false - } - return true + return appCoordinator.applicationShouldAllowExtensionPointIdentifier(extensionPointIdentifier) } // URI scheme links and AirDrop func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey: Any] = [:]) -> Bool { - return handleUniversalLink(url: url, source: .customUrlScheme) + return appCoordinator.applicationOpenUrl(url, options: options) } func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool { - let hasHandledIntent = appCoordinator.handleIntent(userActivity: userActivity) - if hasHandledIntent { - return true - } - - var handled = false - if let url = userActivity.webpageURL { - handled = handleUniversalLink(url: url, source: .deeplink) - } - //TODO: if we handle other types of URLs, check if handled==false, then we pass the url to another handlers - return handled + return appCoordinator.applicationContinueUserActivity(userActivity, restorationHandler: restorationHandler) } func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) { //no op } - - private func handleUniversalLink(url: URL, source: UrlSource) -> Bool { - let handled = appCoordinator.handleUniversalLink(url: url, source: source) - return handled - } } diff --git a/AlphaWalletTests/Coordinators/AppCoordinatorTests.swift b/AlphaWalletTests/Coordinators/AppCoordinatorTests.swift index 41dc758f5..9b65a6143 100644 --- a/AlphaWalletTests/Coordinators/AppCoordinatorTests.swift +++ b/AlphaWalletTests/Coordinators/AppCoordinatorTests.swift @@ -19,7 +19,10 @@ class AppCoordinatorTests: XCTestCase { window: UIWindow(), analytics: FakeAnalyticsService(), keystore: FakeEtherKeystore(), - walletAddressesStore: fakeWalletAddressesStore(wallets: [.make()]), securedStorage: KeychainStorage.make()) + walletAddressesStore: fakeWalletAddressesStore(wallets: [.make()]), + navigationController: FakeNavigationController(), + securedStorage: KeychainStorage.make() + ) XCTAssertTrue(coordinator.navigationController.viewControllers[0].isSplashScreen) coordinator.start() @@ -39,7 +42,8 @@ class AppCoordinatorTests: XCTestCase { recentlyUsedWallet: .make() ), walletAddressesStore: fakeWalletAddressesStore(wallets: [.make()]), - navigationController: FakeNavigationController(), securedStorage: KeychainStorage.make() + navigationController: FakeNavigationController(), + securedStorage: KeychainStorage.make() ) coordinator.start() @@ -62,7 +66,9 @@ class AppCoordinatorTests: XCTestCase { wallets: [.make()], recentlyUsedWallet: .make() ), - walletAddressesStore: fakeWalletAddressesStore(wallets: [.make()]), securedStorage: KeychainStorage.make() + walletAddressesStore: fakeWalletAddressesStore(wallets: [.make()]), + navigationController: FakeNavigationController(), + securedStorage: KeychainStorage.make() ) coordinator.start() coordinator.reset() @@ -83,7 +89,8 @@ class AppCoordinatorTests: XCTestCase { recentlyUsedWallet: .make() ), walletAddressesStore: fakeWalletAddressesStore(wallets: [.make()]), - navigationController: FakeNavigationController(), securedStorage: KeychainStorage.make() + navigationController: FakeNavigationController(), + securedStorage: KeychainStorage.make() ) coordinator.start() coordinator.showInitialWalletCoordinator() @@ -104,7 +111,8 @@ class AppCoordinatorTests: XCTestCase { recentlyUsedWallet: .make() ), walletAddressesStore: fakeWalletAddressesStore(wallets: [.make()]), - navigationController: FakeNavigationController(), securedStorage: KeychainStorage.make() + navigationController: FakeNavigationController(), + securedStorage: KeychainStorage.make() ) coordinator.start() @@ -127,7 +135,9 @@ class AppCoordinatorTests: XCTestCase { wallets: [.make()], recentlyUsedWallet: .make() ), - walletAddressesStore: fakeWalletAddressesStore(wallets: [.make()]), securedStorage: KeychainStorage.make() + walletAddressesStore: fakeWalletAddressesStore(wallets: [.make()]), + navigationController: FakeNavigationController(), + securedStorage: KeychainStorage.make() ) coordinator.start() @@ -144,7 +154,10 @@ class AppCoordinatorTests: XCTestCase { window: .init(), analytics: FakeAnalyticsService(), keystore: FakeEtherKeystore(), - walletAddressesStore: fakeWalletAddressesStore(wallets: [.make()]), securedStorage: KeychainStorage.make()) + walletAddressesStore: fakeWalletAddressesStore(wallets: [.make()]), + navigationController: FakeNavigationController(), + securedStorage: KeychainStorage.make() + ) coordinator.start()