diff --git a/FlowCrypt/Common UI/AttachmentManager.swift b/FlowCrypt/Common UI/AttachmentManager.swift index e32027cff..92908597d 100644 --- a/FlowCrypt/Common UI/AttachmentManager.swift +++ b/FlowCrypt/Common UI/AttachmentManager.swift @@ -9,6 +9,7 @@ import UIKit import Combine +@MainActor protocol AttachmentManagerType { func open(_ attachment: MessageAttachment) } @@ -49,13 +50,19 @@ extension AttachmentManager: AttachmentManagerType { .sinkFuture( receiveValue: {}, receiveError: { [weak self] error in - self?.controller?.showToast( - "\("message_attachment_saved_with_error".localized) \(error.localizedDescription)" - ) + self?.handle(error) } ) .store(in: &self.cancellable) } + + private func handle(_ error: Error) { + Task { + await controller?.showToast( + "\("message_attachment_saved_with_error".localized) \(error.localizedDescription)" + ) + } + } } // MARK: - FilesManagerPresenter diff --git a/FlowCrypt/Common UI/Refreshable.swift b/FlowCrypt/Common UI/Refreshable.swift index a633b10de..0f3d07269 100644 --- a/FlowCrypt/Common UI/Refreshable.swift +++ b/FlowCrypt/Common UI/Refreshable.swift @@ -8,7 +8,7 @@ import Foundation - protocol Refreshable { - - func startRefreshing() - } +@MainActor +protocol Refreshable { + func startRefreshing() +} diff --git a/FlowCrypt/Controllers/Compose/ComposeViewController.swift b/FlowCrypt/Controllers/Compose/ComposeViewController.swift index 339644693..92d9cb2ec 100644 --- a/FlowCrypt/Controllers/Compose/ComposeViewController.swift +++ b/FlowCrypt/Controllers/Compose/ComposeViewController.swift @@ -21,7 +21,6 @@ private struct ComposedDraft: Equatable { * - User can be redirected here from *InboxViewController* by tapping on *+* * - Or from *ThreadDetailsViewController* controller by tapping on *reply* **/ -@MainActor final class ComposeViewController: TableNodeViewController { private lazy var logger = Logger.nested(Self.self) @@ -932,7 +931,6 @@ extension ComposeViewController: PHPickerViewControllerDelegate { }) } } - } } diff --git a/FlowCrypt/Controllers/Inbox/Container/InboxViewContainerController.swift b/FlowCrypt/Controllers/Inbox/Container/InboxViewContainerController.swift index c2f877cc8..9e7c26a6f 100644 --- a/FlowCrypt/Controllers/Inbox/Container/InboxViewContainerController.swift +++ b/FlowCrypt/Controllers/Inbox/Container/InboxViewContainerController.swift @@ -32,7 +32,7 @@ final class InboxViewContainerController: TableNodeViewController { let folderService: FoldersServiceType let decorator: InboxViewControllerContainerDecorator - @MainActor private var state: State = .loading { + private var state: State = .loading { didSet { handleNewState() } } @@ -68,7 +68,7 @@ final class InboxViewContainerController: TableNodeViewController { } } - @MainActor private func handleFetched(folders: [FolderViewModel]) { + private func handleFetched(folders: [FolderViewModel]) { guard folders.isNotEmpty else { state = .empty return diff --git a/FlowCrypt/Controllers/Inbox/InboxViewController+Factory.swift b/FlowCrypt/Controllers/Inbox/InboxViewController+Factory.swift index fb14c4967..8abf182ac 100644 --- a/FlowCrypt/Controllers/Inbox/InboxViewController+Factory.swift +++ b/FlowCrypt/Controllers/Inbox/InboxViewController+Factory.swift @@ -10,6 +10,7 @@ import Foundation import UIKit class InboxViewControllerFactory { + @MainActor static func make(with viewModel: InboxViewModel) -> InboxViewController { guard let currentAuthType = DataService.shared.currentAuthType else { fatalError("Internal inconsistency") diff --git a/FlowCrypt/Controllers/Inbox/InboxViewController.swift b/FlowCrypt/Controllers/Inbox/InboxViewController.swift index b3fa24a47..d1e173e79 100644 --- a/FlowCrypt/Controllers/Inbox/InboxViewController.swift +++ b/FlowCrypt/Controllers/Inbox/InboxViewController.swift @@ -7,6 +7,7 @@ import FlowCryptCommon import FlowCryptUI import Foundation +@MainActor final class InboxViewController: ASDKViewController { private lazy var logger = Logger.nested(Self.self) diff --git a/FlowCrypt/Controllers/MessageList Extension/MsgListViewController.swift b/FlowCrypt/Controllers/MessageList Extension/MsgListViewController.swift index 2866b2622..c768d426c 100644 --- a/FlowCrypt/Controllers/MessageList Extension/MsgListViewController.swift +++ b/FlowCrypt/Controllers/MessageList Extension/MsgListViewController.swift @@ -8,6 +8,7 @@ import UIKit +@MainActor protocol MsgListViewController { func open(with message: InboxRenderable, path: String) @@ -30,11 +31,9 @@ extension MsgListViewController where Self: UIViewController { private func openDraft(with message: Message) { guard let email = DataService.shared.email else { return } - Task { - let controller = await ComposeViewController(email: email) - await controller.updateWithMessage(message: message) - await navigationController?.pushViewController(controller, animated: true) - } + let controller = ComposeViewController(email: email) + controller.updateWithMessage(message: message) + navigationController?.pushViewController(controller, animated: true) } private func openMsg(with message: Message, path: String) { diff --git a/FlowCrypt/Controllers/Settings/Backup/Backups Option Scene/BackupOptionsViewController.swift b/FlowCrypt/Controllers/Settings/Backup/Backups Option Scene/BackupOptionsViewController.swift index 388107fab..8c8644223 100644 --- a/FlowCrypt/Controllers/Settings/Backup/Backups Option Scene/BackupOptionsViewController.swift +++ b/FlowCrypt/Controllers/Settings/Backup/Backups Option Scene/BackupOptionsViewController.swift @@ -21,6 +21,7 @@ enum BackupOption: Int, CaseIterable, Equatable { } } +@MainActor final class BackupOptionsViewController: ASDKViewController { enum Parts: Int, CaseIterable { case email, download, action, info diff --git a/FlowCrypt/Controllers/Settings/Backup/Backups Scene/BackupViewController.swift b/FlowCrypt/Controllers/Settings/Backup/Backups Scene/BackupViewController.swift index 75eb944b3..a77747db9 100644 --- a/FlowCrypt/Controllers/Settings/Backup/Backups Scene/BackupViewController.swift +++ b/FlowCrypt/Controllers/Settings/Backup/Backups Scene/BackupViewController.swift @@ -9,6 +9,7 @@ import AsyncDisplayKit import FlowCryptUI +@MainActor final class BackupViewController: ASDKViewController { private enum Parts: Int, CaseIterable { case info, action diff --git a/FlowCrypt/Controllers/Settings/Backup/Backups Seleckt Key Scene/BackupSelectKeyViewController.swift b/FlowCrypt/Controllers/Settings/Backup/Backups Seleckt Key Scene/BackupSelectKeyViewController.swift index 0c3d7c680..5aca0a769 100644 --- a/FlowCrypt/Controllers/Settings/Backup/Backups Seleckt Key Scene/BackupSelectKeyViewController.swift +++ b/FlowCrypt/Controllers/Settings/Backup/Backups Seleckt Key Scene/BackupSelectKeyViewController.swift @@ -10,6 +10,7 @@ import AsyncDisplayKit import FlowCryptUI import Foundation +@MainActor final class BackupSelectKeyViewController: ASDKViewController { private let backupService: BackupServiceType private let service: ServiceActor diff --git a/FlowCrypt/Controllers/Settings/KeySettings/Key List/KeySettingsViewController.swift b/FlowCrypt/Controllers/Settings/KeySettings/Key List/KeySettingsViewController.swift index b6bb36ae1..8fae926bf 100644 --- a/FlowCrypt/Controllers/Settings/KeySettings/Key List/KeySettingsViewController.swift +++ b/FlowCrypt/Controllers/Settings/KeySettings/Key List/KeySettingsViewController.swift @@ -15,7 +15,6 @@ import FlowCryptUI * - User can proceed to importing keys *SetupManuallyImportKeyViewController* * - User can see detail information for the key in *KeyDetailViewController* */ -@MainActor final class KeySettingsViewController: TableNodeViewController { private var keys: [KeyDetails] = [] private let decorator: KeySettingsViewDecorator diff --git a/FlowCrypt/Controllers/Setup/PassPhraseSaveable.swift b/FlowCrypt/Controllers/Setup/PassPhraseSaveable.swift index d8772e9d6..2c054724f 100644 --- a/FlowCrypt/Controllers/Setup/PassPhraseSaveable.swift +++ b/FlowCrypt/Controllers/Setup/PassPhraseSaveable.swift @@ -8,6 +8,7 @@ import FlowCryptUI +@MainActor protocol PassPhraseSaveable { var storageMethod: StorageMethod { get set } var passPhraseIndexes: [IndexPath] { get } diff --git a/FlowCrypt/Controllers/Setup/SetupGenerateKeyViewController.swift b/FlowCrypt/Controllers/Setup/SetupGenerateKeyViewController.swift index 9dcef28a2..d4aaf7b85 100644 --- a/FlowCrypt/Controllers/Setup/SetupGenerateKeyViewController.swift +++ b/FlowCrypt/Controllers/Setup/SetupGenerateKeyViewController.swift @@ -28,7 +28,6 @@ enum CreateKeyError: Error { * - Here user can enter a pass phrase (can be saved in memory or in encrypted storage) and generate a key * - After key is generated, user will be redirected to **main flow** (inbox view) */ -@MainActor final class SetupGenerateKeyViewController: SetupCreatePassphraseAbstractViewController { private let backupService: BackupServiceType diff --git a/FlowCrypt/Controllers/Setup/SetupManuallyImportKeyViewController.swift b/FlowCrypt/Controllers/Setup/SetupManuallyImportKeyViewController.swift index fcba07ec9..3f6d31dd0 100644 --- a/FlowCrypt/Controllers/Setup/SetupManuallyImportKeyViewController.swift +++ b/FlowCrypt/Controllers/Setup/SetupManuallyImportKeyViewController.swift @@ -78,9 +78,7 @@ final class SetupManuallyImportKeyViewController: TableNodeViewController { } private func updateSubtitle() { - DispatchQueue.main.async { - self.node.reloadRows(at: [Parts.description.indexPath], with: .fade) - } + node.reloadRows(at: [Parts.description.indexPath], with: .fade) } } diff --git a/FlowCrypt/Controllers/SetupImap/SetupImapViewController.swift b/FlowCrypt/Controllers/SetupImap/SetupImapViewController.swift index 0e50ca8d6..278272c62 100644 --- a/FlowCrypt/Controllers/SetupImap/SetupImapViewController.swift +++ b/FlowCrypt/Controllers/SetupImap/SetupImapViewController.swift @@ -509,13 +509,9 @@ extension SetupImapViewController { do { try await self.imap.connectImap(session: imapSessionToCheck) try await self.imap.connectSmtp(session: smtpSession) - DispatchQueue.main.async { - self.handleSuccessfulConnection() - } + handleSuccessfulConnection() } catch { - DispatchQueue.main.async { - self.handleConnection(error: error) - } + handleConnection(error: error) } } } diff --git a/FlowCrypt/Controllers/SideMenu/Main/SideMenuNavigationController.swift b/FlowCrypt/Controllers/SideMenu/Main/SideMenuNavigationController.swift index 2637f56a0..c5579f0fb 100644 --- a/FlowCrypt/Controllers/SideMenu/Main/SideMenuNavigationController.swift +++ b/FlowCrypt/Controllers/SideMenu/Main/SideMenuNavigationController.swift @@ -6,6 +6,7 @@ import ENSwiftSideMenu import FlowCryptUI import UIKit +@MainActor protocol SideMenuViewController { func didOpen() } diff --git a/FlowCrypt/Controllers/SideMenu/Menu/MyMenuViewController.swift b/FlowCrypt/Controllers/SideMenu/Menu/MyMenuViewController.swift index 8bdd4a061..499c80351 100644 --- a/FlowCrypt/Controllers/SideMenu/Menu/MyMenuViewController.swift +++ b/FlowCrypt/Controllers/SideMenu/Menu/MyMenuViewController.swift @@ -13,6 +13,7 @@ import FlowCryptUI * On tap on each folder user should be redirected to `InboxViewController` with selected folder * On settings tap user will be redirected to `SettingsViewController` */ +@MainActor final class MyMenuViewController: ASDKViewController { private enum Constants { static let allMail = "folder_all_mail".localized @@ -174,13 +175,9 @@ extension MyMenuViewController { Task { do { let folders = try await foldersProvider.fetchFolders(isForceReload: true) - DispatchQueue.main.async { - self.handleNewFolders(with: folders) - } + handleNewFolders(with: folders) } catch { - DispatchQueue.main.async { - self.handleError(with: error) - } + handleError(with: error) } } } diff --git a/FlowCrypt/Controllers/SideMenu/NavigationController/NavigationChildController.swift b/FlowCrypt/Controllers/SideMenu/NavigationController/NavigationChildController.swift index 4d4f4fd13..dd27c2bb3 100644 --- a/FlowCrypt/Controllers/SideMenu/NavigationController/NavigationChildController.swift +++ b/FlowCrypt/Controllers/SideMenu/NavigationController/NavigationChildController.swift @@ -8,6 +8,7 @@ import UIKit +@MainActor protocol NavigationChildController { var navigationItem: UINavigationItem { get } var shouldShowBackButton: Bool { get } diff --git a/FlowCrypt/Controllers/Threads/MessageActionsHandler.swift b/FlowCrypt/Controllers/Threads/MessageActionsHandler.swift index e1d20e543..f751229be 100644 --- a/FlowCrypt/Controllers/Threads/MessageActionsHandler.swift +++ b/FlowCrypt/Controllers/Threads/MessageActionsHandler.swift @@ -10,6 +10,7 @@ import UIKit import FlowCryptUI import FlowCryptCommon +@MainActor protocol MessageActionsHandler: AnyObject { var currentFolderPath: String { get } var trashFolderProvider: TrashFolderProviderType { get } @@ -33,9 +34,7 @@ extension MessageActionsHandler where Self: UIViewController { Task { do { let path = try await trashFolderProvider.getTrashFolderPath() - DispatchQueue.main.async { - self.setupNavigationBarItems(with: path) - } + setupNavigationBarItems(with: path) } catch { // todo - handle? logger.logError("setupNavigationBar: \(error)") @@ -95,22 +94,18 @@ extension MessageActionsHandler where Self: UIViewController { Task { do { let trashPath = try await trashFolderProvider.getTrashFolderPath() - DispatchQueue.main.async { - guard let trashPath = trashPath else { - return - } - if self.currentFolderPath.caseInsensitiveCompare(trashPath) == .orderedSame { - self.awaitUserConfirmation { [weak self] in - self?.permanentlyDelete() - } - } else { - self.moveToTrash(with: trashPath) + guard let trashPath = trashPath else { + return + } + if self.currentFolderPath.caseInsensitiveCompare(trashPath) == .orderedSame { + self.awaitUserConfirmation { [weak self] in + self?.permanentlyDelete() } + } else { + self.moveToTrash(with: trashPath) } } catch { - DispatchQueue.main.async { - self.showToast(error.localizedDescription) - } + showToast(error.localizedDescription) } } } diff --git a/FlowCrypt/Extensions/UIViewController+Spinner.swift b/FlowCrypt/Extensions/UIViewController+Spinner.swift index f8d3cdf8a..32f01b5ee 100644 --- a/FlowCrypt/Extensions/UIViewController+Spinner.swift +++ b/FlowCrypt/Extensions/UIViewController+Spinner.swift @@ -5,7 +5,7 @@ // Created by Roma Sosnovsky on 25/10/21 // Copyright © 2017-present FlowCrypt a. s. All rights reserved. // - + import MBProgressHUD import UIKit @@ -14,47 +14,44 @@ extension UIViewController { MBProgressHUD.forView(view) ?? MBProgressHUD.showAdded(to: view, animated: true) } + @MainActor func showSpinner(_ message: String = "loading_title".localized, isUserInteractionEnabled: Bool = false) { - DispatchQueue.main.async { - guard self.view.subviews.first(where: { $0 is MBProgressHUD }) == nil else { - // hud is already shown - return - } - self.view.isUserInteractionEnabled = isUserInteractionEnabled - - let spinner = MBProgressHUD.showAdded(to: self.view, animated: true) - spinner.label.text = message - spinner.isUserInteractionEnabled = isUserInteractionEnabled + guard self.view.subviews.first(where: { $0 is MBProgressHUD }) == nil else { + // hud is already shown + return } + self.view.isUserInteractionEnabled = isUserInteractionEnabled + + let spinner = MBProgressHUD.showAdded(to: self.view, animated: true) + spinner.label.text = message + spinner.isUserInteractionEnabled = isUserInteractionEnabled } + @MainActor func updateSpinner(label: String = "compose_uploading".localized, progress: Float? = nil, systemImageName: String? = nil) { - DispatchQueue.main.async { - if let progress = progress { - if progress >= 1, let imageName = systemImageName { - self.updateSpinner(label: "compose_sent".localized, - systemImageName: imageName) - } else { - self.showProgressHUD(progress: progress, label: label) - } - } else if let imageName = systemImageName { - self.showProgressHUDWithCustomImage(imageName: imageName, label: label) + if let progress = progress { + if progress >= 1, let imageName = systemImageName { + self.updateSpinner(label: "compose_sent".localized, + systemImageName: imageName) } else { - self.currentProgressHUD.mode = .indeterminate - self.currentProgressHUD.label.text = label + self.showProgressHUD(progress: progress, label: label) } + } else if let imageName = systemImageName { + self.showProgressHUDWithCustomImage(imageName: imageName, label: label) + } else { + self.currentProgressHUD.mode = .indeterminate + self.currentProgressHUD.label.text = label } } + @MainActor func hideSpinner() { - DispatchQueue.main.async { - self.view.subviews - .compactMap { $0 as? MBProgressHUD } - .forEach { $0.hide(animated: true) } - self.view.isUserInteractionEnabled = true - } + self.view.subviews + .compactMap { $0 as? MBProgressHUD } + .forEach { $0.hide(animated: true) } + self.view.isUserInteractionEnabled = true } } diff --git a/FlowCrypt/Extensions/UIViewControllerExtensions.swift b/FlowCrypt/Extensions/UIViewControllerExtensions.swift index 49e4c7278..a09a8d9a8 100644 --- a/FlowCrypt/Extensions/UIViewControllerExtensions.swift +++ b/FlowCrypt/Extensions/UIViewControllerExtensions.swift @@ -20,6 +20,7 @@ extension UIViewController { /// - duration: Toast presented duration. Default is 3.0 /// - position: Bottom by default. Can be top, center, bottom. /// - completion: Notify when toast dissapeared + @MainActor func showToast( _ message: String, title: String? = nil, @@ -27,24 +28,22 @@ extension UIViewController { position: ToastPosition = .bottom, completion: ShowToastCompletion? = nil ) { - DispatchQueue.main.async { - guard let view = UIApplication.shared.keyWindow?.rootViewController?.view else { - assertionFailure("Key window hasn't rootViewController") - return - } - view.hideAllToasts() - view.endEditing(true) + guard let view = UIApplication.shared.keyWindow?.rootViewController?.view else { + assertionFailure("Key window hasn't rootViewController") + return + } + view.hideAllToasts() + view.endEditing(true) - view.makeToast( - message, - duration: duration, - position: position, - title: title, - completion: completion - ) + view.makeToast( + message, + duration: duration, + position: position, + title: title, + completion: completion + ) - ToastManager.shared.isTapToDismissEnabled = true - } + ToastManager.shared.isTapToDismissEnabled = true } } @@ -72,30 +71,28 @@ extension UIViewController { showAlert(message: formatted, onOk: onOk) } + @MainActor func showAlert(title: String? = "Error", message: String, onOk: (() -> Void)? = nil) { - DispatchQueue.main.async { - self.view.hideAllToasts() - self.hideSpinner() - let alert = UIAlertController(title: title, message: message, preferredStyle: .alert) - alert.addAction(UIAlertAction(title: "OK", style: .destructive) { _ in onOk?() }) - self.present(alert, animated: true, completion: nil) - } + self.view.hideAllToasts() + hideSpinner() + let alert = UIAlertController(title: title, message: message, preferredStyle: .alert) + alert.addAction(UIAlertAction(title: "OK", style: .destructive) { _ in onOk?() }) + self.present(alert, animated: true, completion: nil) } + @MainActor func showRetryAlert( title: String? = "Error", message: String, onRetry: (() -> Void)? = nil, onOk: (() -> Void)? = nil ) { - DispatchQueue.main.async { - self.view.hideAllToasts() - self.hideSpinner() - let alert = UIAlertController(title: title, message: message, preferredStyle: .alert) - alert.addAction(UIAlertAction(title: "Retry", style: .cancel) { _ in onRetry?() }) - alert.addAction(UIAlertAction(title: "OK", style: .default) { _ in onOk?() }) - self.present(alert, animated: true, completion: nil) - } + self.view.hideAllToasts() + hideSpinner() + let alert = UIAlertController(title: title, message: message, preferredStyle: .alert) + alert.addAction(UIAlertAction(title: "Retry", style: .cancel) { _ in onRetry?() }) + alert.addAction(UIAlertAction(title: "OK", style: .default) { _ in onOk?() }) + present(alert, animated: true, completion: nil) } func keyboardHeight(from notification: Notification) -> CGFloat { diff --git a/FlowCrypt/Functionality/Error Handling/ErrorHandler.swift b/FlowCrypt/Functionality/Error Handling/ErrorHandler.swift index 518dccb49..aa7cbcc17 100644 --- a/FlowCrypt/Functionality/Error Handling/ErrorHandler.swift +++ b/FlowCrypt/Functionality/Error Handling/ErrorHandler.swift @@ -24,6 +24,7 @@ extension UIViewController { } // MARK: - ErrorHandler +@MainActor protocol ErrorHandler { func handle(error: Error, for viewController: UIViewController) -> Bool } diff --git a/FlowCrypt/Functionality/Mail Provider/UsersMailSession Provider/UserMailSessionProvider.swift b/FlowCrypt/Functionality/Mail Provider/UsersMailSession Provider/UserMailSessionProvider.swift index a67f7cbdc..e7fe7382d 100644 --- a/FlowCrypt/Functionality/Mail Provider/UsersMailSession Provider/UserMailSessionProvider.swift +++ b/FlowCrypt/Functionality/Mail Provider/UsersMailSession Provider/UserMailSessionProvider.swift @@ -12,7 +12,6 @@ protocol UsersMailSessionProvider { // MARK: - GmailService extension GmailService: UsersMailSessionProvider { - @discardableResult func renewSession() async throws { try await userService.renewSession() } @@ -20,8 +19,7 @@ extension GmailService: UsersMailSessionProvider { // MARK: - Imap extension Imap: UsersMailSessionProvider { - @discardableResult func renewSession() async throws { - try await self.setupSession() + setupSession() } } diff --git a/FlowCrypt/Functionality/Services/GlobalRouter.swift b/FlowCrypt/Functionality/Services/GlobalRouter.swift index 11657e79e..f3be6cf75 100644 --- a/FlowCrypt/Functionality/Services/GlobalRouter.swift +++ b/FlowCrypt/Functionality/Services/GlobalRouter.swift @@ -9,11 +9,12 @@ import FlowCryptCommon import UIKit +@MainActor protocol GlobalRouterType { - @MainActor func proceed() - @MainActor func signIn(with route: GlobalRoutingType) - @MainActor func switchActive(user: User) - @MainActor func signOut() + func proceed() + func signIn(with route: GlobalRoutingType) + func switchActive(user: User) + func signOut() } enum GlobalRoutingType { @@ -28,9 +29,9 @@ enum GlobalRoutingError: Error { } // MARK: - GlobalRouter -final class GlobalRouter: GlobalRouterType { +final class GlobalRouter { - @MainActor private var keyWindow: UIWindow { + private var keyWindow: UIWindow { let application = UIApplication.shared guard let delegate = (application.delegate as? AppDelegate) else { fatalError("missing AppDelegate in GlobalRouter.reset()") @@ -53,55 +54,16 @@ final class GlobalRouter: GlobalRouterType { } // MARK: - Proceed -extension GlobalRouter { +extension GlobalRouter: GlobalRouterType { /// proceed to flow (signing/setup/app) depends on user status (isLoggedIn/isSetupFinished) - @MainActor func proceed() { + func proceed() { validateEncryptedStorage { userAccountService.cleanupSessions() proceed(with: nil) } } - @MainActor private func validateEncryptedStorage(_ completion: () -> Void) { - let storage = EncryptedStorage() - do { - try storage.validate() - completion() - } catch { - let controller = InvalidStorageViewController( - error: error, - encryptedStorage: storage, - router: self - ) - keyWindow.rootViewController = UINavigationController(rootViewController: controller) - keyWindow.makeKeyAndVisible() - } - } - - @MainActor private func proceed(with session: SessionType?) { - logger.logInfo("proceed for session \(session.debugDescription)") - - Task { - AppStartup().initializeApp(window: keyWindow, session: session) - } - } - - @MainActor private func handleGmailError(_ error: Error) { - logger.logInfo("gmail login failed with error \(error.localizedDescription)") - if let gmailUserError = error as? GoogleUserServiceError, - case .userNotAllowedAllNeededScopes(let missingScopes) = gmailUserError { - DispatchQueue.main.async { - let topNavigation = (self.keyWindow.rootViewController as? UINavigationController) - let checkAuthViewControlelr = CheckAuthScopesViewController(missingScopes: missingScopes) - topNavigation?.pushViewController(checkAuthViewControlelr, animated: true) - } - } - } -} - -// MARK: - -extension GlobalRouter { - @MainActor func signIn(with route: GlobalRoutingType) { + func signIn(with route: GlobalRoutingType) { logger.logInfo("Sign in with \(route)") switch route { @@ -121,7 +83,7 @@ extension GlobalRouter { } } - @MainActor func signOut() { + func signOut() { if let session = userAccountService.startActiveSessionForNextUser() { logger.logInfo("Start session for another email user \(session)") proceed(with: session) @@ -132,7 +94,7 @@ extension GlobalRouter { } } - @MainActor func switchActive(user: User) { + func switchActive(user: User) { logger.logInfo("Switching active user \(user)") guard let session = userAccountService.switchActiveSessionFor(user: user) else { logger.logWarning("Can't switch active user with \(user.email)") @@ -140,4 +102,37 @@ extension GlobalRouter { } proceed(with: session) } + + private func validateEncryptedStorage(_ completion: () -> Void) { + let storage = EncryptedStorage() + do { + try storage.validate() + completion() + } catch { + let controller = InvalidStorageViewController( + error: error, + encryptedStorage: storage, + router: self + ) + keyWindow.rootViewController = UINavigationController(rootViewController: controller) + keyWindow.makeKeyAndVisible() + } + } + + @MainActor + private func proceed(with session: SessionType?) { + logger.logInfo("proceed for session \(session.debugDescription)") + AppStartup().initializeApp(window: keyWindow, session: session) + } + + @MainActor + private func handleGmailError(_ error: Error) { + logger.logInfo("gmail login failed with error \(error.localizedDescription)") + if let gmailUserError = error as? GoogleUserServiceError, + case .userNotAllowedAllNeededScopes(let missingScopes) = gmailUserError { + let topNavigation = (self.keyWindow.rootViewController as? UINavigationController) + let checkAuthViewControlelr = CheckAuthScopesViewController(missingScopes: missingScopes) + topNavigation?.pushViewController(checkAuthViewControlelr, animated: true) + } + } } diff --git a/FlowCryptUI/Nodes/TableViewController.swift b/FlowCryptUI/Nodes/TableViewController.swift index 2ea4c50a0..d6506df1e 100644 --- a/FlowCryptUI/Nodes/TableViewController.swift +++ b/FlowCryptUI/Nodes/TableViewController.swift @@ -8,6 +8,7 @@ import AsyncDisplayKit +@MainActor open class TableNodeViewController: ASDKViewController { public override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { super.traitCollectionDidChange(previousTraitCollection)